Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
- OpenCode Review, Strix Security Scan, and PR Review Merge Scheduler are
organization-level required workflows from `ContextualWisdomLab/.github`.
Do not copy them into this repository.
- ScopeWeave's repository-local `opencode.jsonc` is development configuration,
not a replacement for the organization review workflow. It uses NVIDIA NIM
only and reads the process-local `NVIDIA_API_KEY` binding. Organization CI
owns secret injection and maps the organization `NVIDIA_NIM_API_KEY` secret
into that process binding; do not add a repository-local OpenCode workflow or
restore GitHub Models/COPILOT credentials to this configuration.
- Keep companion SCA workflows development-only; do not add runtime
dependencies.
- If GitHub CLI output emits Projects(classic) deprecation warnings,
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Switched the repository-local OpenCode development configuration from GitHub
Models to an NVIDIA NIM-only candidate set while preserving organization-level
review-workflow ownership in `ContextualWisdomLab/.github`.
- Accepted XML whitespace before exact Microsoft Project element delimiters
while preserving the linear, regex-free import scanner and rejecting
attributes, longer names, non-XML whitespace, nested unmatched blocks, and
Expand Down
35 changes: 17 additions & 18 deletions opencode.jsonc
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"$schema": "https://opencode.ai/config.json",
"model": "github-models/openai/gpt-5",
"small_model": "github-models/deepseek/deepseek-v3-0324",
"enabled_providers": ["github-models"],
"model": "nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5",
"small_model": "nvidia-nim/meta/llama-3.1-8b-instruct",
"enabled_providers": ["nvidia-nim"],
"mcp": {
"codegraph": {
"type": "local",
Expand Down Expand Up @@ -37,37 +37,36 @@
}
},
"provider": {
"github-models": {
"nvidia-nim": {
"npm": "@ai-sdk/openai-compatible",
"name": "GitHub Models",
"name": "NVIDIA NIM",
"options": {
"baseURL": "https://models.github.ai/inference",
"apiKey": "{env:STRIX_GITHUB_MODELS_TOKEN}"
"baseURL": "https://integrate.api.nvidia.com/v1",
"apiKey": "{env:NVIDIA_API_KEY}"
},
"models": {
"openai/gpt-5": {
"name": "OpenAI GPT-5",
"nvidia/llama-3.3-nemotron-super-49b-v1.5": {
"name": "NVIDIA Llama 3.3 Nemotron Super 49B v1.5",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 200000,
"output": 100000
"context": 131072,
"output": 65536
}
},
"deepseek/deepseek-r1-0528": {
"name": "DeepSeek R1 0528",
"meta/llama-3.1-8b-instruct": {
"name": "Meta Llama 3.1 8B Instruct (NIM)",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 128000,
"context": 131072,
"output": 4096
}
},
"deepseek/deepseek-v3-0324": {
"name": "DeepSeek V3 0324",
"meta/llama-3.3-70b-instruct": {
"name": "Meta Llama 3.3 70B Instruct (NIM)",
"tool_call": true,
"limit": {
"context": 128000,
"context": 131072,
"output": 4096
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"coverage": "npm run test:coverage",
"server": "node server/server.mjs",
"test:api": "node tests/api/auth-secret.test.mjs && node tests/api/smoke.mjs && node tests/api/ratelimit.test.mjs && node tests/api/attachment-status.test.mjs && node tests/api/session-revocation.test.mjs",
"test:unit": "node tests/unit/analytics.test.mjs && node tests/unit/cpm.test.mjs && node tests/unit/baseline-compare.test.mjs && node tests/unit/workload.test.mjs && node tests/unit/cost-evm.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && node tests/unit/dep-types.test.mjs && node tests/unit/weekly-report.test.mjs && node tests/unit/clearfolio.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/sprint-stats.test.mjs && node tests/unit/burndown.test.mjs && node tests/unit/pm-analysis.test.mjs && node tests/unit/cloud-sync-security.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/coverage-script-contract.test.mjs && node tests/unit/toast-accessibility.test.mjs",
"test:unit": "node tests/unit/opencode-config.test.mjs && node tests/unit/changelog-release-notes.test.mjs && node tests/unit/analytics.test.mjs && node tests/unit/cpm.test.mjs && node tests/unit/baseline-compare.test.mjs && node tests/unit/workload.test.mjs && node tests/unit/cost-evm.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && node tests/unit/dep-types.test.mjs && node tests/unit/weekly-report.test.mjs && node tests/unit/clearfolio.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/sprint-stats.test.mjs && node tests/unit/burndown.test.mjs && node tests/unit/pm-analysis.test.mjs && node tests/unit/cloud-sync-security.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/coverage-script-contract.test.mjs && node tests/unit/toast-accessibility.test.mjs",
"test:coverage": "c8 --all --include=app.js --include=cloud-sync.js --include=scripts/ci/static_coverage_evidence.mjs --include=server/attachment_status.mjs --include=server/app.mjs --include=server/auth.mjs --include=server/clearfolio.mjs --include=server/orchestrator.mjs --reporter=json --reporter=json-summary npm run test:coverage:cases",
"test:coverage:cases": "node tests/unit/coverage-script-contract.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && npm run test:api",
"test:e2e": "playwright test",
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/changelog-release-notes.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';

const changelog = readFileSync(new URL('../../CHANGELOG.md', import.meta.url), 'utf8');

test('released changelog versions keep their published notes', () => {
assert.match(changelog, /## \[1\.0\.0\] - 2026-04-20/);
assert.match(changelog, /Initial ScopeWeave Planner release with tree-table editing/);
assert.match(changelog, /## \[1\.0\.1\] - 2026-06-25/);
assert.match(changelog, /O\(1\) 해시맵\(Map\) 기반의 캐싱 조회 로직/);
});
41 changes: 41 additions & 0 deletions tests/unit/opencode-config.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import test from 'node:test';

const config = JSON.parse(readFileSync(new URL('../../opencode.jsonc', import.meta.url), 'utf8'));
const agents = readFileSync(new URL('../../AGENTS.md', import.meta.url), 'utf8');

test('OpenCode development config uses only currently hosted NVIDIA NIM candidates', () => {
assert.equal(config.model, 'nvidia-nim/nvidia/llama-3.3-nemotron-super-49b-v1.5');
assert.equal(config.small_model, 'nvidia-nim/meta/llama-3.1-8b-instruct');
assert.deepEqual(config.enabled_providers, ['nvidia-nim']);

const provider = config.provider?.['nvidia-nim'];
assert.ok(provider, 'NVIDIA NIM provider must be configured');
assert.equal(provider.options?.baseURL, 'https://integrate.api.nvidia.com/v1');
assert.equal(provider.options?.apiKey, '{env:NVIDIA_API_KEY}');
assert.ok(provider.models?.['nvidia/llama-3.3-nemotron-super-49b-v1.5']);
assert.ok(provider.models?.['meta/llama-3.1-8b-instruct']);
assert.ok(provider.models?.['meta/llama-3.3-70b-instruct']);
assert.equal(
provider.models['meta/llama-3.3-70b-instruct'].limit?.output,
4096,
'70B output must stay within the NVIDIA NIM max_tokens range of 1-4096',
);

const serialized = JSON.stringify(config);
assert.doesNotMatch(serialized, /github-models/i);
assert.doesNotMatch(serialized, /STRIX_GITHUB_MODELS_TOKEN/);
assert.doesNotMatch(serialized, /COPILOT_GITHUB_TOKEN/);
});

test('AGENTS.md keeps the local NVIDIA_API_KEY binding separate from the org NIM secret', () => {
assert.match(agents, /NVIDIA_API_KEY/);
assert.match(agents, /NVIDIA_NIM_API_KEY/);
assert.match(
agents,
/maps the organization `NVIDIA_NIM_API_KEY` secret/,
'org CI must map NVIDIA_NIM_API_KEY into the process-local NVIDIA_API_KEY binding',
);
assert.doesNotMatch(agents, /COPILOT_GITHUB_TOKEN/);
});
Loading