sneakoscope 0.6.90 → 0.6.96
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 +15 -9
- package/package.json +1 -1
- package/src/cli/main.mjs +62 -14
- package/src/cli/maintenance-commands.mjs +11 -6
- package/src/core/fsx.mjs +1 -1
- package/src/core/goal-workflow.mjs +17 -12
- package/src/core/hooks-runtime.mjs +27 -23
- package/src/core/init.mjs +13 -8
- package/src/core/pipeline.mjs +48 -3
- package/src/core/routes.mjs +49 -14
- package/src/core/team-live.mjs +1 -1
- package/src/core/warp-ui.mjs +58 -7
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
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/
|
|
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, a maximum-speed Computer Use lane, a fast Goal bridge for native `/goal` persistence, Context7 evidence checks, DB safety, TriWiki context tracking, Honest Mode, and release-readiness gates.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
@@ -43,12 +43,13 @@ sks selftest --mock
|
|
|
43
43
|
|
|
44
44
|
| Area | What it does |
|
|
45
45
|
| --- | --- |
|
|
46
|
-
| CLI runtime | `sks
|
|
46
|
+
| CLI runtime | `sks warp open` and `sks --mad` explicitly launch Codex CLI with Warp; bare `sks` only prints help/readiness surfaces. |
|
|
47
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. |
|
|
48
48
|
| Team orchestration | Runs substantial work through ambiguity handling, scouts, TriWiki refresh, debate, runtime task graphs, worker inboxes, implementation, review, cleanup, reflection, and Honest Mode. |
|
|
49
49
|
| From-Chat-IMG | Turns chat screenshots plus original attachments into source-bound work orders, then requires scoped QA evidence before completion. |
|
|
50
50
|
| QA loop | Dogfoods UI/API behavior with safety gates, Codex Computer Use-only UI evidence, safe fixes, and rechecks. |
|
|
51
|
-
|
|
|
51
|
+
| 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. |
|
|
52
|
+
| 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. |
|
|
52
53
|
| TriWiki voxels | Maintains `.sneakoscope/wiki/context-pack.json` as the context SSOT with coordinate anchors, voxel metadata, `attention.use_first`, and `attention.hydrate_first`. |
|
|
53
54
|
| Context7 | Requires current docs for external packages, APIs, MCPs, SDKs, and framework/runtime behavior when correctness depends on current guidance. |
|
|
54
55
|
| DB safety | Treats SQL, migrations, Supabase, RLS, and destructive operations as high risk. |
|
|
@@ -154,12 +155,12 @@ sks fix-path
|
|
|
154
155
|
### Open Codex CLI With Warp
|
|
155
156
|
|
|
156
157
|
```sh
|
|
157
|
-
sks
|
|
158
|
+
sks warp open
|
|
158
159
|
sks warp check
|
|
159
160
|
sks warp status --once
|
|
160
161
|
```
|
|
161
162
|
|
|
162
|
-
`sks` writes a Warp Launch Configuration for Codex CLI and opens it through Warp's public URI scheme when running in
|
|
163
|
+
`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.
|
|
163
164
|
|
|
164
165
|
### MAD Warp Launch
|
|
165
166
|
|
|
@@ -201,7 +202,7 @@ Agent sessions communicate through the bounded Team transcript. Use `sks team me
|
|
|
201
202
|
|
|
202
203
|
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.
|
|
203
204
|
|
|
204
|
-
### QA, Goal, Research, DB, Wiki, GX
|
|
205
|
+
### QA, Computer Use, Goal, Research, DB, Wiki, GX
|
|
205
206
|
|
|
206
207
|
```sh
|
|
207
208
|
sks qa-loop prepare "http://localhost:3000"
|
|
@@ -222,6 +223,10 @@ sks proof-field scan --json --intent "small CLI change"
|
|
|
222
223
|
sks code-structure scan --json
|
|
223
224
|
```
|
|
224
225
|
|
|
226
|
+
`sks goal` and `$Goal` only prepare/control the native `/goal` persistence bridge. They do not replace Team, QA, DB, or other implementation routes; use the selected execution route for the actual work and verification. Context7 is only needed for Goal when external API/library documentation becomes relevant.
|
|
227
|
+
|
|
228
|
+
Use `$Computer-Use` or `$CU` inside Codex App when the task specifically needs Codex Computer Use speed for UI/browser/visual work. This lane intentionally skips Team debate, QA-LOOP clarification, subagents, and upfront TriWiki refresh. It still requires Codex Computer Use as the evidence source, and it defers TriWiki refresh/validate plus Honest Mode to the final closeout.
|
|
229
|
+
|
|
225
230
|
## Codex App Usage
|
|
226
231
|
|
|
227
232
|
Sneakoscope has two surfaces:
|
|
@@ -272,11 +277,12 @@ Use these inside Codex App or another agent prompt. They are prompt commands, no
|
|
|
272
277
|
| --- | --- |
|
|
273
278
|
| `$Team` | You want implementation, code changes, or substantial repo work. |
|
|
274
279
|
| `$From-Chat-IMG` | You have a chat screenshot plus original attachments and want each visible request mapped to work. |
|
|
275
|
-
| `$DFix` | You need a tiny design/content edit such as copy, label, color, spacing, or translation. |
|
|
280
|
+
| `$DFix` | You need a tiny design/content edit such as copy, label, color, spacing, or translation, with no Team/TriWiki/reflection recording and only a one-line DFix Honest check. |
|
|
276
281
|
| `$Answer` | You want an answer only and no implementation should start. |
|
|
277
282
|
| `$SKS` | You need setup, status, usage, or workflow help. |
|
|
278
283
|
| `$QA-LOOP` | You want UI/API dogfooding, safe fixes, and rechecks. |
|
|
279
|
-
| `$
|
|
284
|
+
| `$Computer-Use` / `$CU` | You want the fastest Codex Computer Use lane for UI/browser/visual inspection or small safe fixes. |
|
|
285
|
+
| `$Goal` | You want a fast SKS bridge overlay for Codex native persisted `/goal` continuation. |
|
|
280
286
|
| `$Research` | You need frontier-style research with hypotheses and falsification. |
|
|
281
287
|
| `$AutoResearch` | You want iterative improve/test/keep-or-discard optimization. |
|
|
282
288
|
| `$DB` | You need database, Supabase, migration, SQL, or MCP safety checks. |
|
|
@@ -302,7 +308,7 @@ sks selftest --mock
|
|
|
302
308
|
|
|
303
309
|
```sh
|
|
304
310
|
sks warp check
|
|
305
|
-
sks
|
|
311
|
+
sks warp open
|
|
306
312
|
```
|
|
307
313
|
|
|
308
314
|
For the high-reasoning full-access profile:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.96",
|
|
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",
|
package/src/cli/main.mjs
CHANGED
|
@@ -43,7 +43,7 @@ import { buildPromptContext } from '../core/prompt-context-builder.mjs';
|
|
|
43
43
|
import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
|
|
44
44
|
import { GOAL_WORKFLOW_ARTIFACT } from '../core/goal-workflow.mjs';
|
|
45
45
|
import { CODEX_APP_DOCS_URL, codexAppIntegrationStatus, formatCodexAppStatus } from '../core/codex-app.mjs';
|
|
46
|
-
import { buildWarpLaunchConfigYaml, buildWarpLaunchPlan, buildWarpOpenArgs, runWarpLaunchConfigSyntaxCheck, warpReadiness, warpStatusKind, defaultWarpWorkspaceName, formatWarpBanner, launchWarpTeamView, launchWarpUi, platformWarpInstallHint, runWarpStatus, sanitizeWarpWorkspaceName, teamLaneStyle, writeWarpLaunchConfig } from '../core/warp-ui.mjs';
|
|
46
|
+
import { buildWarpLaunchConfigYaml, buildWarpLaunchPlan, buildWarpOpenArgs, isWarpShellSession, runWarpLaunchConfigSyntaxCheck, warpOpenLaunchDecision, warpReadiness, warpStatusKind, defaultWarpWorkspaceName, formatWarpBanner, launchWarpTeamView, launchWarpUi, platformWarpInstallHint, runWarpStatus, sanitizeWarpWorkspaceName, teamLaneStyle, writeWarpLaunchConfig } from '../core/warp-ui.mjs';
|
|
47
47
|
import { autoReviewProfileName, autoReviewStatus, autoReviewSummary, enableAutoReview, disableAutoReview, enableMadHighProfile, madHighProfileName } from '../core/auto-review.mjs';
|
|
48
48
|
import { buildTeamPlan, codeStructureCommand, dbCommand, defaultBeta, defaultVGraph, evalCommand, gcCommand, goalCommand, gxCommand, harnessCommand, hproofCommand, memoryCommand, migrateWikiContextPack, parseTeamCreateArgs, perfCommand, profileCommand, projectWikiClaims, proofFieldCommand, qaLoopCommand, quickstartCommand, researchCommand, statsCommand, team, teamWorkflowMarkdown, validateArtifactsCommand, wikiCommand, wikiVoxelRowCount, writeWikiContextPack } from './maintenance-commands.mjs';
|
|
49
49
|
|
|
@@ -65,12 +65,12 @@ export async function main(args) {
|
|
|
65
65
|
if (isAutoReviewFlag(args[0])) return autoReviewCommand('start', args.slice(1));
|
|
66
66
|
const [cmd, sub, ...rest] = args;
|
|
67
67
|
const tail = sub === undefined ? [] : [sub, ...rest];
|
|
68
|
-
if (!cmd) return
|
|
68
|
+
if (!cmd) return help();
|
|
69
69
|
if (cmd === '--help' || cmd === '-h') return help();
|
|
70
70
|
if (cmd === '--version' || cmd === '-v' || cmd === 'version') return version();
|
|
71
71
|
if (cmd === 'postinstall') return postinstall();
|
|
72
72
|
if (cmd === 'wizard' || cmd === 'ui') return wizard(tail);
|
|
73
|
-
if (cmd === 'warp') return
|
|
73
|
+
if (cmd === 'warp') return !sub || String(sub).startsWith('--') ? warpCommand('check', tail) : warpCommand(sub, rest);
|
|
74
74
|
if (cmd === 'auto-review' || cmd === 'autoreview') return autoReviewCommand(sub, rest);
|
|
75
75
|
if (cmd === 'update-check') return updateCheck(tail);
|
|
76
76
|
if (cmd === 'help') return help(tail);
|
|
@@ -139,7 +139,7 @@ Usage:
|
|
|
139
139
|
sks --mad [--high]
|
|
140
140
|
sks auto-review status|enable|start [--high]
|
|
141
141
|
sks --Auto-review [--high]
|
|
142
|
-
sks warp [--workspace name]
|
|
142
|
+
sks warp open [--workspace name]
|
|
143
143
|
sks warp status [--once]
|
|
144
144
|
sks dollar-commands [--json]
|
|
145
145
|
sks dfix
|
|
@@ -218,10 +218,6 @@ function shouldShowWizard() {
|
|
|
218
218
|
return Boolean(input.isTTY && output.isTTY && process.env.SKS_NO_WIZARD !== '1' && process.env.CI !== 'true');
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
function shouldLaunchWarpUi() {
|
|
222
|
-
return Boolean(input.isTTY && output.isTTY && process.env.SKS_NO_WARP !== '1' && process.env.CI !== 'true');
|
|
223
|
-
}
|
|
224
|
-
|
|
225
221
|
function isAutoReviewFlag(value) {
|
|
226
222
|
return /^--?auto[-_]?review$/i.test(String(value || ''));
|
|
227
223
|
}
|
|
@@ -523,7 +519,7 @@ async function updateCheck(args = []) {
|
|
|
523
519
|
if (result.update_available) console.log('Run: npm i -g sneakoscope');
|
|
524
520
|
}
|
|
525
521
|
|
|
526
|
-
const DOLLAR_DEFAULT_PIPELINE_TEXT = 'Default pipeline: questions -> $Answer, small design/content -> $DFix, code -> $Team. Use $From-Chat-IMG only for chat screenshot plus original attachments. Use $MAD-SKS only as an explicit scoped DB authorization modifier that can be combined with another $ route. No route may invent unrequested fallback implementation code.';
|
|
522
|
+
const DOLLAR_DEFAULT_PIPELINE_TEXT = 'Default pipeline: questions -> $Answer, small design/content -> $DFix, Computer Use UI/browser speed work -> $Computer-Use, code -> $Team. Use $From-Chat-IMG only for chat screenshot plus original attachments. Use $MAD-SKS only as an explicit scoped DB authorization modifier that can be combined with another $ route. No route may invent unrequested fallback implementation code.';
|
|
527
523
|
|
|
528
524
|
function commands(args = []) {
|
|
529
525
|
if (flag(args, '--json')) return console.log(JSON.stringify({ aliases: ['sks', 'sneakoscope'], dollar_commands: DOLLAR_COMMANDS, app_skill_aliases: DOLLAR_COMMAND_ALIASES, commands: COMMAND_CATALOG }, null, 2));
|
|
@@ -593,12 +589,13 @@ Examples:
|
|
|
593
589
|
$DFix Change the CTA label to "Start"
|
|
594
590
|
|
|
595
591
|
Purpose:
|
|
596
|
-
Fast design/content fixes only. DFix bypasses the general SKS prompt pipeline and uses an ultralight task list.
|
|
592
|
+
Fast design/content fixes only. DFix bypasses the general SKS prompt pipeline and uses an ultralight, no-record task list.
|
|
597
593
|
|
|
598
594
|
Rules:
|
|
599
595
|
List the exact micro-edits, inspect only needed files, apply only those edits.
|
|
600
|
-
Do not run mission state, ambiguity gates, TriWiki
|
|
596
|
+
Do not run mission state, ambiguity gates, TriWiki/TriFix/reflection/state recording, Context7 routing, subagents, Goal, Research, eval, or broad redesign.
|
|
601
597
|
Run only cheap verification when useful.
|
|
598
|
+
Start the final answer with "DFix 완료 요약:" and include one "DFix 솔직모드:" line for verified, not verified, and remaining issues.
|
|
602
599
|
`);
|
|
603
600
|
}
|
|
604
601
|
|
|
@@ -1104,7 +1101,7 @@ async function warpCommand(sub = 'start', args = []) {
|
|
|
1104
1101
|
if (flag(args, '--json')) console.log(JSON.stringify(result, null, 2));
|
|
1105
1102
|
return;
|
|
1106
1103
|
}
|
|
1107
|
-
console.error('Usage: sks warp
|
|
1104
|
+
console.error('Usage: sks warp open|start|check|status|banner [--workspace name]');
|
|
1108
1105
|
process.exitCode = 1;
|
|
1109
1106
|
}
|
|
1110
1107
|
|
|
@@ -1421,7 +1418,7 @@ function usage(args = []) {
|
|
|
1421
1418
|
bootstrap: ['Bootstrap', '', ' sks bootstrap', ' sks setup --bootstrap', '', 'Creates project SKS files, Codex App skills/hooks/config, state/guard files, then checks Codex App, Context7, and warp.'],
|
|
1422
1419
|
root: ['Root', '', ' sks root [--json]', '', 'Inside a project, SKS uses that project root. Outside any project marker, runtime commands use the per-user global SKS root instead of writing .sneakoscope into the current random folder.'],
|
|
1423
1420
|
deps: ['Dependencies', '', ' sks deps check [--json]', ' sks deps install [warp|codex|context7|all] [--yes]', '', 'warp on macOS uses Homebrew only after approval.'],
|
|
1424
|
-
warp: ['warp', '', ' sks', ' sks warp check', ' sks warp status --once', ' sks deps install warp'],
|
|
1421
|
+
warp: ['warp', '', ' sks warp open', ' sks warp check', ' sks warp status --once', ' sks deps install warp', '', 'Warp launch is explicit. Running bare `sks` prints help and never opens Warp by itself.'],
|
|
1425
1422
|
team: ['Team', '', ' sks team "task" executor:5 reviewer:2 user:1', ' sks team watch latest', ' sks team lane latest --agent analysis_scout_1 --follow', ' sks team message latest --from analysis_scout_1 --to executor_1 --message "handoff note"', ' sks team cleanup-warp latest', '', '$Team runs questions -> contract -> scouts -> TriWiki attention -> debate -> runtime graph/inbox -> fresh executors -> review -> cleanup -> reflection -> Honest.'],
|
|
1426
1423
|
'qa-loop': ['QA-LOOP', '', ' sks qa-loop prepare "QA this app"', ' sks qa-loop answer <MISSION_ID> answers.json', ' sks qa-loop run <MISSION_ID> --max-cycles 8', '', 'Report: YYYY-MM-DD-v<version>-qa-report.md'],
|
|
1427
1424
|
goal: ['Goal', '', ' sks goal create "task"', ' sks goal status latest', ' sks goal pause latest', ' sks goal resume latest', ' sks goal clear latest'],
|
|
@@ -1932,9 +1929,10 @@ async function selftest() {
|
|
|
1932
1929
|
maxOutputBytes: 64 * 1024
|
|
1933
1930
|
});
|
|
1934
1931
|
if (dfixPromptHook.code !== 0) throw new Error(`selftest failed: DFix prompt hook exited ${dfixPromptHook.code}: ${dfixPromptHook.stderr}`);
|
|
1932
|
+
if (await exists(path.join(tmp, '.sneakoscope', 'state', 'light-route-stop.json'))) throw new Error('selftest failed: DFix prompt hook created persistent light-route state');
|
|
1935
1933
|
const dfixStopHook = await runProcess(process.execPath, [path.join(packageRoot(), 'bin', 'sks.mjs'), 'hook', 'stop'], {
|
|
1936
1934
|
cwd: tmp,
|
|
1937
|
-
input: JSON.stringify({ cwd: tmp, last_assistant_message: 'DFix 완료 요약: CTA 라벨만
|
|
1935
|
+
input: JSON.stringify({ cwd: tmp, last_assistant_message: 'DFix 완료 요약: CTA 라벨만 변경했습니다.\nDFix 솔직모드: 검증=대상 파일 확인 통과, 미검증=없음, 남은 문제=없음.' }),
|
|
1938
1936
|
timeoutMs: 15000,
|
|
1939
1937
|
maxOutputBytes: 64 * 1024
|
|
1940
1938
|
});
|
|
@@ -2024,10 +2022,23 @@ async function selftest() {
|
|
|
2024
2022
|
if (!warpSyntax.ok || !warpLaunchYaml.includes('name: "sks-mad-selftest"') || !warpLaunchYaml.includes('commands:')) throw new Error('selftest failed: MAD Warp launch configuration was not generated with name and command');
|
|
2025
2023
|
const warpOpenArgs = buildWarpOpenArgs(workspacePlan);
|
|
2026
2024
|
if (!warpOpenArgs.includes('open') || !warpOpenArgs.some((arg) => String(arg).includes('warp://launch/sks-mad-selftest.yaml'))) throw new Error('selftest failed: MAD Warp launch URI is not stable by workspace name');
|
|
2025
|
+
if (!isWarpShellSession({ TERM_PROGRAM: 'WarpTerminal' })) throw new Error('selftest failed: Warp shell session env was not detected');
|
|
2026
|
+
const warpNestedDecision = warpOpenLaunchDecision({ env: { TERM_PROGRAM: 'WarpTerminal' } });
|
|
2027
|
+
if (warpNestedDecision.open || !warpNestedDecision.current_session) throw new Error('selftest failed: nested Warp launch was not redirected to current session');
|
|
2027
2028
|
const oldWarpConfigDir = process.env.SKS_WARP_LAUNCH_CONFIG_DIR;
|
|
2028
2029
|
process.env.SKS_WARP_LAUNCH_CONFIG_DIR = path.join(tmp, 'warp-launch-configs');
|
|
2029
2030
|
const writtenWarpConfig = await writeWarpLaunchConfig({ ...workspacePlan, command: 'codex', title: 'sks-mad-selftest' }, [{ cwd: tmp, command: 'codex --profile sks-mad-high', focused: true }]);
|
|
2030
2031
|
if (!(await exists(writtenWarpConfig.config_path)) || !writtenWarpConfig.record.launch_uri.includes('warp://launch/')) throw new Error('selftest failed: Warp launch configuration was not persisted for URI launch');
|
|
2032
|
+
const currentSessionLaunch = await launchWarpUi(['--workspace', 'sks-current-session-selftest'], {
|
|
2033
|
+
root: tmp,
|
|
2034
|
+
codex: { bin: 'printf', version: 'mock' },
|
|
2035
|
+
app: { ok: true, guidance: [] },
|
|
2036
|
+
warp: { ok: true, version: 'Warp.app' },
|
|
2037
|
+
env: { TERM_PROGRAM: 'WarpTerminal' },
|
|
2038
|
+
dryRunCurrentSession: true,
|
|
2039
|
+
quiet: true
|
|
2040
|
+
});
|
|
2041
|
+
if (!currentSessionLaunch.opened?.current_session || currentSessionLaunch.opened?.skipped) throw new Error('selftest failed: Warp shell launch did not stay in the current session');
|
|
2031
2042
|
if (oldWarpConfigDir === undefined) delete process.env.SKS_WARP_LAUNCH_CONFIG_DIR;
|
|
2032
2043
|
else process.env.SKS_WARP_LAUNCH_CONFIG_DIR = oldWarpConfigDir;
|
|
2033
2044
|
if (warpStatusKind({ ok: false, bin: null }) !== 'missing') throw new Error('selftest failed: missing warp was not labeled missing');
|
|
@@ -2249,6 +2260,31 @@ async function selftest() {
|
|
|
2249
2260
|
const hookState = await readJson(stateFile(hookGoalTmp), {});
|
|
2250
2261
|
if (hookState.phase !== 'GOAL_READY' || hookState.mode !== 'GOAL') throw new Error('selftest failed: $Goal hook did not set ready state');
|
|
2251
2262
|
if (!(await exists(path.join(missionDir(hookGoalTmp, hookState.mission_id), GOAL_WORKFLOW_ARTIFACT)))) throw new Error('selftest failed: $Goal hook did not write goal workflow artifact');
|
|
2263
|
+
const hookGoalDelegationTmp = tmpdir();
|
|
2264
|
+
await initProject(hookGoalDelegationTmp, {});
|
|
2265
|
+
const hookGoalDelegationPayload = JSON.stringify({ cwd: hookGoalDelegationTmp, prompt: '$Goal 설치 화면 문제 근본적으로 구현 수정해줘' });
|
|
2266
|
+
const hookGoalDelegationResult = await runProcess(process.execPath, [hookBin, 'hook', 'user-prompt-submit'], { cwd: hookGoalDelegationTmp, input: hookGoalDelegationPayload, env: { SKS_DISABLE_UPDATE_CHECK: '1' }, timeoutMs: 15000, maxOutputBytes: 256 * 1024 });
|
|
2267
|
+
if (hookGoalDelegationResult.code !== 0) throw new Error(`selftest failed: $Goal implementation delegation hook exited ${hookGoalDelegationResult.code}: ${hookGoalDelegationResult.stderr}`);
|
|
2268
|
+
const hookGoalDelegationJson = JSON.parse(hookGoalDelegationResult.stdout);
|
|
2269
|
+
const hookGoalDelegationContext = hookGoalDelegationJson.hookSpecificOutput?.additionalContext || '';
|
|
2270
|
+
const hookGoalDelegationBridgeMatch = hookGoalDelegationContext.match(/Goal bridge mission: (M-[A-Za-z0-9-]+)/);
|
|
2271
|
+
if (!hookGoalDelegationBridgeMatch || !hookGoalDelegationContext.includes('Delegated execution route: $Team')) throw new Error('selftest failed: $Goal implementation prompt did not prepare a bridge plus Team delegation');
|
|
2272
|
+
if (!hookGoalDelegationContext.includes('MANDATORY ambiguity-removal gate activated') || !hookGoalDelegationContext.includes('Route: $Team')) throw new Error('selftest failed: $Goal implementation delegation did not prepare Team ambiguity gate');
|
|
2273
|
+
const hookGoalDelegationState = await readJson(stateFile(hookGoalDelegationTmp), {});
|
|
2274
|
+
if (hookGoalDelegationState.mode !== 'TEAM' || hookGoalDelegationState.phase !== 'TEAM_CLARIFICATION_AWAITING_ANSWERS' || hookGoalDelegationState.implementation_allowed !== false) throw new Error('selftest failed: $Goal implementation delegation did not leave Team gate current');
|
|
2275
|
+
if (!(await exists(path.join(missionDir(hookGoalDelegationTmp, hookGoalDelegationBridgeMatch[1]), GOAL_WORKFLOW_ARTIFACT)))) throw new Error('selftest failed: $Goal implementation delegation did not write bridge workflow artifact');
|
|
2276
|
+
const activeGoalMissionId = hookState.mission_id;
|
|
2277
|
+
const hookGoalOverlayPayload = JSON.stringify({ cwd: hookGoalTmp, prompt: '설치 화면 문제 근본적으로 구현 수정해줘' });
|
|
2278
|
+
const hookGoalOverlayResult = await runProcess(process.execPath, [hookBin, 'hook', 'user-prompt-submit'], { cwd: hookGoalTmp, input: hookGoalOverlayPayload, env: { SKS_DISABLE_UPDATE_CHECK: '1' }, timeoutMs: 15000, maxOutputBytes: 256 * 1024 });
|
|
2279
|
+
if (hookGoalOverlayResult.code !== 0) throw new Error(`selftest failed: active Goal overlay hook exited ${hookGoalOverlayResult.code}: ${hookGoalOverlayResult.stderr}`);
|
|
2280
|
+
const hookGoalOverlayJson = JSON.parse(hookGoalOverlayResult.stdout);
|
|
2281
|
+
const hookGoalOverlayContext = hookGoalOverlayJson.hookSpecificOutput?.additionalContext || '';
|
|
2282
|
+
if (!hookGoalOverlayContext.includes('MANDATORY ambiguity-removal gate activated') || !hookGoalOverlayContext.includes('Route: $Team')) throw new Error('selftest failed: active Goal hijacked a plain Korean implementation prompt instead of preparing Team');
|
|
2283
|
+
if (!hookGoalOverlayContext.includes(`Active Goal overlay: existing Goal mission ${activeGoalMissionId}`) || !hookGoalOverlayContext.includes('goal-workflow.json')) throw new Error('selftest failed: active Goal overlay context was not included with the new route');
|
|
2284
|
+
if (hookGoalOverlayContext.indexOf('MANDATORY ambiguity-removal gate activated') > hookGoalOverlayContext.indexOf('Active Goal overlay:')) throw new Error('selftest failed: active Goal overlay appeared before the newly prepared Team gate');
|
|
2285
|
+
const hookGoalOverlayState = await readJson(stateFile(hookGoalTmp), {});
|
|
2286
|
+
if (hookGoalOverlayState.mission_id === activeGoalMissionId || hookGoalOverlayState.mode !== 'TEAM' || hookGoalOverlayState.phase !== 'TEAM_CLARIFICATION_AWAITING_ANSWERS' || hookGoalOverlayState.implementation_allowed !== false) throw new Error('selftest failed: active Goal overlay did not leave a new Team ambiguity mission current');
|
|
2287
|
+
if (!(await exists(path.join(missionDir(hookGoalTmp, hookGoalOverlayState.mission_id), 'required-answers.schema.json')))) throw new Error('selftest failed: active Goal overlay Team mission did not write ambiguity schema');
|
|
2252
2288
|
const hookUpdateCurrentTmp = tmpdir();
|
|
2253
2289
|
await initProject(hookUpdateCurrentTmp, {});
|
|
2254
2290
|
const hookUpdateCurrentPayload = JSON.stringify({ cwd: hookUpdateCurrentTmp, prompt: '상태 확인해줘' });
|
|
@@ -2500,7 +2536,10 @@ async function selftest() {
|
|
|
2500
2536
|
if (hookDfixJson.hookSpecificOutput?.additionalContext?.includes('Mission:')) throw new Error('selftest failed: $DFix created route mission state');
|
|
2501
2537
|
if (!hookDfixJson.hookSpecificOutput?.additionalContext?.includes('DFix ultralight pipeline active')) throw new Error('selftest failed: $DFix hook missing ultralight pipeline guidance');
|
|
2502
2538
|
if (!hookDfixJson.hookSpecificOutput?.additionalContext?.includes('Task list:')) throw new Error('selftest failed: $DFix hook missing micro task list');
|
|
2539
|
+
if (!hookDfixJson.hookSpecificOutput?.additionalContext?.includes('DFix 완료 요약')) throw new Error('selftest failed: $DFix hook missing no-record final marker guidance');
|
|
2540
|
+
if (!hookDfixJson.hookSpecificOutput?.additionalContext?.includes('DFix 솔직모드')) throw new Error('selftest failed: $DFix hook missing lightweight Honest Mode guidance');
|
|
2503
2541
|
if (!hookDfixJson.systemMessage?.includes('DFix ultralight')) throw new Error('selftest failed: $DFix hook missing ultralight system message');
|
|
2542
|
+
if (await exists(path.join(hookDfixTmp, '.sneakoscope', 'state', 'light-route-stop.json'))) throw new Error('selftest failed: $DFix hook created persistent light-route state');
|
|
2504
2543
|
const hookDfixState = await readJson(stateFile(hookDfixTmp), {});
|
|
2505
2544
|
if (String(hookDfixState.phase || '').includes('CLARIFICATION_AWAITING_ANSWERS')) throw new Error('selftest failed: $DFix state entered clarification gate');
|
|
2506
2545
|
const inferredDfixPayload = JSON.stringify({ cwd: hookTeamTmp, prompt: '버튼 라벨 바꿔줘' });
|
|
@@ -2783,6 +2822,8 @@ async function selftest() {
|
|
|
2783
2822
|
if (maxTextParsed.agentSessions !== 6 || maxTextParsed.roleCounts.executor !== 6) throw new Error('selftest failed: team max-agent text parsing');
|
|
2784
2823
|
const roleParsed = parseTeamCreateArgs(['executor:5', 'reviewer:2', 'user:1', '작업']);
|
|
2785
2824
|
if (roleParsed.roleCounts.executor !== 5 || roleParsed.roleCounts.reviewer !== 2 || roleParsed.agentSessions !== 5 || roleParsed.prompt !== '작업') throw new Error('selftest failed: team role-count parsing');
|
|
2825
|
+
const openWarpFlagParsed = parseTeamCreateArgs(['--open-warp', '작업']);
|
|
2826
|
+
if (openWarpFlagParsed.prompt !== '작업') throw new Error('selftest failed: team --open-warp leaked into prompt');
|
|
2786
2827
|
const roleTeamPlan = buildTeamPlan(teamId, '역할 팀 테스트', { roleCounts: roleParsed.roleCounts });
|
|
2787
2828
|
if (roleTeamPlan.roster.debate_team.length !== 5) throw new Error('selftest failed: executor role count not reflected in debate team size');
|
|
2788
2829
|
if (roleTeamPlan.roster.analysis_team.length !== 5) throw new Error('selftest failed: executor role count not reflected in analysis scout team');
|
|
@@ -2796,6 +2837,7 @@ async function selftest() {
|
|
|
2796
2837
|
if (!warpTeam.launch_uri?.includes(encodeURIComponent(`sks-team-${teamId}.yaml`))) throw new Error('selftest failed: Team warp launch URI is not named for visibility');
|
|
2797
2838
|
if (routeReasoning(routePrompt('$Research frontier idea'), '$Research frontier idea').effort !== 'xhigh') throw new Error('selftest failed: research reasoning not xhigh');
|
|
2798
2839
|
if (routeReasoning(routePrompt('$From-Chat-IMG 채팅 이미지 작업'), '$From-Chat-IMG 채팅 이미지 작업').effort !== 'xhigh') throw new Error('selftest failed: From-Chat-IMG reasoning not xhigh');
|
|
2840
|
+
if (routeReasoning(routePrompt('$Computer-Use localhost UI smoke'), '$Computer-Use localhost UI smoke').effort !== 'low') throw new Error('selftest failed: Computer Use fast lane reasoning not low');
|
|
2799
2841
|
if (routeReasoning(routePrompt('$DB migration'), '$DB migration').effort !== 'high') throw new Error('selftest failed: logical reasoning not high');
|
|
2800
2842
|
const lowReasoning = routeReasoning({ id: 'LowSmoke', reasoningPolicy: 'low' }, 'small metadata read');
|
|
2801
2843
|
if (lowReasoning.effort !== 'low' || lowReasoning.profile !== 'sks-task-low') throw new Error('selftest failed: low reasoning did not route to sks-task-low');
|
|
@@ -2835,13 +2877,19 @@ async function selftest() {
|
|
|
2835
2877
|
if (routePrompt('implement feature')?.id !== 'Team') throw new Error('selftest failed: implementation prompt did not default to Team');
|
|
2836
2878
|
if (routePrompt('$SKS implement feature')?.id !== 'Team') throw new Error('selftest failed: $SKS implementation prompt did not promote to Team');
|
|
2837
2879
|
if (routePrompt('$From-Chat-IMG 채팅 기록 이미지와 첨부 이미지로 고객사 요청 수정 작업 수행해줘')?.id !== 'Team') throw new Error('selftest failed: explicit chat capture client work did not promote to Team');
|
|
2880
|
+
if (routePrompt('$Computer-Use localhost 화면 빠르게 검증해줘')?.id !== 'ComputerUse') throw new Error('selftest failed: $Computer-Use did not route to ComputerUse fast lane');
|
|
2881
|
+
if (routePrompt('$CU localhost 화면 빠르게 검증해줘')?.id !== 'ComputerUse') throw new Error('selftest failed: $CU did not route to ComputerUse fast lane');
|
|
2882
|
+
if (routePrompt('computer use 사용하는 파이프라인은 마지막에 triwiki honest mode만 실행되게 조정해줘')?.id !== 'ComputerUse') throw new Error('selftest failed: Computer Use pipeline request was misrouted away from fast lane');
|
|
2883
|
+
if (routePrompt('triwiki나 honest mode가 마지막에만 실행되게 computer use 파이프라인 조정해줘')?.id !== 'ComputerUse') throw new Error('selftest failed: Computer Use directive was hijacked by Wiki route');
|
|
2838
2884
|
if (routePrompt('$SKS show me available workflows')?.id !== 'SKS') throw new Error('selftest failed: $SKS workflow discovery should remain SKS');
|
|
2839
2885
|
if (routeRequiresSubagents(routePrompt('이 파이프라인은 왜 이렇게 동작해?'), '이 파이프라인은 왜 이렇게 동작해?')) throw new Error('selftest failed: Answer route requires subagents');
|
|
2840
2886
|
if (!routeRequiresSubagents(routePrompt('implement feature'), 'implement feature')) throw new Error('selftest failed: default Team implementation route does not require subagents');
|
|
2841
2887
|
if (!routeRequiresSubagents(routePrompt('$Team implement feature'), '$Team implement feature')) throw new Error('selftest failed: Team route does not require subagents');
|
|
2888
|
+
if (routeRequiresSubagents(routePrompt('$Computer-Use localhost UI smoke'), '$Computer-Use localhost UI smoke')) throw new Error('selftest failed: Computer Use fast lane requires subagents');
|
|
2842
2889
|
if (!routeRequiresSubagents(routePrompt('$Goal implement feature'), '$Goal implement feature')) throw new Error('selftest failed: Goal implementation route does not require subagents');
|
|
2843
2890
|
if (routeRequiresSubagents(routePrompt('$Help commands'), '$Help commands')) throw new Error('selftest failed: Help route incorrectly requires subagents');
|
|
2844
2891
|
if (!reflectionRequiredForRoute(routePrompt('$Team implement feature'))) throw new Error('selftest failed: Team route does not require reflection');
|
|
2892
|
+
if (reflectionRequiredForRoute(routePrompt('$Computer-Use localhost UI smoke'))) throw new Error('selftest failed: Computer Use fast lane requires full-route reflection');
|
|
2845
2893
|
if (!reflectionRequiredForRoute(routePrompt('$DB migration'))) throw new Error('selftest failed: DB route does not require reflection');
|
|
2846
2894
|
if (reflectionRequiredForRoute(routePrompt('$DFix button label'))) throw new Error('selftest failed: DFix route incorrectly requires reflection');
|
|
2847
2895
|
if (reflectionRequiredForRoute(routePrompt('이 파이프라인은 왜 이렇게 동작해?'))) throw new Error('selftest failed: Answer route incorrectly requires reflection');
|
|
@@ -354,7 +354,7 @@ async function goalCreate(args) {
|
|
|
354
354
|
if (!prompt) throw new Error('Missing goal task prompt.');
|
|
355
355
|
const { id, dir, mission } = await createMission(root, { mode: 'goal', prompt });
|
|
356
356
|
const workflow = await writeGoalWorkflow(dir, mission, { action: 'create', prompt });
|
|
357
|
-
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: 'GOAL_READY', questions_allowed: true, implementation_allowed: true, native_goal: workflow.native_goal, stop_gate: '
|
|
357
|
+
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: 'GOAL_READY', questions_allowed: true, implementation_allowed: true, native_goal: workflow.native_goal, stop_gate: 'none' });
|
|
358
358
|
console.log(`Goal mission created: ${id}`);
|
|
359
359
|
console.log(`Artifact: ${path.relative(root, path.join(dir, GOAL_WORKFLOW_ARTIFACT))}`);
|
|
360
360
|
console.log(`Bridge: ${path.relative(root, path.join(dir, GOAL_BRIDGE_ARTIFACT))}`);
|
|
@@ -367,7 +367,7 @@ async function goalControl(action, args) {
|
|
|
367
367
|
if (!id) throw new Error(`Usage: sks goal ${action} <mission-id|latest>`);
|
|
368
368
|
const { dir } = await loadMission(root, id);
|
|
369
369
|
const workflow = await updateGoalWorkflow(dir, action);
|
|
370
|
-
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: `GOAL_${String(action).toUpperCase()}`, native_goal: workflow.native_goal, questions_allowed: true, implementation_allowed: action !== 'pause' && action !== 'clear' });
|
|
370
|
+
await setCurrent(root, { mission_id: id, mode: 'GOAL', route: 'Goal', route_command: '$Goal', phase: `GOAL_${String(action).toUpperCase()}`, native_goal: workflow.native_goal, questions_allowed: true, implementation_allowed: action !== 'pause' && action !== 'clear', stop_gate: 'none' });
|
|
371
371
|
console.log(`Goal ${action}: ${id}`);
|
|
372
372
|
console.log(`Native Codex control: ${workflow.native_goal.slash_command}`);
|
|
373
373
|
}
|
|
@@ -1348,10 +1348,12 @@ export async function gxCommand(sub, args) {
|
|
|
1348
1348
|
export async function team(args) {
|
|
1349
1349
|
const teamSubcommands = new Set(['log', 'tail', 'watch', 'lane', 'status', 'dashboard', 'event', 'message', 'cleanup-warp']);
|
|
1350
1350
|
if (teamSubcommands.has(args[0])) return teamCommand(args[0], args.slice(1));
|
|
1351
|
-
const
|
|
1351
|
+
const openWarp = flag(args, '--open-warp') || flag(args, '--warp-open');
|
|
1352
|
+
const cleanCreateArgs = args.filter((arg) => !['--open-warp', '--warp-open'].includes(String(arg)));
|
|
1353
|
+
const opts = parseTeamCreateArgs(cleanCreateArgs);
|
|
1352
1354
|
const { prompt, agentSessions, roleCounts, roster } = opts;
|
|
1353
1355
|
if (!prompt) {
|
|
1354
|
-
console.error('Usage: sks team "task" [executor:5 reviewer:2 user:1] [--agents N] [--json]');
|
|
1356
|
+
console.error('Usage: sks team "task" [executor:5 reviewer:2 user:1] [--agents N] [--open-warp] [--json]');
|
|
1355
1357
|
console.error(' sks team log|tail|watch|lane|status|message|cleanup-warp [mission-id|latest]');
|
|
1356
1358
|
console.error(' sks team event [mission-id|latest] --agent <name> --phase <phase> --message "..."');
|
|
1357
1359
|
console.error(' sks team message [mission-id|latest] --from <agent> --to <agent|all> --message "..."');
|
|
@@ -1414,7 +1416,7 @@ export async function team(args) {
|
|
|
1414
1416
|
questions: path.join(dir, 'questions.md'),
|
|
1415
1417
|
codex_agents: ['analysis_scout', 'team_consensus', 'implementation_worker', 'db_safety_reviewer', 'qa_reviewer']
|
|
1416
1418
|
};
|
|
1417
|
-
result.warp = await launchWarpTeamView({ root, missionId: id, plan, promptFile: result.workflow, json: flag(args, '--json') });
|
|
1419
|
+
result.warp = await launchWarpTeamView({ root, missionId: id, plan, promptFile: result.workflow, json: flag(args, '--json') || !openWarp });
|
|
1418
1420
|
if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
|
|
1419
1421
|
console.log(`Team mission created: ${id}`);
|
|
1420
1422
|
console.log(`Plan: ${path.relative(root, result.plan)}`);
|
|
@@ -1424,7 +1426,10 @@ export async function team(args) {
|
|
|
1424
1426
|
console.log(`Runtime graph: ${path.relative(root, result.team_graph)}`);
|
|
1425
1427
|
console.log(`Worker inbox: ${path.relative(root, result.worker_inbox_dir)}`);
|
|
1426
1428
|
console.log(`Live: ${path.relative(root, result.live)}`);
|
|
1427
|
-
if (result.warp.ready)
|
|
1429
|
+
if (result.warp.ready) {
|
|
1430
|
+
const warpState = result.warp.created ? 'opened' : 'not opened; use --open-warp for a launch configuration';
|
|
1431
|
+
console.log(`warp: ${warpState} ${result.warp.opened_lane_count || result.warp.agents.length} agent lane(s) in ${result.warp.workspace_ref || result.warp.workspace}`);
|
|
1432
|
+
}
|
|
1428
1433
|
else console.log(`warp: blocked (${Array.from(new Set(result.warp.blockers || [])).join('; ')})`);
|
|
1429
1434
|
console.log(`Watch: sks team watch ${id}`);
|
|
1430
1435
|
console.log('Use $Team in Codex App or the Warp launch view from this CLI flow to run scouts, debate/consensus, runtime graph/inbox handoff, then a fresh implementation team with disjoint ownership.');
|
package/src/core/fsx.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import os from 'node:os';
|
|
|
5
5
|
import crypto from 'node:crypto';
|
|
6
6
|
import { spawn } from 'node:child_process';
|
|
7
7
|
|
|
8
|
-
export const PACKAGE_VERSION = '0.6.
|
|
8
|
+
export const PACKAGE_VERSION = '0.6.96';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
|
|
@@ -26,15 +26,18 @@ export async function writeGoalWorkflow(dir, mission, opts = {}) {
|
|
|
26
26
|
prompt,
|
|
27
27
|
native_goal: {
|
|
28
28
|
slash_command: nativeGoalCommand(action, prompt),
|
|
29
|
-
workflow_kind: '
|
|
29
|
+
workflow_kind: 'native /goal persistence bridge',
|
|
30
30
|
controls: ['create', 'pause', 'resume', 'clear'],
|
|
31
31
|
runtime_continuation: true,
|
|
32
32
|
app_server_api_backed: true,
|
|
33
33
|
model_tools_available: true
|
|
34
34
|
},
|
|
35
35
|
pipeline_contract: {
|
|
36
|
+
overlay_only: true,
|
|
36
37
|
ralph_removed: true,
|
|
37
|
-
ambiguity_gate: 'use normal SKS ambiguity gates
|
|
38
|
+
ambiguity_gate: 'Goal creates/controls the native /goal persistence bridge only; use normal SKS ambiguity gates on the selected execution route when implementation is needed',
|
|
39
|
+
context7: 'optional for Goal bridge/control unless external API/library documentation is involved',
|
|
40
|
+
implementation: 'continue implementation through the selected SKS execution route; Goal is not a heavyweight independent implementation pipeline',
|
|
38
41
|
evidence: ['goal-workflow.json', 'goal-bridge.md']
|
|
39
42
|
},
|
|
40
43
|
phase: action === 'clear' ? 'reporting' : 'intake',
|
|
@@ -44,9 +47,9 @@ export async function writeGoalWorkflow(dir, mission, opts = {}) {
|
|
|
44
47
|
{
|
|
45
48
|
timestamp: nowIso(),
|
|
46
49
|
phase: 'intake',
|
|
47
|
-
summary: 'Goal workflow bridge created.',
|
|
48
|
-
completed_checkboxes: ['goal
|
|
49
|
-
open_checkboxes: ['continue
|
|
50
|
+
summary: 'Goal workflow bridge created as a native /goal persistence overlay.',
|
|
51
|
+
completed_checkboxes: ['goal bridge artifact written'],
|
|
52
|
+
open_checkboxes: ['continue the selected SKS execution route when implementation is needed'],
|
|
50
53
|
blockers: [],
|
|
51
54
|
evidence: [GOAL_WORKFLOW_ARTIFACT, GOAL_BRIDGE_ARTIFACT]
|
|
52
55
|
}
|
|
@@ -54,7 +57,7 @@ export async function writeGoalWorkflow(dir, mission, opts = {}) {
|
|
|
54
57
|
resume_context: {
|
|
55
58
|
stable_requirements: prompt ? [prompt] : [],
|
|
56
59
|
current_files: [GOAL_WORKFLOW_ARTIFACT, GOAL_BRIDGE_ARTIFACT],
|
|
57
|
-
decisions: ['Codex native /goal is the persisted continuation surface'],
|
|
60
|
+
decisions: ['Codex native /goal is the persisted continuation surface', '$Goal is a lightweight bridge overlay, not an independent implementation pipeline'],
|
|
58
61
|
known_mistakes_to_avoid: ['do not clear noisy context without writing a structured handoff first'],
|
|
59
62
|
active_skills: ['goal'],
|
|
60
63
|
active_agents: []
|
|
@@ -79,7 +82,7 @@ export async function updateGoalWorkflow(dir, action) {
|
|
|
79
82
|
action,
|
|
80
83
|
status: action === 'clear' ? 'cleared' : action === 'pause' ? 'paused' : action === 'resume' ? 'resumed' : current.status || 'created',
|
|
81
84
|
updated_at: nowIso(),
|
|
82
|
-
phase: action === 'pause' ? 'reporting' : action === 'resume' ? '
|
|
85
|
+
phase: action === 'pause' ? 'reporting' : action === 'resume' ? 'continuation' : action === 'clear' ? 'retro' : current.phase || 'intake',
|
|
83
86
|
native_goal: {
|
|
84
87
|
...(current.native_goal || {}),
|
|
85
88
|
slash_command: nativeGoalCommand(action, current.prompt || '')
|
|
@@ -89,7 +92,7 @@ export async function updateGoalWorkflow(dir, action) {
|
|
|
89
92
|
{
|
|
90
93
|
timestamp: nowIso(),
|
|
91
94
|
phase: action,
|
|
92
|
-
summary: `Goal ${action} requested through
|
|
95
|
+
summary: `Goal ${action} requested through native /goal bridge overlay.`,
|
|
93
96
|
completed_checkboxes: [`goal ${action} artifact update`],
|
|
94
97
|
open_checkboxes: action === 'clear' ? ['handoff preserved before noisy context clear'] : [],
|
|
95
98
|
blockers: [],
|
|
@@ -104,7 +107,7 @@ export async function updateGoalWorkflow(dir, action) {
|
|
|
104
107
|
}
|
|
105
108
|
|
|
106
109
|
function goalBridgeMarkdown(workflow) {
|
|
107
|
-
return `# SKS Goal Bridge
|
|
110
|
+
return `# SKS Goal Persistence Bridge
|
|
108
111
|
|
|
109
112
|
Mission: ${workflow.mission_id}
|
|
110
113
|
Status: ${workflow.status}
|
|
@@ -118,11 +121,13 @@ Run this in the Codex TUI when interactive native goal control is available:
|
|
|
118
121
|
${workflow.native_goal.slash_command}
|
|
119
122
|
\`\`\`
|
|
120
123
|
|
|
121
|
-
## SKS
|
|
124
|
+
## SKS Bridge Contract
|
|
122
125
|
|
|
123
126
|
- Ralph route is removed from the user-facing SKS surface.
|
|
124
|
-
- This
|
|
127
|
+
- This file is a fast SKS overlay for Codex native persisted \`/goal\` workflow semantics.
|
|
128
|
+
- \`$Goal\` is not a heavyweight independent implementation pipeline.
|
|
125
129
|
- SKS still records route evidence in \`${GOAL_WORKFLOW_ARTIFACT}\` and this bridge file.
|
|
126
|
-
- If implementation work is needed, continue through the
|
|
130
|
+
- If implementation work is needed, continue through the selected SKS execution route gates for that work and report verification evidence honestly.
|
|
131
|
+
- Context7 is optional for Goal bridge/control unless external API/library documentation becomes relevant.
|
|
127
132
|
`;
|
|
128
133
|
}
|
|
@@ -16,7 +16,6 @@ const LIGHT_ROUTE_STOP_ARTIFACT = 'light-route-stop.json';
|
|
|
16
16
|
const STOP_REPEAT_GUARD_WINDOW_MS = 10 * 60 * 1000;
|
|
17
17
|
const STOP_REPEAT_GUARD_MAX_ENTRIES = 25;
|
|
18
18
|
const DEFAULT_STOP_REPEAT_GUARD_LIMIT = 2;
|
|
19
|
-
const LIGHT_ROUTE_STOP_WINDOW_MS = 10 * 60 * 1000;
|
|
20
19
|
|
|
21
20
|
async function loadHookPayload() {
|
|
22
21
|
const raw = await readStdin();
|
|
@@ -113,7 +112,7 @@ async function hookUserPrompt(root, state, payload, noQuestion) {
|
|
|
113
112
|
const command = dollarCommand(prompt);
|
|
114
113
|
const route = routePrompt(prompt);
|
|
115
114
|
const bypassActiveRoute = route?.id === 'DFix' || route?.id === 'Answer';
|
|
116
|
-
|
|
115
|
+
const goalOverlay = activeGoalOverlayContext(state, route);
|
|
117
116
|
if (isClarificationAwaiting(state) && !looksLikeClarificationCancel(prompt)) {
|
|
118
117
|
const activeContext = await activeRouteContext(root, state);
|
|
119
118
|
const teamDigest = await teamLiveDigest(root, state);
|
|
@@ -123,8 +122,9 @@ async function hookUserPrompt(root, state, payload, noQuestion) {
|
|
|
123
122
|
const teamDigest = bypassActiveRoute ? null : await teamLiveDigest(root, state);
|
|
124
123
|
const activeContext = await activeRouteContext(root, state);
|
|
125
124
|
const contexts = [updateContext];
|
|
126
|
-
if (activeContext && !command && !bypassActiveRoute) contexts.push(routePipelineContext(prompt), activeContext);
|
|
125
|
+
if (activeContext && !command && !bypassActiveRoute && !goalOverlay) contexts.push(routePipelineContext(prompt), activeContext);
|
|
127
126
|
else contexts.push((await prepareRoute(root, prompt, state)).additionalContext);
|
|
127
|
+
if (goalOverlay) contexts.push(goalOverlay);
|
|
128
128
|
if (teamDigest?.context) contexts.push(teamDigest.context);
|
|
129
129
|
const additionalContext = contexts.filter(Boolean).join('\n\n');
|
|
130
130
|
return { continue: true, additionalContext, systemMessage: joinSystemMessages(visibleHookMessage('user-prompt-submit', additionalContext), teamDigest?.system) };
|
|
@@ -146,6 +146,16 @@ function looksLikeClarificationCancel(prompt = '') {
|
|
|
146
146
|
return /^(cancel|reset|restart|new mission|새로|취소|중단|리셋|다시 시작)\b/i.test(String(prompt || '').trim());
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
function activeGoalOverlayContext(state = {}, route = null) {
|
|
150
|
+
if (state.mode !== 'GOAL' || !state.mission_id) return '';
|
|
151
|
+
if (!route || route.id === 'Goal' || route.id === 'DFix' || route.id === 'Answer') return '';
|
|
152
|
+
return [
|
|
153
|
+
`Active Goal overlay: existing Goal mission ${state.mission_id} remains available for lightweight continuation context only.`,
|
|
154
|
+
`Do not let that active Goal hijack this new ${route.command || '$SKS'} prompt. The newly prepared route mission and gate are authoritative for this turn.`,
|
|
155
|
+
`Goal artifact: .sneakoscope/missions/${state.mission_id}/goal-workflow.json. Use Codex native /goal controls only if the user explicitly returns to $Goal.`
|
|
156
|
+
].join('\n');
|
|
157
|
+
}
|
|
158
|
+
|
|
149
159
|
async function hookPreTool(root, state, payload, noQuestion) {
|
|
150
160
|
const harnessDecision = await checkHarnessModification(root, payload, { phase: 'pre-tool' });
|
|
151
161
|
if (harnessDecision.action === 'block') {
|
|
@@ -225,7 +235,8 @@ async function hookPermission(root, state, payload, noQuestion) {
|
|
|
225
235
|
}
|
|
226
236
|
|
|
227
237
|
async function hookStop(root, state, payload, noQuestion) {
|
|
228
|
-
|
|
238
|
+
const last = extractLastMessage(payload);
|
|
239
|
+
if (!noQuestion && (hasDfixLightCompletion(last) || await consumeLightRouteStop(root, payload))) {
|
|
229
240
|
return {
|
|
230
241
|
continue: true,
|
|
231
242
|
systemMessage: 'SKS: DFix ultralight finalization accepted; full-route Honest Mode loopback is not required.'
|
|
@@ -234,7 +245,6 @@ async function hookStop(root, state, payload, noQuestion) {
|
|
|
234
245
|
const routeDecision = await evaluateStop(root, state, payload, { noQuestion });
|
|
235
246
|
if (routeDecision) return routeDecision;
|
|
236
247
|
if (!noQuestion) {
|
|
237
|
-
const last = extractLastMessage(payload);
|
|
238
248
|
if (!hasHonestMode(last)) {
|
|
239
249
|
const reason = 'SKS Honest Mode is required before finishing. Re-check the actual goal, verify evidence/tests, state gaps honestly, and only then provide the final answer. Include a short "SKS Honest Mode" or "솔직모드" section.';
|
|
240
250
|
const repeatDecision = await finalizationRepeatDecision(root, state, payload, reason, 'honest_mode_missing');
|
|
@@ -267,24 +277,6 @@ async function hookStop(root, state, payload, noQuestion) {
|
|
|
267
277
|
};
|
|
268
278
|
}
|
|
269
279
|
|
|
270
|
-
async function recordLightRouteStop(root, route = {}, payload = {}, prompt = '') {
|
|
271
|
-
const now = nowIso();
|
|
272
|
-
const expires = new Date(Date.parse(now) + LIGHT_ROUTE_STOP_WINDOW_MS).toISOString();
|
|
273
|
-
const file = path.join(root, '.sneakoscope', 'state', LIGHT_ROUTE_STOP_ARTIFACT);
|
|
274
|
-
await writeJsonAtomic(file, {
|
|
275
|
-
schema_version: 1,
|
|
276
|
-
route: route.id || null,
|
|
277
|
-
route_command: route.command || null,
|
|
278
|
-
mode: route.mode || null,
|
|
279
|
-
conversation_id: conversationId(payload),
|
|
280
|
-
prompt_hash: sha256(String(prompt || '')).slice(0, 16),
|
|
281
|
-
created_at: now,
|
|
282
|
-
expires_at: expires,
|
|
283
|
-
pending_stop_bypass: true,
|
|
284
|
-
stop_policy: 'dfix_ultralight_bypasses_full_route_honest_mode'
|
|
285
|
-
}).catch(() => null);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
280
|
async function consumeLightRouteStop(root, payload = {}) {
|
|
289
281
|
const file = path.join(root, '.sneakoscope', 'state', LIGHT_ROUTE_STOP_ARTIFACT);
|
|
290
282
|
const record = await readJson(file, null).catch(() => null);
|
|
@@ -303,6 +295,17 @@ async function consumeLightRouteStop(root, payload = {}) {
|
|
|
303
295
|
return true;
|
|
304
296
|
}
|
|
305
297
|
|
|
298
|
+
function hasDfixLightCompletion(text) {
|
|
299
|
+
const s = String(text || '');
|
|
300
|
+
const marker = /^\s*(?:\*\*)?\s*(?:\$?DFix|dfix)\s*(?:완료\s*요약|completion\s+summary)\s*[::]/im.test(s);
|
|
301
|
+
if (!marker) return false;
|
|
302
|
+
const honest = /^\s*(?:\*\*)?\s*(?:\$?DFix|dfix)\s*(?:솔직모드|honest(?:\s+mode)?)\s*[::]/im.test(s);
|
|
303
|
+
if (!honest) return false;
|
|
304
|
+
const verification = /(검증|확인|통과|verified|verification|checked|evidence|근거)/i.test(s);
|
|
305
|
+
const gap = /(미검증|남은|문제|gap|remaining|not verified|not run|blocker|차단|불가|없음|none)/i.test(s);
|
|
306
|
+
return verification && gap;
|
|
307
|
+
}
|
|
308
|
+
|
|
306
309
|
function explicitConversationId(payload = {}) {
|
|
307
310
|
return payload.conversation_id || payload.thread_id || payload.session_id || payload.chat_id || null;
|
|
308
311
|
}
|
|
@@ -771,6 +774,7 @@ function visibleHookMessage(name, text = '') {
|
|
|
771
774
|
if (body.includes('SKS answer-only pipeline active')) return 'SKS: answer-only research context injected.';
|
|
772
775
|
if (body.includes('SKS wiki pipeline active')) return 'SKS: wiki refresh context injected.';
|
|
773
776
|
if (body.includes('$Goal route prepared')) return 'SKS: Goal workflow bridge prepared for native Codex /goal continuation.';
|
|
777
|
+
if (body.includes('Computer Use fast lane active')) return 'SKS: Computer Use fast lane injected; defer TriWiki/Honest Mode to final closeout.';
|
|
774
778
|
if (body.includes('MANDATORY ambiguity-removal gate') || body.includes('VISIBLE RESPONSE CONTRACT') || body.includes('Required questions still pending')) return 'SKS: clarification questions must be shown in chat before the route can continue.';
|
|
775
779
|
if (body.includes('$Team route prepared') || body.includes('Team route')) return 'SKS: Team route, live transcript, and subagent plan injected.';
|
|
776
780
|
if (body.includes('$QA-LOOP route prepared') || body.includes('QA-LOOP')) return 'SKS: QA-LOOP route and safety checklist injected.';
|
package/src/core/init.mjs
CHANGED
|
@@ -90,7 +90,7 @@ function isSksManagedHook(hook) {
|
|
|
90
90
|
return hook.type === 'command' && /\bhook\s+(?:user-prompt-submit|pre-tool|post-tool|permission-request|stop)\b/.test(command) && /\b(?:sks|sneakoscope|sks\.mjs)\b/.test(command);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const AGENTS_BLOCK = "\n# Sneakoscope Codex Managed Rules\n\nThis repository uses Sneakoscope Codex.\n\n## Core Rules\n\n- Codex native `/goal` workflows are the persisted continuation surface; Ralph is removed from the user-facing SKS surface.\n- Keep runtime state bounded: raw logs go to files, prompts get tails/summaries, and `sks gc` may prune stale artifacts.\n- Before substantive work, SKS checks npm for a newer package. If newer, ask update-now vs skip-for-this-conversation.\n- Versioning is managed by the SKS pre-commit hook; check `sks versioning status`. Bypass only with `SKS_DISABLE_VERSIONING=1`.\n- Installed harness files are immutable to LLM edits: `.codex/*`, `.agents/skills/`, `.codex/agents/`, `.sneakoscope/*policy*.json`, `AGENTS.md`, and `node_modules/sneakoscope`. The Sneakoscope engine source repo is the only automatic exception.\n- OMX/DCodex conflicts block setup/doctor. Show `sks conflicts prompt`; cleanup requires explicit human approval.\n- Do not stop at a plan when implementation was requested. Finish, verify, or report the hard blocker.\n- Do not create unrequested fallback implementation code. If the requested path is impossible, block with evidence instead of inventing substitute behavior.\n\n## Routes\n\n- General execution/code-changing prompts default to `$Team`: analysis scouts, TriWiki refresh/validate, read-only debate, consensus, concrete runtime task graph/inboxes, fresh executor team, review, integration, Honest Mode.\n- `$Goal`
|
|
93
|
+
const AGENTS_BLOCK = "\n# Sneakoscope Codex Managed Rules\n\nThis repository uses Sneakoscope Codex.\n\n## Core Rules\n\n- Codex native `/goal` workflows are the persisted continuation surface; Ralph is removed from the user-facing SKS surface.\n- Keep runtime state bounded: raw logs go to files, prompts get tails/summaries, and `sks gc` may prune stale artifacts.\n- Before substantive work, SKS checks npm for a newer package. If newer, ask update-now vs skip-for-this-conversation.\n- Versioning is managed by the SKS pre-commit hook; check `sks versioning status`. Bypass only with `SKS_DISABLE_VERSIONING=1`.\n- Installed harness files are immutable to LLM edits: `.codex/*`, `.agents/skills/`, `.codex/agents/`, `.sneakoscope/*policy*.json`, `AGENTS.md`, and `node_modules/sneakoscope`. The Sneakoscope engine source repo is the only automatic exception.\n- OMX/DCodex conflicts block setup/doctor. Show `sks conflicts prompt`; cleanup requires explicit human approval.\n- Do not stop at a plan when implementation was requested. Finish, verify, or report the hard blocker.\n- Do not create unrequested fallback implementation code. If the requested path is impossible, block with evidence instead of inventing substitute behavior.\n\n## Routes\n\n- General execution/code-changing prompts default to `$Team`: analysis scouts, TriWiki refresh/validate, read-only debate, consensus, concrete runtime task graph/inboxes, fresh executor team, review, integration, Honest Mode.\n- `$Computer-Use` / `$CU` is the maximum-speed Codex Computer Use lane for UI/browser/visual tasks: skip Team debate and upfront TriWiki loops, use Codex Computer Use directly, then refresh/validate TriWiki and run Honest Mode at final closeout.\n- `$Goal` is a fast bridge/overlay for Codex native `/goal` create/pause/resume/clear persistence controls; implementation continues through the selected SKS execution route.\n- TriWiki recall must stay bounded. Use `sks wiki sweep` to record demote, soft-forget, archive, delete, promote-to-skill, and promote-to-rule candidates instead of injecting every old claim.\n- Team missions must keep schema-backed evidence current: `work-order-ledger.json`, `effort-decision.json`, `team-dashboard-state.json`, and route-specific visual/dogfood artifacts where applicable. Use `sks validate-artifacts latest` before claiming those artifacts pass.\n- `$DFix` is only for tiny design/content edits and bypasses the main pipeline, Team, TriWiki/TriFix/reflection recording, and persistent route state; it still uses a one-line DFix-specific Honest check before final. `$Answer`, `$Help`, and `$Wiki` stay lightweight.\n- For code work, surface route/guard/write scopes first, split independent worker scopes when available, and keep parent-owned integration and verification.\n- Design work reads `design.md`; if missing, use `design-system-builder`. Image/logo/raster assets use `imagegen`.\n- Research, AutoResearch, performance, token, accuracy, SEO/GEO, or workflow-improvement claims need experiment/eval evidence. Do not claim live model accuracy without a scored dataset.\n- Treat handwritten files above 3000 lines as split-review risks. Run `sks code-structure scan` and prefer extraction before adding substantial logic.\n\n## Evidence And Context\n\n- Context7 is required for external libraries, APIs, MCPs, package managers, SDKs, and generated docs: resolve-library-id then query-docs.\n- When tech stack, framework, package, runtime, or deployment-platform versions change, use Context7 or official vendor web docs, record current syntax/security/limit guidance as high-priority TriWiki claims, then refresh and validate before coding.\n- TriWiki is the context-tracking SSOT for long-running missions, Team handoffs, and context-pressure recovery. Read `.sneakoscope/wiki/context-pack.json` before each stage, use `attention.use_first` for compact high-trust recall, hydrate `attention.hydrate_first` from source before risky or lower-trust decisions, refresh after findings or artifact changes, and validate before handoffs/final claims.\n- Source priority: current code/tests/config, decision contract, vgraph, beta, GX render/snapshot metadata, LLM Wiki coordinate index, then model knowledge only if allowed.\n- Final response before stop: summarize what was done, what changed for the user/repo, what was verified, and what remains unverified or blocked; then run Honest Mode. Say what passed and what was not verified.\n- `$From-Chat-IMG` uses forensic visual effort, not ordinary Team effort. Completion is blocked until source inventory, visual mapping, work-order coverage, scoped dogfood/QA, and post-fix verification artifacts are present and valid.\n\n## Safety\n\n- Database access is high risk. Use read-only inspection by default; live data mutation is out of scope unless a sealed contract allows local or branch-only migration files.\n- MAD and MAD-SKS widen only explicit scoped permissions; they still do not authorize unrequested fallback implementation code.\n- Task completion requires relevant tests or justification, zero unsupported critical claims, accepted visual/wiki drift, and final evidence.\n\n## Codex App\n\nUse `.codex/SNEAKOSCOPE.md`, generated `.agents/skills`, `.codex/hooks.json`, and SKS dollar commands (`$sks`, `$team`, `$computer-use`, `$cu`, `$goal`, `$dfix`, `$qa-loop`, etc.) as the app control surface.\n";
|
|
94
94
|
|
|
95
95
|
export async function initProject(root, opts = {}) {
|
|
96
96
|
const created = [];
|
|
@@ -514,27 +514,30 @@ function codexAppQuickReference(scope, commandPrefix) {
|
|
|
514
514
|
'dollar-commands:',
|
|
515
515
|
...DOLLAR_COMMANDS.map((c) => `- \`${c.command}\`: ${c.route}`),
|
|
516
516
|
`Picker skills: ${DOLLAR_COMMAND_ALIASES.map((x) => x.app_skill).join(', ')}.`,
|
|
517
|
-
'Routing: Answer direct, DFix ultralight, execution routes ask only scope/safety/behavior/acceptance-changing questions before sealing answers.',
|
|
517
|
+
'Routing: Answer direct, DFix ultralight no-record, execution routes ask only scope/safety/behavior/acceptance-changing questions before sealing answers.',
|
|
518
518
|
`Full routes write reflection.md, record lessons to ${REFLECTION_MEMORY_PATH}, refresh/pack TriWiki, validate, then final-answer with a user-visible completion summary plus Honest Mode.`,
|
|
519
519
|
`Runtime root: ${commandPrefix} root shows whether SKS is using the nearest project root or the per-user global SKS runtime root; outside any project marker, runtime commands use the global root instead of writing .sneakoscope into the current random directory.`,
|
|
520
520
|
`Context Tracking: TriWiki SSOT. Before each route phase read only the latest coordinate+voxel overlay pack at .sneakoscope/wiki/context-pack.json; coordinate-only legacy packs are invalid. Use attention.use_first for compact high-trust recall and hydrate attention.hydrate_first from source before risky/lower-trust decisions. During every stage hydrate low-trust claims from source/hash/RGBA anchors; after changes run ${commandPrefix} wiki refresh or pack; before handoff/final run ${commandPrefix} wiki validate .sneakoscope/wiki/context-pack.json.`,
|
|
521
521
|
stackCurrentDocsPolicyText(commandPrefix),
|
|
522
|
-
`Team Warp view: ${commandPrefix} team "task"
|
|
523
|
-
`Runtime: open Codex App once, then run ${commandPrefix} bootstrap, ${commandPrefix} deps check, or ${commandPrefix}
|
|
522
|
+
`Team Warp view: ${commandPrefix} team "task" prepares live watch/lane commands without opening Warp by default; add --open-warp when you explicitly want a Warp Launch Configuration with an overview watch pane plus color-coded split per-agent lanes; ${commandPrefix} team lane latest --agent analysis_scout_1 --follow shows one agent's status, assigned runtime tasks, recent agent events, direct messages, and fallback global tail; ${commandPrefix} team message latest --from analysis_scout_1 --to executor_1 --message "handoff note" mirrors bounded agent communication into transcript/lane panes; ${commandPrefix} team cleanup-warp latest marks the SKS launch record complete and asks follow panes to show a cleanup summary then stop.`,
|
|
523
|
+
`Runtime: open Codex App once, then run ${commandPrefix} bootstrap, ${commandPrefix} deps check, or ${commandPrefix} warp open when you explicitly want a Warp/Codex CLI launch.`,
|
|
524
524
|
`Guard: generated harness files are immutable outside the engine source repo; check ${commandPrefix} guard check; conflicts use ${commandPrefix} conflicts prompt with human approval.`
|
|
525
525
|
].join('\n') + '\n';
|
|
526
526
|
}
|
|
527
527
|
|
|
528
528
|
export async function installSkills(root) {
|
|
529
529
|
const skills = {
|
|
530
|
-
'dfix': `---\nname: dfix\ndescription: Ultralight fast design/content fix mode for $DFix or $dfix requests and inferred simple edits such as text color, copy, labels, spacing, or translation.\n---\n\nUse for tiny copy/color/label/spacing/translation edits. List exact micro-edits, inspect only needed files, apply only those edits, and run cheap verification. Bypass broad SKS routing, Goal, Research, eval, redesign, and repeated full-route Honest Mode loops. Read \`design.md\` for UI work when present; use imagegen for image/logo/raster assets.\n`,
|
|
530
|
+
'dfix': `---\nname: dfix\ndescription: Ultralight fast design/content fix mode for $DFix or $dfix requests and inferred simple edits such as text color, copy, labels, spacing, or translation.\n---\n\nUse for tiny copy/color/label/spacing/translation edits. List exact micro-edits, inspect only needed files, apply only those edits, and run cheap verification. Bypass broad SKS routing, mission state, TriWiki/TriFix/reflection/state recording, Goal, Research, eval, redesign, and repeated full-route Honest Mode loops. Start the final answer with \`DFix 완료 요약:\` and include one \`DFix 솔직모드:\` line covering verified, not verified, and remaining issues. Read \`design.md\` for UI work when present; use imagegen for image/logo/raster assets.\n`,
|
|
531
531
|
'answer': `---\nname: answer\ndescription: Answer-only research route for ordinary questions that should not start implementation.\n---\n\nUse for explanations, comparisons, status, facts, source-backed research, or docs guidance. Use repo/TriWiki first for project-local facts; hydrate low-trust claims from source. Browse or use Context7 for current external package/API/framework/MCP docs. End with a concise answer summary plus Honest Mode; do not create missions, subagents, or file edits.\n`,
|
|
532
532
|
'sks': `---\nname: sks\ndescription: General Sneakoscope Codex command route for $SKS or $sks usage, setup, status, and workflow help.\n---\n\nUse local SKS commands: bootstrap, deps, commands, quickstart, codex-app, context7, guard, conflicts, reasoning, wiki, pipeline. Promote code-changing work to Team unless Answer/DFix/Help/Wiki/safety route fits. Surface route/guard/scope, use TriWiki, do not edit installed harness files outside this engine repo, and require human-approved conflict cleanup.\n`,
|
|
533
533
|
'wiki': `---\nname: wiki\ndescription: Dollar-command route for $Wiki TriWiki refresh, pack, validate, and prune commands.\n---\n\nUse for $Wiki or Korean wiki-refresh requests. Refresh/update/갱신: run sks wiki refresh, then validate .sneakoscope/wiki/context-pack.json. Pack: run sks wiki pack, then validate. Prune/clean/정리: use sks wiki refresh --prune, or sks wiki prune --dry-run for inspection. Report claims, anchors, trust, attention.use_first/hydrate_first, validation, and blockers. Do not start ambiguity-gated implementation, subagents, or unrelated work.\n`,
|
|
534
534
|
'team': `---\nname: team\ndescription: SKS Team orchestration for $Team/code work; $From-Chat-IMG is the explicit chat-image alias.\n---\n\nUse for $Team/code work. Ambiguity gate first. Write team-roster.json; team-gate.json needs team_roster_confirmed=true. executor:N means N scouts, N debate voices, then fresh N executors. After consensus, compile team-graph.json, team-runtime-tasks.json, team-decomposition-report.json, and team-inbox/ so worker handoff uses concrete runtime task ids with role/path/domain/lane hints. Refresh/validate TriWiki before debate, implementation, review, and final; consume attention.use_first and hydrate attention.hydrate_first before risky decisions. Log events and use sks team message for bounded inter-agent communication in transcript/lane panes. Color-coded Warp lanes distinguish overview/scout/planning/execution/review/safety sessions. End with cleanup-warp or a cleanup event so follow panes show cleanup and stop; pass team-session-cleanup.json, then reflection and Honest Mode. Parent integrates/verifies.\n\n${chatCaptureIntakeText()}\n`,
|
|
535
535
|
'from-chat-img': `---\nname: from-chat-img\ndescription: Explicit $From-Chat-IMG Team alias for chat screenshot plus attachment analysis.\n---\n\nUse only for From-Chat-IMG/$From-Chat-IMG. It enters the normal Team pipeline. Treat uploads as chat screenshot plus originals. Use Codex Computer Use visual inspection when available, list requirements first, match regions to attachments with confidence, write ${FROM_CHAT_IMG_COVERAGE_ARTIFACT}, ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT}, ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT}, and ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT}, then continue Team gates, review, reflection, and Honest Mode. ${CODEX_COMPUTER_USE_ONLY_POLICY} The ledger must account for every visible customer request, screenshot image region, and separate attachment; ${FROM_CHAT_IMG_CHECKLIST_ARTIFACT} must have a checked item for each request, image-region/attachment match, work item, scoped QA-LOOP, and verification step; ${FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT} stores temporary TriWiki-backed session context with expires_after_sessions=${FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS}. ${FROM_CHAT_IMG_QA_LOOP_ARTIFACT} must prove QA-LOOP ran over the exact customer-request work-order range after implementation, with every work item covered, post-fix verification complete, and zero unresolved findings. team-gate.json cannot pass From-Chat-IMG completion until unresolved_items is empty, every checklist box is checked, and scoped_qa_loop_completed=true.\n`,
|
|
536
536
|
'qa-loop': `---\nname: qa-loop\ndescription: $QA-LOOP dogfoods UI/API as human proxy with safety gates, Codex Computer Use-only UI evidence, safe fixes, rechecks, and a QA report.\n---\n\nUse only $QA-LOOP. Ask scope, target, mutation, login. Credentials are runtime-only; never save secrets. UI-level E2E needs Codex Computer Use evidence or must be marked unverified; Chrome MCP, Browser Use, Playwright, Selenium, Puppeteer, and other browser automation do not satisfy UI/browser verification. Deployed targets are read-only; destructive removal is forbidden. After answer/run, dogfood real flows, apply safe contract-allowed code/test/docs fixes, recheck, and do not pass qa-gate.json with unresolved findings or without post_fix_verification_complete. Finish qa-ledger, date/version report, gate, completion summary, and Honest Mode.\n`,
|
|
537
|
-
'
|
|
537
|
+
'computer-use': `---\nname: computer-use\ndescription: Maximum-speed $Computer-Use/$CU lane for Codex Computer Use UI/browser/visual tasks.\n---\n\nUse only when the user invokes $Computer-Use/$CU or asks for a Computer Use-specific fast lane. Skip Team debate, QA-LOOP clarification, upfront TriWiki refresh, Context7, subagents, and reflection unless explicitly requested. Infer the smallest target, use Codex Computer Use directly, and never substitute Playwright, Chrome MCP, Browser Use, Selenium, Puppeteer, or other browser automation for UI/browser evidence. If Computer Use is unavailable, mark UI/browser evidence unverified and stop with the blocker. At the end only, refresh or pack TriWiki, validate it, then provide a concise completion summary plus Honest Mode.\n`,
|
|
538
|
+
'computer-use-fast': `---\nname: computer-use-fast\ndescription: Alias for the maximum-speed $Computer-Use/$CU Codex Computer Use lane.\n---\n\nUse the same rules as computer-use: skip Team debate, QA-LOOP clarification, upfront TriWiki refresh, Context7, subagents, and reflection unless explicitly requested. Use Codex Computer Use directly; never substitute Playwright, Chrome MCP, Browser Use, Selenium, Puppeteer, or other browser automation for UI/browser evidence. At the end only, refresh/pack TriWiki, validate it, then provide a concise completion summary plus Honest Mode.\n`,
|
|
539
|
+
'cu': `---\nname: cu\ndescription: Short alias for the maximum-speed $Computer-Use Codex Computer Use lane.\n---\n\nUse the same rules as computer-use. This is a speed lane for focused UI/browser/visual tasks that require Codex Computer Use evidence, with TriWiki refresh/validate and Honest Mode deferred to final closeout.\n`,
|
|
540
|
+
'goal': `---\nname: goal\ndescription: Fast $Goal/$goal bridge overlay for Codex native persisted /goal workflows.\n---\n\nUse when the user invokes $Goal/$goal or asks to persist a workflow with Codex native /goal continuation. Prepare with sks goal create or the $Goal route, write only the lightweight bridge artifacts, then use native Codex /goal create, pause, resume, and clear controls where available. Goal does not replace Team, QA, DB, or other SKS execution routes; continue implementation through the selected route and use Context7 only when external API/library docs are involved. Do not recreate the old no-question loop.\n`,
|
|
538
541
|
'research': `---\nname: research\ndescription: Dollar-command route for $Research or $research frontier discovery workflows.\n---\n\nUse when the user invokes $Research/$research or asks for research, hypotheses, new mechanisms, falsification, or testable predictions. Prefer sks research prepare and sks research run. Do not use for ordinary code edits.\n`,
|
|
539
542
|
'autoresearch': `---\nname: autoresearch\ndescription: Dollar-command route for $AutoResearch or $autoresearch iterative experiment loops.\n---\n\nUse for $AutoResearch, iterative improvement, SEO/GEO, ranking, workflow, benchmark, or experiments. Define program, hypothesis, experiment, metric, keep/discard, falsification, next step, and Honest Mode. Load seo-geo-optimizer for README/npm/GitHub/schema/AI-search work.\n`,
|
|
540
543
|
'db': `---\nname: db\ndescription: Dollar-command route for $DB or $db database and Supabase safety checks.\n---\n\nUse when the user invokes $DB/$db or the task touches SQL, Supabase, Postgres, migrations, Prisma, Drizzle, Knex, MCP database tools, or production data. Run or follow sks db policy, sks db scan, sks db classify, and sks db check. Destructive database operations remain forbidden.\n`,
|
|
@@ -579,7 +582,7 @@ export async function installSkills(root) {
|
|
|
579
582
|
}
|
|
580
583
|
|
|
581
584
|
function enrichSkillContent(name, content) {
|
|
582
|
-
if (!['sks', 'answer', 'wiki', 'team', 'qa-loop', 'goal', 'research', 'autoresearch', 'db', 'gx', 'reflection', 'prompt-pipeline', 'pipeline-runner', 'context7-docs', 'turbo-context-pack', 'hproof-evidence-bind'].includes(name)) return content;
|
|
585
|
+
if (!['sks', 'answer', 'wiki', 'team', 'qa-loop', 'computer-use', 'computer-use-fast', 'cu', 'goal', 'research', 'autoresearch', 'db', 'gx', 'reflection', 'prompt-pipeline', 'pipeline-runner', 'context7-docs', 'turbo-context-pack', 'hproof-evidence-bind'].includes(name)) return content;
|
|
583
586
|
const text = String(content || '').trimEnd();
|
|
584
587
|
if (text.includes('TriWiki context-tracking SSOT')) return text;
|
|
585
588
|
return `${text}
|
|
@@ -594,7 +597,9 @@ Context tracking:
|
|
|
594
597
|
}
|
|
595
598
|
|
|
596
599
|
async function writeSkillMetadata(dir, name) {
|
|
597
|
-
const effort = ['
|
|
600
|
+
const effort = ['computer-use', 'computer-use-fast', 'cu'].includes(name)
|
|
601
|
+
? 'low'
|
|
602
|
+
: ['research', 'autoresearch', 'research-discovery', 'autoresearch-loop', 'from-chat-img'].includes(name)
|
|
598
603
|
? 'xhigh'
|
|
599
604
|
: (['dfix', 'sks', 'help'].includes(name) ? 'medium' : 'high');
|
|
600
605
|
await ensureDir(path.join(dir, 'agents'));
|
package/src/core/pipeline.mjs
CHANGED
|
@@ -36,6 +36,7 @@ export function promptPipelineContext(prompt, route = routePrompt(prompt)) {
|
|
|
36
36
|
const fastDesign = route?.id === 'DFix';
|
|
37
37
|
if (fastDesign) return dfixQuickContext(prompt, route);
|
|
38
38
|
if (route?.id === 'Answer') return answerOnlyContext(prompt, route);
|
|
39
|
+
if (route?.id === 'ComputerUse') return computerUseFastContext(prompt, route);
|
|
39
40
|
const lines = [
|
|
40
41
|
`SKS skill-first pipeline active. Route: ${route?.command || '$SKS'} (${route?.route || 'general SKS workflow'}).`,
|
|
41
42
|
reasoningInstruction(reasoning),
|
|
@@ -81,7 +82,7 @@ export function dfixQuickContext(prompt, route = routePrompt(prompt)) {
|
|
|
81
82
|
'2. Inspect only the files needed to locate that target.',
|
|
82
83
|
'3. Apply only the listed design/content edit; for UI/UX micro-edits read design.md when present, and use imagegen for any image/logo/raster asset.',
|
|
83
84
|
'4. Run only cheap verification when useful, such as syntax check, focused test, or local render smoke.',
|
|
84
|
-
'5. Final response:
|
|
85
|
+
'5. Final response: start with `DFix 완료 요약:` and include one `DFix 솔직모드:` line with verified / not verified / remaining issue status. Do not create TriWiki/TriFix/reflection/state records and do not enter repeated full-route Honest Mode loops.'
|
|
85
86
|
].join('\n');
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -111,6 +112,7 @@ export async function prepareRoute(root, prompt, state = {}) {
|
|
|
111
112
|
if (!route) return { route: null, additionalContext: promptPipelineContext(prompt, null) };
|
|
112
113
|
if (route.id === 'DFix') return prepareDfixQuickRoute(route, task);
|
|
113
114
|
if (route.id === 'Answer') return prepareAnswerOnlyRoute(route, task);
|
|
115
|
+
if (route.id === 'ComputerUse') return prepareComputerUseFastRoute(route, task);
|
|
114
116
|
if (route.id === 'Wiki') return prepareWikiQuickRoute(route, task);
|
|
115
117
|
if (route.id === 'Goal') return prepareGoal(root, route, task, routeNeedsContext7(route, prompt));
|
|
116
118
|
const required = routeNeedsContext7(route, prompt);
|
|
@@ -143,6 +145,30 @@ async function prepareAnswerOnlyRoute(route, task) {
|
|
|
143
145
|
};
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
async function prepareComputerUseFastRoute(route, task) {
|
|
149
|
+
return {
|
|
150
|
+
route,
|
|
151
|
+
additionalContext: computerUseFastContext(task, route)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function computerUseFastContext(prompt, route = routePrompt(prompt)) {
|
|
156
|
+
const task = stripDollarCommand(prompt) || String(prompt || '').trim();
|
|
157
|
+
return [
|
|
158
|
+
`Computer Use fast lane active. Route: ${route?.command || '$Computer-Use'} (${route?.route || 'Computer Use fast lane'}).`,
|
|
159
|
+
'Speed contract: do not enter Team, QA-LOOP clarification, repeated upfront TriWiki refresh, Context7, subagent orchestration, debate, reflection, or broad planning unless the user explicitly requests that heavier route.',
|
|
160
|
+
`Task: ${task}`,
|
|
161
|
+
'Execution order:',
|
|
162
|
+
'1. Infer the smallest UI/browser/visual target and acceptance from the prompt and current app context.',
|
|
163
|
+
'2. Use Codex Computer Use directly for the focused screen/browser action or inspection. Do not substitute Playwright, Chrome MCP, Browser Use, Selenium, Puppeteer, or other browser automation for UI/browser evidence.',
|
|
164
|
+
'3. If Computer Use is unavailable, mark UI/browser evidence unverified and stop with the exact blocker instead of switching tools.',
|
|
165
|
+
'4. Apply only safe, directly requested fixes when the prompt asks for correction; otherwise report observed evidence only.',
|
|
166
|
+
'5. At the end only, run `sks wiki refresh` or `sks wiki pack`, then `sks wiki validate .sneakoscope/wiki/context-pack.json` when the repo/runtime is available.',
|
|
167
|
+
'6. Final response must include a short completion summary plus SKS Honest Mode: evidence used, tests/checks run, and any unverified UI/browser claims.',
|
|
168
|
+
CODEX_COMPUTER_USE_ONLY_POLICY
|
|
169
|
+
].join('\n');
|
|
170
|
+
}
|
|
171
|
+
|
|
146
172
|
async function prepareWikiQuickRoute(route, task) {
|
|
147
173
|
return {
|
|
148
174
|
route,
|
|
@@ -187,8 +213,27 @@ export async function activeRouteContext(root, state) {
|
|
|
187
213
|
async function prepareGoal(root, route, task, required) {
|
|
188
214
|
const { id, dir, mission } = await createMission(root, { mode: 'goal', prompt: task });
|
|
189
215
|
const workflow = await writeGoalWorkflow(dir, mission, { action: 'create', prompt: task });
|
|
190
|
-
await writeJsonAtomic(path.join(dir, 'route-context.json'), { route: route.id, command: route.command, mode: route.mode, task, required_skills: route.requiredSkills, context7_required: required, native_goal: workflow.native_goal, stop_gate:
|
|
191
|
-
|
|
216
|
+
await writeJsonAtomic(path.join(dir, 'route-context.json'), { route: route.id, command: route.command, mode: route.mode, task, required_skills: route.requiredSkills, context7_required: required, native_goal: workflow.native_goal, stop_gate: route.stopGate });
|
|
217
|
+
const executionRoute = routePrompt(task);
|
|
218
|
+
const shouldDelegateExecution = routeRequiresSubagents(route, task)
|
|
219
|
+
&& executionRoute
|
|
220
|
+
&& !['Answer', 'DFix', 'Goal', 'Help'].includes(executionRoute.id);
|
|
221
|
+
if (shouldDelegateExecution) {
|
|
222
|
+
await appendJsonl(path.join(dir, 'events.jsonl'), { ts: nowIso(), type: 'goal.delegated_execution_route', route: executionRoute.id, command: executionRoute.command });
|
|
223
|
+
const delegated = await prepareRoute(root, task, {});
|
|
224
|
+
return {
|
|
225
|
+
route,
|
|
226
|
+
additionalContext: [
|
|
227
|
+
`$Goal bridge prepared as a lightweight native /goal persistence overlay.
|
|
228
|
+
Goal bridge mission: ${id}
|
|
229
|
+
Goal artifact: .sneakoscope/missions/${id}/${GOAL_WORKFLOW_ARTIFACT}
|
|
230
|
+
Native Codex control: ${workflow.native_goal.slash_command}
|
|
231
|
+
Delegated execution route: ${executionRoute.command}. The delegated route mission is authoritative for implementation, verification, and final gates.`,
|
|
232
|
+
delegated.additionalContext
|
|
233
|
+
].filter(Boolean).join('\n\n')
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
await setCurrent(root, routeState(id, route, 'GOAL_READY', required, { prompt: task, native_goal: workflow.native_goal, stop_gate: route.stopGate, implementation_allowed: true, questions_allowed: true }));
|
|
192
237
|
return routeContext(route, id, task, required, `Use Codex native ${workflow.native_goal.slash_command} control for persisted continuation, then continue the relevant SKS route gates for any implementation work.`);
|
|
193
238
|
}
|
|
194
239
|
|
package/src/core/routes.mjs
CHANGED
|
@@ -45,6 +45,8 @@ export const RECOMMENDED_SKILLS = [
|
|
|
45
45
|
'design-system-builder',
|
|
46
46
|
'design-ui-editor',
|
|
47
47
|
'imagegen',
|
|
48
|
+
'computer-use',
|
|
49
|
+
'computer-use-fast',
|
|
48
50
|
'db-safety-guard',
|
|
49
51
|
REFLECTION_SKILL_NAME,
|
|
50
52
|
'honest-mode'
|
|
@@ -148,7 +150,7 @@ export const ROUTES = [
|
|
|
148
150
|
command: '$DFix',
|
|
149
151
|
mode: 'DFIX',
|
|
150
152
|
route: 'fast design/content fix',
|
|
151
|
-
description: 'Small UI/content edits such as text color, copy, label, spacing, or translation. Bypasses the general SKS pipeline and runs an ultralight task-list path.',
|
|
153
|
+
description: 'Small UI/content edits such as text color, copy, label, spacing, or translation. Bypasses the general SKS pipeline and runs an ultralight, no-record task-list path.',
|
|
152
154
|
requiredSkills: ['dfix'],
|
|
153
155
|
lifecycle: ['micro_task_list', 'targeted_inspection', 'listed_edits_only', 'cheap_verification'],
|
|
154
156
|
context7Policy: 'optional',
|
|
@@ -215,17 +217,33 @@ export const ROUTES = [
|
|
|
215
217
|
cliEntrypoint: 'sks qa-loop prepare|answer|run|status',
|
|
216
218
|
examples: ['$QA-LOOP dogfood UI and API against local dev', '$QA-LOOP deployed smoke only']
|
|
217
219
|
},
|
|
220
|
+
{
|
|
221
|
+
id: 'ComputerUse',
|
|
222
|
+
command: '$Computer-Use',
|
|
223
|
+
mode: 'COMPUTER_USE',
|
|
224
|
+
route: 'Computer Use fast lane',
|
|
225
|
+
description: 'Maximum-speed Codex Computer Use lane for UI/browser/visual tasks: skip Team debate and upfront TriWiki loops, run only focused Computer Use steps, then finish with evidence, TriWiki refresh/validate, and Honest Mode.',
|
|
226
|
+
requiredSkills: ['computer-use', 'honest-mode'],
|
|
227
|
+
dollarAliases: ['$CU'],
|
|
228
|
+
appSkillAliases: ['computer-use-fast', 'cu'],
|
|
229
|
+
lifecycle: ['fast_intake', 'focused_computer_use_steps', 'evidence_summary', 'final_triwiki_refresh_validate', 'honest_mode'],
|
|
230
|
+
context7Policy: 'optional',
|
|
231
|
+
reasoningPolicy: 'low',
|
|
232
|
+
stopGate: 'none',
|
|
233
|
+
cliEntrypoint: 'Codex App prompt route only: $Computer-Use <target/task>',
|
|
234
|
+
examples: ['$Computer-Use check the local UI as fast as possible', '$CU localhost screen smoke']
|
|
235
|
+
},
|
|
218
236
|
{
|
|
219
237
|
id: 'Goal',
|
|
220
238
|
command: '$Goal',
|
|
221
239
|
mode: 'GOAL',
|
|
222
|
-
route: 'native
|
|
223
|
-
description: '
|
|
224
|
-
requiredSkills: ['goal', '
|
|
225
|
-
lifecycle: ['
|
|
226
|
-
context7Policy: '
|
|
227
|
-
reasoningPolicy: '
|
|
228
|
-
stopGate: '
|
|
240
|
+
route: 'native /goal persistence bridge',
|
|
241
|
+
description: 'Fast overlay that records a bridge artifact for Codex native persisted /goal create, pause, resume, and clear controls; implementation continues through the selected SKS execution route.',
|
|
242
|
+
requiredSkills: ['goal', 'honest-mode'],
|
|
243
|
+
lifecycle: ['goal_bridge_artifact', 'native_goal_create_or_control', 'selected_sks_route_continuation', 'honest_mode'],
|
|
244
|
+
context7Policy: 'if_external_docs',
|
|
245
|
+
reasoningPolicy: 'medium',
|
|
246
|
+
stopGate: 'none',
|
|
229
247
|
cliEntrypoint: 'sks goal create|pause|resume|clear|status',
|
|
230
248
|
examples: ['$Goal persist this migration workflow with native /goal continuation']
|
|
231
249
|
},
|
|
@@ -354,7 +372,7 @@ export const COMMAND_CATALOG = [
|
|
|
354
372
|
{ name: 'root', usage: 'sks root [--json]', description: 'Show whether SKS is using a project root or the per-user global SKS runtime root.' },
|
|
355
373
|
{ name: 'deps', usage: 'sks deps check|install [warp|codex|context7|all] [--yes]', description: 'Check or guided-install Node/npm PATH, Codex CLI/App, Context7, Browser Use, Computer Use, warp, and Homebrew on macOS.' },
|
|
356
374
|
{ name: 'codex-app', usage: 'sks codex-app [check|open]', description: 'Check Codex App install and first-party MCP/plugin readiness, then show app setup files and examples.' },
|
|
357
|
-
{ name: 'warp', usage: 'sks warp
|
|
375
|
+
{ name: 'warp', usage: 'sks warp open|check|status [--workspace name]', description: 'Explicitly open the SKS warp runtime, or check/status without launching Warp.' },
|
|
358
376
|
{ name: 'mad', usage: 'sks --mad [--high]', description: 'Open a one-shot warp Codex CLI workspace with the SKS MAD full-access auto-review profile.' },
|
|
359
377
|
{ name: 'auto-review', usage: 'sks auto-review status|enable|start [--high] | sks --Auto-review --high', description: 'Enable Codex automatic approval review and launch SKS warp with the auto-review profile.' },
|
|
360
378
|
{ name: 'dollar-commands', usage: 'sks dollar-commands [--json]', description: 'List Codex App $ commands such as $DFix and $Team.' },
|
|
@@ -371,7 +389,7 @@ export const COMMAND_CATALOG = [
|
|
|
371
389
|
{ name: 'doctor', usage: 'sks doctor [--fix] [--local-only] [--json] [--install-scope global|project]', description: 'Check and repair SKS generated files, while blocking setup if another Codex harness is detected.' },
|
|
372
390
|
{ name: 'init', usage: 'sks init [--force] [--local-only] [--install-scope global|project]', description: 'Initialize the local SKS control surface.' },
|
|
373
391
|
{ name: 'selftest', usage: 'sks selftest [--mock]', description: 'Run local smoke tests without calling a model.' },
|
|
374
|
-
{ name: 'goal', usage: 'sks goal create|pause|resume|clear|status ...', description: 'Prepare and control SKS bridge
|
|
392
|
+
{ name: 'goal', usage: 'sks goal create|pause|resume|clear|status ...', description: 'Prepare and control the fast SKS bridge overlay for Codex native persisted /goal workflows.' },
|
|
375
393
|
{ name: 'research', usage: 'sks research prepare|run|status ...', description: 'Run frontier-style research missions with novelty and falsification gates.' },
|
|
376
394
|
{ name: 'db', usage: 'sks db policy|scan|mcp-config|classify|check ...', description: 'Inspect and enforce database/Supabase safety policy.' },
|
|
377
395
|
{ name: 'eval', usage: 'sks eval run|compare|thresholds ...', description: 'Run deterministic context-quality and performance evidence checks.' },
|
|
@@ -455,6 +473,7 @@ export function routePrompt(prompt) {
|
|
|
455
473
|
return route;
|
|
456
474
|
}
|
|
457
475
|
if (hasFromChatImgSignal(text)) return routeById('Team');
|
|
476
|
+
if (looksLikeComputerUseFastLane(text)) return routeById('ComputerUse');
|
|
458
477
|
if (looksLikeFastDesignFix(text)) return routeById('DFix');
|
|
459
478
|
if (looksLikeQuestionShapedDirective(text)) return routeById('Team');
|
|
460
479
|
if (looksLikeAnswerOnlyRequest(text)) return routeById('Answer');
|
|
@@ -464,12 +483,19 @@ export function routePrompt(prompt) {
|
|
|
464
483
|
if (/\b(qa[-\s]?loop|qaloop|e2e\s+qa|qa\s+e2e)\b/i.test(text)) return routeById('QALoop');
|
|
465
484
|
if (/\b(autoresearch|experiment|benchmark|SEO|GEO|ranking|optimi[sz]e|improve metric|discoverability|visibility|github stars?|npm downloads?|검색|노출|스타|다운로드)\b/i.test(text)) return routeById('AutoResearch');
|
|
466
485
|
if (/\b(research|hypothesis|falsify|novelty|frontier|조사|연구)\b/i.test(text)) return routeById('Research');
|
|
467
|
-
if (/(wiki\s+(refresh|pack|validate|prune)|triwiki\s+(refresh|pack|validate)|위키\s*(갱신|리프레시|정리|검증|패킹)|트라이위키|triwiki)/i.test(text)) return routeById('Wiki');
|
|
486
|
+
if (/(wiki\s+(refresh|pack|validate|prune)|triwiki\s+(refresh|pack|validate)|위키\s*(갱신|리프레시|정리|검증|패킹)|트라이위키|triwiki)/i.test(text) && !looksLikeDirectWorkRequest(text)) return routeById('Wiki');
|
|
468
487
|
if (/\b(GX|vgraph|visual context|render cartridge|wiki coordinate|rgba|trig|llm wiki)\b/i.test(text)) return routeById('GX');
|
|
469
488
|
if (looksLikeTeamDefaultWork(text)) return routeById('Team');
|
|
470
489
|
return routeById('SKS');
|
|
471
490
|
}
|
|
472
491
|
|
|
492
|
+
export function looksLikeComputerUseFastLane(prompt = '') {
|
|
493
|
+
const text = String(prompt || '');
|
|
494
|
+
const computerUseCue = /\b(computer\s*use|codex\s+computer\s+use|computer-use)\b|컴퓨터\s*유즈|컴퓨터\s*사용|컴퓨터유즈/i.test(text);
|
|
495
|
+
if (!computerUseCue) return false;
|
|
496
|
+
return /\b(ui|browser|visual|screen|screenshot|e2e|qa|dogfood|fast|lane|pipeline|localhost|web|app|page)\b|화면|브라우저|시각|스크린|캡처|검증|빠른|고속|파이프라인|작업|속도/i.test(text);
|
|
497
|
+
}
|
|
498
|
+
|
|
473
499
|
export function looksLikeTeamDefaultWork(prompt = '') {
|
|
474
500
|
const text = String(prompt || '').trim();
|
|
475
501
|
if (!text) return false;
|
|
@@ -515,16 +541,17 @@ export function routeRequiresSubagents(route, prompt = '') {
|
|
|
515
541
|
if (!route) return false;
|
|
516
542
|
if (route.id === 'Team') return true;
|
|
517
543
|
if (route.id === 'SKS') return looksLikeTeamDefaultWork(prompt);
|
|
518
|
-
if (route.id === 'Help' || route.id === 'Answer' || route.id === 'Wiki') return false;
|
|
544
|
+
if (route.id === 'Help' || route.id === 'Answer' || route.id === 'Wiki' || route.id === 'ComputerUse') return false;
|
|
519
545
|
if (route.id === 'Research' || route.id === 'AutoResearch') return true;
|
|
520
|
-
if (route.id === 'Goal'
|
|
546
|
+
if (route.id === 'Goal') return looksLikeExecutionWork(prompt) || looksLikeTeamDefaultWork(stripDollarCommand(prompt));
|
|
547
|
+
if (route.id === 'DB' || route.id === 'GX') return looksLikeExecutionWork(prompt);
|
|
521
548
|
if (route.id === 'DFix') return looksLikeCodeChangingWork(prompt) && !looksLikeFastDesignFix(prompt);
|
|
522
549
|
return looksLikeExecutionWork(prompt);
|
|
523
550
|
}
|
|
524
551
|
|
|
525
552
|
export function reflectionRequiredForRoute(route) {
|
|
526
553
|
const id = String(route?.id || route?.mode || route?.route || route || '').replace(/^\$/, '');
|
|
527
|
-
return /^(team|qaloop|qa-loop|
|
|
554
|
+
return /^(team|qaloop|qa-loop|research|autoresearch|db|database|madsks|mad-sks|gx)$/i.test(id);
|
|
528
555
|
}
|
|
529
556
|
|
|
530
557
|
export function looksLikeCodeChangingWork(prompt = '') {
|
|
@@ -539,6 +566,14 @@ export function looksLikeExecutionWork(prompt = '') {
|
|
|
539
566
|
|
|
540
567
|
export function subagentExecutionPolicyText(route, prompt = '') {
|
|
541
568
|
const required = routeRequiresSubagents(route, prompt);
|
|
569
|
+
if (route?.id === 'Goal') {
|
|
570
|
+
if (!required) return 'Subagent policy: Goal itself is a lightweight native /goal persistence overlay; subagents are not required for bridge creation/control.';
|
|
571
|
+
return [
|
|
572
|
+
'Subagent policy: Goal itself remains a lightweight native /goal persistence overlay.',
|
|
573
|
+
'Because the prompt also asks for code-changing or execution work, continue that work through the selected SKS execution route and apply that route\'s worker/reviewer policy there.',
|
|
574
|
+
noUnrequestedFallbackCodePolicyText()
|
|
575
|
+
].join(' ');
|
|
576
|
+
}
|
|
542
577
|
if (!required) {
|
|
543
578
|
return 'Subagent policy: optional for this route; use subagents only when parallel exploration materially helps.';
|
|
544
579
|
}
|
package/src/core/team-live.mjs
CHANGED
|
@@ -219,7 +219,7 @@ export function parseTeamSpecArgs(args = []) {
|
|
|
219
219
|
i++;
|
|
220
220
|
continue;
|
|
221
221
|
}
|
|
222
|
-
if (arg === '--json') continue;
|
|
222
|
+
if (arg === '--json' || arg === '--open-warp' || arg === '--warp-open') continue;
|
|
223
223
|
cleanArgs.push(args[i]);
|
|
224
224
|
}
|
|
225
225
|
return { cleanArgs, ...normalizeTeamSpec({ roleCounts, agentSessions: explicitSession }) };
|
package/src/core/warp-ui.mjs
CHANGED
|
@@ -64,6 +64,31 @@ export function warpLaunchUri(configPathOrFilename) {
|
|
|
64
64
|
return `warp://launch/${encodeURIComponent(filename)}`;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
export function isWarpShellSession(env = process.env) {
|
|
68
|
+
if (truthyEnv(env.WARP_IS_LOCAL_SHELL_SESSION)) return true;
|
|
69
|
+
if (truthyEnv(env.WARP_SESSION_ID)) return true;
|
|
70
|
+
return String(env.TERM_PROGRAM || '') === 'WarpTerminal';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function warpOpenLaunchDecision(opts = {}) {
|
|
74
|
+
const args = Array.isArray(opts.args) ? opts.args : [];
|
|
75
|
+
const env = opts.env || process.env;
|
|
76
|
+
if (opts.forceOpen === true || opts.open === true || args.includes('--open') || args.includes('--force-open') || truthyEnv(env.SKS_WARP_FORCE_OPEN) || truthyEnv(env.SKS_WARP_OPEN)) {
|
|
77
|
+
return { open: true, reason: 'forced' };
|
|
78
|
+
}
|
|
79
|
+
if (opts.skipOpen === true || opts.noOpen === true || opts.open === false || args.includes('--no-open') || truthyEnv(env.SKS_WARP_SKIP_OPEN) || truthyEnv(env.SKS_WARP_NO_OPEN)) {
|
|
80
|
+
return { open: false, reason: 'opening disabled by option/env' };
|
|
81
|
+
}
|
|
82
|
+
if (isWarpShellSession(env)) {
|
|
83
|
+
return { open: false, current_session: true, reason: 'already inside Warp shell session' };
|
|
84
|
+
}
|
|
85
|
+
return { open: true, reason: 'default' };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function truthyEnv(value) {
|
|
89
|
+
return value !== undefined && value !== null && !/^(?:0|false|no|off)$/i.test(String(value).trim());
|
|
90
|
+
}
|
|
91
|
+
|
|
67
92
|
export async function findWarpApp() {
|
|
68
93
|
const env = process.env.SKS_WARP_APP || process.env.WARP_APP;
|
|
69
94
|
if (env && await exists(env)) return env;
|
|
@@ -222,7 +247,7 @@ export function formatWarpBanner(status = null) {
|
|
|
222
247
|
' $DFix $Answer $SKS $Team $QA-LOOP $Goal $Research $AutoResearch $DB $GX $Wiki $Help',
|
|
223
248
|
'',
|
|
224
249
|
'CLI-first runtime:',
|
|
225
|
-
' sks
|
|
250
|
+
' sks warp open explicitly open a Warp Codex CLI launch configuration',
|
|
226
251
|
' sks --mad open one-shot MAD full-access auto-review launch configuration',
|
|
227
252
|
' sks team "task" prepare Team mission and Warp split-pane live view',
|
|
228
253
|
'',
|
|
@@ -317,18 +342,20 @@ export async function writeWarpLaunchConfig(plan = {}, panes = []) {
|
|
|
317
342
|
return { config_path: configPath, yaml, record };
|
|
318
343
|
}
|
|
319
344
|
|
|
320
|
-
export async function openWarpLaunchConfig(configPath) {
|
|
345
|
+
export async function openWarpLaunchConfig(configPath, opts = {}) {
|
|
321
346
|
const uri = warpLaunchUri(configPath);
|
|
347
|
+
const decision = warpOpenLaunchDecision(opts);
|
|
348
|
+
if (!decision.open) return { ok: false, skipped: true, reason: decision.reason, uri, stdout: '', stderr: '' };
|
|
322
349
|
if (process.platform === 'darwin') {
|
|
323
350
|
const run = await runProcess('open', [uri], { timeoutMs: 5000, maxOutputBytes: 16 * 1024 }).catch((err) => ({ code: 1, stderr: err.message, stdout: '' }));
|
|
324
|
-
return { ok: run.code === 0, uri, stdout: run.stdout || '', stderr: run.stderr || '' };
|
|
351
|
+
return { ok: run.code === 0, skipped: false, reason: decision.reason, uri, stdout: run.stdout || '', stderr: run.stderr || '' };
|
|
325
352
|
}
|
|
326
353
|
const opener = await which('xdg-open').catch(() => null);
|
|
327
354
|
if (opener) {
|
|
328
355
|
const run = await runProcess(opener, [uri], { timeoutMs: 5000, maxOutputBytes: 16 * 1024 }).catch((err) => ({ code: 1, stderr: err.message, stdout: '' }));
|
|
329
|
-
return { ok: run.code === 0, uri, stdout: run.stdout || '', stderr: run.stderr || '' };
|
|
356
|
+
return { ok: run.code === 0, skipped: false, reason: decision.reason, uri, stdout: run.stdout || '', stderr: run.stderr || '' };
|
|
330
357
|
}
|
|
331
|
-
return { ok: false, uri, stderr: 'No platform URI opener found' };
|
|
358
|
+
return { ok: false, skipped: false, reason: decision.reason, uri, stdout: '', stderr: 'No platform URI opener found' };
|
|
332
359
|
}
|
|
333
360
|
|
|
334
361
|
export async function launchWarpUi(args = [], opts = {}) {
|
|
@@ -344,16 +371,40 @@ export async function launchWarpUi(args = [], opts = {}) {
|
|
|
344
371
|
if (args.includes('--status-only')) return { plan };
|
|
345
372
|
const command = codexLaunchCommand(plan.root, plan.codex.bin, plan.codexArgs);
|
|
346
373
|
const written = await writeWarpLaunchConfig({ ...plan, command }, [{ cwd: plan.root, command, focused: true }]);
|
|
347
|
-
const
|
|
374
|
+
const decision = warpOpenLaunchDecision({ ...opts, args });
|
|
375
|
+
const opened = decision.current_session
|
|
376
|
+
? runWarpCommandInCurrentSession(command, { cwd: plan.root, dryRun: opts.dryRunCurrentSession || opts.dryRun })
|
|
377
|
+
: await openWarpLaunchConfig(written.config_path, { ...opts, args });
|
|
348
378
|
if (!args.includes('--quiet')) {
|
|
349
379
|
console.log(`SKS Warp launch configuration: ${written.config_path}`);
|
|
350
380
|
console.log(`Warp URI: ${written.record.launch_uri}`);
|
|
351
|
-
if (opened.
|
|
381
|
+
if (opened.current_session) console.log(`Warp: current session (${opened.reason || 'already inside Warp shell session'})`);
|
|
382
|
+
else if (opened.ok) console.log('Warp: opened');
|
|
383
|
+
else if (opened.skipped) console.log(`Warp: skipped (${opened.reason || 'opening disabled'})`);
|
|
352
384
|
else if (!opened.skipped) console.log(`Warp: not opened (${opened.stderr || 'URI opener failed'})`);
|
|
353
385
|
}
|
|
354
386
|
return { plan, created: true, config_path: written.config_path, launch_uri: written.record.launch_uri, opened };
|
|
355
387
|
}
|
|
356
388
|
|
|
389
|
+
function runWarpCommandInCurrentSession(command, opts = {}) {
|
|
390
|
+
if (opts.dryRun) return { ok: true, current_session: true, skipped: false, reason: 'dry run current Warp session', command };
|
|
391
|
+
const shell = process.env.SHELL || '/bin/sh';
|
|
392
|
+
const run = spawnSync(shell, ['-lc', command], {
|
|
393
|
+
cwd: opts.cwd || process.cwd(),
|
|
394
|
+
stdio: 'inherit',
|
|
395
|
+
env: process.env
|
|
396
|
+
});
|
|
397
|
+
return {
|
|
398
|
+
ok: run.status === 0,
|
|
399
|
+
current_session: true,
|
|
400
|
+
skipped: false,
|
|
401
|
+
reason: 'ran in current Warp shell session',
|
|
402
|
+
code: run.status,
|
|
403
|
+
signal: run.signal || null,
|
|
404
|
+
stderr: run.error?.message || ''
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
|
|
357
408
|
function printWarpLaunchBlocked(plan, opts = {}) {
|
|
358
409
|
if (opts.concise) {
|
|
359
410
|
console.error('SKS Warp launch blocked.');
|