sneakoscope 0.7.6 → 0.7.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![](https://github.com/mandarange/Sneakoscope-Codex/raw/dev/docs/assets/sneakoscope-codex-logo.png)
4
4
 
5
- Sneakoscope Codex (`sks`, displayed as `ㅅㅋㅅ`) is a Codex CLI/App harness for repeatable agent workflows. It adds terminal commands, Codex App `$` prompt commands, warp-native CLI workspaces, Team/QA/Research routes, inspectable pipeline plans, a maximum-speed Computer Use lane, a fast Goal bridge for native `/goal` persistence, Context7 evidence checks, DB safety, TriWiki context tracking, lightweight skill dreaming, Honest Mode, and release-readiness gates.
5
+ Sneakoscope Codex (`sks`, displayed as `ㅅㅋㅅ`) is a Codex CLI/App harness for repeatable agent workflows. It adds terminal commands, Codex App `$` prompt commands, tmux-native CLI workspaces, Team/QA/Research routes, inspectable pipeline plans, a maximum-speed Computer Use lane, a fast Goal bridge for native `/goal` persistence, Context7 evidence checks, DB safety, TriWiki context tracking, lightweight skill dreaming, Honest Mode, and release-readiness gates.
6
6
 
7
7
  ## Quick Start
8
8
 
@@ -43,17 +43,19 @@ sks selftest --mock
43
43
 
44
44
  | Area | What it does |
45
45
  | --- | --- |
46
- | CLI runtime | `sks warp open` and `sks --mad` explicitly launch Codex CLI with Warp; bare `sks` only prints help/readiness surfaces. |
47
- | Codex App commands | Installs generated skills so `$Team`, `$From-Chat-IMG`, `$DFix`, `$QA-LOOP`, `$Goal`, `$DB`, `$Wiki`, `$Help`, and related routes are visible in prompt workflows. |
46
+ | CLI runtime | `sks tmux open` and `sks --mad` explicitly launch Codex CLI with tmux; bare `sks` only prints help/readiness surfaces. |
47
+ | Codex App commands | Installs generated skills so `$Team`, `$From-Chat-IMG`, `$DFix`, `$QA-LOOP`, `$PPT`, `$Goal`, `$DB`, `$Wiki`, `$Help`, and related routes are visible in prompt workflows. |
48
48
  | Pipeline plans | Writes `pipeline-plan.json` for stateful routes so the runtime lane, kept stages, skipped stages, verification commands, and no-unrequested-fallback invariant are visible with `sks pipeline plan`. |
49
49
  | Team orchestration | Runs substantial work through ambiguity handling, scouts, TriWiki refresh, debate, runtime task graphs, worker inboxes, implementation, review, cleanup, reflection, and Honest Mode; narrow work should use Proof Field evidence to skip unrelated pipeline work instead of expanding Team. |
50
50
  | Skill dreaming | Records cheap generated-skill usage counters in JSON and only periodically scans `.agents/skills` for keep, merge, prune, and improvement candidates. Reports are recommendation-only and never delete skills automatically. |
51
51
  | From-Chat-IMG | Turns chat screenshots plus original attachments into source-bound work orders, then requires scoped QA evidence before completion. |
52
52
  | QA loop | Dogfoods UI/API behavior with safety gates, Codex Computer Use-only UI evidence, safe fixes, and rechecks. |
53
+ | PPT pipeline | Uses `$PPT` for simple, restrained, information-first HTML/PDF presentation artifacts, first asking delivery context, audience profile, STP strategy, decision context, and 3+ pain-point to solution/aha mappings before source research, design-system work, HTML/PDF export, and render QA. Independent strategy/render/file-write phases run in parallel where inputs allow and are recorded in `ppt-parallel-report.json`; editable source HTML is preserved under `source-html/`, PPT-only temporary build files are cleaned after completion, and generated image assets must prefer Codex App built-in image generation through `$imagegen`. |
53
54
  | Computer Use fast lane | Uses `$Computer-Use` / `$CU` for UI/browser/visual work that needs maximum speed: skip Team debate and upfront TriWiki loops, use Codex Computer Use directly, then refresh/validate TriWiki and run Honest Mode at final closeout. |
54
55
  | Goal | Provides a fast SKS bridge overlay for Codex native persisted `/goal` create, pause, resume, and clear controls; implementation continues through the selected SKS execution route. |
55
56
  | TriWiki voxels | Maintains `.sneakoscope/wiki/context-pack.json` as the context SSOT with coordinate anchors, voxel metadata, `attention.use_first`, and `attention.hydrate_first`. |
56
57
  | Context7 | Requires current docs for external packages, APIs, MCPs, SDKs, and framework/runtime behavior when correctness depends on current guidance. |
58
+ | getdesign.md | Grounds `design.md`, UI/UX design systems, and presentation-like HTML/PDF artifacts in the official getdesign.md reference and Codex skill path. |
57
59
  | DB safety | Treats SQL, migrations, Supabase, RLS, and destructive operations as high risk. |
58
60
  | Release hygiene | Checks versioning, changelog, package contents, tarball size, syntax, selftests, and dry-run publishing. |
59
61
 
@@ -63,21 +65,21 @@ sks selftest --mock
63
65
  - npm
64
66
  - Codex CLI for terminal workflows
65
67
  - Codex App for app-facing workflows, with Codex Computer Use required for UI/browser evidence
66
- - Warp for the CLI-first runtime
68
+ - tmux for the CLI-first runtime
67
69
  - Context7 MCP for current-docs-gated routes
68
70
 
69
- Install Warp from [warp.dev/download](https://www.warp.dev/download). On macOS, Homebrew users can also install it with:
71
+ Install tmux from [tmux.dev/download](https://www.tmux.dev/download). On macOS, Homebrew users can also install it with:
70
72
 
71
73
  ```sh
72
- brew install --cask warp
74
+ brew install tmux
73
75
  ```
74
76
 
75
77
  `sks --mad` is stricter than the normal runtime path:
76
78
 
77
79
  - Checks npm for a newer `sneakoscope` before launch and asks whether to update when the terminal can answer y/n.
78
80
  - Installs the latest Codex CLI with `npm i -g @openai/codex@latest` when it is missing and you approve or pass `--yes`.
79
- - Requires Warp to be installed before opening the Launch Configuration.
80
- - Writes a named Warp Launch Configuration and opens it through `warp://launch/<name>.yaml`.
81
+ - Requires tmux 3.x or newer before opening the session.
82
+ - Creates or reuses a named detached tmux session, splits panes, and prints the attach command.
81
83
 
82
84
  ## Installation
83
85
 
@@ -95,6 +97,8 @@ sks bootstrap
95
97
 
96
98
  Project setup writes shared `.gitignore` entries for generated SKS files: `.sneakoscope/`, `.codex/`, `.agents/`, and managed `AGENTS.md`. Use `sks setup --local-only` when you want those excludes kept only in `.git/info/exclude`.
97
99
 
100
+ During npm postinstall, SKS also installs generated Codex App skills and tries the official getdesign Codex skill command, `skills add MohtashamMurshid/getdesign`, when the `skills` CLI is available. If that CLI is missing, setup still installs the generated `getdesign-reference` skill so UI/UX and presentation design-system work keeps using [getdesign.md](https://getdesign.md/) as a required reference.
101
+
98
102
  ### One-Shot Install
99
103
 
100
104
  Use this when you do not want to keep a global install:
@@ -148,30 +152,30 @@ sks --version
148
152
  ```sh
149
153
  sks bootstrap
150
154
  sks deps check
151
- sks deps install warp
155
+ sks deps install tmux
152
156
  sks codex-app check
153
157
  sks doctor --fix
154
158
  sks fix-path
155
159
  ```
156
160
 
157
- ### Open Codex CLI With Warp
161
+ ### Open Codex CLI With tmux
158
162
 
159
163
  ```sh
160
- sks warp open
161
- sks warp check
162
- sks warp status --once
164
+ sks tmux open
165
+ sks tmux check
166
+ sks tmux status --once
163
167
  ```
164
168
 
165
- `sks warp open` writes a Warp Launch Configuration for Codex CLI and opens it through Warp's public URI scheme only when that is explicitly requested. When it is already running inside Warp, SKS runs Codex in the current terminal session instead of opening another Warp window. `sks` and `sks warp check` are diagnostic/help surfaces and do not start a workspace.
169
+ `sks tmux open` creates or reuses a named tmux session for Codex CLI only when that is explicitly requested. `sks` and `sks tmux check` are diagnostic/help surfaces and do not start a workspace.
166
170
 
167
- ### MAD Warp Launch
171
+ ### MAD tmux Launch
168
172
 
169
173
  ```sh
170
174
  sks --mad
171
175
  sks --mad --yes
172
176
  ```
173
177
 
174
- This creates/uses the `sks-mad-high` Codex profile for a one-shot full-access, high-reasoning Warp launch with `approval_policy = "on-request"` and `approvals_reviewer = "auto_review"`. It is scoped to that explicit command and does not change normal SKS/DB safety defaults. Repeat launches overwrite the same named SKS MAD Launch Configuration.
178
+ This creates/uses the `sks-mad-high` Codex profile for a one-shot full-access, high-reasoning tmux session with `approval_policy = "on-request"` and `approvals_reviewer = "auto_review"`. It is scoped to that explicit command and does not change normal SKS/DB safety defaults. Repeat launches reuse the same named SKS MAD tmux session.
175
179
 
176
180
  MAD does not disable the pipeline contract: stages, executors, reviewers, and auto-review policy still must not invent unrequested fallback implementation code. If the requested path cannot be implemented, SKS should block with evidence rather than add substitute behavior.
177
181
 
@@ -190,19 +194,19 @@ sks team "implement this feature" executor:3 reviewer:1
190
194
  sks team watch latest
191
195
  sks team lane latest --agent analysis_scout_1 --follow
192
196
  sks team message latest --from analysis_scout_1 --to executor_1 --message "handoff note"
193
- sks team cleanup-warp latest
197
+ sks team cleanup-tmux latest
194
198
  sks team status latest
195
199
  sks team dashboard latest
196
200
  sks team log latest
197
201
  ```
198
202
 
199
- Team mode prepares the mission, records live events, compiles runtime tasks and worker inboxes, writes schema-backed effort/work-order/dashboard artifacts, and opens a named Warp Team Launch Configuration with split live lanes when Warp is available. `sks team dashboard` renders the cockpit panes for mission overview, agent lanes, task DAG, QA/dogfood, artifacts/evidence, and performance.
203
+ Team mode prepares the mission, records live events, compiles runtime tasks and worker inboxes, writes schema-backed effort/work-order/dashboard artifacts, and opens a named tmux Team session with split live lanes when tmux is available. `sks team dashboard` renders the cockpit panes for mission overview, agent lanes, task DAG, QA/dogfood, artifacts/evidence, and performance.
200
204
 
201
- The Warp Team launch is a live orchestration screen: the first pane follows `sks team watch <mission-id> --follow` as the mission overview, and neighboring split panes follow individual `sks team lane <mission-id> --agent <name> --follow` views. SKS gives lanes role-specific colors, labels, and terminal titles, so scouts, planning/debate voices, executors, reviewers, and safety lanes are visually distinct while the same evidence is mirrored into `team-transcript.jsonl`, `team-live.md`, and `team-dashboard.json`.
205
+ The tmux Team launch is a live orchestration screen: the first pane follows `sks team watch <mission-id> --follow` as the mission overview, and neighboring split panes follow individual `sks team lane <mission-id> --agent <name> --follow` views. SKS gives lanes role-specific colors, labels, and terminal titles, so scouts, planning/debate voices, executors, reviewers, and safety lanes are visually distinct while the same evidence is mirrored into `team-transcript.jsonl`, `team-live.md`, and `team-dashboard.json`.
202
206
 
203
207
  Agent sessions communicate through the bounded Team transcript. Use `sks team message <mission-id|latest> --from <agent> --to <agent|all> --message "..."` to add direct or broadcast messages; lane panes show messages addressed to that agent plus the fallback global tail.
204
208
 
205
- When the Team route reaches `session_cleanup`, SKS marks the Warp launch record complete and asks `watch --follow` / `lane --follow` panes to show a cleanup summary and stop. You can also run `sks team cleanup-warp <mission-id|latest>` manually, or `sks team cleanup-warp latest --close` to remove the generated Launch Configuration. Warp's public URI/Launch Configuration surface does not expose a live pane-close API, so the panes remain user-controlled.
209
+ When the Team route reaches `session_cleanup`, SKS marks the tmux session record complete and asks `watch --follow` / `lane --follow` panes to show a cleanup summary and stop. You can also run `sks team cleanup-tmux <mission-id|latest>` manually, or `sks team cleanup-tmux latest --close` to kill the recorded tmux session.
206
210
 
207
211
  ### QA, Computer Use, Goal, Research, DB, Wiki, GX
208
212
 
@@ -278,7 +282,7 @@ Default setup adds these generated SKS paths to the project `.gitignore`; `--loc
278
282
 
279
283
  Use `sks dollar-commands` to confirm that terminal discovery and Codex App prompt commands agree.
280
284
 
281
- TriWiki is intentionally sparse: `sks wiki sweep` records demote, soft-forget, archive, delete, promote-to-skill, and promote-to-rule candidates instead of injecting every old claim into future prompts. `sks harness fixture` validates the broader Harness Growth Factory contract: deliberate forgetting fixtures, skill card metadata, experiment schema, tool-error taxonomy, permission profiles, MultiAgentV2 defaults, and Warp cockpit view coverage. `sks code-structure scan` flags handwritten files above 1000/2000/3000-line thresholds so new logic can be extracted before command files become harder to maintain.
285
+ TriWiki is intentionally sparse: `sks wiki sweep` records demote, soft-forget, archive, delete, promote-to-skill, and promote-to-rule candidates instead of injecting every old claim into future prompts. `sks harness fixture` validates the broader Harness Growth Factory contract: deliberate forgetting fixtures, skill card metadata, experiment schema, tool-error taxonomy, permission profiles, MultiAgentV2 defaults, and tmux cockpit view coverage. `sks code-structure scan` flags handwritten files above 1000/2000/3000-line thresholds so new logic can be extracted before command files become harder to maintain.
282
286
 
283
287
  ## Prompt `$` Commands
284
288
 
@@ -318,8 +322,8 @@ sks selftest --mock
318
322
  ### Start A CLI Workspace
319
323
 
320
324
  ```sh
321
- sks warp check
322
- sks warp open
325
+ sks tmux check
326
+ sks tmux open
323
327
  ```
324
328
 
325
329
  For the high-reasoning full-access profile:
@@ -381,14 +385,14 @@ npm install -g .
381
385
 
382
386
  If the global command is stale, reinstall globally from the repo or from npm.
383
387
 
384
- ### Warp is missing
388
+ ### tmux is missing
385
389
 
386
390
  ```sh
387
- sks deps install warp
388
- sks warp check
391
+ sks deps install tmux
392
+ sks tmux check
389
393
  ```
390
394
 
391
- Install Warp from [warp.dev/download](https://www.warp.dev/download) or run `brew install --cask warp` on macOS, then re-run `sks warp check`.
395
+ Install tmux from [tmux.dev/download](https://www.tmux.dev/download) or run `brew install tmux` on macOS, then re-run `sks tmux check`.
392
396
 
393
397
  ### Codex App tools are missing
394
398
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "ㅅㅋㅅ",
4
- "version": "0.7.6",
4
+ "version": "0.7.13",
5
5
  "description": "Sneakoscope Codex: database-safe Codex CLI/App harness with Team, Goal, AutoResearch, TriWiki, and Honest Mode.",
6
6
  "type": "module",
7
7
  "homepage": "https://github.com/mandarange/Sneakoscope-Codex#readme",
@@ -57,7 +57,7 @@
57
57
  "harness",
58
58
  "codex-cli",
59
59
  "codex-app",
60
- "warp",
60
+ "tmux",
61
61
  "auto-review",
62
62
  "browser-use",
63
63
  "computer-use",
@@ -0,0 +1,163 @@
1
+ import { projectRoot, readJson, runProcess, sksRoot } from '../core/fsx.mjs';
2
+ import { getCodexInfo } from '../core/codex-adapter.mjs';
3
+ import { context7Docs, context7Resolve, context7Text, context7Tools } from '../core/context7-client.mjs';
4
+ import { context7Evidence, recordContext7Evidence } from '../core/pipeline.mjs';
5
+ import { stateFile } from '../core/mission.mjs';
6
+ import { checkContext7, ensureProjectContext7Config } from './install-helpers.mjs';
7
+
8
+ const flag = (args, name) => args.includes(name);
9
+
10
+ export async function context7Command(sub = 'check', args = []) {
11
+ const action = sub || 'check';
12
+ const setupScope = action === 'setup' ? readOption(args, '--scope', flag(args, '--global') ? 'global' : 'project') : null;
13
+ const root = action === 'setup' && setupScope === 'project' ? await projectRoot() : await sksRoot();
14
+ if (action === 'check') {
15
+ const result = await checkContext7(root);
16
+ if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
17
+ console.log('SKS Context7 MCP\n');
18
+ console.log(`Project config: ${result.project.ok ? 'ok' : 'missing'} ${result.project.path}`);
19
+ console.log(`Global config: ${result.global.ok ? 'ok' : 'missing'} ${result.global.path}`);
20
+ console.log(`Codex mcp list: ${result.codex_mcp_list.ok ? 'ok' : result.codex_mcp_list.checked ? 'missing' : 'not checked'}`);
21
+ console.log(`Ready: ${result.ok ? 'yes' : 'no'}`);
22
+ if (!result.ok) console.log('\nRun: sks context7 setup --scope project');
23
+ return;
24
+ }
25
+ if (action === 'tools') {
26
+ const result = await context7Tools({ timeoutMs: readNumberOption(args, '--timeout-ms', 30000) });
27
+ if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
28
+ console.log('SKS Context7 Local MCP Tools\n');
29
+ console.log(`Server: ${result.server.info?.name || 'context7'} ${result.server.info?.version || ''}`.trim());
30
+ console.log(`Command: ${result.server.command} ${result.server.args.join(' ')}`);
31
+ console.log(`Tools: ${result.tool_names.join(', ') || 'none'}`);
32
+ if (!result.tool_names.includes('resolve-library-id') || !result.tool_names.some((name) => name === 'query-docs' || name === 'get-library-docs')) {
33
+ process.exitCode = 1;
34
+ console.log('\nContext7 local MCP is missing the required resolve/docs tools.');
35
+ }
36
+ return;
37
+ }
38
+ if (action === 'resolve') {
39
+ const positional = positionalArgs(args);
40
+ const libraryName = positional.join(' ').trim();
41
+ if (!libraryName) throw new Error('Usage: sks context7 resolve <library-name> [--query "..."] [--json]');
42
+ const result = await context7Resolve(libraryName, {
43
+ query: readOption(args, '--query', libraryName),
44
+ timeoutMs: readNumberOption(args, '--timeout-ms', 30000)
45
+ });
46
+ if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
47
+ console.log('SKS Context7 Resolve\n');
48
+ console.log(`Library: ${libraryName}`);
49
+ console.log(`ID: ${result.library_id || 'not resolved'}`);
50
+ console.log(`Server: ${result.server.info?.name || 'context7'} ${result.server.info?.version || ''}`.trim());
51
+ const text = context7Text(result.result).split(/\n/).slice(0, 24).join('\n').trim();
52
+ if (text) console.log(`\n${text}`);
53
+ if (!result.ok || !result.library_id) process.exitCode = 1;
54
+ return;
55
+ }
56
+ if (action === 'docs') {
57
+ const positional = positionalArgs(args);
58
+ const libraryNameOrId = positional.join(' ').trim();
59
+ if (!libraryNameOrId) throw new Error('Usage: sks context7 docs <library-name|/org/project> [--query "..."] [--topic "..."] [--tokens N] [--json]');
60
+ const result = await context7Docs(libraryNameOrId, {
61
+ query: readOption(args, '--query', readOption(args, '--topic', libraryNameOrId)),
62
+ topic: readOption(args, '--topic', libraryNameOrId),
63
+ tokens: readNumberOption(args, '--tokens', 2000),
64
+ timeoutMs: readNumberOption(args, '--timeout-ms', 30000)
65
+ });
66
+ if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
67
+ printContext7DocsResult(result, { title: 'SKS Context7 Docs' });
68
+ if (!result.ok) process.exitCode = 1;
69
+ return;
70
+ }
71
+ if (action === 'evidence') {
72
+ const positional = positionalArgs(args);
73
+ const missionArg = positional.shift();
74
+ const libraryNameOrId = positional.join(' ').trim();
75
+ if (!missionArg || !libraryNameOrId) throw new Error('Usage: sks context7 evidence <mission-id|latest> <library-name|/org/project> [--query "..."] [--topic "..."] [--tokens N] [--json]');
76
+ const missionId = await resolveMissionId(root, missionArg);
77
+ if (!missionId) throw new Error('No mission found for Context7 evidence.');
78
+ const result = await context7Docs(libraryNameOrId, {
79
+ query: readOption(args, '--query', readOption(args, '--topic', libraryNameOrId)),
80
+ topic: readOption(args, '--topic', libraryNameOrId),
81
+ tokens: readNumberOption(args, '--tokens', 2000),
82
+ timeoutMs: readNumberOption(args, '--timeout-ms', 30000)
83
+ });
84
+ const state = { ...(await readJson(stateFile(root), {})), mission_id: missionId };
85
+ await recordContext7Evidence(root, state, { tool_name: 'resolve-library-id', library: libraryNameOrId, library_id: result.library_id, source: result.resolve ? 'sks context7 evidence' : 'sks context7 evidence explicit-library-id' });
86
+ if (result.docs_tool) {
87
+ await recordContext7Evidence(root, state, { tool_name: result.docs_tool, library_id: result.library_id, source: 'sks context7 evidence' });
88
+ }
89
+ const evidence = await context7Evidence(root, state);
90
+ const out = { ...result, mission_id: missionId, evidence };
91
+ if (flag(args, '--json')) return console.log(JSON.stringify(out, null, 2));
92
+ printContext7DocsResult(result, { title: 'SKS Context7 Evidence' });
93
+ console.log(`\nMission: ${missionId}`);
94
+ console.log(`Evidence: ${evidence.ok ? 'ok' : 'missing'} resolve=${evidence.resolve ? 'yes' : 'no'} docs=${evidence.docs ? 'yes' : 'no'} events=${evidence.count}`);
95
+ if (!result.ok || !evidence.ok) process.exitCode = 1;
96
+ return;
97
+ }
98
+ if (action === 'setup') {
99
+ const scope = setupScope;
100
+ const transport = readOption(args, '--transport', flag(args, '--remote') ? 'remote' : 'local');
101
+ if (!['project', 'global'].includes(scope)) throw new Error('Invalid Context7 scope. Use project or global.');
102
+ if (!['local', 'remote'].includes(transport)) throw new Error('Invalid Context7 transport. Use local or remote.');
103
+ if (scope === 'project') {
104
+ const changed = await ensureProjectContext7Config(root, transport);
105
+ const result = await checkContext7(root);
106
+ if (flag(args, '--json')) return console.log(JSON.stringify({ changed, ...result }, null, 2));
107
+ console.log(`Context7 project MCP ${changed ? 'configured' : 'already configured'} in .codex/config.toml`);
108
+ console.log(`Ready: ${result.ok ? 'yes' : 'no'}`);
109
+ return;
110
+ }
111
+ const codex = await getCodexInfo();
112
+ if (!codex.bin) throw new Error('Codex CLI missing. Install separately: npm i -g @openai/codex, or set SKS_CODEX_BIN.');
113
+ const cmdArgs = transport === 'remote'
114
+ ? ['mcp', 'add', 'context7', '--url', 'https://mcp.context7.com/mcp']
115
+ : ['mcp', 'add', 'context7', '--', 'npx', '-y', '@upstash/context7-mcp@latest'];
116
+ const result = await runProcess(codex.bin, cmdArgs, { timeoutMs: 30000, maxOutputBytes: 64 * 1024 });
117
+ if (flag(args, '--json')) return console.log(JSON.stringify({ command: `${codex.bin} ${cmdArgs.join(' ')}`, result }, null, 2));
118
+ if (result.code !== 0) throw new Error(result.stderr || result.stdout || 'codex mcp add failed');
119
+ console.log('Context7 global MCP configured.');
120
+ return;
121
+ }
122
+ throw new Error(`Unknown context7 command: ${action}`);
123
+ }
124
+
125
+ function printContext7DocsResult(result, opts = {}) {
126
+ console.log(`${opts.title || 'SKS Context7 Docs'}\n`);
127
+ console.log(`Library ID: ${result.library_id || 'not resolved'}`);
128
+ console.log(`Docs tool: ${result.docs_tool || 'missing'}`);
129
+ console.log(`Server: ${result.server?.info?.name || 'context7'} ${result.server?.info?.version || ''}`.trim());
130
+ const text = context7Text(result.docs).split(/\n/).slice(0, 48).join('\n').trim();
131
+ if (text) console.log(`\n${text}`);
132
+ if (result.error) console.log(`\nError: ${result.error}`);
133
+ }
134
+
135
+ function readOption(args, name, fallback) {
136
+ const i = args.indexOf(name);
137
+ return i >= 0 && args[i + 1] ? args[i + 1] : fallback;
138
+ }
139
+
140
+ function readNumberOption(args, name, fallback) {
141
+ const raw = readOption(args, name, null);
142
+ if (raw == null) return fallback;
143
+ const n = Number(raw);
144
+ return Number.isFinite(n) ? n : fallback;
145
+ }
146
+
147
+ function positionalArgs(args = []) {
148
+ const out = [];
149
+ for (let i = 0; i < args.length; i++) {
150
+ const arg = args[i];
151
+ if (String(arg).startsWith('--')) {
152
+ if (args[i + 1] && !String(args[i + 1]).startsWith('--')) i++;
153
+ continue;
154
+ }
155
+ out.push(arg);
156
+ }
157
+ return out;
158
+ }
159
+
160
+ async function resolveMissionId(root, arg) {
161
+ const { findLatestMission } = await import('../core/mission.mjs');
162
+ return (!arg || arg === 'latest') ? findLatestMission(root) : arg;
163
+ }