diff --git a/AGENTS.md b/AGENTS.md index 7a5b65ac..d1613bb0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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, diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f784cc4..53e6d29f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/opencode.jsonc b/opencode.jsonc index a5ab3396..a3cb617b 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -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", @@ -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 } } diff --git a/package.json b/package.json index 0162a1d4..dc32b12b 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/tests/unit/changelog-release-notes.test.mjs b/tests/unit/changelog-release-notes.test.mjs new file mode 100644 index 00000000..d886f3e1 --- /dev/null +++ b/tests/unit/changelog-release-notes.test.mjs @@ -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\) 기반의 캐싱 조회 로직/); +}); diff --git a/tests/unit/opencode-config.test.mjs b/tests/unit/opencode-config.test.mjs new file mode 100644 index 00000000..f95ff46f --- /dev/null +++ b/tests/unit/opencode-config.test.mjs @@ -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/); +});