sneakoscope 0.6.98 → 0.7.0
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 +13 -2
- package/package.json +1 -1
- package/src/cli/main.mjs +112 -12
- package/src/cli/maintenance-commands.mjs +65 -3
- package/src/core/fsx.mjs +1 -1
- package/src/core/init.mjs +18 -9
- package/src/core/perf-bench.mjs +28 -4
- package/src/core/pipeline.mjs +268 -35
- package/src/core/proof-field.mjs +79 -5
- package/src/core/research.mjs +12 -11
- package/src/core/routes.mjs +13 -4
- package/src/core/skill-forge.mjs +376 -1
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/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.
|
|
5
|
+
Sneakoscope Codex (`sks`, displayed as `ㅅㅋㅅ`) is a Codex CLI/App harness for repeatable agent workflows. It adds terminal commands, Codex App `$` prompt commands, warp-native CLI workspaces, Team/QA/Research routes, inspectable pipeline plans, a maximum-speed Computer Use lane, a fast Goal bridge for native `/goal` persistence, Context7 evidence checks, DB safety, TriWiki context tracking, lightweight skill dreaming, Honest Mode, and release-readiness gates.
|
|
6
6
|
|
|
7
7
|
## Quick Start
|
|
8
8
|
|
|
@@ -45,7 +45,9 @@ sks selftest --mock
|
|
|
45
45
|
| --- | --- |
|
|
46
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
|
+
| Pipeline plans | Writes `pipeline-plan.json` for stateful routes so the runtime lane, kept stages, skipped stages, verification commands, and no-unrequested-fallback invariant are visible with `sks pipeline plan`. |
|
|
49
|
+
| Team orchestration | Runs substantial work through ambiguity handling, scouts, TriWiki refresh, debate, runtime task graphs, worker inboxes, implementation, review, cleanup, reflection, and Honest Mode; narrow work should use Proof Field evidence to skip unrelated pipeline work instead of expanding Team. |
|
|
50
|
+
| Skill dreaming | Records cheap generated-skill usage counters in JSON and only periodically scans `.agents/skills` for keep, merge, prune, and improvement candidates. Reports are recommendation-only and never delete skills automatically. |
|
|
49
51
|
| From-Chat-IMG | Turns chat screenshots plus original attachments into source-bound work orders, then requires scoped QA evidence before completion. |
|
|
50
52
|
| QA loop | Dogfoods UI/API behavior with safety gates, Codex Computer Use-only UI evidence, safe fixes, and rechecks. |
|
|
51
53
|
| 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. |
|
|
@@ -217,12 +219,21 @@ sks harness fixture --json
|
|
|
217
219
|
sks gx init homepage
|
|
218
220
|
sks gx render homepage --format html
|
|
219
221
|
sks validate-artifacts latest --json
|
|
222
|
+
sks pipeline plan latest --proof-field --json
|
|
220
223
|
sks perf run --json
|
|
221
224
|
sks perf workflow --json --intent "small CLI change" --changed src/cli/main.mjs,src/core/routes.mjs
|
|
222
225
|
sks proof-field scan --json --intent "small CLI change"
|
|
226
|
+
sks skill-dream status
|
|
227
|
+
sks skill-dream run --json
|
|
223
228
|
sks code-structure scan --json
|
|
224
229
|
```
|
|
225
230
|
|
|
231
|
+
`sks pipeline plan` is the 0.7 runtime map. It reads or refreshes `.sneakoscope/missions/<id>/pipeline-plan.json`, then shows which lane is active, which stages are kept or skipped, which verification commands are required, and whether the no-unrequested-fallback invariant is present.
|
|
232
|
+
|
|
233
|
+
`sks proof-field scan` is SKS's lightweight outcome rubric: it maps the goal to proof cones, records unrelated work that can be skipped with evidence, reports a simplicity score, and names escalation triggers for when the route must return to the full Team/Honest proof path. When `execution_lane.lane` is `proof_field_fast_lane`, SKS can keep the parent-owned minimal patch plus listed verification and skip Team debate, fresh executor teams, broad route rework, and unrelated checks. Database, security, visual-forensic, unknown, broad, failed, or unsupported-claim signals fail closed to the normal Team/Honest path. Use `sks pipeline plan --proof-field` after changed files are known to bind that Proof Field decision to the mission plan.
|
|
234
|
+
|
|
235
|
+
`sks skill-dream` keeps generated skill complexity bounded without doing a heavy evaluation on every prompt. Route use writes compact counters to `.sneakoscope/skills/dream-state.json`; after the configured count/cooldown threshold, or when you run `sks skill-dream run`, SKS scans `.agents/skills` and writes `.sneakoscope/reports/skill-dream-latest.json` with keep, merge, prune, and improvement candidates. The report is intentionally advisory: deleting or merging skills requires explicit approval.
|
|
236
|
+
|
|
226
237
|
`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
238
|
|
|
228
239
|
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.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sneakoscope",
|
|
3
3
|
"displayName": "ㅅㅋㅅ",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
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
|
@@ -25,8 +25,8 @@ import { defaultEvaluationScenario, runEvaluationBenchmark } from '../core/evalu
|
|
|
25
25
|
import { buildResearchPrompt, evaluateResearchGate, writeMockResearchResult, writeResearchPlan } from '../core/research.mjs';
|
|
26
26
|
import { contextCapsule } from '../core/triwiki-attention.mjs';
|
|
27
27
|
import { rgbaKey, rgbaToWikiCoord, validateWikiCoordinateIndex } from '../core/wiki-coordinate.mjs';
|
|
28
|
-
import { ALLOWED_REASONING_EFFORTS, CODEX_COMPUTER_USE_EVIDENCE_SOURCE, CODEX_COMPUTER_USE_ONLY_POLICY, COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_SOURCE_INVENTORY_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, FROM_CHAT_IMG_VISUAL_MAP_ARTIFACT, FROM_CHAT_IMG_WORK_ORDER_ARTIFACT, RECOMMENDED_SKILLS, ROUTES, USAGE_TOPICS, context7ConfigToml, hasContext7ConfigText, hasFromChatImgSignal, looksLikeAnswerOnlyRequest, noUnrequestedFallbackCodePolicyText, reflectionRequiredForRoute, reasoningInstruction, routePrompt, routeReasoning, routeRequiresSubagents, stackCurrentDocsPolicy, triwikiContextTracking } from '../core/routes.mjs';
|
|
29
|
-
import { context7Evidence, evaluateStop, recordContext7Evidence, recordSubagentEvidence } from '../core/pipeline.mjs';
|
|
28
|
+
import { ALLOWED_REASONING_EFFORTS, CODEX_COMPUTER_USE_EVIDENCE_SOURCE, CODEX_COMPUTER_USE_ONLY_POLICY, COMMAND_CATALOG, DOLLAR_COMMAND_ALIASES, DOLLAR_COMMANDS, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_SOURCE_INVENTORY_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, FROM_CHAT_IMG_VISUAL_MAP_ARTIFACT, FROM_CHAT_IMG_WORK_ORDER_ARTIFACT, RECOMMENDED_SKILLS, ROUTES, USAGE_TOPICS, context7ConfigToml, hasContext7ConfigText, hasFromChatImgSignal, looksLikeAnswerOnlyRequest, noUnrequestedFallbackCodePolicyText, reflectionRequiredForRoute, reasoningInstruction, routePrompt, routeReasoning, routeRequiresSubagents, speedLanePolicyText, stackCurrentDocsPolicy, triwikiContextTracking } from '../core/routes.mjs';
|
|
29
|
+
import { PIPELINE_PLAN_ARTIFACT, buildPipelinePlan, context7Evidence, evaluateStop, recordContext7Evidence, recordSubagentEvidence, validatePipelinePlan, writePipelinePlan } from '../core/pipeline.mjs';
|
|
30
30
|
import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, validateTeamRuntimeArtifacts, writeTeamRuntimeArtifacts } from '../core/team-dag.mjs';
|
|
31
31
|
import { appendTeamEvent, initTeamLive, parseTeamSpecText, readTeamDashboard, readTeamLive, readTeamTranscriptTail, renderTeamAgentLane } from '../core/team-live.mjs';
|
|
32
32
|
import { ARTIFACT_FILES, validateDogfoodReport, validateEffortDecision, validateFromChatImgVisualMap, validateSkillCandidate, validateSkillInjectionDecision, validateTeamDashboardState, validateWorkOrderLedger } from '../core/artifact-schemas.mjs';
|
|
@@ -34,10 +34,10 @@ import { selectEffort, writeEffortDecision } from '../core/effort-orchestrator.m
|
|
|
34
34
|
import { createWorkOrderLedger } from '../core/work-order-ledger.mjs';
|
|
35
35
|
import { buildFromChatImgVisualMap } from '../core/from-chat-img-forensics.mjs';
|
|
36
36
|
import { classifyDogfoodFinding, createDogfoodReport, writeDogfoodReport } from '../core/dogfood-loop.mjs';
|
|
37
|
-
import { createSkillCandidate, decideSkillInjection, writeSkillCandidate, writeSkillForgeReport, writeSkillInjectionDecision } from '../core/skill-forge.mjs';
|
|
37
|
+
import { createSkillCandidate, decideSkillInjection, skillDreamFixture, writeSkillCandidate, writeSkillForgeReport, writeSkillInjectionDecision } from '../core/skill-forge.mjs';
|
|
38
38
|
import { classifyToolError, harnessGrowthReport } from '../core/evaluation.mjs';
|
|
39
39
|
import { runWorkflowPerfBench, validateWorkflowPerfReport } from '../core/perf-bench.mjs';
|
|
40
|
-
import { proofFieldFixture, validateProofFieldReport } from '../core/proof-field.mjs';
|
|
40
|
+
import { buildProofField, proofFieldFixture, validateProofFieldReport } from '../core/proof-field.mjs';
|
|
41
41
|
import { recordMistake, writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
|
|
42
42
|
import { buildPromptContext } from '../core/prompt-context-builder.mjs';
|
|
43
43
|
import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
|
|
@@ -45,7 +45,7 @@ import { GOAL_WORKFLOW_ARTIFACT } from '../core/goal-workflow.mjs';
|
|
|
45
45
|
import { CODEX_APP_DOCS_URL, codexAppIntegrationStatus, formatCodexAppStatus } from '../core/codex-app.mjs';
|
|
46
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
|
-
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';
|
|
48
|
+
import { buildTeamPlan, codeStructureCommand, dbCommand, defaultBeta, defaultVGraph, evalCommand, gcCommand, goalCommand, gxCommand, harnessCommand, hproofCommand, memoryCommand, migrateWikiContextPack, parseTeamCreateArgs, perfCommand, profileCommand, projectWikiClaims, proofFieldCommand, qaLoopCommand, quickstartCommand, researchCommand, skillDreamCommand, statsCommand, team, teamWorkflowMarkdown, validateArtifactsCommand, wikiCommand, wikiVoxelRowCount, writeWikiContextPack } from './maintenance-commands.mjs';
|
|
49
49
|
|
|
50
50
|
const flag = (args, name) => args.includes(name);
|
|
51
51
|
const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();
|
|
@@ -104,6 +104,7 @@ export async function main(args) {
|
|
|
104
104
|
if (cmd === 'validate-artifacts') return validateArtifactsCommand(tail);
|
|
105
105
|
if (cmd === 'perf') return perfCommand(sub, rest);
|
|
106
106
|
if (cmd === 'proof-field') return proofFieldCommand(sub, rest);
|
|
107
|
+
if (cmd === 'skill-dream') return skillDreamCommand(sub, rest);
|
|
107
108
|
if (cmd === 'code-structure') return codeStructureCommand(sub, rest);
|
|
108
109
|
if (cmd === 'memory') return memoryCommand(sub, rest);
|
|
109
110
|
if (cmd === 'gx') return gxCommand(sub, rest);
|
|
@@ -148,7 +149,7 @@ Usage:
|
|
|
148
149
|
sks qa-loop run <mission-id|latest> [--mock] [--max-cycles N]
|
|
149
150
|
sks qa-loop status <mission-id|latest>
|
|
150
151
|
sks context7 check|setup|tools|resolve|docs|evidence ...
|
|
151
|
-
sks pipeline status|resume [--json]
|
|
152
|
+
sks pipeline status|resume|plan [--json] [--proof-field]
|
|
152
153
|
sks pipeline answer <mission-id|latest> <answers.json>
|
|
153
154
|
sks guard check [--json]
|
|
154
155
|
sks conflicts check|prompt [--json]
|
|
@@ -182,6 +183,7 @@ Usage:
|
|
|
182
183
|
sks eval compare --baseline old.json --candidate new.json [--json]
|
|
183
184
|
sks perf run|workflow [--json] [--intent "task"] [--changed file1,file2]
|
|
184
185
|
sks proof-field scan [--json] [--intent "task"]
|
|
186
|
+
sks skill-dream status|run|record [--json]
|
|
185
187
|
sks harness fixture [--json]
|
|
186
188
|
sks code-structure scan [--json]
|
|
187
189
|
sks wiki coords --rgba 12,34,56,255
|
|
@@ -728,13 +730,16 @@ async function pipeline(sub = 'status', args = []) {
|
|
|
728
730
|
const root = await sksRoot();
|
|
729
731
|
const action = sub || 'status';
|
|
730
732
|
if (action === 'answer') return pipelineAnswer(root, args);
|
|
733
|
+
if (action === 'plan') return pipelinePlan(root, args);
|
|
731
734
|
const state = await readJson(stateFile(root), {});
|
|
732
735
|
const evidence = await context7Evidence(root, state);
|
|
736
|
+
const plan = state.mission_id ? await readJson(path.join(missionDir(root, state.mission_id), PIPELINE_PLAN_ARTIFACT), null) : null;
|
|
733
737
|
const stop = await evaluateStop(root, state, { last_assistant_message: 'SKS Honest Mode verification evidence gap' }, { noQuestion: false });
|
|
734
738
|
const result = {
|
|
735
739
|
root,
|
|
736
740
|
state,
|
|
737
741
|
context7: evidence,
|
|
742
|
+
plan: plan ? pipelinePlanSummary(plan, root, state.mission_id) : null,
|
|
738
743
|
stop_gate: state.stop_gate || null,
|
|
739
744
|
next_action: stop?.reason || 'No active blocking route gate detected.'
|
|
740
745
|
};
|
|
@@ -745,12 +750,92 @@ async function pipeline(sub = 'status', args = []) {
|
|
|
745
750
|
console.log(`Route: ${state.route_command || state.route || 'none'}`);
|
|
746
751
|
console.log(`Phase: ${state.phase || 'IDLE'}`);
|
|
747
752
|
console.log(`Mission: ${state.mission_id || 'none'}`);
|
|
753
|
+
if (plan) {
|
|
754
|
+
console.log(`Plan: ${path.relative(root, path.join(missionDir(root, state.mission_id), PIPELINE_PLAN_ARTIFACT))}`);
|
|
755
|
+
console.log(`Lane: ${plan.runtime_lane?.lane || 'unknown'} (${plan.runtime_lane?.source || 'unknown'})`);
|
|
756
|
+
console.log(`Stages: keep ${plan.stage_summary?.kept ?? '?'} / skip ${plan.stage_summary?.skipped ?? '?'}`);
|
|
757
|
+
}
|
|
748
758
|
console.log(`Reasoning: ${state.reasoning_effort || 'medium'}${state.reasoning_profile ? ` (${state.reasoning_profile})` : ''}${state.reasoning_temporary ? ' temporary' : ''}`);
|
|
749
759
|
console.log(`Stop gate: ${state.stop_gate || 'none'}`);
|
|
750
760
|
console.log(`Context7: ${state.context7_required ? (evidence.ok ? 'ok' : 'required-missing') : 'optional'} (${evidence.count || 0} event(s))`);
|
|
751
761
|
console.log(`Next: ${result.next_action}`);
|
|
752
762
|
}
|
|
753
763
|
|
|
764
|
+
async function pipelinePlan(root, args = []) {
|
|
765
|
+
const state = await readJson(stateFile(root), {});
|
|
766
|
+
const missionArg = pipelineMissionArg(args);
|
|
767
|
+
const id = await resolveMissionId(root, missionArg);
|
|
768
|
+
let dir = null;
|
|
769
|
+
let mission = {};
|
|
770
|
+
let routeContext = {};
|
|
771
|
+
if (id) {
|
|
772
|
+
const loaded = await loadMission(root, id);
|
|
773
|
+
dir = loaded.dir;
|
|
774
|
+
mission = loaded.mission || {};
|
|
775
|
+
routeContext = await readJson(path.join(dir, 'route-context.json'), {});
|
|
776
|
+
const existing = await readJson(path.join(dir, PIPELINE_PLAN_ARTIFACT), null);
|
|
777
|
+
if (existing && !flag(args, '--refresh') && !flag(args, '--proof-field')) {
|
|
778
|
+
if (flag(args, '--json')) return console.log(JSON.stringify({ ok: validatePipelinePlan(existing).ok, plan_path: path.join(dir, PIPELINE_PLAN_ARTIFACT), plan: existing }, null, 2));
|
|
779
|
+
return printPipelinePlan(root, id, existing);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
const intent = readOption(args, '--intent', routeContext.task || mission.prompt || state.prompt || '');
|
|
783
|
+
const route = ROUTES.find((candidate) => candidate.id === routeContext.route || candidate.command === routeContext.command || candidate.id === state.route || candidate.command === state.route_command)
|
|
784
|
+
|| routePrompt(routeContext.command || state.route_command || intent || '$SKS');
|
|
785
|
+
const changedRaw = readOption(args, '--changed', '');
|
|
786
|
+
const proofField = flag(args, '--proof-field') ? await buildProofField(root, { intent, changedFiles: changedRaw ? changedRaw.split(',') : undefined }) : null;
|
|
787
|
+
const contract = dir ? await readJson(path.join(dir, 'decision-contract.json'), {}) : {};
|
|
788
|
+
const ambiguity = {
|
|
789
|
+
required: Boolean(routeContext.clarification_gate || state.ambiguity_gate_required),
|
|
790
|
+
passed: Boolean(state.ambiguity_gate_passed || state.clarification_passed),
|
|
791
|
+
status: state.clarification_required ? 'awaiting_answers' : (state.ambiguity_gate_passed ? 'contract_sealed' : undefined),
|
|
792
|
+
contract_hash: contract?.sealed_hash || null
|
|
793
|
+
};
|
|
794
|
+
const planInput = { missionId: id || null, route, task: intent, required: Boolean(routeContext.context7_required || state.context7_required), ambiguity, proofField };
|
|
795
|
+
const plan = dir ? await writePipelinePlan(dir, planInput) : buildPipelinePlan(planInput);
|
|
796
|
+
const validation = validatePipelinePlan(plan);
|
|
797
|
+
if (flag(args, '--json')) return console.log(JSON.stringify({ ok: validation.ok, validation, plan_path: dir ? path.join(dir, PIPELINE_PLAN_ARTIFACT) : null, plan }, null, 2));
|
|
798
|
+
printPipelinePlan(root, id || 'none', plan);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
function pipelineMissionArg(args = []) {
|
|
802
|
+
const valueFlags = new Set(['--intent', '--changed']);
|
|
803
|
+
for (let i = 0; i < args.length; i++) {
|
|
804
|
+
const arg = String(args[i]);
|
|
805
|
+
if (valueFlags.has(arg)) {
|
|
806
|
+
i++;
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
if (!arg.startsWith('--')) return arg;
|
|
810
|
+
}
|
|
811
|
+
return 'latest';
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
function pipelinePlanSummary(plan, root, id) {
|
|
815
|
+
return {
|
|
816
|
+
path: id ? path.join(missionDir(root, id), PIPELINE_PLAN_ARTIFACT) : null,
|
|
817
|
+
validation: validatePipelinePlan(plan),
|
|
818
|
+
lane: plan.runtime_lane?.lane || null,
|
|
819
|
+
source: plan.runtime_lane?.source || null,
|
|
820
|
+
kept: plan.stage_summary?.kept ?? null,
|
|
821
|
+
skipped: plan.stage_summary?.skipped ?? null,
|
|
822
|
+
next_actions: plan.next_actions || []
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
function printPipelinePlan(root, id, plan) {
|
|
827
|
+
const validation = validatePipelinePlan(plan);
|
|
828
|
+
console.log('SKS Pipeline Plan\n');
|
|
829
|
+
console.log(`Mission: ${id}`);
|
|
830
|
+
console.log(`Route: ${plan.route?.command || plan.route?.id || 'unknown'}`);
|
|
831
|
+
console.log(`Lane: ${plan.runtime_lane?.lane || 'unknown'} (${plan.runtime_lane?.source || 'unknown'})`);
|
|
832
|
+
console.log(`Valid: ${validation.ok ? 'yes' : `no (${validation.issues.join(', ')})`}`);
|
|
833
|
+
if (id && id !== 'none') console.log(`Artifact: ${path.relative(root, path.join(missionDir(root, id), PIPELINE_PLAN_ARTIFACT))}`);
|
|
834
|
+
console.log(`Stages: keep ${plan.stage_summary?.kept ?? 0}, skip ${plan.stage_summary?.skipped ?? 0}, n/a ${plan.stage_summary?.not_applicable ?? 0}`);
|
|
835
|
+
console.log(`Verify: ${(plan.verification || []).join('; ')}`);
|
|
836
|
+
console.log(`Next: ${(plan.next_actions || []).join(' -> ')}`);
|
|
837
|
+
}
|
|
838
|
+
|
|
754
839
|
async function pipelineAnswer(root, args = []) {
|
|
755
840
|
const [missionArg, answerFile] = args;
|
|
756
841
|
const id = await resolveMissionId(root, missionArg);
|
|
@@ -770,6 +855,7 @@ async function pipelineAnswer(root, args = []) {
|
|
|
770
855
|
|| routePrompt(routeContext.command || routeContext.route || '$SKS');
|
|
771
856
|
await appendJsonlBounded(path.join(dir, 'events.jsonl'), { ts: nowIso(), type: 'pipeline.clarification.contract_sealed', route: route?.id || routeContext.route, hash: result.contract.sealed_hash });
|
|
772
857
|
const materialized = await materializeAfterPipelineAnswer(root, id, dir, mission, route, routeContext, result.contract);
|
|
858
|
+
const pipelinePlan = await writePipelinePlan(dir, { missionId: id, route, task: materialized.prompt || routeContext.task || mission.prompt || '', required: Boolean(routeContext.context7_required), ambiguity: { required: true, passed: true, status: 'contract_sealed', contract_hash: result.contract.sealed_hash } });
|
|
773
859
|
if (route?.id === 'QALoop') await writeQaLoopArtifacts(dir, mission, result.contract);
|
|
774
860
|
await setCurrent(root, {
|
|
775
861
|
mission_id: id,
|
|
@@ -791,16 +877,19 @@ async function pipelineAnswer(root, args = []) {
|
|
|
791
877
|
ambiguity_gate_required: true,
|
|
792
878
|
ambiguity_gate_passed: true,
|
|
793
879
|
implementation_allowed: true,
|
|
880
|
+
pipeline_plan_ready: validatePipelinePlan(pipelinePlan).ok,
|
|
881
|
+
pipeline_plan_path: PIPELINE_PLAN_ARTIFACT,
|
|
794
882
|
reasoning_effort: route ? routeReasoning(route, routeContext.task || mission.prompt || '').effort : 'medium',
|
|
795
883
|
reasoning_profile: route ? routeReasoning(route, routeContext.task || mission.prompt || '').profile : 'sks-task-medium',
|
|
796
884
|
reasoning_temporary: true,
|
|
797
885
|
prompt: materialized.prompt || routeContext.task || mission.prompt || '',
|
|
798
886
|
...materialized.state
|
|
799
887
|
});
|
|
800
|
-
if (flag(args, '--json')) return console.log(JSON.stringify({ ok: true, mission_id: id, route: route?.id || routeContext.route, hash: result.contract.sealed_hash, validation: result.validation }, null, 2));
|
|
888
|
+
if (flag(args, '--json')) return console.log(JSON.stringify({ ok: true, mission_id: id, route: route?.id || routeContext.route, hash: result.contract.sealed_hash, validation: result.validation, pipeline_plan: path.join(dir, PIPELINE_PLAN_ARTIFACT) }, null, 2));
|
|
801
889
|
console.log(`SKS ambiguity gate passed for ${id}`);
|
|
802
890
|
console.log(`Route: ${route?.command || routeContext.command || '$SKS'}`);
|
|
803
891
|
console.log(`Hash: ${result.contract.sealed_hash}`);
|
|
892
|
+
console.log(`Plan: ${path.relative(root, path.join(dir, PIPELINE_PLAN_ARTIFACT))}`);
|
|
804
893
|
console.log('Next: continue the original route lifecycle using decision-contract.json.');
|
|
805
894
|
}
|
|
806
895
|
|
|
@@ -1426,6 +1515,7 @@ function usage(args = []) {
|
|
|
1426
1515
|
dollar: ['Dollar Commands', '', formatDollarCommandsCompact(' '), '', 'Terminal: sks dollar-commands [--json]'],
|
|
1427
1516
|
wiki: ['TriWiki', '', ' sks wiki pack', ' sks wiki refresh [--prune]', ' sks wiki sweep latest --json', ' sks wiki validate .sneakoscope/wiki/context-pack.json', ' sks wiki prune --dry-run --json', '', 'Packs include attention.use_first and attention.hydrate_first for compact recall plus source hydration. Sweep records intentional forgetting and promotion candidates.'],
|
|
1428
1517
|
harness: ['Harness Growth', '', ' sks harness fixture --json', ' sks harness review --json', '', 'Runs deterministic fixtures for deliberate forgetting, skill cards, harness experiments, tool error taxonomy, permission profiles, MultiAgentV2, and Warp cockpit views.'],
|
|
1518
|
+
'skill-dream': ['Skill Dreaming', '', ' sks skill-dream status', ' sks skill-dream run --json', ' sks skill-dream record --route team --skills team,prompt-pipeline', '', 'Records cheap JSON usage counters in .sneakoscope/skills/dream-state.json and periodically writes recommendation-only keep/merge/prune/improve reports. It never deletes or merges skills automatically.'],
|
|
1429
1519
|
'code-structure': ['Code Structure', '', ' sks code-structure scan', ' sks code-structure scan --json', '', 'Flags handwritten source files above 1000/2000/3000-line thresholds and records split-review exceptions.'],
|
|
1430
1520
|
gx: ['GX', '', ' sks gx init architecture-atlas', ' sks gx render architecture-atlas --format all', ' sks gx validate architecture-atlas']
|
|
1431
1521
|
};
|
|
@@ -2385,6 +2475,7 @@ async function selftest() {
|
|
|
2385
2475
|
if (!hookTeamJson.hookSpecificOutput?.additionalContext?.includes('Codex plan-tool interaction')) throw new Error('selftest failed: $Team ambiguity gate did not inject plan-tool guidance');
|
|
2386
2476
|
const hookTeamState = await readJson(stateFile(hookTeamTmp), {});
|
|
2387
2477
|
if (hookTeamState.phase !== 'TEAM_CLARIFICATION_AWAITING_ANSWERS' || hookTeamState.implementation_allowed !== false) throw new Error('selftest failed: $Team hook did not lock execution behind ambiguity gate');
|
|
2478
|
+
if (!hookTeamState.pipeline_plan_ready || !(await exists(path.join(missionDir(hookTeamTmp, hookTeamState.mission_id), PIPELINE_PLAN_ARTIFACT)))) throw new Error('selftest failed: $Team hook did not write a pending pipeline plan');
|
|
2388
2479
|
if (await exists(path.join(missionDir(hookTeamTmp, hookTeamState.mission_id), 'team-plan.json'))) throw new Error('selftest failed: Team plan was created before ambiguity gate passed');
|
|
2389
2480
|
const hookTeamPendingResult = await runProcess(process.execPath, [hookBin, 'hook', 'user-prompt-submit'], { cwd: hookTeamTmp, input: JSON.stringify({ cwd: hookTeamTmp, prompt: '$Team 새 작업으로 넘어가' }), env: { SKS_DISABLE_UPDATE_CHECK: '1' }, timeoutMs: 15000, maxOutputBytes: 256 * 1024 });
|
|
2390
2481
|
if (hookTeamPendingResult.code !== 0) throw new Error(`selftest failed: pending clarification hook exited ${hookTeamPendingResult.code}: ${hookTeamPendingResult.stderr}`);
|
|
@@ -2422,8 +2513,9 @@ async function selftest() {
|
|
|
2422
2513
|
const pipelineAnswerResult = await runProcess(process.execPath, [hookBin, 'pipeline', 'answer', 'latest', hookTeamAnswersPath], { cwd: hookTeamTmp, env: { SKS_DISABLE_UPDATE_CHECK: '1' }, timeoutMs: 15000, maxOutputBytes: 64 * 1024 });
|
|
2423
2514
|
if (pipelineAnswerResult.code !== 0) throw new Error(`selftest failed: pipeline answer exited ${pipelineAnswerResult.code}: ${pipelineAnswerResult.stderr}`);
|
|
2424
2515
|
const answeredTeamState = await readJson(stateFile(hookTeamTmp), {});
|
|
2425
|
-
if (answeredTeamState.phase !== 'TEAM_PARALLEL_ANALYSIS_SCOUTING' || !answeredTeamState.ambiguity_gate_passed || answeredTeamState.implementation_allowed !== true || !answeredTeamState.team_plan_ready) throw new Error('selftest failed: pipeline answer did not materialize Team after ambiguity gate');
|
|
2516
|
+
if (answeredTeamState.phase !== 'TEAM_PARALLEL_ANALYSIS_SCOUTING' || !answeredTeamState.ambiguity_gate_passed || answeredTeamState.implementation_allowed !== true || !answeredTeamState.team_plan_ready || !answeredTeamState.pipeline_plan_ready) throw new Error('selftest failed: pipeline answer did not materialize Team after ambiguity gate');
|
|
2426
2517
|
if (!(await exists(path.join(missionDir(hookTeamTmp, hookTeamState.mission_id), 'decision-contract.json')))) throw new Error('selftest failed: pipeline answer did not seal decision contract');
|
|
2518
|
+
if (validatePipelinePlan(await readJson(path.join(missionDir(hookTeamTmp, hookTeamState.mission_id), PIPELINE_PLAN_ARTIFACT))).ok !== true) throw new Error('selftest failed: pipeline answer did not refresh a valid pipeline plan');
|
|
2427
2519
|
if (!(await exists(path.join(missionDir(hookTeamTmp, hookTeamState.mission_id), 'team-plan.json'))) || !(await exists(path.join(missionDir(hookTeamTmp, hookTeamState.mission_id), 'team-live.md')))) throw new Error('selftest failed: Team artifacts missing after ambiguity gate passed');
|
|
2428
2520
|
const honestLoopTmp = tmpdir();
|
|
2429
2521
|
await initProject(honestLoopTmp, {});
|
|
@@ -2748,10 +2840,10 @@ async function selftest() {
|
|
|
2748
2840
|
await writeJsonAtomic(path.join(fromChatCoverageDir, 'team-gate.json'), { ...passedTeamGate, from_chat_img_required: true, from_chat_img_request_coverage: true });
|
|
2749
2841
|
const coveredFromChatStop = await evaluateStop(fromChatCoverageTmp, fromChatCoverageState, { last_assistant_message: 'SKS Honest Mode verification evidence gap' }, { noQuestion: false });
|
|
2750
2842
|
if (coveredFromChatStop?.decision !== 'block' || String(coveredFromChatStop.reason || '').includes('from-chat-img') || !String(coveredFromChatStop.reason || '').includes(TEAM_SESSION_CLEANUP_ARTIFACT)) throw new Error('selftest failed: valid From-Chat-IMG artifacts did not hand off to session cleanup gate');
|
|
2751
|
-
await recordContext7Evidence(routeGateTmp, gateState, { tool_name: '
|
|
2843
|
+
await recordContext7Evidence(routeGateTmp, gateState, { tool_name: 'mcp__context7__resolve_library_id', library: 'react' });
|
|
2752
2844
|
const resolveOnlyStop = await evaluateStop(routeGateTmp, gateState, { last_assistant_message: 'SKS Honest Mode verification evidence gap' }, { noQuestion: false });
|
|
2753
2845
|
if (resolveOnlyStop?.decision !== 'block') throw new Error('selftest failed: resolve-only Context7 evidence unblocked route');
|
|
2754
|
-
await recordContext7Evidence(routeGateTmp, gateState, { tool_name: '
|
|
2846
|
+
await recordContext7Evidence(routeGateTmp, gateState, { tool_name: 'mcp__context7__query_docs', library_id: '/facebook/react' });
|
|
2755
2847
|
const missingCleanupStop = await evaluateStop(routeGateTmp, gateState, { last_assistant_message: 'SKS Honest Mode verification evidence gap' }, { noQuestion: false });
|
|
2756
2848
|
if (missingCleanupStop?.decision !== 'block' || !String(missingCleanupStop.reason || '').includes(TEAM_SESSION_CLEANUP_ARTIFACT)) throw new Error('selftest failed: Team route did not block missing session cleanup gate');
|
|
2757
2849
|
await writeJsonAtomic(path.join(gateDir, TEAM_SESSION_CLEANUP_ARTIFACT), passedTeamSessionCleanup);
|
|
@@ -2863,6 +2955,8 @@ async function selftest() {
|
|
|
2863
2955
|
if (!validateSkillCandidate(skillCandidate).ok) throw new Error('selftest failed: active skill candidate rejected');
|
|
2864
2956
|
const injection = decideSkillInjection({ route: 'from-chat-img', task_signature: 'reference images', skills: [skillCandidate, { ...skillCandidate, id: 'deprecated', status: 'deprecated' }] });
|
|
2865
2957
|
if (!validateSkillInjectionDecision(injection).ok || injection.injected.length !== 1) throw new Error('selftest failed: skill injection did not respect active/top-K filtering');
|
|
2958
|
+
const skillDream = await skillDreamFixture(path.join(tmp, 'skill-dream-fixture'));
|
|
2959
|
+
if (!skillDream.passed) throw new Error('selftest failed: skill dreaming did not keep used skills, recommend unused generated skills, and preserve custom skills');
|
|
2866
2960
|
const promptContext = buildPromptContext({ stable: ['stable'], policies: ['policy'], dynamic: ['dynamic'] });
|
|
2867
2961
|
if (promptContext.blocks[0]?.cache_region !== 'stable_prefix' || promptContext.blocks.at(-1)?.cache_region !== 'dynamic_suffix') throw new Error('selftest failed: prompt context did not place dynamic context last');
|
|
2868
2962
|
const repeatedMistake = await recordMistake(teamDir, { route: 'from-chat-img', gate: 'visual-map', reason: 'unmatched-reference' });
|
|
@@ -2961,13 +3055,19 @@ async function selftest() {
|
|
|
2961
3055
|
if (!harnessReport.forgetting.fixture.passed || !harnessReport.warp.views.includes('Harness Experiments View') || !harnessReport.reliability.tool_error_taxonomy.includes('Unknown')) throw new Error('selftest failed: harness growth fixture incomplete');
|
|
2962
3056
|
const proofField = await proofFieldFixture();
|
|
2963
3057
|
if (!proofField.validation.ok || !validateProofFieldReport(proofField.report).ok) throw new Error('selftest failed: proof field report invalid');
|
|
2964
|
-
if (!proofField.checks.route_cone_selected || !proofField.checks.cli_cone_selected || !proofField.checks.catastrophic_guard_present || !proofField.checks.negative_release_work_recorded) throw new Error('selftest failed: proof field fixture checks incomplete');
|
|
3058
|
+
if (!proofField.checks.route_cone_selected || !proofField.checks.cli_cone_selected || !proofField.checks.catastrophic_guard_present || !proofField.checks.negative_release_work_recorded || !proofField.checks.outcome_rubric_present || !proofField.checks.simplicity_score_usable || !proofField.checks.execution_fast_lane_selected) throw new Error('selftest failed: proof field fixture checks incomplete');
|
|
3059
|
+
if (!speedLanePolicyText().includes('proof_field_fast_lane') || !proofField.report.execution_lane?.skip_when_fast?.includes('planning_debate')) throw new Error('selftest failed: Proof Field speed lane policy missing');
|
|
3060
|
+
const fastPipelinePlan = buildPipelinePlan({ route: routePrompt('$Team small CLI help update'), task: 'small CLI help surface update', proofField: proofField.report });
|
|
3061
|
+
if (!validatePipelinePlan(fastPipelinePlan).ok || fastPipelinePlan.runtime_lane?.lane !== 'proof_field_fast_lane' || !fastPipelinePlan.skipped_stages.includes('planning_debate') || !fastPipelinePlan.invariants.includes('no_unrequested_fallback_code')) throw new Error('selftest failed: pipeline plan did not encode fast lane stage skips and fallback guard');
|
|
3062
|
+
const broadProofField = await buildProofField(tmp, { intent: 'database security route refactor', changedFiles: ['src/core/db-safety.mjs', 'src/core/routes.mjs', 'src/cli/main.mjs', 'README.md'] });
|
|
3063
|
+
const broadPipelinePlan = buildPipelinePlan({ route: routePrompt('$Team database security route refactor'), task: 'database security route refactor', proofField: broadProofField });
|
|
3064
|
+
if (!validatePipelinePlan(broadPipelinePlan).ok || broadPipelinePlan.runtime_lane?.lane === 'proof_field_fast_lane' || broadPipelinePlan.skipped_stages.includes('planning_debate')) throw new Error('selftest failed: pipeline plan did not fail closed for broad/security work');
|
|
2965
3065
|
const workflowPerf = await runWorkflowPerfBench(tmp, {
|
|
2966
3066
|
iterations: 2,
|
|
2967
3067
|
intent: 'small CLI help surface update',
|
|
2968
3068
|
changedFiles: ['src/cli/maintenance-commands.mjs', 'src/core/routes.mjs']
|
|
2969
3069
|
});
|
|
2970
|
-
if (!validateWorkflowPerfReport(workflowPerf).ok || workflowPerf.metrics.decision_mode !== 'fast_lane' || !workflowPerf.metrics.fast_lane_eligible) throw new Error('selftest failed: workflow perf proof field did not produce a valid fast lane report');
|
|
3070
|
+
if (!validateWorkflowPerfReport(workflowPerf).ok || workflowPerf.metrics.decision_mode !== 'fast_lane' || workflowPerf.metrics.execution_lane !== 'proof_field_fast_lane' || workflowPerf.metrics.pipeline_lane !== 'proof_field_fast_lane' || !workflowPerf.metrics.fast_lane_eligible || !workflowPerf.metrics.fast_lane_allowed || Number(workflowPerf.metrics.simplicity_score) < 0.75 || Number(workflowPerf.metrics.outcome_criteria_passed) < 3) throw new Error('selftest failed: workflow perf proof field did not produce a valid outcome-scored fast lane report');
|
|
2971
3071
|
if (classifyToolError({ message: 'operation timed out' }) !== 'Timeout' || classifyToolError({ message: 'unclassified weirdness' }) !== 'Unknown') throw new Error('selftest failed: tool error taxonomy classification');
|
|
2972
3072
|
const coord = rgbaToWikiCoord({ r: 12, g: 34, b: 56, a: 255 });
|
|
2973
3073
|
if (coord.schema !== 'sks.wiki-coordinate.v1' || coord.xyzw.length !== 4) throw new Error('selftest failed: RGBA wiki coordinate conversion');
|
|
@@ -15,7 +15,7 @@ import { renderCartridge, validateCartridge, driftCartridge, snapshotCartridge }
|
|
|
15
15
|
import { DEFAULT_EVAL_THRESHOLDS, compareEvaluationReports, runEvaluationBenchmark } from '../core/evaluation.mjs';
|
|
16
16
|
import { contextCapsule } from '../core/triwiki-attention.mjs';
|
|
17
17
|
import { rgbaKey, rgbaToWikiCoord, validateWikiCoordinateIndex } from '../core/wiki-coordinate.mjs';
|
|
18
|
-
import { ALLOWED_REASONING_EFFORTS, CODEX_COMPUTER_USE_ONLY_POLICY, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_SOURCE_INVENTORY_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, FROM_CHAT_IMG_VISUAL_MAP_ARTIFACT, FROM_CHAT_IMG_WORK_ORDER_ARTIFACT, ROUTES, hasFromChatImgSignal, routePrompt, stackCurrentDocsPolicy, triwikiContextTracking } from '../core/routes.mjs';
|
|
18
|
+
import { ALLOWED_REASONING_EFFORTS, CODEX_COMPUTER_USE_ONLY_POLICY, DOLLAR_SKILL_NAMES, FROM_CHAT_IMG_CHECKLIST_ARTIFACT, FROM_CHAT_IMG_COVERAGE_ARTIFACT, FROM_CHAT_IMG_QA_LOOP_ARTIFACT, FROM_CHAT_IMG_SOURCE_INVENTORY_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT, FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS, FROM_CHAT_IMG_VISUAL_MAP_ARTIFACT, FROM_CHAT_IMG_WORK_ORDER_ARTIFACT, RECOMMENDED_SKILLS, ROUTES, hasFromChatImgSignal, routePrompt, stackCurrentDocsPolicy, triwikiContextTracking } from '../core/routes.mjs';
|
|
19
19
|
import { TEAM_DECOMPOSITION_ARTIFACT, TEAM_GRAPH_ARTIFACT, TEAM_INBOX_DIR, TEAM_RUNTIME_TASKS_ARTIFACT, teamRuntimePlanMetadata, teamRuntimeRequiredArtifacts, writeTeamRuntimeArtifacts } from '../core/team-dag.mjs';
|
|
20
20
|
import { appendTeamEvent, formatRoleCounts, initTeamLive, normalizeTeamSpec, parseTeamSpecArgs, readTeamControl, readTeamDashboard, readTeamLive, readTeamTranscriptTail, renderTeamAgentLane, renderTeamCleanupSummary, renderTeamWatch, requestTeamSessionCleanup, teamCleanupRequested } from '../core/team-live.mjs';
|
|
21
21
|
import { ARTIFACT_FILES, writeValidationReport } from '../core/artifact-schemas.mjs';
|
|
@@ -25,11 +25,12 @@ import { writeFromChatImgArtifacts } from '../core/from-chat-img-forensics.mjs';
|
|
|
25
25
|
import { renderTeamDashboardState, writeTeamDashboardState } from '../core/team-dashboard-renderer.mjs';
|
|
26
26
|
import { runPerfBench, runWorkflowPerfBench } from '../core/perf-bench.mjs';
|
|
27
27
|
import { writeProofFieldReport } from '../core/proof-field.mjs';
|
|
28
|
+
import { PIPELINE_PLAN_ARTIFACT, validatePipelinePlan, writePipelinePlan } from '../core/pipeline.mjs';
|
|
28
29
|
import { GOAL_BRIDGE_ARTIFACT, GOAL_WORKFLOW_ARTIFACT, updateGoalWorkflow, writeGoalWorkflow } from '../core/goal-workflow.mjs';
|
|
29
30
|
import { scanCodeStructure, writeCodeStructureReport } from '../core/code-structure.mjs';
|
|
30
31
|
import { writeMemorySweepReport } from '../core/memory-governor.mjs';
|
|
31
32
|
import { cleanupWarpTeamView, launchWarpTeamView } from '../core/warp-ui.mjs';
|
|
32
|
-
import { writeSkillForgeReport } from '../core/skill-forge.mjs';
|
|
33
|
+
import { loadSkillDreamState, recordSkillDreamEvent, runSkillDream, writeSkillForgeReport } from '../core/skill-forge.mjs';
|
|
33
34
|
import { writeMistakeMemoryReport } from '../core/mistake-memory.mjs';
|
|
34
35
|
import { checkDbOperation, checkSqlFile, classifyCommand, classifySql, loadDbSafetyPolicy, safeSupabaseMcpConfig, scanDbSafety } from '../core/db-safety.mjs';
|
|
35
36
|
import { harnessGrowthReport, writeHarnessGrowthReport } from '../core/evaluation.mjs';
|
|
@@ -573,6 +574,58 @@ export async function proofFieldCommand(sub, args = []) {
|
|
|
573
574
|
console.log(`Report: ${path.relative(root, report.report_path)}`);
|
|
574
575
|
}
|
|
575
576
|
|
|
577
|
+
export async function skillDreamCommand(sub, args = []) {
|
|
578
|
+
const action = sub && !String(sub).startsWith('--') ? sub : 'status';
|
|
579
|
+
const actionArgs = action === sub ? args : [sub, ...args].filter(Boolean);
|
|
580
|
+
if (!['status', 'run', 'record', 'help', '--help'].includes(action)) {
|
|
581
|
+
console.error('Usage: sks skill-dream status|run|record [--json]');
|
|
582
|
+
process.exitCode = 1;
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (action === 'help' || action === '--help') {
|
|
586
|
+
console.log('Usage: sks skill-dream status|run|record [--json]');
|
|
587
|
+
console.log('Records cheap generated-skill usage counters and periodically reports keep, merge, prune, and improvement candidates. Reports never delete skills automatically.');
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const root = await sksRoot();
|
|
591
|
+
if (action === 'record') {
|
|
592
|
+
const skills = readFlagValue(actionArgs, '--skills', '').split(',').map((x) => x.trim()).filter(Boolean);
|
|
593
|
+
const result = await recordSkillDreamEvent(root, {
|
|
594
|
+
route: readFlagValue(actionArgs, '--route', positionalArgs(actionArgs).join(' ') || 'manual'),
|
|
595
|
+
command: readFlagValue(actionArgs, '--command', null),
|
|
596
|
+
required_skills: skills,
|
|
597
|
+
prompt_signature: readFlagValue(actionArgs, '--prompt-signature', null)
|
|
598
|
+
}, { known_skill_names: knownGeneratedSkillNames() });
|
|
599
|
+
if (flag(actionArgs, '--json')) return console.log(JSON.stringify(result, null, 2));
|
|
600
|
+
console.log('SKS Skill Dream Record');
|
|
601
|
+
console.log(`Events since last run: ${result.state.counters.events_since_last_run}`);
|
|
602
|
+
console.log(`Due: ${result.due.due ? 'yes' : 'no'} (${result.due.reason_codes.join(', ')})`);
|
|
603
|
+
if (result.report) console.log(`Report: ${path.relative(root, result.report.report_path)}`);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
if (action === 'run') {
|
|
607
|
+
const report = await runSkillDream(root, { force: true, known_skill_names: knownGeneratedSkillNames() });
|
|
608
|
+
if (flag(actionArgs, '--json')) return console.log(JSON.stringify(report, null, 2));
|
|
609
|
+
console.log('SKS Skill Dream');
|
|
610
|
+
console.log(`Inventory: ${report.inventory.total} skills (${report.inventory.generated} generated, ${report.inventory.unknown_or_user} unknown/user)`);
|
|
611
|
+
console.log(`Keep: ${report.keep.length}`);
|
|
612
|
+
console.log(`Merge candidates: ${report.merge_candidates.length}`);
|
|
613
|
+
console.log(`Prune candidates: ${report.prune_candidates.length}`);
|
|
614
|
+
console.log(`Improve candidates: ${report.improve_candidates.length}`);
|
|
615
|
+
console.log(`Apply mode: ${report.apply_mode}; no auto delete: ${report.no_auto_delete ? 'yes' : 'no'}`);
|
|
616
|
+
console.log(`Report: ${path.relative(root, report.report_path)}`);
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const state = await loadSkillDreamState(root);
|
|
620
|
+
if (flag(actionArgs, '--json')) return console.log(JSON.stringify(state, null, 2));
|
|
621
|
+
console.log('SKS Skill Dream Status');
|
|
622
|
+
console.log(`State: .sneakoscope/skills/dream-state.json`);
|
|
623
|
+
console.log(`Events since last run: ${state.counters.events_since_last_run}/${state.policy.min_events_between_runs}`);
|
|
624
|
+
console.log(`Cooldown: ${state.policy.min_interval_hours}h`);
|
|
625
|
+
console.log(`Last run: ${state.last_run_at || 'never'}`);
|
|
626
|
+
console.log(`Next: ${state.next_run?.due ? 'due' : (state.next_run?.reason_codes || ['not due']).join(', ')}`);
|
|
627
|
+
}
|
|
628
|
+
|
|
576
629
|
export async function harnessCommand(sub, args = []) {
|
|
577
630
|
const action = sub || 'fixture';
|
|
578
631
|
if (!['fixture', 'review'].includes(action)) {
|
|
@@ -1249,7 +1302,7 @@ export async function statsCommand(args) {
|
|
|
1249
1302
|
|
|
1250
1303
|
function positionalArgs(args = []) {
|
|
1251
1304
|
const out = [];
|
|
1252
|
-
const valueFlags = new Set(['--format', '--iterations', '--out', '--baseline', '--candidate', '--install-scope', '--max-cycles', '--depth', '--scope', '--transport', '--query', '--topic', '--tokens', '--timeout-ms', '--sql', '--command', '--project-ref', '--agent', '--phase', '--message', '--role', '--max-anchors', '--lines', '--intent', '--changed']);
|
|
1305
|
+
const valueFlags = new Set(['--format', '--iterations', '--out', '--baseline', '--candidate', '--install-scope', '--max-cycles', '--depth', '--scope', '--transport', '--query', '--topic', '--tokens', '--timeout-ms', '--sql', '--command', '--project-ref', '--agent', '--phase', '--message', '--role', '--max-anchors', '--lines', '--intent', '--changed', '--route', '--skills', '--prompt-signature']);
|
|
1253
1306
|
for (let i = 0; i < args.length; i++) {
|
|
1254
1307
|
const arg = String(args[i]);
|
|
1255
1308
|
if (valueFlags.has(arg)) {
|
|
@@ -1266,6 +1319,10 @@ function readFlagValue(args, name, fallback) {
|
|
|
1266
1319
|
return i >= 0 && args[i + 1] ? args[i + 1] : fallback;
|
|
1267
1320
|
}
|
|
1268
1321
|
|
|
1322
|
+
function knownGeneratedSkillNames() {
|
|
1323
|
+
return Array.from(new Set([...DOLLAR_SKILL_NAMES, ...RECOMMENDED_SKILLS]));
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1269
1326
|
function cartridgeName(args, fallback = 'architecture-atlas') {
|
|
1270
1327
|
const raw = positionalArgs(args)[0] || fallback;
|
|
1271
1328
|
return String(raw).trim().replace(/[\\/]+/g, '-').replace(/[^A-Za-z0-9_.-]+/g, '-').replace(/^-+|-+$/g, '') || fallback;
|
|
@@ -1406,6 +1463,9 @@ export async function team(args) {
|
|
|
1406
1463
|
let dashboardState = await writeTeamDashboardState(dir, { missionId: id, mission: { id, mode: 'team' }, effort: effortDecision.selected_effort, phase: 'intake', next_action: fromChatImgRequired ? 'complete visual source inventory and work-order mapping' : 'run Team analysis scouts' });
|
|
1407
1464
|
await writeJsonAtomic(path.join(dir, 'team-gate.json'), { passed: false, team_roster_confirmed: true, analysis_artifact: false, triwiki_refreshed: false, triwiki_validated: false, consensus_artifact: false, ...runtime.gate_fields, implementation_team_fresh: false, review_artifact: false, integration_evidence: false, session_cleanup: false, context7_evidence: false, ...(fromChatImgRequired ? { from_chat_img_required: true, from_chat_img_request_coverage: false } : {}) });
|
|
1408
1465
|
dashboardState = await writeTeamDashboardState(dir, { missionId: id, mission: { id, mode: 'team' }, effort: effortDecision.selected_effort, phase: 'intake', next_action: fromChatImgRequired ? 'complete visual source inventory and work-order mapping' : 'run Team analysis scouts' });
|
|
1466
|
+
const route = routePrompt(`$Team ${prompt}`) || ROUTES.find((candidate) => candidate.id === 'Team');
|
|
1467
|
+
const pipelinePlan = await writePipelinePlan(dir, { missionId: id, route, task: prompt, required: false, ambiguity: { required: false, status: 'team_cli_direct' } });
|
|
1468
|
+
await setCurrent(root, { mission_id: id, route: 'Team', route_command: '$Team', mode: 'TEAM', phase: 'TEAM_PARALLEL_ANALYSIS_SCOUTING', questions_allowed: false, implementation_allowed: true, context7_required: false, context7_verified: false, subagents_required: true, subagents_verified: false, reflection_required: true, visible_progress_required: true, context_tracking: 'triwiki', required_skills: route?.requiredSkills || ['team'], stop_gate: 'team-gate.json', reasoning_effort: 'high', reasoning_profile: 'sks-logic-high', reasoning_temporary: true, agent_sessions: agentSessions, role_counts: roleCounts, team_roster_confirmed: true, team_graph_ready: runtime.ok, team_live_ready: true, from_chat_img_required: fromChatImgRequired, pipeline_plan_ready: validatePipelinePlan(pipelinePlan).ok, pipeline_plan_path: PIPELINE_PLAN_ARTIFACT, prompt });
|
|
1409
1469
|
const result = {
|
|
1410
1470
|
mission_id: id,
|
|
1411
1471
|
mission_dir: dir,
|
|
@@ -1421,6 +1481,7 @@ export async function team(args) {
|
|
|
1421
1481
|
dashboard_state: path.join(dir, ARTIFACT_FILES.team_dashboard_state),
|
|
1422
1482
|
effort_decision: path.join(dir, ARTIFACT_FILES.effort_decision),
|
|
1423
1483
|
work_order_ledger: path.join(dir, ARTIFACT_FILES.work_order_ledger),
|
|
1484
|
+
pipeline_plan: path.join(dir, PIPELINE_PLAN_ARTIFACT),
|
|
1424
1485
|
dashboard_state_valid: dashboardState.ok,
|
|
1425
1486
|
context_pack: path.join(root, '.sneakoscope', 'wiki', 'context-pack.json'),
|
|
1426
1487
|
agent_sessions: agentSessions,
|
|
@@ -1433,6 +1494,7 @@ export async function team(args) {
|
|
|
1433
1494
|
if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
|
|
1434
1495
|
console.log(`Team mission created: ${id}`);
|
|
1435
1496
|
console.log(`Plan: ${path.relative(root, result.plan)}`);
|
|
1497
|
+
console.log(`Pipeline plan: ${path.relative(root, result.pipeline_plan)}`);
|
|
1436
1498
|
console.log(`Agent sessions: ${agentSessions}`);
|
|
1437
1499
|
console.log(`Role counts: ${formatRoleCounts(roleCounts)}`);
|
|
1438
1500
|
console.log(`Workflow: ${path.relative(root, result.workflow)}`);
|
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.
|
|
8
|
+
export const PACKAGE_VERSION = '0.7.0';
|
|
9
9
|
export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
|
|
10
10
|
export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
|
|
11
11
|
|