sneakoscope 3.1.4 → 3.1.6
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 +8 -36
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/crates/sks-core/src/main.rs +1 -1
- package/dist/.sks-build-stamp.json +4 -4
- package/dist/bin/sks.js +1 -1
- package/dist/cli/command-registry.js +1 -2
- package/dist/cli/install-helpers.js +56 -4
- package/dist/commands/codex-app.js +1 -11
- package/dist/commands/codex-lb.js +12 -9
- package/dist/commands/codex-native.js +68 -0
- package/dist/commands/doctor.js +64 -0
- package/dist/core/codex-app/codex-agent-role-sync.js +69 -11
- package/dist/core/codex-app/codex-agent-type-probe.js +202 -0
- package/dist/core/codex-app/codex-app-execution-profile.js +43 -14
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -4
- package/dist/core/codex-app/codex-app-harness-matrix.js +4 -65
- package/dist/core/codex-app/codex-app-types.js +21 -0
- package/dist/core/codex-app/codex-hook-approval-probe.js +188 -0
- package/dist/core/codex-app/codex-hook-lifecycle.js +34 -10
- package/dist/core/codex-app/codex-init-deep.js +154 -3
- package/dist/core/codex-app/codex-skill-sync.js +84 -9
- package/dist/core/codex-native/codex-native-capability-cache.js +21 -0
- package/dist/core/codex-native/codex-native-feature-broker.js +182 -0
- package/dist/core/codex-native/codex-native-feature-matrix.js +31 -0
- package/dist/core/codex-native/codex-native-harness-compat.js +54 -0
- package/dist/core/codex-native/codex-native-interop-policy.js +58 -0
- package/dist/core/codex-native/codex-native-invocation-router.js +112 -0
- package/dist/core/codex-native/codex-native-pattern-analysis.js +56 -0
- package/dist/core/codex-native/codex-native-reference-evidence.js +2 -0
- package/dist/core/codex-native/codex-native-reference-source.js +110 -0
- package/dist/core/codex-native/codex-native-rename-map.js +25 -0
- package/dist/core/commands/mad-sks-command.js +37 -2
- package/dist/core/commands/qa-loop-command.js +3 -2
- package/dist/core/commands/research-command.js +2 -2
- package/dist/core/doctor/doctor-zellij-repair.js +5 -1
- package/dist/core/feature-fixtures.js +3 -4
- package/dist/core/feature-registry.js +5 -2
- package/dist/core/fsx.js +1 -1
- package/dist/core/image/image-artifact-path-contract.js +18 -1
- package/dist/core/init.js +4 -1
- package/dist/core/loops/loop-continuation-enforcer.js +11 -3
- package/dist/core/loops/loop-owner-inference.js +3 -0
- package/dist/core/loops/loop-planner.js +28 -5
- package/dist/core/loops/loop-worker-runtime.js +52 -8
- package/dist/core/naruto/naruto-loop-worker-router.js +11 -2
- package/dist/core/qa-loop.js +62 -4
- package/dist/core/research/research-cycle-runner.js +1 -0
- package/dist/core/research/research-stage-runner.js +9 -2
- package/dist/core/research.js +68 -1
- package/dist/core/routes.js +2 -3
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/homebrew-policy.js +0 -1
- package/dist/core/zellij/zellij-self-heal-types.js +45 -0
- package/dist/core/zellij/zellij-self-heal.js +69 -8
- package/dist/core/zellij/zellij-update.js +9 -1
- package/dist/scripts/sks-3-1-4-directive-check-lib.js +1 -30
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +318 -0
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +522 -0
- package/package.json +53 -9
- package/dist/cli/hermes-command.js +0 -99
- package/dist/cli/openclaw-command.js +0 -83
- package/dist/commands/hermes.js +0 -5
- package/dist/commands/openclaw.js +0 -3
- package/dist/core/codex-app/lazycodex-analysis.js +0 -51
- package/dist/core/codex-app/lazycodex-interop-policy.js +0 -49
- package/dist/core/hermes.js +0 -192
- package/dist/core/openclaw.js +0 -171
package/dist/core/qa-loop.js
CHANGED
|
@@ -2,6 +2,8 @@ import path from 'node:path';
|
|
|
2
2
|
import { exists, nowIso, readJson, readText, writeJsonAtomic, writeTextAtomic, PACKAGE_VERSION } from './fsx.js';
|
|
3
3
|
import { CODEX_WEB_VERIFICATION_EVIDENCE_SOURCE, CODEX_WEB_VERIFICATION_POLICY, evidenceMentionsForbiddenBrowserAutomation, evidenceMentionsForbiddenWebComputerUseEvidence } from './routes.js';
|
|
4
4
|
import { appendAgentLedgerEvent, initializeAgentCentralLedger } from './agents/agent-central-ledger.js';
|
|
5
|
+
import { resolveCodexAppExecutionProfile } from './codex-app/codex-app-execution-profile.js';
|
|
6
|
+
import { resolveCodexNativeInvocationPlan } from './codex-native/codex-native-invocation-router.js';
|
|
5
7
|
export const QA_LOOP_ROUTE = 'QALoop';
|
|
6
8
|
const QA_REPORT_SUFFIX = 'qa-report.md';
|
|
7
9
|
const UI_CHROME_EXTENSION_FIRST_ACK = 'use_codex_chrome_extension_first_no_computer_use_for_web_ui_or_mark_unverified';
|
|
@@ -320,6 +322,11 @@ export function defaultQaGate(contract = {}, opts = {}) {
|
|
|
320
322
|
image_artifact_path_contract_present: false,
|
|
321
323
|
image_artifact_path_contract_artifact: null,
|
|
322
324
|
image_artifact_path_contract_blockers: [],
|
|
325
|
+
codex_app_execution_profile: opts.executionProfile ? compactExecutionProfile(opts.executionProfile) : null,
|
|
326
|
+
codex_app_execution_profile_artifact: opts.executionProfile ? 'qa-loop/execution-profile.json' : null,
|
|
327
|
+
codex_app_hooks_approval_required: opts.executionProfile?.hooks_approval_required === true,
|
|
328
|
+
codex_app_agent_role_strategy: opts.executionProfile?.agent_role_strategy || null,
|
|
329
|
+
codex_native_invocation: opts.codexNativeInvocation || null,
|
|
323
330
|
api_e2e_required: apiRequired,
|
|
324
331
|
unsafe_external_side_effects: false,
|
|
325
332
|
corrective_loop_enabled: corrective,
|
|
@@ -338,16 +345,25 @@ export async function writeQaLoopArtifacts(dir, mission, contract) {
|
|
|
338
345
|
const a = contract.answers || {};
|
|
339
346
|
const checklist = qaChecklist(a);
|
|
340
347
|
const reportFile = qaReportFilename();
|
|
348
|
+
const root = missionRootFromDir(dir);
|
|
349
|
+
const executionProfile = root ? await resolveCodexAppExecutionProfile({ root }).catch(() => null) : null;
|
|
350
|
+
const codexNativeInvocation = root ? await resolveQaCodexNativeInvocation(root, mission.id).catch(() => null) : null;
|
|
351
|
+
if (executionProfile)
|
|
352
|
+
await writeJsonAtomic(path.join(dir, 'qa-loop', 'execution-profile.json'), executionProfile).catch(() => undefined);
|
|
353
|
+
if (codexNativeInvocation)
|
|
354
|
+
await writeJsonAtomic(path.join(dir, 'qa-loop', 'codex-native-invocation.json'), codexNativeInvocation).catch(() => undefined);
|
|
341
355
|
await writeJsonAtomic(path.join(dir, 'qa-ledger.json'), {
|
|
342
356
|
schema_version: 1,
|
|
343
357
|
generated_at: nowIso(),
|
|
344
358
|
mission_id: mission.id,
|
|
345
359
|
qa_report_file: reportFile,
|
|
360
|
+
codex_app_execution_profile: executionProfile ? compactExecutionProfile(executionProfile) : null,
|
|
361
|
+
codex_native_invocation: codexNativeInvocation,
|
|
346
362
|
target: { scope: a.QA_SCOPE, environment: a.TARGET_ENVIRONMENT, base_url: a.TARGET_BASE_URL, api_base_url: a.API_BASE_URL },
|
|
347
363
|
safety: { mutation_policy: a.QA_MUTATION_POLICY, deployed_destructive_tests_allowed: 'never', credentials: 'temp_only_never_saved', ui_evidence: 'codex_chrome_extension_first_required_for_web_ui_e2e' },
|
|
348
364
|
checklist
|
|
349
365
|
});
|
|
350
|
-
await writeJsonAtomic(path.join(dir, 'qa-gate.json'), defaultQaGate(contract, { reportFile }));
|
|
366
|
+
await writeJsonAtomic(path.join(dir, 'qa-gate.json'), defaultQaGate(contract, { reportFile, executionProfile, codexNativeInvocation }));
|
|
351
367
|
await writeTextAtomic(path.join(dir, reportFile), qaReportTemplate(mission, contract, checklist));
|
|
352
368
|
return { checklist_count: checklist.length, report_file: reportFile };
|
|
353
369
|
}
|
|
@@ -432,6 +448,11 @@ export async function writeMockQaResult(dir, mission, contract) {
|
|
|
432
448
|
image_artifact_path_contract_present: previousGate.image_artifact_path_contract_present === true,
|
|
433
449
|
image_artifact_path_contract_artifact: previousGate.image_artifact_path_contract_artifact || null,
|
|
434
450
|
image_artifact_path_contract_blockers: previousGate.image_artifact_path_contract_blockers || [],
|
|
451
|
+
codex_app_execution_profile: previousGate.codex_app_execution_profile || null,
|
|
452
|
+
codex_app_execution_profile_artifact: previousGate.codex_app_execution_profile_artifact || null,
|
|
453
|
+
codex_app_hooks_approval_required: previousGate.codex_app_hooks_approval_required === true,
|
|
454
|
+
codex_app_agent_role_strategy: previousGate.codex_app_agent_role_strategy || null,
|
|
455
|
+
codex_native_invocation: previousGate.codex_native_invocation || null,
|
|
435
456
|
blockers: previousGate.blockers || [],
|
|
436
457
|
passed: !uiRequired,
|
|
437
458
|
qa_report_written: true,
|
|
@@ -453,7 +474,23 @@ export async function writeMockQaResult(dir, mission, contract) {
|
|
|
453
474
|
});
|
|
454
475
|
return evaluateQaGate(dir);
|
|
455
476
|
}
|
|
456
|
-
|
|
477
|
+
async function resolveQaCodexNativeInvocation(root, missionId) {
|
|
478
|
+
const [visualReview, hookEvidence, imageFollowup] = await Promise.all([
|
|
479
|
+
resolveCodexNativeInvocationPlan({ root, missionId, route: '$QA-LOOP', desiredCapability: 'visual-review' }),
|
|
480
|
+
resolveCodexNativeInvocationPlan({ root, missionId, route: '$QA-LOOP', desiredCapability: 'hook-evidence' }),
|
|
481
|
+
resolveCodexNativeInvocationPlan({ root, missionId, route: '$Image', desiredCapability: 'image-followup' })
|
|
482
|
+
]);
|
|
483
|
+
return {
|
|
484
|
+
visual_review: visualReview.selected_strategy,
|
|
485
|
+
visual_review_plan: visualReview,
|
|
486
|
+
hook_evidence_policy: hookEvidence.env.SKS_CODEX_NATIVE_HOOK_EVIDENCE_POLICY,
|
|
487
|
+
hook_evidence_plan: hookEvidence,
|
|
488
|
+
image_path_strategy: imageFollowup.selected_strategy === 'codex-app-native' ? 'model-visible-path' : 'artifact-path',
|
|
489
|
+
image_followup_plan: imageFollowup,
|
|
490
|
+
hook_derived_evidence_counted: hookEvidence.selected_strategy !== 'blocked'
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
export function buildQaLoopPrompt({ id, mission, contract, cycle, previous, reportFile, imagePathContract, appHandoff, executionProfile }) {
|
|
457
494
|
const report = reportFile && isQaReportFilename(reportFile) ? reportFile : 'the date/version-prefixed report named by qa-gate.json.qa_report_file';
|
|
458
495
|
const imageContractText = imagePathContract
|
|
459
496
|
? `\nIMAGE PATH CONTRACT:\n${JSON.stringify(imagePathContract, null, 2)}\nUse model_visible_path values for follow-up image edits; do not invent generated image paths.\n`
|
|
@@ -461,6 +498,9 @@ export function buildQaLoopPrompt({ id, mission, contract, cycle, previous, repo
|
|
|
461
498
|
const appHandoffText = appHandoff
|
|
462
499
|
? `\nCODEX DESKTOP /app HANDOFF:\n${JSON.stringify(appHandoff, null, 2)}\nThis is desktop-app review status only and is not web UI evidence.\n`
|
|
463
500
|
: '';
|
|
501
|
+
const executionProfileText = executionProfile
|
|
502
|
+
? `\nCODEX APP EXECUTION PROFILE:\n${JSON.stringify(compactExecutionProfile(executionProfile), null, 2)}\nUse this routing profile for agent role strategy and app/headless assumptions.\n`
|
|
503
|
+
: '';
|
|
464
504
|
return `SKS QA-LOOP
|
|
465
505
|
MISSION: ${id}
|
|
466
506
|
TASK: ${mission.prompt}
|
|
@@ -473,7 +513,7 @@ GATE: passed=false while unresolved_findings or unresolved_fixable_findings > 0,
|
|
|
473
513
|
ARTIFACTS: update qa-ledger.json, ${report}, qa-gate.json, and qa-loop/cycle-${cycle}/.
|
|
474
514
|
CONTRACT:
|
|
475
515
|
${JSON.stringify(contract, null, 2)}
|
|
476
|
-
${imageContractText}${appHandoffText}
|
|
516
|
+
${imageContractText}${appHandoffText}${executionProfileText}
|
|
477
517
|
Previous tail:
|
|
478
518
|
${String(previous || '').slice(-2500)}
|
|
479
519
|
`;
|
|
@@ -486,7 +526,8 @@ export async function qaStatus(dir) {
|
|
|
486
526
|
const imagePathContract = await readJson(path.join(dir, 'qa-loop', 'image-artifact-path-contract.json'), null);
|
|
487
527
|
const reportFile = qaReportFileFromGate(gate?.gate || gate || {}) || ledger?.qa_report_file || null;
|
|
488
528
|
const report = reportFile && isQaReportFilename(reportFile) ? await readText(path.join(dir, reportFile), '') : '';
|
|
489
|
-
|
|
529
|
+
const executionProfile = await readJson(path.join(dir, 'qa-loop', 'execution-profile.json'), null);
|
|
530
|
+
return { gate, checklist_count: ledger?.checklist?.length ?? null, report_file: reportFile, report_written: Boolean(report.trim()), desktop_app_handoff: appHandoff, desktop_app_confirmation: appConfirmation, desktop_review_complete: appConfirmation?.verdict === 'pass', image_path_contract: imagePathContract, codex_app_execution_profile: executionProfile };
|
|
490
531
|
}
|
|
491
532
|
function qaChecklist(a) {
|
|
492
533
|
const cases = [
|
|
@@ -504,6 +545,23 @@ function qaChecklist(a) {
|
|
|
504
545
|
cases.push(['report.evidence', 'Record pass/fail/blocked/skipped with evidence.'], ['report.corrective_loop', 'Record fixes, rechecks, unresolved findings, deferred blockers.'], ['report.honest', 'Run Honest Mode.']);
|
|
505
546
|
return cases.map(([id, title]) => ({ id, title, status: 'pending', evidence: [] }));
|
|
506
547
|
}
|
|
548
|
+
function missionRootFromDir(dir) {
|
|
549
|
+
const normalized = path.resolve(String(dir || ''));
|
|
550
|
+
const marker = `${path.sep}.sneakoscope${path.sep}missions${path.sep}`;
|
|
551
|
+
const idx = normalized.indexOf(marker);
|
|
552
|
+
return idx > 0 ? normalized.slice(0, idx) : null;
|
|
553
|
+
}
|
|
554
|
+
function compactExecutionProfile(profile) {
|
|
555
|
+
return profile ? {
|
|
556
|
+
mode: profile.mode || 'unknown',
|
|
557
|
+
agent_role_strategy: profile.agent_role_strategy || 'message-role',
|
|
558
|
+
hooks_approval_required: profile.hooks_approval_required === true,
|
|
559
|
+
hook_approval_state: profile.hook_approval_state || 'unknown',
|
|
560
|
+
app_handoff_ready: profile.app_handoff_ready === true,
|
|
561
|
+
plugin_mcp_inventory_ready: profile.plugin_mcp_inventory_ready === true,
|
|
562
|
+
artifact_path: profile.artifact_path || '.sneakoscope/reports/codex-app-execution-profile.json'
|
|
563
|
+
} : null;
|
|
564
|
+
}
|
|
507
565
|
function qaReportTemplate(mission, contract, checklist) {
|
|
508
566
|
const a = contract.answers || {};
|
|
509
567
|
return `# QA-LOOP Report\n\nMission: ${mission.id}\nTarget: ${a.TARGET_BASE_URL || 'unset'}\nScope: ${a.QA_SCOPE || 'unset'}\nEnvironment: ${a.TARGET_ENVIRONMENT || 'unset'}\n\n## Safety\n\n- Deployed destructive tests: never\n- Credentials: temp-only, never saved\n- UI evidence: ${CODEX_WEB_VERIFICATION_POLICY}\n\n## Checklist\n\n${checklist.map((item) => `- [ ] ${item.id}: ${item.title}`).join('\n')}\n\n## Findings\n\nTBD\n\n## Corrections And Rechecks\n\nTBD\n\n## Honest Mode\n\nTBD\n`;
|
|
@@ -63,6 +63,7 @@ export async function runResearchCycle(inputOrDir, legacyGraph = null, legacyOpt
|
|
|
63
63
|
blockers: [...new Set(blockers)],
|
|
64
64
|
stages: stageResults.map((stage) => stage.stage_id),
|
|
65
65
|
stage_results: stageResults,
|
|
66
|
+
codex_app_execution_profile: input.plan?.codex_app_execution_profile || null,
|
|
66
67
|
parallelism: {
|
|
67
68
|
max_parallel_stages: maxParallel,
|
|
68
69
|
max_observed_parallel: maxObservedParallel,
|
|
@@ -91,7 +91,7 @@ async function runSourceShardStage(input, startedAt) {
|
|
|
91
91
|
const validation = validateResearchSourceShardOutput(output);
|
|
92
92
|
await writeJsonAtomic(path.join(input.dir, artifact), output);
|
|
93
93
|
await writeTextAtomic(path.join(input.dir, 'research', `cycle-${input.cycle}`, 'source-notes', `${layer.id}.md`), `# Source shard: ${layer.label}\n\n${output.sources.map((source) => `- ${source.id}: ${source.title}`).join('\n')}\n`);
|
|
94
|
-
return baseResult(input, startedAt, 'source_shard', validation.ok ? 'passed' : 'blocked', [artifact, `research/cycle-${input.cycle}/source-notes/${layer.id}.md`], validation.blockers, { layer_id: layer.id, source_count: output.sources.length });
|
|
94
|
+
return baseResult(input, startedAt, 'source_shard', validation.ok ? 'passed' : 'blocked', [artifact, `research/cycle-${input.cycle}/source-notes/${layer.id}.md`], validation.blockers, { layer_id: layer.id, source_count: output.sources.length, source_tool_route: researchSourceToolRoute(input.plan) });
|
|
95
95
|
}
|
|
96
96
|
const codex = await runResearchCodexStage({
|
|
97
97
|
root: input.root,
|
|
@@ -333,9 +333,16 @@ function baseResult(input, startedAt, stageKind, status, outputArtifacts, blocke
|
|
|
333
333
|
backend: input.backend,
|
|
334
334
|
worker_result_path: typeof metrics.worker_result_path === 'string' ? metrics.worker_result_path : null,
|
|
335
335
|
blockers: [...new Set(blockers.map(String).filter(Boolean))],
|
|
336
|
-
metrics
|
|
336
|
+
metrics: {
|
|
337
|
+
...metrics,
|
|
338
|
+
codex_app_execution_profile: input.plan?.codex_app_execution_profile || null,
|
|
339
|
+
source_tool_route: metrics.source_tool_route || researchSourceToolRoute(input.plan)
|
|
340
|
+
}
|
|
337
341
|
};
|
|
338
342
|
}
|
|
343
|
+
function researchSourceToolRoute(plan) {
|
|
344
|
+
return plan?.web_research_policy?.source_tool_routing?.mode || (plan?.codex_app_execution_profile?.plugin_mcp_inventory_ready ? 'plugin-mcp-inventory-first' : 'codex-cli-or-web-fallback');
|
|
345
|
+
}
|
|
339
346
|
async function buildResearchGateSeed(dir, plan) {
|
|
340
347
|
const sourceLedger = await readJson(path.join(dir, 'source-ledger.json'), null);
|
|
341
348
|
const claimMatrix = await readJson(path.join(dir, 'claim-evidence-matrix.json'), null);
|
package/dist/core/research.js
CHANGED
|
@@ -17,6 +17,8 @@ import { writeResearchHandoffArtifacts } from './research/research-handoff.js';
|
|
|
17
17
|
import { RESEARCH_WORK_GRAPH_ARTIFACT, writeResearchWorkGraph } from './research/research-work-graph.js';
|
|
18
18
|
import { researchPromptContractText, validateResearchPromptContract } from './research/research-prompt-contract.js';
|
|
19
19
|
import { buildRealisticResearchPaper, buildRealisticResearchReport } from './research/research-realistic-report.js';
|
|
20
|
+
import { resolveCodexAppExecutionProfile } from './codex-app/codex-app-execution-profile.js';
|
|
21
|
+
import { resolveCodexNativeInvocationPlan } from './codex-native/codex-native-invocation-router.js';
|
|
20
22
|
export const RESEARCH_PAPER_ARTIFACT = 'research-paper.md';
|
|
21
23
|
export const RESEARCH_SOURCE_SKILL_ARTIFACT = 'research-source-skill.md';
|
|
22
24
|
export const RESEARCH_GENIUS_SUMMARY_ARTIFACT = 'genius-opinion-summary.md';
|
|
@@ -252,6 +254,15 @@ export function createResearchPlan(prompt, opts = {}) {
|
|
|
252
254
|
const createdAt = nowIso();
|
|
253
255
|
const paperArtifact = researchPaperArtifactName(prompt, createdAt, opts);
|
|
254
256
|
const nativeAgentPlan = researchNativeAgentPlan(prompt, { paperArtifact, missionId: opts.missionId });
|
|
257
|
+
const executionProfile = opts.executionProfile || null;
|
|
258
|
+
const codexNativeInvocation = opts.codexNativeInvocation || null;
|
|
259
|
+
const sourceStrategy = codexNativeInvocation?.mcp_source?.selected_strategy === 'codex-app-native'
|
|
260
|
+
? 'mcp-plugin-candidates'
|
|
261
|
+
: codexNativeInvocation?.web_search?.selected_strategy === 'codex-cli-headless'
|
|
262
|
+
? 'web-sources'
|
|
263
|
+
: executionProfile?.plugin_mcp_inventory_ready
|
|
264
|
+
? 'mcp-plugin-candidates'
|
|
265
|
+
: 'local-files';
|
|
255
266
|
return {
|
|
256
267
|
schema_version: 1,
|
|
257
268
|
mission_id: opts.missionId || null,
|
|
@@ -262,6 +273,8 @@ export function createResearchPlan(prompt, opts = {}) {
|
|
|
262
273
|
paper_artifact: paperArtifact,
|
|
263
274
|
quality_contract: DEFAULT_RESEARCH_QUALITY_CONTRACT,
|
|
264
275
|
native_agent_plan: nativeAgentPlan,
|
|
276
|
+
codex_app_execution_profile: executionProfile ? compactExecutionProfile(executionProfile) : null,
|
|
277
|
+
codex_native_invocation: codexNativeInvocation,
|
|
265
278
|
agent_sessions: nativeAgentPlan.personas,
|
|
266
279
|
agent_batches: nativeAgentPlan.batches,
|
|
267
280
|
autoresearch_cycle_policy: nativeAgentPlan.autoresearch_cycle_policy,
|
|
@@ -318,6 +331,13 @@ export function createResearchPlan(prompt, opts = {}) {
|
|
|
318
331
|
web_research_policy: {
|
|
319
332
|
mode: 'layered_source_retrieval_and_triangulation',
|
|
320
333
|
requirement: 'Use every safely available public web/source route before synthesis, separated into source layers so the final claim is not dominated by one corpus or platform.',
|
|
334
|
+
source_tool_routing: {
|
|
335
|
+
mode: sourceStrategy,
|
|
336
|
+
plugin_mcp_inventory_ready: executionProfile?.plugin_mcp_inventory_ready === true,
|
|
337
|
+
execution_profile_artifact: executionProfile?.artifact_path || '.sneakoscope/reports/codex-app-execution-profile.json',
|
|
338
|
+
codex_native_invocation_artifact: codexNativeInvocation ? 'research/codex-native-invocation.json' : null,
|
|
339
|
+
rule: 'Prefer verified plugin/MCP candidates when available; otherwise record source-tool blockers instead of assuming live search coverage.'
|
|
340
|
+
},
|
|
321
341
|
query_sets: [
|
|
322
342
|
'first-principles and theory sources',
|
|
323
343
|
'plain-language explanations and empirical examples',
|
|
@@ -417,6 +437,9 @@ export function researchPlanMarkdown(plan) {
|
|
|
417
437
|
lines.push(`Depth: ${plan.depth}`);
|
|
418
438
|
lines.push(`Methodology: ${plan.methodology}`);
|
|
419
439
|
lines.push(`Research paper: ${researchPaperArtifactForPlan(plan)}`);
|
|
440
|
+
if (plan.codex_app_execution_profile) {
|
|
441
|
+
lines.push(`Execution profile: ${plan.codex_app_execution_profile.mode}; agent role strategy ${plan.codex_app_execution_profile.agent_role_strategy}`);
|
|
442
|
+
}
|
|
420
443
|
if (plan.execution_policy) {
|
|
421
444
|
lines.push(`Execution: ${plan.execution_policy.normal_run}; default cycle timeout ${plan.execution_policy.default_cycle_timeout_minutes} minutes`);
|
|
422
445
|
if (plan.execution_policy.default_max_cycles)
|
|
@@ -468,6 +491,8 @@ export function researchPlanMarkdown(plan) {
|
|
|
468
491
|
lines.push('## Web Research Policy');
|
|
469
492
|
lines.push(`Mode: ${plan.web_research_policy.mode}`);
|
|
470
493
|
lines.push(`Requirement: ${plan.web_research_policy.requirement}`);
|
|
494
|
+
if (plan.web_research_policy.source_tool_routing)
|
|
495
|
+
lines.push(`Source tool routing: ${plan.web_research_policy.source_tool_routing.mode}`);
|
|
471
496
|
for (const querySet of plan.web_research_policy.query_sets || [])
|
|
472
497
|
lines.push(`- query set: ${querySet}`);
|
|
473
498
|
if (plan.web_research_policy.skill_creator?.artifact)
|
|
@@ -537,7 +562,11 @@ export function countGeniusOpinionSummaries(text = '') {
|
|
|
537
562
|
}).length;
|
|
538
563
|
}
|
|
539
564
|
export async function writeResearchPlan(dir, prompt, opts = {}) {
|
|
540
|
-
const
|
|
565
|
+
const root = opts.root || missionRootFromDir(String(dir || ''));
|
|
566
|
+
const executionProfile = opts.executionProfile || (root ? await resolveCodexAppExecutionProfile({ root }).catch(() => null) : null);
|
|
567
|
+
const missionId = opts.missionId || path.basename(String(dir || ''));
|
|
568
|
+
const codexNativeInvocation = root ? await resolveResearchCodexNativeInvocation(root, missionId).catch(() => null) : null;
|
|
569
|
+
const plan = createResearchPlan(prompt, { ...opts, executionProfile, codexNativeInvocation });
|
|
541
570
|
const noveltyLedger = {
|
|
542
571
|
schema_version: 1,
|
|
543
572
|
entries: [],
|
|
@@ -553,6 +582,10 @@ export async function writeResearchPlan(dir, prompt, opts = {}) {
|
|
|
553
582
|
const experimentPlan = defaultExperimentPlan(plan);
|
|
554
583
|
const replicationPack = defaultReplicationPack(plan);
|
|
555
584
|
await writeJsonAtomic(path.join(dir, 'research-plan.json'), plan);
|
|
585
|
+
if (executionProfile)
|
|
586
|
+
await writeJsonAtomic(path.join(dir, 'research', 'execution-profile.json'), executionProfile).catch(() => undefined);
|
|
587
|
+
if (codexNativeInvocation)
|
|
588
|
+
await writeJsonAtomic(path.join(dir, 'research', 'codex-native-invocation.json'), codexNativeInvocation).catch(() => undefined);
|
|
556
589
|
await writeTextAtomic(path.join(dir, 'research-plan.md'), researchPlanMarkdown(plan));
|
|
557
590
|
await writeTextAtomic(path.join(dir, RESEARCH_SOURCE_SKILL_ARTIFACT), researchSourceSkillMarkdown(plan));
|
|
558
591
|
await writeResearchQualityContract(dir, plan.quality_contract);
|
|
@@ -575,6 +608,40 @@ export async function writeResearchPlan(dir, prompt, opts = {}) {
|
|
|
575
608
|
await appendJsonlBounded(path.join(dir, 'events.jsonl'), { ts: nowIso(), type: 'research.plan.created', depth: plan.depth });
|
|
576
609
|
return plan;
|
|
577
610
|
}
|
|
611
|
+
async function resolveResearchCodexNativeInvocation(root, missionId) {
|
|
612
|
+
const [pluginSource, mcpSource, webSearch] = await Promise.all([
|
|
613
|
+
resolveCodexNativeInvocationPlan({ root, missionId, route: '$Research', desiredCapability: 'plugin-source' }),
|
|
614
|
+
resolveCodexNativeInvocationPlan({ root, missionId, route: '$Research', desiredCapability: 'mcp-source' }),
|
|
615
|
+
resolveCodexNativeInvocationPlan({ root, missionId, route: '$Research', desiredCapability: 'web-search' })
|
|
616
|
+
]);
|
|
617
|
+
return {
|
|
618
|
+
plugin_source: pluginSource,
|
|
619
|
+
mcp_source: mcpSource,
|
|
620
|
+
web_search: webSearch,
|
|
621
|
+
selected_source_strategy: mcpSource.selected_strategy === 'codex-app-native'
|
|
622
|
+
? 'mcp-plugin-candidates'
|
|
623
|
+
: webSearch.selected_strategy === 'codex-cli-headless'
|
|
624
|
+
? 'web-sources'
|
|
625
|
+
: 'local-files',
|
|
626
|
+
hook_derived_source_evidence_allowed: false
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
function missionRootFromDir(dir) {
|
|
630
|
+
const normalized = path.resolve(String(dir || ''));
|
|
631
|
+
const marker = `${path.sep}.sneakoscope${path.sep}missions${path.sep}`;
|
|
632
|
+
const idx = normalized.indexOf(marker);
|
|
633
|
+
return idx > 0 ? normalized.slice(0, idx) : null;
|
|
634
|
+
}
|
|
635
|
+
function compactExecutionProfile(profile) {
|
|
636
|
+
return profile ? {
|
|
637
|
+
mode: profile.mode || 'unknown',
|
|
638
|
+
agent_role_strategy: profile.agent_role_strategy || 'message-role',
|
|
639
|
+
hooks_approval_required: profile.hooks_approval_required === true,
|
|
640
|
+
hook_approval_state: profile.hook_approval_state || 'unknown',
|
|
641
|
+
plugin_mcp_inventory_ready: profile.plugin_mcp_inventory_ready === true,
|
|
642
|
+
artifact_path: profile.artifact_path || '.sneakoscope/reports/codex-app-execution-profile.json'
|
|
643
|
+
} : null;
|
|
644
|
+
}
|
|
578
645
|
export async function writeResearchNativeAgentLedger(dir, plan, opts = {}) {
|
|
579
646
|
const missionId = opts.missionId || plan?.mission_id;
|
|
580
647
|
if (!missionId)
|
package/dist/core/routes.js
CHANGED
|
@@ -30,7 +30,7 @@ export const FROM_CHAT_IMG_CHECKLIST_ARTIFACT = 'from-chat-img-checklist.md';
|
|
|
30
30
|
export const FROM_CHAT_IMG_TEMP_TRIWIKI_ARTIFACT = 'from-chat-img-temp-triwiki.json';
|
|
31
31
|
export const FROM_CHAT_IMG_QA_LOOP_ARTIFACT = 'from-chat-img-qa-loop.json';
|
|
32
32
|
export const FROM_CHAT_IMG_TEMP_TRIWIKI_SESSIONS = 5;
|
|
33
|
-
export const USAGE_TOPICS = 'install|setup|bootstrap|root|deps|zellij|tmux|auto-review|team|qa-loop|ppt|image-ux-review|goal|fast-mode|research|db|git|codex|codex-app|hooks|features|all-features|
|
|
33
|
+
export const USAGE_TOPICS = 'install|setup|bootstrap|root|deps|zellij|tmux|auto-review|team|qa-loop|ppt|image-ux-review|goal|fast-mode|research|db|git|codex|codex-app|codex-native|hooks|features|all-features|dfix|commit|commit-and-push|design|imagegen|dollar|context7|xai|pipeline|reasoning|guard|conflicts|versioning|eval|harness|hproof|gx|wiki|wrongness|code-structure|proof-field|skill-dream|rust';
|
|
34
34
|
export const CODEX_COMPUTER_USE_EVIDENCE_SOURCE = 'codex_computer_use';
|
|
35
35
|
export const CODEX_WEB_VERIFICATION_EVIDENCE_SOURCE = 'codex_chrome_extension';
|
|
36
36
|
export const CODEX_IMAGEGEN_EVIDENCE_SOURCE = 'codex_app_imagegen_gpt_image_2';
|
|
@@ -633,11 +633,10 @@ export const COMMAND_CATALOG = [
|
|
|
633
633
|
{ name: 'deps', usage: 'sks deps check [--json] [--yes]', description: 'Check Node/npm, Codex CLI, and Zellij readiness; pass --yes to repair missing Codex CLI/Zellij tooling when supported.' },
|
|
634
634
|
{ name: 'codex', usage: 'sks codex compatibility|version|doctor|schema [--json]', description: 'Check Codex CLI rust-v0.136.0 compatibility, installed version, 0.136 capabilities, inherited 0.135/0.134/0.133 behavior, and vendored hook schema snapshot freshness.' },
|
|
635
635
|
{ name: 'codex-app', usage: 'sks codex-app [check|product-design|product-design --check-only|ensure-product-design|chrome-extension|pat status|remote-control]', description: 'Check Codex App install, Product Design plugin auto-install readiness, Codex Chrome Extension web verification readiness, PAT-safe status, first-party MCP/plugin readiness, and Codex CLI 0.130.0+ remote-control availability.' },
|
|
636
|
+
{ name: 'codex-native', usage: 'sks codex-native status|feature-broker|invocation-plan|init-deep [--json]', description: 'Inspect Codex Native feature broker readiness, invocation routing, pattern evidence, and managed memory setup.' },
|
|
636
637
|
{ name: 'hooks', usage: 'sks hooks explain|status|trust-report|replay|codex-validate|warning-check ... [--json]', description: 'Explain Codex hook events, validate vendored latest 10-event output schemas, replay fixtures, and enforce warning-zero SKS hook policies under the 0.134 compatibility matrix.' },
|
|
637
638
|
{ name: 'codex-lb', usage: 'sks codex-lb status|health|metrics|doctor|circuit|repair|setup ...', description: 'Configure, health-check, repair, and record circuit evidence for codex-lb provider auth without confusing ChatGPT OAuth and proxy keys.' },
|
|
638
639
|
{ name: 'auth', usage: 'sks auth status|health|repair|setup --host <domain> --api-key <key>', description: 'Shortcut for codex-lb provider auth status, health, repair, and setup commands.' },
|
|
639
|
-
{ name: 'openclaw', usage: 'sks openclaw install|path|print [--dir path] [--force] [--json]', description: 'Generate an OpenClaw skill package so OpenClaw agents can discover and use local SKS workflows.' },
|
|
640
|
-
{ name: 'hermes', usage: 'sks hermes install|status|path|print [--dir path] [--force] [--json]', description: 'Generate a Hermes Agent skill package so Hermes agents can discover and use local SKS workflows.' },
|
|
641
640
|
{ name: 'zellij', usage: 'sks zellij status|repair [--json] | sks naruto dashboard latest | sks --mad', description: 'Inspect Zellij runtime status, explain repair (no auto-install), and open the SKS Zellij runtime used by MAD and Naruto lane UI.' },
|
|
642
641
|
{ name: 'tmux', usage: 'sks tmux [--json]', description: 'Show the removed-runtime migration notice and point operators to Zellij.' },
|
|
643
642
|
{ name: 'mad', usage: 'sks --mad [--high]', description: 'Open a one-shot Zellij Codex CLI workspace with the SKS MAD full-access auto-review profile.' },
|
package/dist/core/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const PACKAGE_VERSION = '3.1.
|
|
1
|
+
export const PACKAGE_VERSION = '3.1.6';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { nowIso } from '../fsx.js';
|
|
2
|
+
export function isZellijSelfHealResult(value) {
|
|
3
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
4
|
+
return false;
|
|
5
|
+
const row = value;
|
|
6
|
+
return row.schema === 'sks.zellij-self-heal.v1'
|
|
7
|
+
&& typeof row.ok === 'boolean'
|
|
8
|
+
&& typeof row.requested_by === 'string'
|
|
9
|
+
&& typeof row.strategy === 'string'
|
|
10
|
+
&& row.before !== null
|
|
11
|
+
&& typeof row.before === 'object'
|
|
12
|
+
&& row.after !== null
|
|
13
|
+
&& typeof row.after === 'object'
|
|
14
|
+
&& Array.isArray(row.blockers)
|
|
15
|
+
&& Array.isArray(row.warnings);
|
|
16
|
+
}
|
|
17
|
+
export function normalizeZellijSelfHealResult(value) {
|
|
18
|
+
if (isZellijSelfHealResult(value)) {
|
|
19
|
+
return {
|
|
20
|
+
...value,
|
|
21
|
+
dry_run: value.dry_run === true,
|
|
22
|
+
planned_mutations: Array.isArray(value.planned_mutations) ? value.planned_mutations : []
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
schema: 'sks.zellij-self-heal.v1',
|
|
27
|
+
ok: false,
|
|
28
|
+
requested_by: 'setup',
|
|
29
|
+
fix_requested: false,
|
|
30
|
+
auto_approved: false,
|
|
31
|
+
install_homebrew_allowed: false,
|
|
32
|
+
dry_run: false,
|
|
33
|
+
planned_mutations: [],
|
|
34
|
+
before: { status: 'unknown', version: null, bin: null },
|
|
35
|
+
latest_version: null,
|
|
36
|
+
strategy: 'failed',
|
|
37
|
+
command: null,
|
|
38
|
+
after: { status: 'unknown', version: null, bin: null },
|
|
39
|
+
mutation_guard_artifact: null,
|
|
40
|
+
homebrew: { present: false, bin: null, install_attempted: false, install_allowed: false },
|
|
41
|
+
blockers: ['invalid_zellij_self_heal_result'],
|
|
42
|
+
warnings: [`normalized_at:${nowIso()}`]
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=zellij-self-heal-types.js.map
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
import fs from 'node:fs/promises';
|
|
3
2
|
import path from 'node:path';
|
|
4
3
|
import { ensureDir, nowIso, runProcess, writeJsonAtomic } from '../fsx.js';
|
|
@@ -12,6 +11,7 @@ export async function repairZellijForSks(input) {
|
|
|
12
11
|
const root = path.resolve(input.root || process.cwd());
|
|
13
12
|
const env = input.env || process.env;
|
|
14
13
|
const autoApproved = input.autoApprove === true;
|
|
14
|
+
const dryRun = input.dryRun === true;
|
|
15
15
|
const beforeReport = await capabilitySnapshot(root, env, 'before');
|
|
16
16
|
const before = compactCapability(beforeReport);
|
|
17
17
|
const latest = await latestZellijVersion(env);
|
|
@@ -41,6 +41,9 @@ export async function repairZellijForSks(input) {
|
|
|
41
41
|
if (input.fixRequested !== true) {
|
|
42
42
|
return manualResult(root, input, env, before, latest, brew, 'fix_not_requested');
|
|
43
43
|
}
|
|
44
|
+
if (dryRun) {
|
|
45
|
+
return dryRunResult(root, input, env, before, latest, brew, mutationArtifact);
|
|
46
|
+
}
|
|
44
47
|
if (!autoApproved && input.interactive !== true) {
|
|
45
48
|
return input.allowHeadlessFallback === true
|
|
46
49
|
? headlessResult(root, input, before, latest, brew, 'noninteractive_without_auto_approval')
|
|
@@ -183,10 +186,10 @@ async function capabilitySnapshot(root, env, phase, fallbackVersion) {
|
|
|
183
186
|
require_zellij: false,
|
|
184
187
|
min_version: ZELLIJ_MIN_VERSION,
|
|
185
188
|
version: null,
|
|
186
|
-
bin:
|
|
189
|
+
bin: 'zellij',
|
|
187
190
|
command: ['zellij', '--version'],
|
|
188
191
|
docs_evidence: [],
|
|
189
|
-
blockers: [`zellij_capability_check_failed:${tail(
|
|
192
|
+
blockers: [`zellij_capability_check_failed:${tail(errorMessage(err))}`],
|
|
190
193
|
warnings: [],
|
|
191
194
|
operator_actions: ['Resolve the Zellij capability check failure, then rerun `sks doctor --fix --yes`.']
|
|
192
195
|
}));
|
|
@@ -261,7 +264,7 @@ async function runZellijBrew(root, env, brewBin, args, command) {
|
|
|
261
264
|
env,
|
|
262
265
|
timeoutMs: 180000,
|
|
263
266
|
maxOutputBytes: 256 * 1024
|
|
264
|
-
}).catch((err) => ({ code: 1, stdout: '', stderr:
|
|
267
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: errorMessage(err) }));
|
|
265
268
|
}
|
|
266
269
|
async function runHomebrewInstall(root, env) {
|
|
267
270
|
if (env.SKS_ZELLIJ_SELF_HEAL_FAKE_RUN === '1') {
|
|
@@ -281,7 +284,7 @@ async function runHomebrewInstall(root, env) {
|
|
|
281
284
|
env,
|
|
282
285
|
timeoutMs: 600000,
|
|
283
286
|
maxOutputBytes: 256 * 1024
|
|
284
|
-
}).catch((err) => ({ code: 1, stdout: '', stderr:
|
|
287
|
+
}).catch((err) => ({ code: 1, stdout: '', stderr: errorMessage(err) }));
|
|
285
288
|
}
|
|
286
289
|
async function appendFakeBrewLog(env, args) {
|
|
287
290
|
if (!env.SKS_FAKE_BREW_LOG)
|
|
@@ -289,6 +292,56 @@ async function appendFakeBrewLog(env, args) {
|
|
|
289
292
|
await ensureDir(path.dirname(env.SKS_FAKE_BREW_LOG));
|
|
290
293
|
await fs.appendFile(env.SKS_FAKE_BREW_LOG, `${args.join(' ')}\n`, 'utf8');
|
|
291
294
|
}
|
|
295
|
+
async function dryRunResult(root, input, env, before, latest, brew, mutationArtifact) {
|
|
296
|
+
const policy = !brew.present
|
|
297
|
+
? resolveHomebrewInstallPolicy({
|
|
298
|
+
env,
|
|
299
|
+
installHomebrew: input.installHomebrew === true,
|
|
300
|
+
autoApprove: input.autoApprove === true,
|
|
301
|
+
interactiveAccepted: false
|
|
302
|
+
})
|
|
303
|
+
: null;
|
|
304
|
+
if (!brew.present && policy?.allowed !== true) {
|
|
305
|
+
return input.allowHeadlessFallback === true
|
|
306
|
+
? headlessResult(root, input, before, latest, brew, policy?.blockers[0] || 'homebrew_missing')
|
|
307
|
+
: manualResult(root, input, env, before, latest, brew, policy?.blockers[0] || 'homebrew_missing');
|
|
308
|
+
}
|
|
309
|
+
const planned = [];
|
|
310
|
+
if (!brew.present) {
|
|
311
|
+
planned.push({
|
|
312
|
+
command: HOMEBREW_INSTALL_COMMAND,
|
|
313
|
+
reason: 'homebrew_missing_for_zellij_repair'
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
const install = before.status === 'missing';
|
|
317
|
+
const zellijCommand = install ? 'brew install zellij' : 'brew upgrade zellij';
|
|
318
|
+
planned.push({
|
|
319
|
+
command: zellijCommand,
|
|
320
|
+
reason: install ? 'zellij_missing' : 'zellij_too_old_or_stale'
|
|
321
|
+
});
|
|
322
|
+
const strategy = !brew.present ? 'brew-install-homebrew-then-zellij'
|
|
323
|
+
: install ? 'brew-install-zellij'
|
|
324
|
+
: 'brew-upgrade-zellij';
|
|
325
|
+
return persistSelfHeal(root, input.missionDir, {
|
|
326
|
+
schema: 'sks.zellij-self-heal.v1',
|
|
327
|
+
ok: true,
|
|
328
|
+
requested_by: input.requestedBy,
|
|
329
|
+
fix_requested: true,
|
|
330
|
+
auto_approved: input.autoApprove === true,
|
|
331
|
+
install_homebrew_allowed: policy?.allowed === true,
|
|
332
|
+
dry_run: true,
|
|
333
|
+
planned_mutations: planned,
|
|
334
|
+
before,
|
|
335
|
+
latest_version: latest,
|
|
336
|
+
strategy,
|
|
337
|
+
command: planned.map((row) => row.command).join(' && '),
|
|
338
|
+
after: before,
|
|
339
|
+
mutation_guard_artifact: `${mutationArtifact}#planned`,
|
|
340
|
+
homebrew: { present: brew.present, bin: brew.bin, install_attempted: false, install_allowed: policy?.allowed === true },
|
|
341
|
+
blockers: [],
|
|
342
|
+
warnings: ['dry_run_no_mutation_performed']
|
|
343
|
+
});
|
|
344
|
+
}
|
|
292
345
|
async function manualResult(root, input, env, before, latest, brew, reason) {
|
|
293
346
|
const command = brew.present ? 'sks doctor --fix --yes' : 'sks doctor --fix --install-homebrew --yes';
|
|
294
347
|
return persistSelfHeal(root, input.missionDir, {
|
|
@@ -329,10 +382,15 @@ async function headlessResult(root, input, before, latest, brew, reason) {
|
|
|
329
382
|
});
|
|
330
383
|
}
|
|
331
384
|
async function persistSelfHeal(root, missionDir, result) {
|
|
332
|
-
|
|
385
|
+
const normalized = {
|
|
386
|
+
...result,
|
|
387
|
+
dry_run: result.dry_run === true,
|
|
388
|
+
planned_mutations: result.planned_mutations || []
|
|
389
|
+
};
|
|
390
|
+
await writeJsonAtomic(path.join(root, '.sneakoscope', 'reports', 'zellij-self-heal.json'), normalized).catch(() => undefined);
|
|
333
391
|
if (missionDir)
|
|
334
|
-
await writeJsonAtomic(path.join(missionDir, 'zellij-self-heal.json'),
|
|
335
|
-
return
|
|
392
|
+
await writeJsonAtomic(path.join(missionDir, 'zellij-self-heal.json'), normalized).catch(() => undefined);
|
|
393
|
+
return normalized;
|
|
336
394
|
}
|
|
337
395
|
async function askZellijRepairAllowed(question) {
|
|
338
396
|
if (!(process.stdin.isTTY && process.stdout.isTTY))
|
|
@@ -347,6 +405,9 @@ async function askZellijRepairAllowed(question) {
|
|
|
347
405
|
rl.close();
|
|
348
406
|
}
|
|
349
407
|
}
|
|
408
|
+
function errorMessage(err) {
|
|
409
|
+
return err instanceof Error ? err.message : String(err);
|
|
410
|
+
}
|
|
350
411
|
function tail(value, limit = 1000) {
|
|
351
412
|
return String(value || '').replace(/\s+/g, ' ').trim().slice(-limit);
|
|
352
413
|
}
|
|
@@ -232,17 +232,25 @@ export async function maybePromptZellijUpdateForLaunch(args = [], opts = {}) {
|
|
|
232
232
|
interactive: mode === 'interactive-prompt',
|
|
233
233
|
installHomebrew: opts.installHomebrew === true || list.includes('--install-homebrew'),
|
|
234
234
|
allowHeadlessFallback: opts.allowHeadlessFallback === true,
|
|
235
|
+
dryRun: opts.dryRun === true || list.includes('--dry-run'),
|
|
235
236
|
missionDir: opts.missionDir || null,
|
|
236
237
|
env
|
|
237
238
|
});
|
|
238
239
|
if (repaired.strategy === 'headless-fallback')
|
|
239
240
|
console.log('Zellij repair: headless fallback selected (live_panes=false).');
|
|
241
|
+
else if (repaired.dry_run)
|
|
242
|
+
console.log(`Zellij repair: dry_run planned ${repaired.command || 'none'}`);
|
|
240
243
|
else if (repaired.ok && repaired.command)
|
|
241
244
|
console.log(`Zellij repair: ${repaired.strategy} via ${repaired.command}`);
|
|
242
245
|
else if (!repaired.ok)
|
|
243
246
|
console.log(`Zellij repair required. Run: ${repaired.command || notice.upgrade_command}`);
|
|
247
|
+
const repairedStatus = repaired.strategy === 'headless-fallback' ? 'headless_fallback'
|
|
248
|
+
: !repaired.ok || repaired.strategy === 'manual-required' ? 'repair_required'
|
|
249
|
+
: repaired.strategy === 'brew-upgrade-zellij' ? 'upgraded'
|
|
250
|
+
: repaired.strategy === 'none-current' ? 'noop'
|
|
251
|
+
: 'installed';
|
|
244
252
|
return {
|
|
245
|
-
status:
|
|
253
|
+
status: repairedStatus,
|
|
246
254
|
current: repaired.after.version || repaired.before.version,
|
|
247
255
|
latest: repaired.latest_version,
|
|
248
256
|
command: repaired.command,
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// @ts-nocheck
|
|
3
2
|
import fs from 'node:fs';
|
|
4
3
|
import fsp from 'node:fs/promises';
|
|
5
4
|
import os from 'node:os';
|
|
6
5
|
import path from 'node:path';
|
|
7
|
-
import { spawnSync } from 'node:child_process';
|
|
8
6
|
import { assertGate, emitGate, importDist, root } from './sks-1-18-gate-lib.js';
|
|
9
7
|
export async function runDirective314Gate(id) {
|
|
10
8
|
if (id.startsWith('zellij:'))
|
|
@@ -13,14 +11,10 @@ export async function runDirective314Gate(id) {
|
|
|
13
11
|
return doctorZellijGate(id);
|
|
14
12
|
if (id.startsWith('mad:zellij'))
|
|
15
13
|
return madZellijGate(id);
|
|
16
|
-
if (id === 'lazycodex:analysis')
|
|
17
|
-
return lazycodexAnalysisGate(id);
|
|
18
14
|
if (id.startsWith('codex-app:') || id === 'doctor:codex-app-harness')
|
|
19
15
|
return codexAppGate(id);
|
|
20
16
|
if (id.startsWith('loop:'))
|
|
21
17
|
return loopGate(id);
|
|
22
|
-
if (id === 'lazycodex:interop-policy' || id === 'lazycodex:pattern-adoption-blackbox')
|
|
23
|
-
return lazycodexInteropGate(id);
|
|
24
18
|
throw new Error(`unknown_gate:${id}`);
|
|
25
19
|
}
|
|
26
20
|
async function zellijGate(id) {
|
|
@@ -97,14 +91,6 @@ async function madZellijGate(id) {
|
|
|
97
91
|
}
|
|
98
92
|
emitGate(id, { source_checked: true });
|
|
99
93
|
}
|
|
100
|
-
async function lazycodexAnalysisGate(id) {
|
|
101
|
-
const mod = await importDist('core/codex-app/lazycodex-analysis.js');
|
|
102
|
-
const report = await mod.writeLazyCodexPatternAnalysis(root);
|
|
103
|
-
assertGate(report.patterns.length >= 14, 'LazyCodex analysis must include required patterns', report);
|
|
104
|
-
const docs = mod.renderLazyCodexAnalysisMarkdown(report);
|
|
105
|
-
await fsp.writeFile(path.join(root, 'docs', 'lazycodex-analysis.md'), `${docs}\n`, 'utf8');
|
|
106
|
-
emitGate(id, { patterns: report.patterns.length });
|
|
107
|
-
}
|
|
108
94
|
async function codexAppGate(id) {
|
|
109
95
|
const rootDir = await tempRoot(`sks-${id.replace(/[:/]/g, '-')}-`);
|
|
110
96
|
const previous = swapEnv({
|
|
@@ -131,7 +117,7 @@ async function codexAppGate(id) {
|
|
|
131
117
|
const skillsRoot = path.join(rootDir, 'skills');
|
|
132
118
|
await fsp.mkdir(path.join(skillsRoot, 'ulw-loop'), { recursive: true });
|
|
133
119
|
const report = await mod.syncCodexSksSkills({ root: rootDir, skillsRoot, apply: true });
|
|
134
|
-
assertGate(report.interop.
|
|
120
|
+
assertGate(report.interop.clobbered_external_routes === false && report.external_route_names_preserved.includes('ulw-loop'), 'skill sync must preserve existing external route skills', report);
|
|
135
121
|
return emitGate(id, { desired: report.desired_skills.length });
|
|
136
122
|
}
|
|
137
123
|
if (id === 'codex-app:agent-role-sync') {
|
|
@@ -185,21 +171,6 @@ async function loopGate(id) {
|
|
|
185
171
|
assertGate(report.should_continue === true, 'loop continuation should request resume when proof missing', report);
|
|
186
172
|
emitGate(id, { should_continue: report.should_continue });
|
|
187
173
|
}
|
|
188
|
-
async function lazycodexInteropGate(id) {
|
|
189
|
-
const rootDir = await tempRoot(`sks-${id.replace(/[:/]/g, '-')}-`);
|
|
190
|
-
const previous = swapEnv({ SKS_CODEX_PLUGIN_JSON_FAKE: '1' });
|
|
191
|
-
try {
|
|
192
|
-
const mod = await importDist('core/codex-app/lazycodex-interop-policy.js');
|
|
193
|
-
const skillsRoot = path.join(rootDir, '.codex', 'skills');
|
|
194
|
-
await fsp.mkdir(path.join(skillsRoot, 'start-work'), { recursive: true });
|
|
195
|
-
const report = await mod.buildLazyCodexInteropPolicy({ root: rootDir, codexHome: path.join(rootDir, '.codex') });
|
|
196
|
-
assertGate(report.policy.clobber_lazycodex_skills === false, 'interop policy must not clobber LazyCodex skills', report);
|
|
197
|
-
emitGate(id, { detected: report.lazycodex_detected, collisions: report.detection.collisions.length });
|
|
198
|
-
}
|
|
199
|
-
finally {
|
|
200
|
-
restoreEnv(previous);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
174
|
function fakeZellijEnv(status, opts = {}) {
|
|
204
175
|
return {
|
|
205
176
|
...process.env,
|