sneakoscope 3.1.14 → 4.0.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 +26 -1
- 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/bin/sks.js +1 -1
- package/dist/cli/command-registry.js +6 -13
- package/dist/commands/doctor.js +29 -2
- package/dist/commands/proof.js +8 -0
- package/dist/core/build/build-once-runner.js +66 -0
- package/dist/core/codex/codex-config-readability.js +52 -38
- package/dist/core/commands/check-command.js +132 -0
- package/dist/core/commands/daemon-command.js +14 -0
- package/dist/core/commands/mad-sks-command.js +25 -3
- package/dist/core/commands/release-command.js +52 -0
- package/dist/core/commands/task-command.js +15 -0
- package/dist/core/commands/triwiki-command.js +38 -0
- package/dist/core/daemon/sksd-client.js +9 -0
- package/dist/core/daemon/sksd-ipc.js +9 -0
- package/dist/core/daemon/sksd.js +87 -0
- package/dist/core/doctor/doctor-dirty-planner.js +95 -0
- package/dist/core/doctor/doctor-transaction.js +13 -0
- package/dist/core/feature-fixtures.js +1 -0
- package/dist/core/fsx.js +1 -1
- package/dist/core/init.js +7 -1
- package/dist/core/probes/probe-memoization.js +80 -0
- package/dist/core/release/critical-path-ledger.js +12 -0
- package/dist/core/release/extreme-parallel-scheduler.js +86 -0
- package/dist/core/release/gate-pack-fixture-cache.js +39 -0
- package/dist/core/release/gate-pack-manifest.js +118 -0
- package/dist/core/release/gate-pack-runner.js +257 -0
- package/dist/core/release/release-gate-cache-v2.js +78 -16
- package/dist/core/release/release-gate-dag.js +89 -3
- package/dist/core/release/resource-class-budget.js +22 -0
- package/dist/core/release/sla-scheduler.js +22 -0
- package/dist/core/routes.js +5 -0
- package/dist/core/triwiki/triwiki-affected-graph.js +112 -0
- package/dist/core/triwiki/triwiki-cache-key.js +241 -0
- package/dist/core/triwiki/triwiki-gate-impact-map.js +124 -0
- package/dist/core/triwiki/triwiki-invalidation.js +81 -0
- package/dist/core/triwiki/triwiki-module-card.js +74 -0
- package/dist/core/triwiki/triwiki-proof-bank.js +210 -0
- package/dist/core/triwiki/triwiki-proof-card.js +73 -0
- package/dist/core/triwiki/triwiki-sla-certificate.js +53 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zellij/zellij-launcher.js +13 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +68 -17
- package/dist/scripts/fixtures/fake-codex-config-loader.js +12 -1
- package/dist/scripts/release-4000-required-gates.js +36 -0
- package/dist/scripts/release-4001-required-gates.js +13 -0
- package/dist/scripts/release-gate-dag-runner.js +18 -0
- package/dist/scripts/release-speed-summary.js +9 -0
- package/dist/scripts/sizecheck.js +4 -2
- package/package.json +52 -7
package/README.md
CHANGED
|
@@ -35,7 +35,32 @@ Set up this agent project with Sneakoscope Codex. Use [[mandarange/Sneakoscope-C
|
|
|
35
35
|
|
|
36
36
|
## 🚀 Current Release
|
|
37
37
|
|
|
38
|
-
SKS **
|
|
38
|
+
SKS **4.0.1** is the TriWiki Turbo completion release. It moves default completion toward affected-scope, release-equivalent proof with reusable TriWiki proof cards, real gate pack execution, SLA scheduling, build-once proof, probe memoization, and explicit legacy-runtime migration instead of silent fallback aliases.
|
|
39
|
+
|
|
40
|
+
What changed in 4.0.1:
|
|
41
|
+
|
|
42
|
+
- **TriWiki proof bank.** Proof cards now bind reusable gate proof to input hash, implementation hash, package lock hash, environment allowlist, fixture version, and tool version.
|
|
43
|
+
- **Affected release-equivalent verification.** Changed files map to module cards, gate impact maps, and gate packs so small tasks can run fast without giving up scoped release confidence.
|
|
44
|
+
- **Parallel SLA planning.** Release gate packs, resource budgets, and SLA certificates expose the planned critical path for five-minute foreground verification.
|
|
45
|
+
- **New control surface.** `sks check`, `sks task`, `sks release`, `sks triwiki`, `sks proof bank status`, and `sks daemon` expose the fast proof pipeline.
|
|
46
|
+
- **No silent legacy fallback.** Compatibility aliases are removed; removed runtimes now use explicit migration notices.
|
|
47
|
+
|
|
48
|
+
SKS **3.1.16** was a launch-reliability patch on the 3.1.15 doctor-reliability release. It made `sks --mad` self-bootstrap a fresh project instead of dead-ending on a missing Codex config.
|
|
49
|
+
|
|
50
|
+
What changed in 3.1.16:
|
|
51
|
+
|
|
52
|
+
- **`sks --mad` bootstraps a fresh project.** When the only preflight blocker is a missing managed Codex config (`.codex/config.toml` absent), `sks --mad` now regenerates it — the `sks doctor --fix` equivalent — and re-runs the preflight, instead of blocking and making you run a separate command. An existing but unreadable/EPERM/parse-broken config still blocks and routes you to `sks doctor --fix`.
|
|
53
|
+
- **Missing-config diagnostics are honest.** A missing config no longer cascades into misleading `macos_acl_ls_le_failed` / `macos_flags_ls_lO_failed` / `spawned_child_read_failed` blockers from running file checks on a nonexistent path; the preflight reports only `missing_config` / `missing_codex_dir`.
|
|
54
|
+
|
|
55
|
+
SKS **3.1.15** was a doctor-reliability patch on the 3.1.14 production-hardening release. It ended the endless `sks doctor --fix` loop that kept reporting `codex_cli_config_toml_parse_error` / `cli_ready: no` on the very run that already repaired the config.
|
|
56
|
+
|
|
57
|
+
What changed in 3.1.15:
|
|
58
|
+
|
|
59
|
+
- **`sks doctor --fix` no longer loops on a config it already fixed.** The Codex config-load probe is re-run *after* the Context7/Supabase/startup MCP repairs land, so the readiness verdict reflects the repaired config instead of the stale pre-repair snapshot.
|
|
60
|
+
- **Context7 is seeded on the remote transport.** Managed setup writes `[mcp_servers.context7]` with the streamable-HTTP `url` instead of a local stdio `command`, so the project config never merges with a remote `url` in the global Codex config into the `url is not supported for stdio` error Codex 0.140 rejects.
|
|
61
|
+
- **The config-load operator action is accurate.** A `codex_cli_config_toml_parse_error` now points at both misplaced machine-local keys *and* the Context7/MCP stdio-vs-`url` transport conflict, instead of only suggesting a key hoist that does nothing for a transport conflict.
|
|
62
|
+
|
|
63
|
+
The 3.1.14 production-hardening surface for Codex 0.140 evidence, transactional `sks doctor --fix` repair, MCP readiness, native capability proof, and protected-secret rollback remains intact.
|
|
39
64
|
|
|
40
65
|
What changed in 3.1.14:
|
|
41
66
|
|
|
@@ -4,7 +4,7 @@ use std::io::{self, Read, Seek, SeekFrom};
|
|
|
4
4
|
fn main() {
|
|
5
5
|
let mut args = std::env::args().skip(1);
|
|
6
6
|
match args.next().as_deref() {
|
|
7
|
-
Some("--version") => println!("sks-rs
|
|
7
|
+
Some("--version") => println!("sks-rs 4.0.1"),
|
|
8
8
|
Some("compact-info") => {
|
|
9
9
|
let mut input = String::new();
|
|
10
10
|
let _ = io::stdin().read_to_string(&mut input);
|
package/dist/bin/sks.js
CHANGED
|
@@ -77,6 +77,11 @@ export const COMMANDS = {
|
|
|
77
77
|
help: entry('stable', 'Show SKS help', 'dist/commands/help.js', directCommand(() => import('../commands/help.js'), 'dist/commands/help.js')),
|
|
78
78
|
version: entry('stable', 'Show SKS version', 'dist/commands/version.js', directCommand(() => import('../commands/version.js'), 'dist/commands/version.js')),
|
|
79
79
|
commands: entry('stable', 'List SKS commands', 'dist/core/commands/basic-cli.js', basicArgs('commandsCommand')),
|
|
80
|
+
check: entry('stable', 'Run five-minute proof-bank affected checks', 'dist/core/commands/check-command.js', argsCommand(() => import('../core/commands/check-command.js'), 'checkCommand', 'dist/core/commands/check-command.js')),
|
|
81
|
+
task: entry('stable', 'Run an SLA-bounded SKS task check', 'dist/core/commands/task-command.js', argsCommand(() => import('../core/commands/task-command.js'), 'taskCommand', 'dist/core/commands/task-command.js')),
|
|
82
|
+
release: entry('stable', 'Run affected/full/background release gates', 'dist/core/commands/release-command.js', argsCommand(() => import('../core/commands/release-command.js'), 'releaseCommand', 'dist/core/commands/release-command.js')),
|
|
83
|
+
triwiki: entry('stable', 'Inspect TriWiki index, affected graph, and proof bank', 'dist/core/commands/triwiki-command.js', argsCommand(() => import('../core/commands/triwiki-command.js'), 'triwikiCommand', 'dist/core/commands/triwiki-command.js')),
|
|
84
|
+
daemon: entry('stable', 'Inspect or warm the local SKS daemon cache', 'dist/core/commands/daemon-command.js', argsCommand(() => import('../core/commands/daemon-command.js'), 'daemonCommand', 'dist/core/commands/daemon-command.js')),
|
|
80
85
|
run: entry('beta', 'Classify and execute a task through the SKS trust kernel', 'dist/core/commands/run-command.js', argsCommand(() => import('../core/commands/run-command.js'), 'runCommand', 'dist/core/commands/run-command.js')),
|
|
81
86
|
status: entry('stable', 'Show concise active mission and trust status', 'dist/core/commands/status-command.js', argsCommand(() => import('../core/commands/status-command.js'), 'statusCommand', 'dist/core/commands/status-command.js')),
|
|
82
87
|
root: entry('stable', 'Show active SKS root', 'dist/commands/root.js', directCommand(() => import('../commands/root.js'), 'dist/commands/root.js')),
|
|
@@ -159,19 +164,7 @@ export const COMMANDS = {
|
|
|
159
164
|
bench: entry('beta', 'Run core trust-kernel benchmark budgets', 'dist/core/commands/bench-command.js', argsCommand(() => import('../core/commands/bench-command.js'), 'benchCommand', 'dist/core/commands/bench-command.js'))
|
|
160
165
|
};
|
|
161
166
|
export const TYPED_COMMANDS = COMMANDS;
|
|
162
|
-
export const LEGACY_COMMAND_ALIASES = {
|
|
163
|
-
auth: 'codex-lb',
|
|
164
|
-
mad: 'mad-sks',
|
|
165
|
-
autoreview: 'auto-review',
|
|
166
|
-
dollars: 'dollar-commands',
|
|
167
|
-
'$': 'dollar-commands',
|
|
168
|
-
'ux-review': 'image-ux-review',
|
|
169
|
-
'visual-review': 'image-ux-review',
|
|
170
|
-
'ui-ux-review': 'image-ux-review',
|
|
171
|
-
cu: 'computer-use',
|
|
172
|
-
grok: 'xai',
|
|
173
|
-
memory: 'gc'
|
|
174
|
-
};
|
|
167
|
+
export const LEGACY_COMMAND_ALIASES = {};
|
|
175
168
|
export const COMMAND_ALIASES = {
|
|
176
169
|
...LEGACY_COMMAND_ALIASES,
|
|
177
170
|
'--help': 'help',
|
package/dist/commands/doctor.js
CHANGED
|
@@ -35,6 +35,7 @@ import { repairCodexStartupConfig } from '../core/doctor/codex-startup-config-re
|
|
|
35
35
|
import { repairContext7Mcp } from '../core/doctor/context7-mcp-repair.js';
|
|
36
36
|
import { repairSupabaseMcp } from '../core/doctor/supabase-mcp-repair.js';
|
|
37
37
|
import { runDoctorFixTransaction } from '../core/doctor/doctor-transaction.js';
|
|
38
|
+
import { planDoctorDirtyRepair } from '../core/doctor/doctor-dirty-planner.js';
|
|
38
39
|
import { doctorRepairPostcheck } from '../core/doctor/doctor-repair-postcheck.js';
|
|
39
40
|
import { withSecretPreservationGuard } from '../core/config/config-migration-journal.js';
|
|
40
41
|
export async function run(_command, args = []) {
|
|
@@ -143,7 +144,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
143
144
|
const migrationJournal = flag(args, '--fix')
|
|
144
145
|
? await writeFixMigrationJournal(root, migrationPreFix, configRepair, setupRepair).catch(() => null)
|
|
145
146
|
: null;
|
|
146
|
-
|
|
147
|
+
let codexConfig = configRepair?.after || await inspectCodexConfigReadability(root, configProbeOpts);
|
|
147
148
|
const codexDoctor = await runCodexDoctorBridge({ codexBin: codexBin || null, cwd: root, required: flag(args, '--require-actual-codex') });
|
|
148
149
|
const codexDoctorDiff = compareCodexDoctorBridge(codexDoctorBefore, codexDoctor);
|
|
149
150
|
codexStartupRepair = mergeObservedCodexStartupWarnings(codexStartupRepair, codexDoctor);
|
|
@@ -284,9 +285,22 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
284
285
|
raw_secret_values_recorded: false
|
|
285
286
|
}))
|
|
286
287
|
: null;
|
|
288
|
+
const doctorDirtyPlan = doctorFix
|
|
289
|
+
? planDoctorDirtyRepair(root, [
|
|
290
|
+
'setup',
|
|
291
|
+
'codex_startup_repair',
|
|
292
|
+
'startup_config_repair',
|
|
293
|
+
'context7_repair',
|
|
294
|
+
'context7_mcp_repair',
|
|
295
|
+
'supabase_mcp_repair',
|
|
296
|
+
'command_alias_cleanup',
|
|
297
|
+
'native_capability_repair'
|
|
298
|
+
])
|
|
299
|
+
: null;
|
|
287
300
|
const doctorFixTransaction = doctorFix
|
|
288
301
|
? await runDoctorFixTransaction({
|
|
289
302
|
root,
|
|
303
|
+
dirtyPlan: doctorDirtyPlan,
|
|
290
304
|
phases: [
|
|
291
305
|
{
|
|
292
306
|
id: 'setup',
|
|
@@ -459,6 +473,18 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
459
473
|
blockers: [err?.message || String(err)],
|
|
460
474
|
warnings: []
|
|
461
475
|
}));
|
|
476
|
+
// Re-probe the Codex config AFTER the MCP transport repairs (Context7 remote
|
|
477
|
+
// migration, Supabase read-only, startup config) have landed. `repairCodexConfigEperm`
|
|
478
|
+
// ran its config-load probe ~before~ those repairs, so a config that those repairs
|
|
479
|
+
// fix in THIS run would otherwise keep `codexConfig.ok === false`, making the doctor
|
|
480
|
+
// report `cli_ready: no` / `codex_cli_config_toml_parse_error` on the very run that
|
|
481
|
+
// fixed it — the endless "rerun sks doctor --fix" loop. Only re-probe when the initial
|
|
482
|
+
// probe failed and we are in --fix mode, so healthy configs pay no extra probe cost.
|
|
483
|
+
if (doctorFix && codexConfig?.ok === false) {
|
|
484
|
+
const reinspected = await inspectCodexConfigReadability(root, configProbeOpts).catch(() => null);
|
|
485
|
+
if (reinspected)
|
|
486
|
+
codexConfig = reinspected;
|
|
487
|
+
}
|
|
462
488
|
const pkgBytes = await dirSize(root).catch(() => 0);
|
|
463
489
|
const ready = await writeDoctorReadinessMatrix(root, {
|
|
464
490
|
codex,
|
|
@@ -474,6 +500,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
474
500
|
context7_mcp_repair: context7McpRepair,
|
|
475
501
|
supabase_mcp_repair: supabaseMcpRepair,
|
|
476
502
|
doctor_fix_transaction: doctorFixTransaction,
|
|
503
|
+
doctor_dirty_plan: doctorDirtyPlan,
|
|
477
504
|
doctor_fix_postcheck: doctorFixPostcheck,
|
|
478
505
|
local_model: localModel,
|
|
479
506
|
agent_role_config: agentRoleConfigRepair,
|
|
@@ -540,7 +567,7 @@ async function runDoctor(args = [], root, doctorFix) {
|
|
|
540
567
|
ready,
|
|
541
568
|
sneakoscope: { ok: await exists(`${root}/.sneakoscope`) },
|
|
542
569
|
package: { bytes: pkgBytes, human: formatBytes(pkgBytes) },
|
|
543
|
-
repair: { sks_update: sksUpdate, setup: setupRepair, codex_config: configRepair, migration_journal: migrationJournal, global_sks_installs: globalSksInstallCleanup, agent_role_config: agentRoleConfigRepair, zellij: zellijRepair, context7: context7Repair, codex_startup: codexStartupRepair, startup_config: startupConfigRepair, context7_mcp: context7McpRepair, supabase_mcp: supabaseMcpRepair, doctor_transaction: doctorFixTransaction, doctor_postcheck: doctorFixPostcheck, codex_native: codexNativeRepair, doctor_native_capability: doctorNativeCapabilityRepair, command_aliases: commandAliasCleanup }
|
|
570
|
+
repair: { sks_update: sksUpdate, setup: setupRepair, codex_config: configRepair, migration_journal: migrationJournal, global_sks_installs: globalSksInstallCleanup, agent_role_config: agentRoleConfigRepair, zellij: zellijRepair, context7: context7Repair, codex_startup: codexStartupRepair, startup_config: startupConfigRepair, context7_mcp: context7McpRepair, supabase_mcp: supabaseMcpRepair, doctor_transaction: doctorFixTransaction, doctor_dirty_plan: doctorDirtyPlan, doctor_postcheck: doctorFixPostcheck, codex_native: codexNativeRepair, doctor_native_capability: doctorNativeCapabilityRepair, command_aliases: commandAliasCleanup }
|
|
544
571
|
};
|
|
545
572
|
if (flag(args, '--json')) {
|
|
546
573
|
printJson(result);
|
package/dist/commands/proof.js
CHANGED
|
@@ -9,10 +9,18 @@ import { finalizeRouteWithProof } from '../core/proof/route-finalizer.js';
|
|
|
9
9
|
import { renderProofMarkdown, writeCompletionProof } from '../core/proof/proof-writer.js';
|
|
10
10
|
import { validateCompletionProof } from '../core/proof/validation.js';
|
|
11
11
|
import { buildRuntimeProofSummary, renderRuntimeProofSummary } from '../core/agents/runtime-proof-summary.js';
|
|
12
|
+
import { summarizeTriWikiProofBank } from '../core/triwiki/triwiki-proof-bank.js';
|
|
12
13
|
export async function run(_command, args = []) {
|
|
13
14
|
const root = await projectRoot();
|
|
14
15
|
const action = args[0] || 'show';
|
|
15
16
|
const rest = args.slice(1);
|
|
17
|
+
if (action === 'bank' && rest[0] === 'status') {
|
|
18
|
+
const status = summarizeTriWikiProofBank(root);
|
|
19
|
+
if (flag(args, '--json'))
|
|
20
|
+
return printJson(status);
|
|
21
|
+
console.log(JSON.stringify(status, null, 2));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
16
24
|
if (action === 'latest' && !flag(args, '--completion')) {
|
|
17
25
|
const runtime = await tryRuntimeProofSummary(root);
|
|
18
26
|
if (runtime) {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { computeTriWikiCacheKey } from '../triwiki/triwiki-cache-key.js';
|
|
5
|
+
export const BUILD_ONCE_PROOF_SCHEMA = 'sks.build-once-proof.v1';
|
|
6
|
+
export function runBuildOnce(input) {
|
|
7
|
+
const mode = input.mode || 'incremental';
|
|
8
|
+
const key = computeTriWikiCacheKey({
|
|
9
|
+
root: input.root,
|
|
10
|
+
id: `build-once:${mode}`,
|
|
11
|
+
inputs: ['src/**/*.ts', 'package.json', 'package-lock.json', 'tsconfig.json'],
|
|
12
|
+
implementationFiles: ['tsconfig.json'],
|
|
13
|
+
envAllowlist: ['NODE_ENV', 'CI'],
|
|
14
|
+
fixtureVersion: 'sks-4.0.1'
|
|
15
|
+
});
|
|
16
|
+
const existing = readBuildOnceProof(input.root);
|
|
17
|
+
if (!input.force && existing?.ok === true && existing.cache_key === key.key) {
|
|
18
|
+
return { ...existing, reused: true };
|
|
19
|
+
}
|
|
20
|
+
const started = Date.now();
|
|
21
|
+
const run = spawnSync('npm', ['run', mode === 'clean' ? 'build:clean' : 'build:incremental', '--silent'], {
|
|
22
|
+
cwd: input.root,
|
|
23
|
+
encoding: 'utf8',
|
|
24
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
25
|
+
env: { ...process.env, CI: process.env.CI || 'true' }
|
|
26
|
+
});
|
|
27
|
+
const proof = {
|
|
28
|
+
schema: BUILD_ONCE_PROOF_SCHEMA,
|
|
29
|
+
ok: run.status === 0,
|
|
30
|
+
mode,
|
|
31
|
+
cache_key: key.key,
|
|
32
|
+
source_hash: key.input_hash,
|
|
33
|
+
package_lock_hash: key.package_lock_hash,
|
|
34
|
+
tsconfig_hash: computeTriWikiCacheKey({ root: input.root, id: 'build-once:tsconfig', inputs: ['tsconfig.json'] }).input_hash,
|
|
35
|
+
dist_hash: computeTriWikiCacheKey({ root: input.root, id: 'build-once:dist', inputs: ['dist'] }).input_hash,
|
|
36
|
+
created_at: new Date().toISOString(),
|
|
37
|
+
status: run.status,
|
|
38
|
+
duration_ms: Math.max(0, Date.now() - started),
|
|
39
|
+
reused: false,
|
|
40
|
+
blockers: run.status === 0 ? [] : [`build_failed:${run.status ?? 'signal'}`]
|
|
41
|
+
};
|
|
42
|
+
writeBuildOnceProof(input.root, proof);
|
|
43
|
+
return proof;
|
|
44
|
+
}
|
|
45
|
+
export function readBuildOnceProof(root) {
|
|
46
|
+
const file = buildProofPath(root);
|
|
47
|
+
try {
|
|
48
|
+
if (!fs.existsSync(file))
|
|
49
|
+
return null;
|
|
50
|
+
const json = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
51
|
+
return json.schema === BUILD_ONCE_PROOF_SCHEMA ? json : null;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function writeBuildOnceProof(root, proof) {
|
|
58
|
+
const file = buildProofPath(root);
|
|
59
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
60
|
+
fs.writeFileSync(file, `${JSON.stringify(proof, null, 2)}\n`);
|
|
61
|
+
return file;
|
|
62
|
+
}
|
|
63
|
+
function buildProofPath(root) {
|
|
64
|
+
return path.join(root, 'dist', '.sks-build-proof.json');
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=build-once-runner.js.map
|
|
@@ -17,50 +17,64 @@ export async function inspectCodexConfigReadability(rootInput = process.cwd(), o
|
|
|
17
17
|
classifyBlocker(check).forEach((blocker) => blockers.add(blocker));
|
|
18
18
|
};
|
|
19
19
|
add(await accessCheck('codex_dir_exists', configDir, fs.constants.R_OK | fs.constants.X_OK));
|
|
20
|
-
|
|
20
|
+
const projectConfigExists = await accessCheck('project_config_exists', configPath, fs.constants.R_OK);
|
|
21
|
+
add(projectConfigExists);
|
|
21
22
|
for (const dir of parentDirsFor(root, configPath)) {
|
|
22
23
|
add(await accessCheck('parent_traverse', dir, fs.constants.X_OK));
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
25
|
+
// Fresh project: the managed config simply does not exist yet. Every downstream check
|
|
26
|
+
// (stat, symlink, macOS ACL/flags/xattr, node/child read, codex config load) would
|
|
27
|
+
// operate on a nonexistent path and fail with ENOENT, turning the single real cause —
|
|
28
|
+
// a missing config — into a misleading cascade (`macos_acl_ls_le_failed`,
|
|
29
|
+
// `macos_flags_ls_lO_failed`, `spawned_child_read_failed`, ...). Skip them and report
|
|
30
|
+
// only the honest `missing_config` / `missing_codex_dir` blocker so the caller can
|
|
31
|
+
// regenerate the managed config instead of chasing phantom ACL/permission problems.
|
|
32
|
+
const configMissing = projectConfigExists.error?.code === 'ENOENT';
|
|
33
|
+
if (!configMissing) {
|
|
34
|
+
const lstatCheck = await statCheck('config_lstat', configPath, 'lstat');
|
|
35
|
+
add(lstatCheck);
|
|
36
|
+
const stat = await statCheck('config_stat', configPath, 'stat');
|
|
37
|
+
add(stat);
|
|
38
|
+
if (stat.ok) {
|
|
39
|
+
add({ name: 'config_owner', ok: true, detail: { uid: stat.detail.uid, gid: stat.detail.gid } });
|
|
40
|
+
add({ name: 'config_mode', ok: true, detail: { mode: stat.detail.mode_octal } });
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
if (lstatCheck.ok) {
|
|
43
|
+
const isSymlink = Boolean(lstatCheck.detail.is_symbolic_link);
|
|
44
|
+
const symlinkDetail = { is_symlink: isSymlink };
|
|
45
|
+
if (isSymlink) {
|
|
46
|
+
symlinkDetail.realpath = await fsp.realpath(configPath).catch((err) => ({ error: errorDetail(err) }));
|
|
47
|
+
symlinkDetail.allowed = typeof symlinkDetail.realpath === 'string' && symlinkTargetAllowed(symlinkDetail.realpath, root, opts);
|
|
48
|
+
if (!symlinkDetail.allowed)
|
|
49
|
+
blockers.add('symlink_escape');
|
|
50
|
+
}
|
|
51
|
+
add({ name: 'config_symlink', ok: !isSymlink || symlinkDetail.allowed === true, detail: symlinkDetail });
|
|
52
|
+
}
|
|
53
|
+
if (process.platform === 'darwin') {
|
|
54
|
+
add(await commandCheck('macos_acl_ls_le', 'ls', ['-le', configPath], root));
|
|
55
|
+
const acl = checks.find((check) => check.name === 'macos_acl_ls_le');
|
|
56
|
+
if (/\bdeny\b.*\b(read|readattr|readextattr|readsecurity|search)\b/i.test(String(acl?.detail?.stdout || '')))
|
|
57
|
+
blockers.add('acl_denied');
|
|
58
|
+
const flags = await commandCheck('macos_flags_ls_lO', 'ls', ['-lO', configPath], root);
|
|
59
|
+
add(flags);
|
|
60
|
+
if (/\b(uchg|schg|restricted)\b/.test(String(flags.detail?.stdout || '')))
|
|
61
|
+
blockers.add('flags_locked');
|
|
62
|
+
const xattrs = await commandCheck('macos_xattr', 'xattr', ['-l', configPath], root, { allowExitCodes: [0, 1] });
|
|
63
|
+
add(xattrs);
|
|
64
|
+
add({ name: 'macos_quarantine_xattr', ok: !/com\.apple\.quarantine/.test(String(xattrs.detail?.stdout || '')), detail: { present: /com\.apple\.quarantine/.test(String(xattrs.detail?.stdout || '')) } });
|
|
65
|
+
if (/com\.apple\.quarantine/.test(String(xattrs.detail?.stdout || '')))
|
|
66
|
+
blockers.add('quarantine');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
add({ name: 'macos_metadata', ok: true, status: 'skipped_non_macos' });
|
|
70
|
+
}
|
|
71
|
+
add(await nodeReadCheck(configPath));
|
|
72
|
+
add(await childReadCheck(configPath, root));
|
|
73
|
+
add(await codexCliConfigLoadCheck(root, configPath, opts));
|
|
57
74
|
}
|
|
58
75
|
else {
|
|
59
|
-
add({ name: '
|
|
76
|
+
add({ name: 'config_file_checks', ok: true, status: 'skipped_config_missing', detail: { config_path: configPath } });
|
|
60
77
|
}
|
|
61
|
-
add(await nodeReadCheck(configPath));
|
|
62
|
-
add(await childReadCheck(configPath, root));
|
|
63
|
-
add(await codexCliConfigLoadCheck(root, configPath, opts));
|
|
64
78
|
const report = {
|
|
65
79
|
schema: CODEX_CONFIG_READABILITY_SCHEMA,
|
|
66
80
|
generated_at: nowIso(),
|
|
@@ -176,7 +190,7 @@ function operatorActions(blockers) {
|
|
|
176
190
|
if (blockers.some((item) => /^missing_/.test(item)))
|
|
177
191
|
actions.add('Run `sks doctor --fix` to regenerate the managed Codex project config, then rerun the preflight.');
|
|
178
192
|
if (blockers.includes('codex_cli_config_toml_parse_error'))
|
|
179
|
-
actions.add('Run `sks doctor --fix` (or `sks mad repair-config --apply`) to
|
|
193
|
+
actions.add('Run `sks doctor --fix` (or `sks mad repair-config --apply`) to restore a loadable config.toml. This hoists misplaced machine-local keys back to the top of the file AND migrates a local-stdio Context7/MCP server that conflicts with a remote `url` (the "url is not supported for stdio" error, caused by the global and project configs merging) to the supported transport. If `sks doctor --fix` already reports the Context7/MCP transport repaired, the config is fixed — rerun once to confirm `cli_ready`.');
|
|
180
194
|
if (blockers.includes('codex_cli_config_eperm'))
|
|
181
195
|
actions.add('Run `sks mad repair-config --apply`; if it still fails on macOS, grant Full Disk Access/Files and Folders access to the launching terminal, Warp, iTerm, Terminal, Codex app, or Codex CLI context.');
|
|
182
196
|
if (blockers.includes('EPERM') || blockers.includes('tcc_possible'))
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { flag } from '../../cli/args.js';
|
|
5
|
+
import { printJson } from '../../cli/output.js';
|
|
6
|
+
import { projectRoot } from '../fsx.js';
|
|
7
|
+
const CHECK_SCHEMA = 'sks.check.v1';
|
|
8
|
+
export async function checkCommand(args = []) {
|
|
9
|
+
const root = await projectRoot();
|
|
10
|
+
const tier = readArg(args, '--tier', positionalTier(args) || 'confidence');
|
|
11
|
+
const sla = readArg(args, '--sla', '5m');
|
|
12
|
+
const changedSince = readArg(args, '--changed-since', 'auto');
|
|
13
|
+
const json = flag(args, '--json');
|
|
14
|
+
const planOnly = flag(args, '--plan');
|
|
15
|
+
const triwiki = !flag(args, '--no-triwiki');
|
|
16
|
+
const plan = buildCheckPlan({ tier, sla, changedSince, triwiki });
|
|
17
|
+
if (planOnly) {
|
|
18
|
+
const result = { schema: CHECK_SCHEMA, ok: true, mode: 'plan', ...plan };
|
|
19
|
+
if (json)
|
|
20
|
+
return printJson(result);
|
|
21
|
+
printPlan(result);
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
const steps = [];
|
|
25
|
+
let proofBankSummary = null;
|
|
26
|
+
for (const step of plan.steps) {
|
|
27
|
+
const result = spawnSync(step.command, step.args, {
|
|
28
|
+
cwd: root,
|
|
29
|
+
encoding: 'utf8',
|
|
30
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
31
|
+
shell: false,
|
|
32
|
+
env: { ...process.env, CI: process.env.CI || 'true' }
|
|
33
|
+
});
|
|
34
|
+
const ok = result.status === 0;
|
|
35
|
+
if (step.name === 'proof-bank-summary')
|
|
36
|
+
proofBankSummary = parseJsonObject(String(result.stdout || ''));
|
|
37
|
+
steps.push({ name: step.name, ok, status: result.status, stderr_tail: tail(String(result.stderr || '')) });
|
|
38
|
+
if (!json) {
|
|
39
|
+
if (result.stdout)
|
|
40
|
+
process.stdout.write(result.stdout);
|
|
41
|
+
if (result.stderr)
|
|
42
|
+
process.stderr.write(result.stderr);
|
|
43
|
+
}
|
|
44
|
+
if (!ok) {
|
|
45
|
+
const failed = { schema: CHECK_SCHEMA, ok: false, mode: 'run', ...plan, steps, completion_certificate: latestCertificate(root) || proofBankSummary?.completion_certificate || null, release_speed_summary: proofBankSummary };
|
|
46
|
+
if (json)
|
|
47
|
+
return printJson(failed);
|
|
48
|
+
process.exitCode = result.status || 1;
|
|
49
|
+
return failed;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const result = { schema: CHECK_SCHEMA, ok: true, mode: 'run', ...plan, steps, completion_certificate: latestCertificate(root) || proofBankSummary?.completion_certificate || null, release_speed_summary: proofBankSummary };
|
|
53
|
+
if (json)
|
|
54
|
+
return printJson(result);
|
|
55
|
+
if (result.completion_certificate) {
|
|
56
|
+
console.log(`SKS check certificate: ${result.completion_certificate.confidence} sla_met=${result.completion_certificate.sla_met}`);
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function buildCheckPlan(input) {
|
|
61
|
+
const tier = normalizeTier(input.tier);
|
|
62
|
+
const buildScript = tier === 'release' ? 'build:clean' : 'build:incremental';
|
|
63
|
+
const steps = [];
|
|
64
|
+
if (tier === 'instant') {
|
|
65
|
+
steps.push({ name: 'proof-bank-summary', command: process.execPath, args: ['dist/scripts/release-speed-summary.js'] });
|
|
66
|
+
}
|
|
67
|
+
else if (tier === 'real-check') {
|
|
68
|
+
steps.push({ name: 'real-check', command: process.execPath, args: ['dist/scripts/release-real-check.js'] });
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
steps.push({ name: buildScript, command: 'npm', args: ['run', buildScript, '--silent'] });
|
|
72
|
+
steps.push({ name: `release:${tier}`, command: process.execPath, args: dagArgs(tier, input.changedSince, input.sla) });
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
tier,
|
|
76
|
+
sla: input.sla,
|
|
77
|
+
triwiki: input.triwiki,
|
|
78
|
+
changed_since: input.changedSince,
|
|
79
|
+
build_once: tier === 'release' ? 'clean' : tier === 'real-check' || tier === 'instant' ? 'not_applicable' : 'incremental',
|
|
80
|
+
steps
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function dagArgs(tier, changedSince, sla) {
|
|
84
|
+
if (tier === 'release')
|
|
85
|
+
return ['dist/scripts/release-gate-dag-runner.js', '--preset', 'release', '--full'];
|
|
86
|
+
const preset = tier === 'instant' ? 'fast' : tier === 'affected' || tier === 'confidence' ? 'affected' : tier;
|
|
87
|
+
return ['dist/scripts/release-gate-dag-runner.js', '--preset', preset, '--changed-since', changedSince, '--sla', sla];
|
|
88
|
+
}
|
|
89
|
+
function latestCertificate(root) {
|
|
90
|
+
const direct = path.join(root, '.sneakoscope', 'reports', 'completion-certificate.json');
|
|
91
|
+
if (fs.existsSync(direct))
|
|
92
|
+
return JSON.parse(fs.readFileSync(direct, 'utf8'));
|
|
93
|
+
const base = path.join(root, '.sneakoscope', 'reports', 'release-gates');
|
|
94
|
+
if (!fs.existsSync(base))
|
|
95
|
+
return null;
|
|
96
|
+
const latest = fs.readdirSync(base)
|
|
97
|
+
.map((name) => path.join(base, name, 'completion-certificate.json'))
|
|
98
|
+
.filter((file) => fs.existsSync(file))
|
|
99
|
+
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0];
|
|
100
|
+
return latest ? JSON.parse(fs.readFileSync(latest, 'utf8')) : null;
|
|
101
|
+
}
|
|
102
|
+
function normalizeTier(value) {
|
|
103
|
+
const tier = String(value || '').trim().toLowerCase();
|
|
104
|
+
if (['instant', 'affected', 'confidence', 'release', 'real-check'].includes(tier))
|
|
105
|
+
return tier;
|
|
106
|
+
return 'confidence';
|
|
107
|
+
}
|
|
108
|
+
function positionalTier(args) {
|
|
109
|
+
const first = args.find((arg) => !arg.startsWith('-'));
|
|
110
|
+
return first || null;
|
|
111
|
+
}
|
|
112
|
+
function readArg(args, name, fallback) {
|
|
113
|
+
const index = args.indexOf(name);
|
|
114
|
+
return index >= 0 && args[index + 1] ? String(args[index + 1]) : fallback;
|
|
115
|
+
}
|
|
116
|
+
function tail(value, limit = 1200) {
|
|
117
|
+
return value.length > limit ? value.slice(-limit) : value;
|
|
118
|
+
}
|
|
119
|
+
function parseJsonObject(value) {
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(value);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function printPlan(result) {
|
|
128
|
+
console.log(`SKS check plan: tier=${result.tier} sla=${result.sla} build=${result.build_once}`);
|
|
129
|
+
for (const step of result.steps)
|
|
130
|
+
console.log(`- ${step.name}: ${[step.command, ...step.args].join(' ')}`);
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=check-command.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { flag } from '../../cli/args.js';
|
|
2
|
+
import { printJson } from '../../cli/output.js';
|
|
3
|
+
import { projectRoot } from '../fsx.js';
|
|
4
|
+
import { runSksdClient } from '../daemon/sksd-client.js';
|
|
5
|
+
export async function daemonCommand(args = []) {
|
|
6
|
+
const root = await projectRoot();
|
|
7
|
+
const action = args[0] === 'warm' || args[0] === 'stop' || args[0] === 'status' ? args[0] : 'status';
|
|
8
|
+
const state = runSksdClient(root, action);
|
|
9
|
+
if (flag(args, '--json'))
|
|
10
|
+
return printJson(state);
|
|
11
|
+
console.log(JSON.stringify(state, null, 2));
|
|
12
|
+
return state;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=daemon-command.js.map
|
|
@@ -135,7 +135,24 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
135
135
|
// readability + repair checks still run. SKS_LAUNCH_FULL_CODEX_PROBE=1 restores the
|
|
136
136
|
// old behavior.
|
|
137
137
|
const allowMadRepair = rawArgs.includes('--repair-config') || rawArgs.includes('--fix') || rawArgs.includes('--yes-repair');
|
|
138
|
-
const
|
|
138
|
+
const launchPreflightOpts = { fix: allowMadRepair, launchFast: process.env.SKS_LAUNCH_FULL_CODEX_PROBE !== '1', profile: profile.profile_name, sandbox: 'danger-full-access', serviceTier: 'fast' };
|
|
139
|
+
let launchPreflight = await runCodexLaunchPreflight(launchRoot, launchPreflightOpts);
|
|
140
|
+
// Fresh-project bootstrap: when the ONLY blocker is that the managed Codex config does
|
|
141
|
+
// not exist yet (`.codex/config.toml` absent), regenerate it — exactly what the blocker
|
|
142
|
+
// action tells the user to run via `sks doctor --fix` — and re-run the preflight once,
|
|
143
|
+
// instead of blocking the launch on a trivially-fixable missing config. An EXISTING but
|
|
144
|
+
// unreadable/broken config is NOT auto-fixed here: it still blocks and routes the user
|
|
145
|
+
// to `sks doctor --fix`, so genuine permission/EPERM/parse problems are never masked.
|
|
146
|
+
if (!launchPreflight.ok && !fs.existsSync(path.join(launchRoot, '.codex', 'config.toml'))) {
|
|
147
|
+
try {
|
|
148
|
+
await initProject(launchRoot, { installScope: rawArgs.includes('--local-only') ? 'project' : 'global', localOnly: rawArgs.includes('--local-only'), globalCommand: 'sks' });
|
|
149
|
+
console.error('SKS MAD bootstrapped the missing managed Codex config (`sks doctor --fix` equivalent) and re-ran preflight.');
|
|
150
|
+
launchPreflight = await runCodexLaunchPreflight(launchRoot, launchPreflightOpts);
|
|
151
|
+
}
|
|
152
|
+
catch (bootstrapErr) {
|
|
153
|
+
console.error(`SKS MAD could not bootstrap the managed Codex config: ${bootstrapErr?.message || bootstrapErr}. Run \`sks doctor --fix\`.`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
139
156
|
const afterPreflightUi = beforeUi ? await writeCodexAppUiSnapshot(launchRoot, `mad-after-preflight-${uiSnapshotId}`).catch(() => null) : null;
|
|
140
157
|
const preflightUiDiff = beforeUi && afterPreflightUi ? diffCodexAppUiSnapshots(beforeUi, afterPreflightUi) : null;
|
|
141
158
|
if (preflightUiDiff && !preflightUiDiff.ok) {
|
|
@@ -217,10 +234,15 @@ export async function madHighCommand(args = [], deps = {}) {
|
|
|
217
234
|
SKS_MAD_SKS_PROTECTED_CORE_DIGEST: madLaunch.gate.protected_core_digest
|
|
218
235
|
};
|
|
219
236
|
const launchOpts = codexLbImmediateLaunchOpts(cleanArgs, launchLb, { codexArgs: profile.launch_args, conciseBlockers: true, madSksEnv, launchEnv: madSksEnv });
|
|
220
|
-
const
|
|
237
|
+
const explicitWorkspace = readOption(cleanArgs, '--workspace', readOption(cleanArgs, '--session', null));
|
|
238
|
+
// Only the auto-derived stable `sks-mad-<cwd>` name accumulates panes across
|
|
239
|
+
// runs; when the user names a session explicitly (or codex-lb already minted a
|
|
240
|
+
// fresh unique session) respect it and skip the reset.
|
|
241
|
+
const autoDerivedMadSession = !explicitWorkspace && !launchOpts.session;
|
|
242
|
+
const workspace = explicitWorkspace || launchOpts.session || `sks-mad-${sanitizeZellijSessionName(process.cwd())}`;
|
|
221
243
|
const launch = headlessZellij
|
|
222
244
|
? await writeMadHeadlessZellijFallback(madLaunch, workspace)
|
|
223
|
-
: await launchMadZellijUi([...cleanArgs, '--workspace', workspace], { ...launchOpts, missionId: madLaunch.mission_id, root: madLaunch.root, cwd: process.cwd(), ledgerRoot: path.join(madLaunch.dir, 'agents'), slotCount: 0, requireZellij: process.env.SKS_REQUIRE_ZELLIJ === '1' });
|
|
245
|
+
: await launchMadZellijUi([...cleanArgs, '--workspace', workspace], { ...launchOpts, missionId: madLaunch.mission_id, root: madLaunch.root, cwd: process.cwd(), ledgerRoot: path.join(madLaunch.dir, 'agents'), slotCount: 0, freshSession: autoDerivedMadSession, requireZellij: process.env.SKS_REQUIRE_ZELLIJ === '1' });
|
|
224
246
|
const afterLaunchUi = beforeUi ? await writeCodexAppUiSnapshot(launchRoot, `mad-after-launch-${uiSnapshotId}`).catch(() => null) : null;
|
|
225
247
|
const launchUiDiff = beforeUi && afterLaunchUi ? diffCodexAppUiSnapshots(beforeUi, afterLaunchUi) : null;
|
|
226
248
|
if (launchUiDiff) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { flag } from '../../cli/args.js';
|
|
3
|
+
import { printJson } from '../../cli/output.js';
|
|
4
|
+
import { projectRoot } from '../fsx.js';
|
|
5
|
+
export async function releaseCommand(args = []) {
|
|
6
|
+
const root = await projectRoot();
|
|
7
|
+
const sub = args[0] && !args[0].startsWith('-') ? args[0] : 'affected';
|
|
8
|
+
const json = flag(args, '--json');
|
|
9
|
+
const command = commandForSubcommand(sub);
|
|
10
|
+
if (!command) {
|
|
11
|
+
console.error('Usage: sks release affected|full|background [--json]');
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const result = spawnSync('npm', ['run', command, '--silent'], {
|
|
16
|
+
cwd: root,
|
|
17
|
+
encoding: 'utf8',
|
|
18
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
19
|
+
env: { ...process.env, CI: process.env.CI || 'true' }
|
|
20
|
+
});
|
|
21
|
+
const report = {
|
|
22
|
+
schema: 'sks.release-command.v1',
|
|
23
|
+
ok: result.status === 0,
|
|
24
|
+
subcommand: sub,
|
|
25
|
+
script: command,
|
|
26
|
+
status: result.status,
|
|
27
|
+
stdout_tail: tail(String(result.stdout || '')),
|
|
28
|
+
stderr_tail: tail(String(result.stderr || ''))
|
|
29
|
+
};
|
|
30
|
+
if (json)
|
|
31
|
+
return printJson(report);
|
|
32
|
+
if (result.stdout)
|
|
33
|
+
process.stdout.write(result.stdout);
|
|
34
|
+
if (result.stderr)
|
|
35
|
+
process.stderr.write(result.stderr);
|
|
36
|
+
if (!report.ok)
|
|
37
|
+
process.exitCode = result.status || 1;
|
|
38
|
+
return report;
|
|
39
|
+
}
|
|
40
|
+
function commandForSubcommand(sub) {
|
|
41
|
+
if (sub === 'affected')
|
|
42
|
+
return 'release:check:affected';
|
|
43
|
+
if (sub === 'full')
|
|
44
|
+
return 'release:check:full';
|
|
45
|
+
if (sub === 'background')
|
|
46
|
+
return 'release:check:full';
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function tail(value, limit = 4000) {
|
|
50
|
+
return value.length > limit ? value.slice(-limit) : value;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=release-command.js.map
|