sneakoscope 10.6.2 → 10.7.1
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 +28 -6
- package/config/perf-budgets.v1.json +1 -2
- package/config/skills-hash-ledger.v1.json +7 -2
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/sks-dispatch.js +6 -3
- package/dist/cli/args.js +3 -1
- package/dist/cli/command-manifest-lite.js +48 -114
- package/dist/cli/command-registry.js +1 -18
- package/dist/cli/commands-fast.js +11 -4
- package/dist/cli/help-fast.js +11 -22
- package/dist/cli/help.js +3 -3
- package/dist/cli/install-helpers-codex-lb-config.js +11 -8
- package/dist/cli/install-helpers.js +1 -1
- package/dist/cli/router.js +12 -26
- package/dist/commands/codex-app.js +2 -2
- package/dist/commands/doctor-helpers.js +1 -1
- package/dist/commands/mad-sks.js +2 -2
- package/dist/config/skills-manifest.json +13 -8
- package/dist/core/agent-bridge/async-command.js +2 -2
- package/dist/core/agents/agent-recursion-guard.js +0 -2
- package/dist/core/agents/agent-role-config.js +6 -2
- package/dist/core/agents/sks-model-pin-hygiene.js +150 -0
- package/dist/core/auto-review.js +15 -172
- package/dist/core/code-structure.js +0 -1
- package/dist/core/codex/codex-config-guard.js +18 -13
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +7 -1
- package/dist/core/codex-control/codex-reliability-shield.js +64 -15
- package/dist/core/codex-control/codex-sdk-adapter.js +38 -5
- package/dist/core/codex-lb/bridge-contracts.js +5 -0
- package/dist/core/codex-lb/combined-catalog/builder.js +4 -2
- package/dist/core/codex-lb/combined-catalog/latest-generation.js +7 -34
- package/dist/core/codex-lb/combined-catalog/normalize.js +3 -1
- package/dist/core/codex-lb/desktop-bridge/codex-lb-turn-state.js +35 -0
- package/dist/core/codex-lb/desktop-bridge/compaction-adapter.js +3 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +10 -4
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +92 -30
- package/dist/core/codex-lb/desktop-bridge/provider-handoff.js +79 -0
- package/dist/core/codex-lb/desktop-bridge/responses-websocket.js +57 -13
- package/dist/core/codex-lb/desktop-bridge/security.js +101 -55
- package/dist/core/codex-lb/desktop-bridge/server.js +10 -2
- package/dist/core/codex-lb/desktop-bridge/types.js +3 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +3 -0
- package/dist/core/codex-lb/desktop-controller-v3/catalog.js +13 -0
- package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +0 -9
- package/dist/core/codex-lb/desktop-service.js +10 -13
- package/dist/core/codex-lb/request-route-resolver.js +1 -1
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +0 -1
- package/dist/core/commands/agent-bridge-command.js +1 -1
- package/dist/core/commands/basic-cli.js +60 -233
- package/dist/core/commands/command-utils.js +1 -1
- package/dist/core/commands/gc-command.js +30 -29
- package/dist/core/commands/image-ux-review-command.js +1 -1
- package/dist/core/commands/install-package-command.js +1 -1
- package/dist/core/commands/intent-normalization/normalizer.js +2 -2
- package/dist/core/commands/pipeline-command.js +13 -5
- package/dist/core/commands/plan-command.js +2 -3
- package/dist/core/commands/research-command.js +0 -3
- package/dist/core/commands/review-command.js +1 -1
- package/dist/core/commands/seo-command.js +27 -20
- package/dist/core/commands/status-command.js +8 -2
- package/dist/core/doctor/command-alias-cleanup.js +6 -6
- package/dist/core/evaluation.js +1 -1
- package/dist/core/feature-fixtures.js +9 -43
- package/dist/core/feature-registry.js +9 -27
- package/dist/core/git-hygiene/shared-memory-publish.js +1 -1
- package/dist/core/hooks-runtime/jev-spawn-routing.js +1 -5
- package/dist/core/hooks-runtime/parent-orchestration-gate.js +6 -8
- package/dist/core/hooks-runtime/stop-repeat-guard.js +0 -13
- package/dist/core/hooks-runtime.js +13 -9
- package/dist/core/init/skills.js +27 -16
- package/dist/core/init.js +0 -9
- package/dist/core/install/installed-package-smoke.js +3 -1
- package/dist/core/perf/import-graph-budget.js +0 -1
- package/dist/core/perf/release-latency-slo.js +2 -30
- package/dist/core/pipeline-internals/pipeline-stage-builder.js +2 -4
- package/dist/core/pipeline-internals/runtime-core.js +2 -38
- package/dist/core/proof/route-proof-policy.js +2 -4
- package/dist/core/proof/runtime-truth-matrix.js +2 -2
- package/dist/core/proof-field.js +104 -39
- package/dist/core/provider/provider-context.js +4 -1
- package/dist/core/questions.js +11 -7
- package/dist/core/release/gate-affected-globs.js +0 -2
- package/dist/core/research/research-reviewer-contract.js +34 -0
- package/dist/core/research/research-work-graph.js +1 -1
- package/dist/core/research.js +1 -1
- package/dist/core/routes/constants.js +0 -1
- package/dist/core/routes/diagnostic-allowlist.js +1 -3
- package/dist/core/routes/light-routes.js +1 -2
- package/dist/core/routes.js +1 -1
- package/dist/core/safety/command-contract/contracts.js +5 -1
- package/dist/core/search/context.js +2 -2
- package/dist/core/search-visibility/marketing-truthfulness.js +10 -7
- package/dist/core/search-visibility/marketing.js +194 -149
- package/dist/core/skill-forge.js +1 -361
- package/dist/core/strategy/adhd-orchestrating-gate.js +3 -3
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +2 -6
- package/dist/core/triwiki-wrongness/wrongness-cli.js +9 -27
- package/dist/core/update/update-migration-state.js +10 -40
- package/dist/core/version.js +1 -1
- package/package.json +2 -3
- package/release-gates.v2.json +1 -32
- package/dist/cli/recallpulse-command.js +0 -144
- package/dist/commands/auto-review.js +0 -5
- package/dist/commands/codex-native.js +0 -77
- package/dist/commands/recallpulse.js +0 -5
- package/dist/core/codex-native/codex-native-interop-policy.js +0 -127
- package/dist/core/commands/autoresearch-command.js +0 -4
- package/dist/core/commands/code-structure-command.js +0 -52
- package/dist/core/commands/goal-command.js +0 -43
- package/dist/core/commands/recallpulse-command.js +0 -4
- package/dist/core/commands/remote-command.js +0 -119
- package/dist/core/commands/skill-dream-command.js +0 -43
- package/dist/core/commands/wrongness-command.js +0 -2
- package/dist/core/goal-workflow.js +0 -80
- package/dist/core/mcp/mcp-tool-name-normalizer.js +0 -28
- package/dist/core/recallpulse/policy.js +0 -207
- package/dist/core/recallpulse.js +0 -947
- package/dist/core/remote/audit-idempotency.js +0 -241
- package/dist/core/remote/index.js +0 -10
- package/dist/core/remote/machine-registry.js +0 -167
- package/dist/core/remote/owner-proof.js +0 -216
- package/dist/core/remote/protocol.js +0 -249
- package/dist/core/remote/readiness.js +0 -156
- package/dist/core/remote/session-index.js +0 -61
- package/dist/core/remote/session-snapshot.js +0 -197
- package/dist/core/remote/ssh-worker-client.js +0 -377
- package/dist/core/remote/types.js +0 -10
- package/dist/core/remote/worker.js +0 -360
- package/dist/core/search/context-graph-seeds.js +0 -15
- package/dist/core/verification/context-graph-affected.js +0 -312
- package/dist/core/verification/verification-artifact-lock.js +0 -21
- package/dist/core/verification/verification-dag.js +0 -89
- package/dist/core/verification/verification-result.js +0 -19
- package/dist/core/verification/verification-worker-pool.js +0 -204
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { COMMAND_MANIFEST_LITE } from './command-manifest-lite.js';
|
|
1
|
+
import { COMMAND_MANIFEST_LITE, visibleCommandManifest } from './command-manifest-lite.js';
|
|
2
|
+
import { sksTextLogo } from './output.js';
|
|
2
3
|
export function commandsJsonFast() {
|
|
3
4
|
const commands = COMMAND_MANIFEST_LITE
|
|
4
5
|
.map((entry) => fastCommandRow(entry))
|
|
@@ -9,10 +10,18 @@ export function commandsJsonFast() {
|
|
|
9
10
|
commands
|
|
10
11
|
}, null, 2));
|
|
11
12
|
}
|
|
13
|
+
export function commandsTextFast() {
|
|
14
|
+
const commands = visibleCommandManifest();
|
|
15
|
+
console.log(`${sksTextLogo()}\n\nCommands\n`);
|
|
16
|
+
const width = Math.max(...commands.map((entry) => entry.name.length)) + 2;
|
|
17
|
+
for (const entry of commands)
|
|
18
|
+
console.log(`sks ${entry.name.padEnd(width)}${entry.summary}`);
|
|
19
|
+
console.log('\nRun `sks help <command>` for its usage.');
|
|
20
|
+
}
|
|
12
21
|
function fastCommandRow(entry) {
|
|
13
22
|
const row = {
|
|
14
23
|
name: entry.name,
|
|
15
|
-
usage: `sks ${entry.name}`,
|
|
24
|
+
usage: entry.usage || `sks ${entry.name}`,
|
|
16
25
|
description: entry.summary,
|
|
17
26
|
maturity: entry.maturity
|
|
18
27
|
};
|
|
@@ -20,8 +29,6 @@ function fastCommandRow(entry) {
|
|
|
20
29
|
row.readonly = true;
|
|
21
30
|
if (entry.mutatesRouteState === true)
|
|
22
31
|
row.mutating = true;
|
|
23
|
-
if (entry.deprecated === true)
|
|
24
|
-
row.deprecated = true;
|
|
25
32
|
if (entry.hidden === true)
|
|
26
33
|
row.hidden = true;
|
|
27
34
|
return row;
|
package/dist/cli/help-fast.js
CHANGED
|
@@ -1,35 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { visibleCommandManifest } from './command-manifest-lite.js';
|
|
2
2
|
import { PACKAGE_VERSION } from '../core/version.js';
|
|
3
3
|
export function helpFast() {
|
|
4
4
|
console.log(`SKS
|
|
5
5
|
SNEAKOSCOPE CODEX v${PACKAGE_VERSION}
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Ask Codex for work directly; the main agent does ordinary work and SKS hooks keep it safe.
|
|
8
8
|
|
|
9
9
|
$sks-plan "task" plan only; writes .sneakoscope/plans, no code edits
|
|
10
10
|
$sks-work execute the latest plan with Naruto child agents
|
|
11
11
|
|
|
12
|
-
Local surfaces
|
|
13
|
-
|
|
14
12
|
sks review --staged machine-first diff review
|
|
15
|
-
sks doctor --fix repair
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
sks doctor --fix repair and validate the install
|
|
14
|
+
sks help <command> usage of one command (or a $ route)
|
|
15
|
+
sks dollar-commands every Codex App $ route
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
sks dollar-commands all Codex App $ routes
|
|
21
|
-
sks help [topic] focused help
|
|
17
|
+
Commands
|
|
22
18
|
`);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
function commandRows() {
|
|
29
|
-
return COMMAND_MANIFEST_LITE.map((entry) => ({
|
|
30
|
-
name: entry.name,
|
|
31
|
-
usage: `sks ${entry.name}`,
|
|
32
|
-
description: entry.summary,
|
|
33
|
-
maturity: entry.maturity
|
|
34
|
-
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
19
|
+
const commands = visibleCommandManifest().filter((entry) => entry.maturity !== 'labs');
|
|
20
|
+
const width = Math.max(...commands.map((entry) => entry.name.length)) + 2;
|
|
21
|
+
for (const entry of commands)
|
|
22
|
+
console.log(` sks ${entry.name.padEnd(width)}${entry.summary}`);
|
|
23
|
+
console.log('\nLabs commands (optional routes) are listed by `sks commands`.');
|
|
35
24
|
}
|
package/dist/cli/help.js
CHANGED
|
@@ -6,10 +6,10 @@ export function isHelpRequest(args) {
|
|
|
6
6
|
export function renderManifestHelp(command, entry) {
|
|
7
7
|
if (!entry)
|
|
8
8
|
return `Usage: sks ${command}\n\nNo manifest entry is registered for this command.`;
|
|
9
|
-
const lines = [`Usage: sks ${entry.name} [options]`, '', entry.summary];
|
|
9
|
+
const lines = [`Usage: ${entry.usage || `sks ${entry.name} [options]`}`, '', entry.summary];
|
|
10
|
+
if (entry.description && entry.description !== entry.summary)
|
|
11
|
+
lines.push(entry.description);
|
|
10
12
|
const notes = [];
|
|
11
|
-
if (entry.deprecated)
|
|
12
|
-
notes.push('deprecated — kept only for compatibility');
|
|
13
13
|
if (entry.maturity !== 'stable')
|
|
14
14
|
notes.push(`maturity: ${entry.maturity}`);
|
|
15
15
|
if (entry.readonly)
|
|
@@ -4,13 +4,16 @@ import { escapeRegExp } from '../core/text/regex.js';
|
|
|
4
4
|
export const DESKTOP_BRIDGE_MANAGED_MARKER = '# sks-desktop-bridge-managed';
|
|
5
5
|
export const DESKTOP_BRIDGE_MANAGED_BASE_URL_MARKER = '# sks-desktop-bridge-managed-base-url';
|
|
6
6
|
export const DESKTOP_BRIDGE_MANAGED_MODEL_CATALOG_MARKER = '# sks-desktop-bridge-managed-model-catalog';
|
|
7
|
-
export function
|
|
8
|
-
const
|
|
9
|
-
if (
|
|
10
|
-
return
|
|
11
|
-
if (
|
|
12
|
-
return
|
|
13
|
-
return upsertTopLevelTomlString(
|
|
7
|
+
export function repairManagedCodexLbClientSelection(text) {
|
|
8
|
+
const source = String(text || '');
|
|
9
|
+
if (topLevelTomlString(source, 'model_provider') !== 'codex-lb')
|
|
10
|
+
return source;
|
|
11
|
+
if (!topLevelHasLine(source, DESKTOP_BRIDGE_MANAGED_MARKER) || hasCodexLbProviderTable(source))
|
|
12
|
+
return source;
|
|
13
|
+
return upsertTopLevelTomlString(source, 'model_provider', 'openai');
|
|
14
|
+
}
|
|
15
|
+
export function hasCodexLbProviderTable(text) {
|
|
16
|
+
return /^\s*\[model_providers\.(?:"codex-lb"|codex-lb)\]\s*(?:#.*)?$/m.test(text);
|
|
14
17
|
}
|
|
15
18
|
export function upsertDesktopBridgeManagedConfig(text, input) {
|
|
16
19
|
const bridgeBaseUrl = normalizeManagedBridgeBaseUrl(input.bridgeBaseUrl);
|
|
@@ -39,7 +42,7 @@ export function upsertDesktopBridgeManagedConfig(text, input) {
|
|
|
39
42
|
if (existingCatalog && !catalogOwned) {
|
|
40
43
|
throw new Error('historical_user_owned_config_conflict:model_catalog_json');
|
|
41
44
|
}
|
|
42
|
-
const keepCodexLb = selectedProvider === 'codex-lb';
|
|
45
|
+
const keepCodexLb = selectedProvider === 'codex-lb' && hasCodexLbProviderTable(next);
|
|
43
46
|
next = removeManagedBridgeTopLevelBindings(next);
|
|
44
47
|
next = upsertTopLevelTomlString(next, 'model_provider', keepCodexLb ? 'codex-lb' : 'openai');
|
|
45
48
|
next = addTopLevelMarkerBeforeKey(next, 'model_provider', DESKTOP_BRIDGE_MANAGED_MARKER);
|
|
@@ -24,7 +24,7 @@ export async function postinstall({ bootstrap }) {
|
|
|
24
24
|
if (menuBar.status === 'skipped')
|
|
25
25
|
console.log(describePostinstallMenuBar(menuBar));
|
|
26
26
|
console.log('Next: run `sks bootstrap` when you are ready to initialize SKS.');
|
|
27
|
-
console.log('Dependency diagnostics remain explicit: sks
|
|
27
|
+
console.log('Dependency diagnostics remain explicit: sks doctor');
|
|
28
28
|
console.log('Explicit lifecycle opt-in: SKS_POSTINSTALL_BOOTSTRAP=1 npm i -g sneakoscope');
|
|
29
29
|
console.log('Optional Homebrew/npm-global tool repair remains off unless SKS_POSTINSTALL_AUTO_INSTALL_CLI_TOOLS=1 is also set.');
|
|
30
30
|
const reason = process.env.SKS_POSTINSTALL_NO_BOOTSTRAP === '1'
|
package/dist/cli/router.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
1
|
import { createHash } from 'node:crypto';
|
|
3
2
|
import { COMMAND_ALIASES_LITE, COMMAND_MANIFEST_BY_NAME, COMMAND_NAME_SET, } from './command-manifest-lite.js';
|
|
4
3
|
import { ui as cliUi } from './cli-theme.js';
|
|
@@ -6,7 +5,6 @@ import { helpResult, isHelpRequest, renderManifestHelp } from './help.js';
|
|
|
6
5
|
import { findRetiredGlobalExecutionArgumentErrors } from './global-mode-router.js';
|
|
7
6
|
import { normalizeIntentCommand, } from '../core/commands/intent-normalization/normalizer.js';
|
|
8
7
|
import { narutoUsesCurrentSession } from '../core/subagents/naruto-execution-mode.js';
|
|
9
|
-
const routerIntentStorage = new AsyncLocalStorage();
|
|
10
8
|
export function prepareRouterExecutionIntent(argv, inheritance = {}) {
|
|
11
9
|
const effectiveArgv = argv.length ? [...argv] : ['doctor'];
|
|
12
10
|
const rawCommand = effectiveArgv[0]?.startsWith('$')
|
|
@@ -66,9 +64,8 @@ export function normalizeCommand(args = []) {
|
|
|
66
64
|
export async function dispatch(args) {
|
|
67
65
|
const argv = args ?? process.argv.slice(2);
|
|
68
66
|
try {
|
|
69
|
-
let intent = null;
|
|
70
67
|
try {
|
|
71
|
-
|
|
68
|
+
prepareRouterExecutionIntent(argv);
|
|
72
69
|
}
|
|
73
70
|
catch (error) {
|
|
74
71
|
const code = error instanceof Error ? error.message : String(error);
|
|
@@ -85,9 +82,7 @@ export async function dispatch(args) {
|
|
|
85
82
|
throw error;
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
|
-
return
|
|
89
|
-
? await routerIntentStorage.run(intent.contract, () => dispatchInner(argv))
|
|
90
|
-
: await dispatchInner(argv);
|
|
85
|
+
return await dispatchInner(argv);
|
|
91
86
|
}
|
|
92
87
|
catch (err) {
|
|
93
88
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -178,16 +173,14 @@ async function dispatchInner(argv) {
|
|
|
178
173
|
process.exitCode = 1;
|
|
179
174
|
return commandGate;
|
|
180
175
|
}
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
command,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
});
|
|
190
|
-
if (!migrationGate.ok) {
|
|
176
|
+
const skipMigrationGate = entry.skipMigrationGate === true
|
|
177
|
+
|| entry.readonly === true
|
|
178
|
+
|| safeReadOnlySubcommand(command, rest)
|
|
179
|
+
|| safeActiveRouteVisualQuery(command, rest);
|
|
180
|
+
const migrationGate = skipMigrationGate
|
|
181
|
+
? null
|
|
182
|
+
: await (await import('../core/update/update-migration-state.js')).ensureCurrentMigrationBeforeCommand({ command, args: rest, skipMigrationGate: false });
|
|
183
|
+
if (migrationGate && !migrationGate.ok) {
|
|
191
184
|
console.error('SKS project migration blocked.');
|
|
192
185
|
console.error(`Scope: ${migrationGate.scope || 'project'}`);
|
|
193
186
|
console.error(`Stage: ${migrationGate.failed_stage_id || migrationGate.status}`);
|
|
@@ -306,12 +299,6 @@ export function safeReadOnlySubcommand(command, args) {
|
|
|
306
299
|
if (command === 'codex-app' && ['context-1m', 'context-management'].includes(sub) && (nested === 'status' || nested === '' || nested.startsWith('--'))) {
|
|
307
300
|
return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
|
|
308
301
|
}
|
|
309
|
-
if (command === 'remote' && ['readiness', 'status', 'show'].includes(sub)) {
|
|
310
|
-
return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
|
|
311
|
-
}
|
|
312
|
-
if (command === 'remote' && ['machines', 'machine'].includes(sub) && ['list', 'validate'].includes(nested)) {
|
|
313
|
-
return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
|
|
314
|
-
}
|
|
315
302
|
if (!['status', 'show', 'list', 'observe', 'watch', 'doctor', 'help'].includes(sub))
|
|
316
303
|
return false;
|
|
317
304
|
return !args.some((arg) => ['--fix', '--yes', '-y', '--write', '--apply', '--execute', '--force', '--real'].includes(String(arg)));
|
|
@@ -367,8 +354,7 @@ export function safeActiveRouteContinuation(command, args, state = {}) {
|
|
|
367
354
|
return subcommand === 'run' && !requestedMission;
|
|
368
355
|
}
|
|
369
356
|
const expectedRoutes = new Map([
|
|
370
|
-
['research', ['RESEARCH']],
|
|
371
|
-
['autoresearch', ['AUTORESEARCH', 'RESEARCH']],
|
|
357
|
+
['research', ['RESEARCH', 'AUTORESEARCH']],
|
|
372
358
|
['qa-loop', ['QALOOP']]
|
|
373
359
|
]).get(command);
|
|
374
360
|
if (!expectedRoutes)
|
|
@@ -410,5 +396,5 @@ function activeRouteStateBlocksCommand(state = {}) {
|
|
|
410
396
|
return false;
|
|
411
397
|
if (/(?:DONE|COMPLETE|CLOSED|BLOCKED|FAILED)$/i.test(String(state.phase || '')))
|
|
412
398
|
return false;
|
|
413
|
-
return Boolean(state.route || state.route_command || ['NARUTO', 'QALOOP', 'RESEARCH', 'MADSKS'
|
|
399
|
+
return Boolean(state.route || state.route_command || ['NARUTO', 'QALOOP', 'RESEARCH', 'MADSKS'].includes(mode));
|
|
414
400
|
}
|
|
@@ -70,7 +70,7 @@ export async function run(_command, args = []) {
|
|
|
70
70
|
if (action === 'agent-role-sync')
|
|
71
71
|
return printCodexAppResult(args, await syncCodexAgentRoles({ root: await sksRoot(), apply: flag(args, '--apply') || flag(args, '--fix') }));
|
|
72
72
|
if (action === 'init-deep')
|
|
73
|
-
return printCodexAppResult(args, await runCodexInitDeep({ root: await sksRoot(), apply: !flag(args, '--check-only') && !flag(args, '--dry-run') }));
|
|
73
|
+
return printCodexAppResult(args, await runCodexInitDeep({ root: await sksRoot(), apply: !flag(args, '--check-only') && !flag(args, '--dry-run'), directoryLocal: flag(args, '--directory-local') }));
|
|
74
74
|
if (action === 'hook-lifecycle')
|
|
75
75
|
return printCodexAppResult(args, await buildCodexHookLifecycle({ root: await sksRoot(), apply: flag(args, '--apply') || flag(args, '--fix') }));
|
|
76
76
|
if (action === 'execution-profile')
|
|
@@ -151,7 +151,7 @@ export async function run(_command, args = []) {
|
|
|
151
151
|
process.exitCode = 1;
|
|
152
152
|
return;
|
|
153
153
|
}
|
|
154
|
-
console.error('Usage: sks codex-app check|status|restart|context-management [status|on|off]|context-1m [status|on|off] [--no-restart]|harness-matrix|skill-sync|agent-role-sync|init-deep|hook-lifecycle|execution-profile|role-models|set-role-model --role <name> [--provider <id>] --model <catalog-slug> --reasoning <effort>|reset-role-model --role <name>|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
|
|
154
|
+
console.error('Usage: sks codex-app check|status|restart|context-management [status|on|off]|context-1m [status|on|off] [--no-restart]|harness-matrix|skill-sync|agent-role-sync|init-deep [--directory-local]|hook-lifecycle|execution-profile|role-models|set-role-model --role <name> [--provider <id>] --model <catalog-slug> --reasoning <effort>|reset-role-model --role <name>|product-design [--check-only]|ensure-product-design|chrome-extension|pat status|remote-control [--json]');
|
|
155
155
|
console.error('Provider routing moved to: sks bridge provider configure|validate|enable; sks bridge catalog sync; sks bridge route set-default.');
|
|
156
156
|
process.exitCode = 1;
|
|
157
157
|
}
|
|
@@ -19,7 +19,7 @@ export function buildRuntimeReadiness(matrix) {
|
|
|
19
19
|
].join(' '));
|
|
20
20
|
}
|
|
21
21
|
if (matrix?.features?.project_memory?.ok !== true)
|
|
22
|
-
repairActions.push('Project memory: sks codex-
|
|
22
|
+
repairActions.push('Project memory: sks codex-app init-deep --directory-local');
|
|
23
23
|
return {
|
|
24
24
|
schema: 'sks.runtime-readiness-story.v1',
|
|
25
25
|
codex_native: codexNative,
|
package/dist/commands/mad-sks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { madHighCommand } from '../core/commands/mad-sks-command.js';
|
|
2
|
-
import { PACKAGE_VERSION } from '../core/fsx.js';
|
|
3
1
|
export async function run(_command, args = []) {
|
|
2
|
+
const { madHighCommand } = await import('../core/commands/mad-sks-command.js');
|
|
3
|
+
const { PACKAGE_VERSION } = await import('../core/version.js');
|
|
4
4
|
return madHighCommand(['--mad-sks', ...args], {
|
|
5
5
|
packageVersion: PACKAGE_VERSION
|
|
6
6
|
});
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "sks.skills-manifest.v1",
|
|
3
|
-
"package_version": "10.
|
|
3
|
+
"package_version": "10.7.1",
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
6
6
|
"canonical_name": "sks",
|
|
7
7
|
"type": "official",
|
|
8
|
-
"content_sha256": "
|
|
8
|
+
"content_sha256": "eb09af342c2f2bc3d269e6d1c2f92d718ed069582d1165bfe46600b5c2225a8b",
|
|
9
9
|
"hash_history": [
|
|
10
|
+
"32d97c9b68a0a97794f48bd2f200bb3c0cd68816c00fef3397e86df671342ac5",
|
|
11
|
+
"d5adbf63047d4882258d70bb46017e4aa7b6d5804154c68ef4204d0e0e5916d6",
|
|
10
12
|
"8aa34586ba331f0447668c2ce863fe6c9ec4f881828ebed26ca5ecc754d66840",
|
|
11
13
|
"d0288d27c8bc1c89decb258c6805ed4286cd0d65371ef0eec453be233b39a2a1",
|
|
12
14
|
"905fc5472d36f0780b56f0e09404f42ea20293b1a4615d2050b7db3043231dbd",
|
|
@@ -309,8 +311,9 @@
|
|
|
309
311
|
{
|
|
310
312
|
"canonical_name": "sks-help",
|
|
311
313
|
"type": "official",
|
|
312
|
-
"content_sha256": "
|
|
314
|
+
"content_sha256": "3a20901121eb9a11a31ea797a44c8136a09f26f9862f52a923634aba0767dc0c",
|
|
313
315
|
"hash_history": [
|
|
316
|
+
"17c2a63b163b266dc0d0a503a275d41a5388e1f44be9250b84017f1a549159d4",
|
|
314
317
|
"8b6d7f0cffbd3b141f53a6937fb3d58ba363d495d6da561d8f463ee3b265d975",
|
|
315
318
|
"0b67a2ed2eb1f3f80cf1645bee0c189ecc442d2ec84b1e0b218d800298487920"
|
|
316
319
|
],
|
|
@@ -456,8 +459,9 @@
|
|
|
456
459
|
{
|
|
457
460
|
"canonical_name": "sks-ppt",
|
|
458
461
|
"type": "official",
|
|
459
|
-
"content_sha256": "
|
|
462
|
+
"content_sha256": "93887312718febbb795cab3d09b1d47a30485eee7c6416fb02c78c65ab5c4686",
|
|
460
463
|
"hash_history": [
|
|
464
|
+
"a25e537ff49b5bffdc093a5f772a8d218003ca1bb81e0aa304561684a9551b31",
|
|
461
465
|
"fba3f438b9f22dae0813cd12bf310539a7d2b71c8cd9322eb840514e24884eaf",
|
|
462
466
|
"c9a0d90e12560dd3f04959869051370e6baf46eda6eb63f708ea1661c5c9d041",
|
|
463
467
|
"1d4de05afd42ee5739c0ed925af9e0ac4785fc746e659c60d3d908d465e6386c",
|
|
@@ -493,16 +497,16 @@
|
|
|
493
497
|
{
|
|
494
498
|
"canonical_name": "sks-reasoning-router",
|
|
495
499
|
"type": "official",
|
|
496
|
-
"content_sha256": "
|
|
500
|
+
"content_sha256": "00403fa829bc673966c2e125d5a2d42111ed6fd8c821b1f0e50176127658b888",
|
|
497
501
|
"hash_history": [
|
|
502
|
+
"2ec66071b1c021e8c2ddd8f1ecefd16502c8325adab2c3c804a9e8d4123b1a8d",
|
|
498
503
|
"b0f458caa1c3bd7bb7241a09b80fce5700aeb99b340e84c08a9b2b66bc875ba7",
|
|
499
504
|
"41e14e8d5b93d743096664869ee68c41c86e911b0bbc165bdcd10e4a45faa4b6",
|
|
500
505
|
"03d68436e568b3cee2bffc6ca58819019ca406f7b648ef4704e3465c7c83c114",
|
|
501
506
|
"647f730520a1c7dc89c2642f5b8502624c65a861ae41aecf1fb137db40fd0611",
|
|
502
507
|
"da0ddb58adc68ddeebdb9c45bf111c26eaa64d3e9dffe1dd39d7f30b943b8b88",
|
|
503
508
|
"1595beabf2d31397217311fa1323bd62c801cf6c87db9029ff544c457efec8bb",
|
|
504
|
-
"a7d879d157c6d5b6b81a67dba7b5b731ac18ea986841fe1ab2cafbd6623481c3"
|
|
505
|
-
"dc0b8c6a4093269c2c36b58432b25409704d06fea8ca558f43b598625ca0d9de"
|
|
509
|
+
"a7d879d157c6d5b6b81a67dba7b5b731ac18ea986841fe1ab2cafbd6623481c3"
|
|
506
510
|
],
|
|
507
511
|
"deprecated_aliases": []
|
|
508
512
|
},
|
|
@@ -521,8 +525,9 @@
|
|
|
521
525
|
{
|
|
522
526
|
"canonical_name": "sks-release-review",
|
|
523
527
|
"type": "official",
|
|
524
|
-
"content_sha256": "
|
|
528
|
+
"content_sha256": "dfc2af7dd2c41ab2529ed54b2dca0dfd85e2de0d3304afbfe4a420e6627ce01a",
|
|
525
529
|
"hash_history": [
|
|
530
|
+
"36846d6180051c85e3093e7e405ad9d4d447f7295769f71f8450c18afee50e98",
|
|
526
531
|
"bb6ef28431fd6c390041c9a2855b906fd01a1f6da02111f094258914cf826bb9",
|
|
527
532
|
"7cf879a2efd61822d3dccd4eb69fb704bfbab4b114b820b6dfa0d13b5f20e9fa"
|
|
528
533
|
],
|
|
@@ -9,7 +9,7 @@ import { bridgeClientUrl } from '../codex-lb/desktop-controller-v3/shared.js';
|
|
|
9
9
|
import { runProcess } from '../fsx.js';
|
|
10
10
|
import { createResponsesTransport } from './responses-transport.js';
|
|
11
11
|
import { latestModelForTier } from '../subagents/model-tiers.js';
|
|
12
|
-
const USAGE = 'sks agent-bridge async --prompt "task" [--tools status,
|
|
12
|
+
const USAGE = 'sks agent-bridge async --prompt "task" [--tools status,search] [--json]';
|
|
13
13
|
const MAX_PROMPT_BYTES = 16 * 1024;
|
|
14
14
|
export function redactAsyncToolOutput(stdout) {
|
|
15
15
|
try {
|
|
@@ -21,7 +21,7 @@ export function redactAsyncToolOutput(stdout) {
|
|
|
21
21
|
}
|
|
22
22
|
export function parseAsyncCommandArgs(args) {
|
|
23
23
|
let prompt = '';
|
|
24
|
-
let selected = 'status,
|
|
24
|
+
let selected = 'status,search';
|
|
25
25
|
const seen = new Set();
|
|
26
26
|
for (let i = 0; i < args.length; i++) {
|
|
27
27
|
const flag = args[i];
|
|
@@ -4,9 +4,7 @@ export const AGENT_RECURSION_GUARD_REPORT_SCHEMA = 'sks.agent-recursion-guard.v1
|
|
|
4
4
|
export const AGENT_RECURSIVE_COMMAND_DENYLIST = Object.freeze([
|
|
5
5
|
'sks naruto run',
|
|
6
6
|
'sks research run',
|
|
7
|
-
'sks autoresearch run',
|
|
8
7
|
'sks qa-loop',
|
|
9
|
-
'sks goal',
|
|
10
8
|
'$Naruto',
|
|
11
9
|
'$Work',
|
|
12
10
|
'$Research',
|
|
@@ -5,6 +5,7 @@ import { nowIso, readText, writeJsonAtomic } from '../fsx.js';
|
|
|
5
5
|
import { inspectConfinedPath, moveConfinedPath, removeConfinedDirectoryIfEmpty, removeManagedPathVerified, uniqueConfinedPath, walkConfinedEntries } from '../managed-path-safety.js';
|
|
6
6
|
import { MANAGED_OFFICIAL_SUBAGENT_ROLES, RETIRED_MANAGED_AGENT_ROLE_TOMBSTONES, managedAgentRoleOwnsText } from '../managed-assets/managed-assets-manifest.js';
|
|
7
7
|
import { installOfficialSubagentAgentConfigs, refreshGlobalOfficialSubagentAgentConfigs } from '../subagents/official-subagent-config.js';
|
|
8
|
+
import { reconcileStaleSksModelPins } from './sks-model-pin-hygiene.js';
|
|
8
9
|
export const AGENT_ROLE_CONFIG_REPAIR_SCHEMA = 'sks.agent-role-config-repair.v1';
|
|
9
10
|
export async function repairAgentRoleConfigs(input) {
|
|
10
11
|
const root = path.resolve(input.root);
|
|
@@ -18,6 +19,7 @@ export async function repairAgentRoleConfigs(input) {
|
|
|
18
19
|
...(input.globalRuntimeRoot ? { globalRuntimeRoot: input.globalRuntimeRoot } : {}),
|
|
19
20
|
fix: input.apply === true
|
|
20
21
|
});
|
|
22
|
+
const modelPinHygiene = await reconcileStaleSksModelPins({ root, codexHome, fix: input.apply === true });
|
|
21
23
|
const officialRepair = await installOfficialSubagentAgentConfigs(root, { apply: input.apply === true });
|
|
22
24
|
const globalRepair = path.join(root, '.codex') === codexHome
|
|
23
25
|
? null
|
|
@@ -38,7 +40,7 @@ export async function repairAgentRoleConfigs(input) {
|
|
|
38
40
|
schema: AGENT_ROLE_CONFIG_REPAIR_SCHEMA,
|
|
39
41
|
generated_at: nowIso(),
|
|
40
42
|
ok: input.apply
|
|
41
|
-
? requiredFixes === appliedFixes && manualBlockers.length === 0 && retiredRoleCleanup.ok
|
|
43
|
+
? requiredFixes === appliedFixes && manualBlockers.length === 0 && retiredRoleCleanup.ok && modelPinHygiene.errors.length === 0
|
|
42
44
|
: manualBlockers.length === 0 && retiredRoleCleanup.ok && (globalRepair?.stale.length || 0) === 0,
|
|
43
45
|
apply: input.apply === true,
|
|
44
46
|
missing,
|
|
@@ -51,12 +53,14 @@ export async function repairAgentRoleConfigs(input) {
|
|
|
51
53
|
manual_blockers: manualBlockers,
|
|
52
54
|
manifest_role_ids: MANAGED_OFFICIAL_SUBAGENT_ROLES.map((role) => role.id),
|
|
53
55
|
retired_role_cleanup: retiredRoleCleanup,
|
|
56
|
+
model_pin_hygiene: modelPinHygiene,
|
|
54
57
|
warnings_suppressed: true,
|
|
55
58
|
blockers: [
|
|
56
59
|
...manualBlockers,
|
|
57
60
|
...(!input.apply ? (globalRepair?.stale.map((file) => `stale_global_official_subagent_agent:${globalPath(file)}`) || []) : []),
|
|
58
61
|
...(input.apply && requiredFixes !== appliedFixes ? ['agent_role_config_repair_incomplete'] : []),
|
|
59
|
-
...(!retiredRoleCleanup.ok ? ['retired_agent_role_cleanup_incomplete'] : [])
|
|
62
|
+
...(!retiredRoleCleanup.ok ? ['retired_agent_role_cleanup_incomplete'] : []),
|
|
63
|
+
...modelPinHygiene.errors.map((error) => `model_pin_hygiene_failed:${error}`)
|
|
60
64
|
]
|
|
61
65
|
};
|
|
62
66
|
if (input.reportPath)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import fsp from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { readText, writeTextAtomic } from '../fsx.js';
|
|
4
|
+
import { hasCodexLbProviderTable } from '../../cli/install-helpers-codex-lb-config.js';
|
|
5
|
+
import { hasSksManagedCodexConfigMarker, writeCodexConfigGuarded } from '../codex/codex-config-guard.js';
|
|
6
|
+
import { bridgeRouteIndexPath, combinedBridgeCatalogPath } from '../codex-lb/combined-catalog.js';
|
|
7
|
+
import { readActiveCombinedBridgeCatalog } from '../codex-lb/combined-catalog/persistence.js';
|
|
8
|
+
import { backupInvalidToml } from '../subagents/official-subagent-config.js';
|
|
9
|
+
export const MODEL_PIN_HYGIENE_SCHEMA = 'sks.model-pin-hygiene.v1';
|
|
10
|
+
const LEGACY_ROLE_NAMES = new Set(['sks-planner', 'sks-implementer', 'sks-explorer', 'sks-checker']);
|
|
11
|
+
async function catalogPinState(codexHome) {
|
|
12
|
+
const read = await readActiveCombinedBridgeCatalog(combinedBridgeCatalogPath(codexHome), bridgeRouteIndexPath(codexHome)).catch(() => null);
|
|
13
|
+
if (!read?.ok)
|
|
14
|
+
return null;
|
|
15
|
+
const rows = new Map();
|
|
16
|
+
for (const row of read.catalog.models) {
|
|
17
|
+
for (const id of [row.public_id, row.slug])
|
|
18
|
+
if (typeof id === 'string' && id)
|
|
19
|
+
rows.set(id, row);
|
|
20
|
+
}
|
|
21
|
+
return (model) => {
|
|
22
|
+
const row = rows.get(model);
|
|
23
|
+
if (!row)
|
|
24
|
+
return 'unlisted';
|
|
25
|
+
const visibility = String(row.visibility || 'list').toLowerCase();
|
|
26
|
+
const upgrade = row.upgrade && typeof row.upgrade === 'object' ? row.upgrade.model : null;
|
|
27
|
+
return visibility === 'hide' || visibility === 'hidden' || (typeof upgrade === 'string' && upgrade) ? 'superseded' : 'current';
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function topLevelEnd(lines) {
|
|
31
|
+
const end = lines.findIndex((line) => /^\s*\[/.test(line) || /^\s*developer_instructions\s*=/.test(line));
|
|
32
|
+
return end === -1 ? lines.length : end;
|
|
33
|
+
}
|
|
34
|
+
function stalePinLines(text, pinState, codexLbProviderDefined) {
|
|
35
|
+
const lines = text.split('\n');
|
|
36
|
+
const indexes = [];
|
|
37
|
+
const labels = [];
|
|
38
|
+
for (let index = 0; index < topLevelEnd(lines); index += 1) {
|
|
39
|
+
const match = /^\s*(model|model_provider)\s*=\s*"([^"]*)"\s*(?:#.*)?$/.exec(lines[index] || '');
|
|
40
|
+
if (!match)
|
|
41
|
+
continue;
|
|
42
|
+
const [, key, value] = match;
|
|
43
|
+
const stale = key === 'model_provider'
|
|
44
|
+
? value === 'codex-lb' && !codexLbProviderDefined
|
|
45
|
+
: pinState !== null && pinState(value) !== 'current';
|
|
46
|
+
if (!stale)
|
|
47
|
+
continue;
|
|
48
|
+
indexes.push(index);
|
|
49
|
+
labels.push(`${key} = "${value}"`);
|
|
50
|
+
}
|
|
51
|
+
return { indexes, labels };
|
|
52
|
+
}
|
|
53
|
+
function withoutLines(text, indexes) {
|
|
54
|
+
const drop = new Set(indexes);
|
|
55
|
+
return text.split('\n').filter((_, index) => !drop.has(index)).join('\n');
|
|
56
|
+
}
|
|
57
|
+
const CODEX_LB_SELECTION_EVIDENCE = [
|
|
58
|
+
/^\s*model_provider\s*=\s*["']codex-lb["']\s*(?:#.*)?$/,
|
|
59
|
+
/^\s*\[model_providers\.(?:"codex-lb"|codex-lb)\]\s*(?:#.*)?$/
|
|
60
|
+
];
|
|
61
|
+
function sksOwnedProjectConfig(text) {
|
|
62
|
+
const withoutSelection = text.split('\n')
|
|
63
|
+
.filter((line) => !CODEX_LB_SELECTION_EVIDENCE.some((pattern) => pattern.test(line)))
|
|
64
|
+
.join('\n');
|
|
65
|
+
return hasSksManagedCodexConfigMarker(withoutSelection);
|
|
66
|
+
}
|
|
67
|
+
function isLegacySksRole(file, text) {
|
|
68
|
+
if (/sks_managed_body_sha256/.test(text))
|
|
69
|
+
return false;
|
|
70
|
+
const name = /^\s*name\s*=\s*"([^"]+)"/m.exec(text)?.[1] ?? path.basename(file, '.toml');
|
|
71
|
+
return /^\s*description\s*=\s*"SKS managed\b/m.test(text) || LEGACY_ROLE_NAMES.has(name);
|
|
72
|
+
}
|
|
73
|
+
async function regularFile(file) {
|
|
74
|
+
const stat = await fsp.lstat(file).catch(() => null);
|
|
75
|
+
return Boolean(stat?.isFile() && !stat.isSymbolicLink());
|
|
76
|
+
}
|
|
77
|
+
async function roleFiles(dir) {
|
|
78
|
+
const entries = await fsp.readdir(dir).catch(() => []);
|
|
79
|
+
return entries.filter((name) => name.endsWith('.toml')).sort().map((name) => path.join(dir, name));
|
|
80
|
+
}
|
|
81
|
+
export async function reconcileStaleSksModelPins(input) {
|
|
82
|
+
const root = path.resolve(input.root);
|
|
83
|
+
const codexHome = path.resolve(input.codexHome);
|
|
84
|
+
const pinState = await catalogPinState(codexHome);
|
|
85
|
+
const report = {
|
|
86
|
+
schema: MODEL_PIN_HYGIENE_SCHEMA,
|
|
87
|
+
fix: input.fix,
|
|
88
|
+
catalog_available: pinState !== null,
|
|
89
|
+
changes: [],
|
|
90
|
+
remaining: [],
|
|
91
|
+
errors: []
|
|
92
|
+
};
|
|
93
|
+
const projectConfig = path.join(root, '.codex', 'config.toml');
|
|
94
|
+
const projectText = projectConfig !== path.join(codexHome, 'config.toml') && await regularFile(projectConfig)
|
|
95
|
+
? await readText(projectConfig, '')
|
|
96
|
+
: null;
|
|
97
|
+
const providerDefinedAbove = hasCodexLbProviderTable(await readText(path.join(codexHome, 'config.toml'), ''))
|
|
98
|
+
|| (projectText !== null && hasCodexLbProviderTable(projectText));
|
|
99
|
+
const agentDirs = [...new Set([path.join(codexHome, 'agents'), path.join(root, '.codex', 'agents')])];
|
|
100
|
+
for (const dir of agentDirs) {
|
|
101
|
+
for (const file of await roleFiles(dir)) {
|
|
102
|
+
if (!(await regularFile(file)))
|
|
103
|
+
continue;
|
|
104
|
+
const text = await readText(file, '');
|
|
105
|
+
if (!isLegacySksRole(file, text))
|
|
106
|
+
continue;
|
|
107
|
+
const pins = stalePinLines(text, pinState, providerDefinedAbove || hasCodexLbProviderTable(text));
|
|
108
|
+
if (!pins.indexes.length)
|
|
109
|
+
continue;
|
|
110
|
+
if (!input.fix) {
|
|
111
|
+
report.remaining.push({ file, removed: pins.labels, backup_path: null });
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const backup = await backupInvalidToml(file, text, 'model-pin-hygiene');
|
|
116
|
+
const mode = (await fsp.stat(file)).mode & 0o777;
|
|
117
|
+
await writeTextAtomic(file, withoutLines(text, pins.indexes), { mode });
|
|
118
|
+
report.changes.push({ file, removed: pins.labels, backup_path: backup });
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
report.errors.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
122
|
+
report.remaining.push({ file, removed: pins.labels, backup_path: null });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (projectText !== null) {
|
|
127
|
+
const text = projectText;
|
|
128
|
+
const pins = sksOwnedProjectConfig(text) ? stalePinLines(text, pinState, providerDefinedAbove) : { indexes: [], labels: [] };
|
|
129
|
+
if (pins.indexes.length && !input.fix)
|
|
130
|
+
report.remaining.push({ file: projectConfig, removed: pins.labels, backup_path: null });
|
|
131
|
+
else if (pins.indexes.length) {
|
|
132
|
+
const write = await writeCodexConfigGuarded({
|
|
133
|
+
root,
|
|
134
|
+
configPath: projectConfig,
|
|
135
|
+
before: text,
|
|
136
|
+
mutate: () => withoutLines(text, pins.indexes),
|
|
137
|
+
cause: 'model-pin-hygiene',
|
|
138
|
+
backupTag: 'model-pin-hygiene',
|
|
139
|
+
verifyUnchangedBeforeWrite: true
|
|
140
|
+
});
|
|
141
|
+
if (write.ok)
|
|
142
|
+
report.changes.push({ file: projectConfig, removed: pins.labels, backup_path: write.backup_path });
|
|
143
|
+
else {
|
|
144
|
+
report.errors.push(`${projectConfig}: ${write.status}`);
|
|
145
|
+
report.remaining.push({ file: projectConfig, removed: pins.labels, backup_path: null });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return report;
|
|
150
|
+
}
|