opensip-cli 0.1.14 → 0.1.16
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/dist/bootstrap/artifact-retention.d.ts +62 -0
- package/dist/bootstrap/artifact-retention.d.ts.map +1 -0
- package/dist/bootstrap/artifact-retention.js +117 -0
- package/dist/bootstrap/artifact-retention.js.map +1 -0
- package/dist/bootstrap/artifact-seams.d.ts +21 -1
- package/dist/bootstrap/artifact-seams.d.ts.map +1 -1
- package/dist/bootstrap/artifact-seams.js +76 -4
- package/dist/bootstrap/artifact-seams.js.map +1 -1
- package/dist/bootstrap/atomic-artifact-write.d.ts.map +1 -1
- package/dist/bootstrap/atomic-artifact-write.js +7 -2
- package/dist/bootstrap/atomic-artifact-write.js.map +1 -1
- package/dist/bootstrap/bundled-tools.manifest.json +2 -1
- package/dist/bootstrap/dispatch-fork-core.d.ts +15 -2
- package/dist/bootstrap/dispatch-fork-core.d.ts.map +1 -1
- package/dist/bootstrap/dispatch-fork-core.js +22 -4
- package/dist/bootstrap/dispatch-fork-core.js.map +1 -1
- package/dist/bootstrap/dispatch-host-rpc-handler.d.ts.map +1 -1
- package/dist/bootstrap/dispatch-host-rpc-handler.js +10 -0
- package/dist/bootstrap/dispatch-host-rpc-handler.js.map +1 -1
- package/dist/bootstrap/load-tool-capabilities.js +11 -4
- package/dist/bootstrap/load-tool-capabilities.js.map +1 -1
- package/dist/bootstrap/pre-action-messages.js +1 -1
- package/dist/bootstrap/pre-action-messages.js.map +1 -1
- package/dist/bootstrap/run-plane.d.ts +10 -0
- package/dist/bootstrap/run-plane.d.ts.map +1 -1
- package/dist/bootstrap/run-plane.js +20 -0
- package/dist/bootstrap/run-plane.js.map +1 -1
- package/dist/bootstrap/tool-command-dispatch-types.d.ts +15 -0
- package/dist/bootstrap/tool-command-dispatch-types.d.ts.map +1 -1
- package/dist/bootstrap/tool-command-worker-context.d.ts +5 -4
- package/dist/bootstrap/tool-command-worker-context.d.ts.map +1 -1
- package/dist/bootstrap/tool-command-worker-context.js +6 -4
- package/dist/bootstrap/tool-command-worker-context.js.map +1 -1
- package/dist/bootstrap/tool-command-worker-entry.d.ts.map +1 -1
- package/dist/bootstrap/tool-command-worker-entry.js +30 -5
- package/dist/bootstrap/tool-command-worker-entry.js.map +1 -1
- package/dist/bootstrap/tool-command-worker-rpc.d.ts.map +1 -1
- package/dist/bootstrap/tool-command-worker-rpc.js +23 -1
- package/dist/bootstrap/tool-command-worker-rpc.js.map +1 -1
- package/dist/cli-context.d.ts.map +1 -1
- package/dist/cli-context.js +26 -3
- package/dist/cli-context.js.map +1 -1
- package/dist/commands/agent-catalog.d.ts +9 -56
- package/dist/commands/agent-catalog.d.ts.map +1 -1
- package/dist/commands/agent-catalog.js +8 -199
- package/dist/commands/agent-catalog.js.map +1 -1
- package/dist/commands/assemble-opts.d.ts +13 -0
- package/dist/commands/assemble-opts.d.ts.map +1 -0
- package/dist/commands/assemble-opts.js +85 -0
- package/dist/commands/assemble-opts.js.map +1 -0
- package/dist/commands/history.d.ts +7 -11
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +7 -39
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/host-subcommand-groups.d.ts.map +1 -1
- package/dist/commands/host-subcommand-groups.js +12 -1
- package/dist/commands/host-subcommand-groups.js.map +1 -1
- package/dist/commands/init/agents-md.d.ts.map +1 -1
- package/dist/commands/init/agents-md.js +6 -0
- package/dist/commands/init/agents-md.js.map +1 -1
- package/dist/commands/mount-command-spec-wiring.d.ts +1 -0
- package/dist/commands/mount-command-spec-wiring.d.ts.map +1 -1
- package/dist/commands/mount-command-spec-wiring.js +5 -5
- package/dist/commands/mount-command-spec-wiring.js.map +1 -1
- package/dist/commands/session-show.d.ts.map +1 -1
- package/dist/commands/session-show.js +14 -41
- package/dist/commands/session-show.js.map +1 -1
- package/dist/commands/shared.d.ts +3 -1
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/suite/capturing-context.d.ts +19 -0
- package/dist/commands/suite/capturing-context.d.ts.map +1 -0
- package/dist/commands/suite/capturing-context.js +62 -0
- package/dist/commands/suite/capturing-context.js.map +1 -0
- package/dist/commands/suite/orchestrator.d.ts +12 -0
- package/dist/commands/suite/orchestrator.d.ts.map +1 -0
- package/dist/commands/suite/orchestrator.js +216 -0
- package/dist/commands/suite/orchestrator.js.map +1 -0
- package/dist/commands/suite/suite-add.d.ts +18 -0
- package/dist/commands/suite/suite-add.d.ts.map +1 -0
- package/dist/commands/suite/suite-add.js +130 -0
- package/dist/commands/suite/suite-add.js.map +1 -0
- package/dist/commands/suite/suite-command-specs.d.ts +4 -0
- package/dist/commands/suite/suite-command-specs.d.ts.map +1 -0
- package/dist/commands/suite/suite-command-specs.js +150 -0
- package/dist/commands/suite/suite-command-specs.js.map +1 -0
- package/dist/commands/suite/validate-suite.d.ts +21 -0
- package/dist/commands/suite/validate-suite.d.ts.map +1 -0
- package/dist/commands/suite/validate-suite.js +89 -0
- package/dist/commands/suite/validate-suite.js.map +1 -0
- package/dist/commands/tools/list.d.ts.map +1 -1
- package/dist/commands/tools/list.js +54 -31
- package/dist/commands/tools/list.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/report-compose.js +2 -2
- package/dist/report-compose.js.map +1 -1
- package/dist/ui/result-to-view.d.ts.map +1 -1
- package/dist/ui/result-to-view.js +22 -0
- package/dist/ui/result-to-view.js.map +1 -1
- package/dist/ui/views/misc-views.d.ts.map +1 -1
- package/dist/ui/views/misc-views.js +30 -7
- package/dist/ui/views/misc-views.js.map +1 -1
- package/dist/ui/views/suite-views.d.ts +6 -0
- package/dist/ui/views/suite-views.d.ts.map +1 -0
- package/dist/ui/views/suite-views.js +70 -0
- package/dist/ui/views/suite-views.js.map +1 -0
- package/dist/ui/views/tools-views.d.ts.map +1 -1
- package/dist/ui/views/tools-views.js +2 -0
- package/dist/ui/views/tools-views.js.map +1 -1
- package/package.json +34 -33
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* artifact-retention — host-owned pruning of the per-tool artifact store.
|
|
3
|
+
*
|
|
4
|
+
* The host writes every scanner/baseline/catalog artifact through the
|
|
5
|
+
* `writeArtifact` seam into `<project>/.runtime/artifacts/<tool>/<runId>/<name>`
|
|
6
|
+
* (the substrate composes the `<runId>` segment; ADR-0090 Phase-0 decision 1).
|
|
7
|
+
* Unbounded, that store would grow one run-dir per invocation forever. This
|
|
8
|
+
* helper keeps the N most-recent run-dirs per tool and removes the rest.
|
|
9
|
+
*
|
|
10
|
+
* A separate, pure-IO testable unit (mirroring `atomic-artifact-write.ts` vs
|
|
11
|
+
* `artifact-seams.ts`): the write seam calls it after a successful artifact
|
|
12
|
+
* write, gated on the target living inside the artifact store. Every failure
|
|
13
|
+
* path is defensive — a prune problem must NEVER fail the run, so nothing here
|
|
14
|
+
* throws (the seam additionally wraps the call).
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Default number of per-tool run-dirs retained when `cli.artifacts.keep` is not
|
|
18
|
+
* set in `opensip-cli.config.yml`. MUST match the Zod default declared on
|
|
19
|
+
* `cliConfigSchema.artifacts.keep` (in `@opensip-cli/config`); kept here as a
|
|
20
|
+
* literal because the config layer cannot import from the cli layer.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEFAULT_ARTIFACT_RETENTION_KEEP = 10;
|
|
23
|
+
/**
|
|
24
|
+
* In-flight grace window (A12): a run-dir whose mtime is within this many ms of
|
|
25
|
+
* `now` is NEVER evicted, regardless of its rank past `keep`.
|
|
26
|
+
*
|
|
27
|
+
* A slow CONCURRENT same-tool run creates its dir at scan start and only appends
|
|
28
|
+
* to the report inside it — directory mtime is set at creation and report appends
|
|
29
|
+
* do NOT bump it — so under load that dir can rank below `keep` while the peer is
|
|
30
|
+
* still scanning. A naive rank-only prune would `rmSync` it mid-scan, faulting the
|
|
31
|
+
* peer with a spurious `artifactValid=false`. The window MUST be >= the scanner
|
|
32
|
+
* process budget (`DEFAULT_TIMEOUT_MS` = 300_000 ms in the substrate run loop): a
|
|
33
|
+
* run cannot legitimately be in flight longer than its timeout, so any dir older
|
|
34
|
+
* than this is guaranteed finished and safe to prune. Kept a literal (with a
|
|
35
|
+
* margin over the substrate timeout) because the cli layer must not import the
|
|
36
|
+
* substrate; the comment is the sync point.
|
|
37
|
+
*/
|
|
38
|
+
export declare const ARTIFACT_INFLIGHT_GRACE_MS: number;
|
|
39
|
+
/** Options for {@link pruneArtifactRetention}'s in-flight-safety floor (A12). */
|
|
40
|
+
export interface PruneRetentionOptions {
|
|
41
|
+
/** `Date.now()` by default; injectable for deterministic tests. */
|
|
42
|
+
readonly now?: number;
|
|
43
|
+
/** The current run's dir name (== `runId`) — never pruned even if it ranks low. */
|
|
44
|
+
readonly currentRunId?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Prune `<artifactsDir>/<tool>` down to the `keep` most-recent run-dirs.
|
|
48
|
+
*
|
|
49
|
+
* Run-dirs are ordered newest-first by mtime (tie-broken by name, descending,
|
|
50
|
+
* for determinism); everything past the first `keep` is removed
|
|
51
|
+
* (`rmSync({ recursive: true, force: true })`). Defensive throughout:
|
|
52
|
+
* - missing tool dir → no-op;
|
|
53
|
+
* - `keep <= 0` (or non-finite) → treated as disabled, no-op;
|
|
54
|
+
* - a failed removal is swallowed (best-effort) and never propagated.
|
|
55
|
+
*
|
|
56
|
+
* A12 in-flight safety: a dir is RANK-INDEPENDENTLY retained when it is the
|
|
57
|
+
* current run's own dir (`opts.currentRunId`) or its mtime is within
|
|
58
|
+
* {@link ARTIFACT_INFLIGHT_GRACE_MS} of `now` — a peer run that could still be
|
|
59
|
+
* scanning is never deleted out from under it, regardless of how it ranks.
|
|
60
|
+
*/
|
|
61
|
+
export declare function pruneArtifactRetention(tool: string, artifactsDir: string, keep: number, opts?: PruneRetentionOptions): void;
|
|
62
|
+
//# sourceMappingURL=artifact-retention.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-retention.d.ts","sourceRoot":"","sources":["../../src/bootstrap/artifact-retention.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,0BAA0B,QAAgB,CAAC;AAExD,iFAAiF;AACjF,MAAM,WAAW,qBAAqB;IACpC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AA+CD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,qBAA0B,GAC/B,IAAI,CAeN"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* artifact-retention — host-owned pruning of the per-tool artifact store.
|
|
3
|
+
*
|
|
4
|
+
* The host writes every scanner/baseline/catalog artifact through the
|
|
5
|
+
* `writeArtifact` seam into `<project>/.runtime/artifacts/<tool>/<runId>/<name>`
|
|
6
|
+
* (the substrate composes the `<runId>` segment; ADR-0090 Phase-0 decision 1).
|
|
7
|
+
* Unbounded, that store would grow one run-dir per invocation forever. This
|
|
8
|
+
* helper keeps the N most-recent run-dirs per tool and removes the rest.
|
|
9
|
+
*
|
|
10
|
+
* A separate, pure-IO testable unit (mirroring `atomic-artifact-write.ts` vs
|
|
11
|
+
* `artifact-seams.ts`): the write seam calls it after a successful artifact
|
|
12
|
+
* write, gated on the target living inside the artifact store. Every failure
|
|
13
|
+
* path is defensive — a prune problem must NEVER fail the run, so nothing here
|
|
14
|
+
* throws (the seam additionally wraps the call).
|
|
15
|
+
*/
|
|
16
|
+
import { readdirSync, rmSync, statSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
/**
|
|
19
|
+
* Default number of per-tool run-dirs retained when `cli.artifacts.keep` is not
|
|
20
|
+
* set in `opensip-cli.config.yml`. MUST match the Zod default declared on
|
|
21
|
+
* `cliConfigSchema.artifacts.keep` (in `@opensip-cli/config`); kept here as a
|
|
22
|
+
* literal because the config layer cannot import from the cli layer.
|
|
23
|
+
*/
|
|
24
|
+
export const DEFAULT_ARTIFACT_RETENTION_KEEP = 10;
|
|
25
|
+
/**
|
|
26
|
+
* In-flight grace window (A12): a run-dir whose mtime is within this many ms of
|
|
27
|
+
* `now` is NEVER evicted, regardless of its rank past `keep`.
|
|
28
|
+
*
|
|
29
|
+
* A slow CONCURRENT same-tool run creates its dir at scan start and only appends
|
|
30
|
+
* to the report inside it — directory mtime is set at creation and report appends
|
|
31
|
+
* do NOT bump it — so under load that dir can rank below `keep` while the peer is
|
|
32
|
+
* still scanning. A naive rank-only prune would `rmSync` it mid-scan, faulting the
|
|
33
|
+
* peer with a spurious `artifactValid=false`. The window MUST be >= the scanner
|
|
34
|
+
* process budget (`DEFAULT_TIMEOUT_MS` = 300_000 ms in the substrate run loop): a
|
|
35
|
+
* run cannot legitimately be in flight longer than its timeout, so any dir older
|
|
36
|
+
* than this is guaranteed finished and safe to prune. Kept a literal (with a
|
|
37
|
+
* margin over the substrate timeout) because the cli layer must not import the
|
|
38
|
+
* substrate; the comment is the sync point.
|
|
39
|
+
*/
|
|
40
|
+
export const ARTIFACT_INFLIGHT_GRACE_MS = 6 * 60 * 1000;
|
|
41
|
+
/**
|
|
42
|
+
* Order run-dirs newest-first by mtime, with a deterministic name tie-break
|
|
43
|
+
* (descending) so equal-mtime dirs prune in a stable order.
|
|
44
|
+
*/
|
|
45
|
+
function byMostRecent(a, b) {
|
|
46
|
+
if (a.mtimeMs !== b.mtimeMs)
|
|
47
|
+
return b.mtimeMs - a.mtimeMs;
|
|
48
|
+
if (a.name === b.name)
|
|
49
|
+
return 0;
|
|
50
|
+
return a.name < b.name ? 1 : -1;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* List the immediate child directories of `<artifactsDir>/<tool>` as candidate
|
|
54
|
+
* per-run dirs, each stamped with its mtime. A missing dir (or a path that is a
|
|
55
|
+
* file, not a dir) yields `[]` — nothing to prune. Non-directory entries (a tool
|
|
56
|
+
* writing a file directly under `<tool>/`) are ignored.
|
|
57
|
+
*/
|
|
58
|
+
function listRunDirs(toolDir) {
|
|
59
|
+
let entries;
|
|
60
|
+
try {
|
|
61
|
+
entries = readdirSync(toolDir, { withFileTypes: true });
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// @swallow-ok missing/!dir tool subdir → nothing to prune
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
return entries
|
|
68
|
+
.filter((entry) => entry.isDirectory())
|
|
69
|
+
.map((entry) => {
|
|
70
|
+
const full = join(toolDir, entry.name);
|
|
71
|
+
let mtimeMs = 0;
|
|
72
|
+
try {
|
|
73
|
+
mtimeMs = statSync(full).mtimeMs;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// @swallow-ok unreadable run dir sorts oldest (mtime 0) so it is pruned first
|
|
77
|
+
mtimeMs = 0;
|
|
78
|
+
}
|
|
79
|
+
return { name: entry.name, full, mtimeMs };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Prune `<artifactsDir>/<tool>` down to the `keep` most-recent run-dirs.
|
|
84
|
+
*
|
|
85
|
+
* Run-dirs are ordered newest-first by mtime (tie-broken by name, descending,
|
|
86
|
+
* for determinism); everything past the first `keep` is removed
|
|
87
|
+
* (`rmSync({ recursive: true, force: true })`). Defensive throughout:
|
|
88
|
+
* - missing tool dir → no-op;
|
|
89
|
+
* - `keep <= 0` (or non-finite) → treated as disabled, no-op;
|
|
90
|
+
* - a failed removal is swallowed (best-effort) and never propagated.
|
|
91
|
+
*
|
|
92
|
+
* A12 in-flight safety: a dir is RANK-INDEPENDENTLY retained when it is the
|
|
93
|
+
* current run's own dir (`opts.currentRunId`) or its mtime is within
|
|
94
|
+
* {@link ARTIFACT_INFLIGHT_GRACE_MS} of `now` — a peer run that could still be
|
|
95
|
+
* scanning is never deleted out from under it, regardless of how it ranks.
|
|
96
|
+
*/
|
|
97
|
+
export function pruneArtifactRetention(tool, artifactsDir, keep, opts = {}) {
|
|
98
|
+
if (!Number.isFinite(keep) || keep <= 0)
|
|
99
|
+
return;
|
|
100
|
+
const now = opts.now ?? Date.now();
|
|
101
|
+
const toolDir = join(artifactsDir, tool);
|
|
102
|
+
const runDirs = listRunDirs(toolDir).sort(byMostRecent);
|
|
103
|
+
for (const stale of runDirs.slice(keep)) {
|
|
104
|
+
// A12: never evict a possibly-in-flight peer run even when it ranks past keep.
|
|
105
|
+
if (opts.currentRunId !== undefined && stale.name === opts.currentRunId)
|
|
106
|
+
continue;
|
|
107
|
+
if (now - stale.mtimeMs < ARTIFACT_INFLIGHT_GRACE_MS)
|
|
108
|
+
continue;
|
|
109
|
+
try {
|
|
110
|
+
rmSync(stale.full, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// @swallow-ok best-effort prune; a removal failure must not fail the run
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=artifact-retention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-retention.js","sourceRoot":"","sources":["../../src/bootstrap/artifact-retention.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
* Host-owned general artifact write seam.
|
|
3
3
|
*/
|
|
4
4
|
import { type Logger } from '@opensip-cli/core';
|
|
5
|
+
/** Options for {@link createWriteArtifactSeam}. */
|
|
6
|
+
export interface WriteArtifactSeamOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Number of per-tool run-dirs to retain under `.runtime/artifacts/<tool>/`
|
|
9
|
+
* (`cli.artifacts.keep`). Undefined → {@link DEFAULT_ARTIFACT_RETENTION_KEEP}.
|
|
10
|
+
* The host prunes the store after each write whose target lives inside it.
|
|
11
|
+
*/
|
|
12
|
+
readonly retentionKeep?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build the public `cli.ensureArtifactDir(artifactPath)` implementation
|
|
16
|
+
* (ADR-0091; External Tool Adapter A1/A7).
|
|
17
|
+
*
|
|
18
|
+
* Creates `dirname(artifactPath)` recursively at {@link ARTIFACT_DIR_MODE}. This
|
|
19
|
+
* is the HOST seam a tool calls BEFORE handing the path to an external scanner as
|
|
20
|
+
* its output target, so the per-run dir exists for a scanner that does a bare
|
|
21
|
+
* `open(path, 'w')`. Idempotent (`recursive: true`); a pre-existing dir keeps its
|
|
22
|
+
* mode (only freshly-created dirs get `0o700`, which is exactly the per-run dir).
|
|
23
|
+
*/
|
|
24
|
+
export declare function createEnsureArtifactDirSeam(logger?: Logger): (artifactPath: string) => Promise<void>;
|
|
5
25
|
/** Build the public `cli.writeArtifact(path, bytes)` implementation. */
|
|
6
|
-
export declare function createWriteArtifactSeam(logger?: Logger): (path: string, bytes: string) => Promise<void>;
|
|
26
|
+
export declare function createWriteArtifactSeam(logger?: Logger, options?: WriteArtifactSeamOptions): (path: string, bytes: string) => Promise<void>;
|
|
7
27
|
//# sourceMappingURL=artifact-seams.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-seams.d.ts","sourceRoot":"","sources":["../../src/bootstrap/artifact-seams.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,
|
|
1
|
+
{"version":3,"file":"artifact-seams.d.ts","sourceRoot":"","sources":["../../src/bootstrap/artifact-seams.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAQL,KAAK,MAAM,EAEZ,MAAM,mBAAmB,CAAC;AAM3B,mDAAmD;AACnD,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAwED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,GAAE,MAAsB,GAC7B,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAczC;AAED,wEAAwE;AACxE,wBAAgB,uBAAuB,CACrC,MAAM,GAAE,MAAsB,EAC9B,OAAO,GAAE,wBAA6B,GACrC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CA4BhD"}
|
|
@@ -1,11 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Host-owned general artifact write seam.
|
|
3
3
|
*/
|
|
4
|
-
import { statSync } from 'node:fs';
|
|
5
|
-
import { basename, resolve } from 'node:path';
|
|
6
|
-
import { ConfigurationError, currentScope, SystemError, ToolError, logger as defaultLogger, } from '@opensip-cli/core';
|
|
4
|
+
import { mkdirSync, statSync } from 'node:fs';
|
|
5
|
+
import { basename, dirname, relative, resolve, sep } from 'node:path';
|
|
6
|
+
import { ConfigurationError, currentScope, isPathInside, resolveProjectPaths, SystemError, ToolError, logger as defaultLogger, } from '@opensip-cli/core';
|
|
7
|
+
import { DEFAULT_ARTIFACT_RETENTION_KEEP, pruneArtifactRetention } from './artifact-retention.js';
|
|
7
8
|
import { writeArtifactAtomically } from './atomic-artifact-write.js';
|
|
8
9
|
import { resolveStateLockPolicy } from './state-lock-policy.js';
|
|
10
|
+
/**
|
|
11
|
+
* After a successful artifact write, prune the per-tool run-dirs IFF the target
|
|
12
|
+
* lives inside the project's host-owned artifact store
|
|
13
|
+
* (`.runtime/artifacts/<tool>/<runId>/<name>`). Generic writes outside the store
|
|
14
|
+
* (e.g. a graph `--catalog-output` to an arbitrary path) skip pruning naturally.
|
|
15
|
+
*
|
|
16
|
+
* Fully defensive: a no-project run (no `projectContext`) skips; an unreadable
|
|
17
|
+
* store skips; ANY prune error is logged at debug and never thrown out of the
|
|
18
|
+
* write seam (a retention problem must not fail the run).
|
|
19
|
+
*/
|
|
20
|
+
function maybePruneArtifactStore(target, scope, retentionKeep, log) {
|
|
21
|
+
try {
|
|
22
|
+
const projectRoot = scope?.projectContext?.projectRoot;
|
|
23
|
+
if (projectRoot === undefined)
|
|
24
|
+
return; // project-less run: no store to prune
|
|
25
|
+
const { artifactsDir } = resolveProjectPaths(projectRoot);
|
|
26
|
+
if (!isPathInside(target, artifactsDir))
|
|
27
|
+
return; // not an artifact-store write
|
|
28
|
+
// The dir immediately under the store is the `<tool>` segment; the substrate
|
|
29
|
+
// composes `<tool>/<runId>/<name>` underneath it.
|
|
30
|
+
const tool = relative(artifactsDir, target).split(sep)[0];
|
|
31
|
+
if (tool === undefined || tool === '' || tool === '..')
|
|
32
|
+
return;
|
|
33
|
+
// A12: pass the current run id so its own dir is never pruned, and let the
|
|
34
|
+
// grace-window floor protect concurrent in-flight peers.
|
|
35
|
+
pruneArtifactRetention(tool, artifactsDir, retentionKeep, { currentRunId: scope?.runId });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
log.debug({
|
|
39
|
+
evt: 'state.artifact.retention.prune.skipped',
|
|
40
|
+
module: 'cli:artifact-seams',
|
|
41
|
+
error: error instanceof Error ? error.message : String(error),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
9
45
|
/**
|
|
10
46
|
* @throws {ConfigurationError} When the target already exists as a directory.
|
|
11
47
|
* @throws {Error} When filesystem metadata cannot be read for another reason.
|
|
@@ -27,8 +63,41 @@ function assertWritableFileTarget(path) {
|
|
|
27
63
|
throw error;
|
|
28
64
|
}
|
|
29
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Owner-only mode for the host-owned per-run artifact directory (A7).
|
|
68
|
+
*
|
|
69
|
+
* The dir holds a scanner's raw report, which can carry live secrets/matches.
|
|
70
|
+
* Creating it `0o700` means even a report file the scanner writes at its default
|
|
71
|
+
* umask (typically 0644) is not world-readable, because no other user can
|
|
72
|
+
* traverse the parent dir — closing the window between the scanner's first write
|
|
73
|
+
* and the host's `0o600` re-write through {@link createWriteArtifactSeam}.
|
|
74
|
+
*/
|
|
75
|
+
const ARTIFACT_DIR_MODE = 0o700;
|
|
76
|
+
/**
|
|
77
|
+
* Build the public `cli.ensureArtifactDir(artifactPath)` implementation
|
|
78
|
+
* (ADR-0091; External Tool Adapter A1/A7).
|
|
79
|
+
*
|
|
80
|
+
* Creates `dirname(artifactPath)` recursively at {@link ARTIFACT_DIR_MODE}. This
|
|
81
|
+
* is the HOST seam a tool calls BEFORE handing the path to an external scanner as
|
|
82
|
+
* its output target, so the per-run dir exists for a scanner that does a bare
|
|
83
|
+
* `open(path, 'w')`. Idempotent (`recursive: true`); a pre-existing dir keeps its
|
|
84
|
+
* mode (only freshly-created dirs get `0o700`, which is exactly the per-run dir).
|
|
85
|
+
*/
|
|
86
|
+
export function createEnsureArtifactDirSeam(logger = defaultLogger) {
|
|
87
|
+
return (artifactPath) => Promise.resolve().then(() => {
|
|
88
|
+
const dir = dirname(resolve(artifactPath));
|
|
89
|
+
try {
|
|
90
|
+
mkdirSync(dir, { recursive: true, mode: ARTIFACT_DIR_MODE });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new SystemError(`ensureArtifactDir failed for '${dir}': ${error instanceof Error ? error.message : String(error)}`, { code: 'SYSTEM.ARTIFACT_DIR_FAILED' });
|
|
94
|
+
}
|
|
95
|
+
logger.debug({ evt: 'state.artifact.dir.ensured', module: 'cli:artifact-seams', dir });
|
|
96
|
+
});
|
|
97
|
+
}
|
|
30
98
|
/** Build the public `cli.writeArtifact(path, bytes)` implementation. */
|
|
31
|
-
export function createWriteArtifactSeam(logger = defaultLogger) {
|
|
99
|
+
export function createWriteArtifactSeam(logger = defaultLogger, options = {}) {
|
|
100
|
+
const retentionKeep = options.retentionKeep ?? DEFAULT_ARTIFACT_RETENTION_KEEP;
|
|
32
101
|
return (path, bytes) => Promise.resolve().then(() => {
|
|
33
102
|
const target = resolve(path);
|
|
34
103
|
const scope = currentScope();
|
|
@@ -48,6 +117,9 @@ export function createWriteArtifactSeam(logger = defaultLogger) {
|
|
|
48
117
|
throw error;
|
|
49
118
|
throw new SystemError(`writeArtifact failed for '${target}': ${error instanceof Error ? error.message : String(error)}`, { code: 'SYSTEM.ARTIFACT_WRITE_FAILED' });
|
|
50
119
|
}
|
|
120
|
+
// Retention runs AFTER the write succeeds and covers worker writes too (the
|
|
121
|
+
// worker RPC routes through this same host seam). Never fails the run.
|
|
122
|
+
maybePruneArtifactStore(target, scope, retentionKeep, scope?.logger ?? logger);
|
|
51
123
|
});
|
|
52
124
|
}
|
|
53
125
|
//# sourceMappingURL=artifact-seams.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-seams.js","sourceRoot":"","sources":["../../src/bootstrap/artifact-seams.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"artifact-seams.js","sourceRoot":"","sources":["../../src/bootstrap/artifact-seams.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atomic-artifact-write.d.ts","sourceRoot":"","sources":["../../src/bootstrap/atomic-artifact-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"atomic-artifact-write.d.ts","sourceRoot":"","sources":["../../src/bootstrap/atomic-artifact-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,EAIL,KAAK,MAAM,EACX,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,oBAAoB,GACxB,IAAI,CA4DN"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Owns SARIF and baseline fingerprint JSON exports at the CLI composition root.
|
|
5
5
|
*/
|
|
6
|
-
import { closeSync, mkdirSync, openSync, renameSync, unlinkSync, writeSync } from 'node:fs';
|
|
6
|
+
import { chmodSync, closeSync, mkdirSync, openSync, renameSync, unlinkSync, writeSync, } from 'node:fs';
|
|
7
7
|
import { dirname, join } from 'node:path';
|
|
8
8
|
import { currentScope, generateUUID, withFileLock, } from '@opensip-cli/core';
|
|
9
9
|
import { createStateLockEventBridge } from './state-lock-policy.js';
|
|
@@ -26,7 +26,11 @@ export function writeArtifactAtomically(targetPath, bytes, ctx) {
|
|
|
26
26
|
onEvent: createStateLockEventBridge(ctx.logger),
|
|
27
27
|
}, () => {
|
|
28
28
|
try {
|
|
29
|
-
|
|
29
|
+
// Owner-only read/write (0600). Artifacts can carry findings (and, for
|
|
30
|
+
// external scanners, redacted-but-sensitive context), so they are never
|
|
31
|
+
// group/world-readable. The open mode is umask-masked on some platforms,
|
|
32
|
+
// so we also chmod the rename target below (belt-and-suspenders).
|
|
33
|
+
const fd = openSync(tempPath, 'w', 0o600);
|
|
30
34
|
try {
|
|
31
35
|
writeSync(fd, bytes);
|
|
32
36
|
}
|
|
@@ -34,6 +38,7 @@ export function writeArtifactAtomically(targetPath, bytes, ctx) {
|
|
|
34
38
|
closeSync(fd);
|
|
35
39
|
}
|
|
36
40
|
renameSync(tempPath, targetPath);
|
|
41
|
+
chmodSync(targetPath, 0o600);
|
|
37
42
|
ctx.logger.info({
|
|
38
43
|
evt: 'state.artifact.write.complete',
|
|
39
44
|
module: 'cli:atomic-artifact-write',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atomic-artifact-write.js","sourceRoot":"","sources":["../../src/bootstrap/atomic-artifact-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"atomic-artifact-write.js","sourceRoot":"","sources":["../../src/bootstrap/atomic-artifact-write.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAUpE;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAkB,EAClB,KAAa,EACb,GAAyB;IAEzB,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,GAAG,UAAU,gBAAgB,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,YAAY,EAAE,MAAM,CAAC,CAAC;IAErD,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,YAAY,CACV,QAAQ,EACR;QACE,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,QAAQ,EAAE,UAAU;QACpB,SAAS,EAAE,gBAAgB;QAC3B,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,OAAO,EAAE,0BAA0B,CAAC,GAAG,CAAC,MAAM,CAAC;KAChD,EACD,GAAG,EAAE;QACH,IAAI,CAAC;YACH,uEAAuE;YACvE,wEAAwE;YACxE,yEAAyE;YACzE,kEAAkE;YAClE,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YAC1C,IAAI,CAAC;gBACH,SAAS,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;YACvB,CAAC;oBAAS,CAAC;gBACT,SAAS,CAAC,EAAE,CAAC,CAAC;YAChB,CAAC;YACD,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YACjC,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;gBACd,GAAG,EAAE,+BAA+B;gBACpC,MAAM,EAAE,2BAA2B;gBACnC,SAAS,EAAE,gBAAgB;aAC5B,CAAC,CAAC;YACH,yEAAyE;YACzE,yEAAyE;YACzE,YAAY,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,+BAA+B,EAAE;gBACrF,SAAS,EAAE,gBAAgB;aAC5B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC;gBACH,UAAU,CAAC,QAAQ,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,iBAAiB;YACnB,CAAC;YACD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;gBACf,GAAG,EAAE,4BAA4B;gBACjC,MAAM,EAAE,2BAA2B;gBACnC,KAAK,EAAE,OAAO;aACf,CAAC,CAAC;YACH,YAAY,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,EAAE,4BAA4B,EAAE;gBACnF,SAAS,EAAE,gBAAgB;aAC5B,CAAC,CAAC;YACH,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -43,6 +43,19 @@ export declare function runWorkerSpec(args: {
|
|
|
43
43
|
readonly cliScript?: string;
|
|
44
44
|
readonly timeoutMs?: number;
|
|
45
45
|
}): Promise<ToolCommandResult>;
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Build a structured supervisor-side dispatch error, logged with its failure
|
|
48
|
+
* class. `code` is the worker error's canonical exit-class `ToolErrorCode` (when
|
|
49
|
+
* the worker threw a typed `ToolError`); it preserves the typed exit code across
|
|
50
|
+
* the fork boundary, which flattens the prototype chain. Reconstruction order:
|
|
51
|
+
*
|
|
52
|
+
* 1. `config-invalid` → `ConfigurationError` (exit 2). The frozen config
|
|
53
|
+
* contract — set for a thrown `ConfigurationError` (binary-not-found /
|
|
54
|
+
* no-project / baseline-missing) AND for the deep-config-pass failure.
|
|
55
|
+
* 2. a recognized canonical `code` → that subclass (NotFound → 3, Network → 4,
|
|
56
|
+
* Validation/Configuration → 2, PluginIncompatible → 5, Timeout → 1).
|
|
57
|
+
* 3. otherwise → `SystemError` (exit 1) — genuine worker/transport faults
|
|
58
|
+
* (`spawn` / `exit_nonzero` / `rpc_flood` / `timeout` / `ipc_error`).
|
|
59
|
+
*/
|
|
60
|
+
export declare function dispatchError(spec: ToolCommandWorkerSpec, message: string, failureClass: string, stderrTail?: string, code?: string): ToolError;
|
|
48
61
|
//# sourceMappingURL=dispatch-fork-core.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-fork-core.d.ts","sourceRoot":"","sources":["../../src/bootstrap/dispatch-fork-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,OAAO,
|
|
1
|
+
{"version":3,"file":"dispatch-fork-core.d.ts","sourceRoot":"","sources":["../../src/bootstrap/dispatch-fork-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,OAAO,EAQL,KAAK,SAAS,EACd,KAAK,cAAc,EAEpB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAGV,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,kCAAkC,CAAC;AAE1C,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,SAAU,CAAC;AAEnD,+EAA+E;AAC/E,eAAO,MAAM,iBAAiB,0BAA0B,CAAC;AAQzD,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CASpE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAoB7B;AAqKD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,GACZ,SAAS,CAyBX"}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
25
25
|
import { tmpdir } from 'node:os';
|
|
26
26
|
import { join } from 'node:path';
|
|
27
|
-
import { ConfigurationError, currentScope, currentTraceparent, forkAndSettle, getWorkerLimits, SystemError, } from '@opensip-cli/core';
|
|
27
|
+
import { ConfigurationError, currentScope, currentTraceparent, forkAndSettle, getWorkerLimits, SystemError, toolErrorFromCanonicalCode, } from '@opensip-cli/core';
|
|
28
28
|
import { buildExternalWorkerChildEnv } from './build-external-worker-child-env.js';
|
|
29
29
|
import { BOOTSTRAP_MODULE } from './constants.js';
|
|
30
30
|
import { handleHostRpc } from './dispatch-host-rpc-handler.js';
|
|
@@ -176,8 +176,21 @@ function specLabel(spec) {
|
|
|
176
176
|
/* v8 ignore next -- defensive: a valid spec always carries a commandName OR a hook (the worker entry rejects one that has neither as bad-spec); the 'unknown' fallback is structurally unreachable. */
|
|
177
177
|
return spec.commandName ?? spec.hook ?? 'unknown';
|
|
178
178
|
}
|
|
179
|
-
/**
|
|
180
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Build a structured supervisor-side dispatch error, logged with its failure
|
|
181
|
+
* class. `code` is the worker error's canonical exit-class `ToolErrorCode` (when
|
|
182
|
+
* the worker threw a typed `ToolError`); it preserves the typed exit code across
|
|
183
|
+
* the fork boundary, which flattens the prototype chain. Reconstruction order:
|
|
184
|
+
*
|
|
185
|
+
* 1. `config-invalid` → `ConfigurationError` (exit 2). The frozen config
|
|
186
|
+
* contract — set for a thrown `ConfigurationError` (binary-not-found /
|
|
187
|
+
* no-project / baseline-missing) AND for the deep-config-pass failure.
|
|
188
|
+
* 2. a recognized canonical `code` → that subclass (NotFound → 3, Network → 4,
|
|
189
|
+
* Validation/Configuration → 2, PluginIncompatible → 5, Timeout → 1).
|
|
190
|
+
* 3. otherwise → `SystemError` (exit 1) — genuine worker/transport faults
|
|
191
|
+
* (`spawn` / `exit_nonzero` / `rpc_flood` / `timeout` / `ipc_error`).
|
|
192
|
+
*/
|
|
193
|
+
export function dispatchError(spec, message, failureClass, stderrTail, code) {
|
|
181
194
|
const label = specLabel(spec);
|
|
182
195
|
currentScope()?.logger.error({
|
|
183
196
|
evt: 'cli.tool.dispatch_failed',
|
|
@@ -193,6 +206,11 @@ export function dispatchError(spec, message, failureClass, stderrTail) {
|
|
|
193
206
|
stderrTail,
|
|
194
207
|
});
|
|
195
208
|
}
|
|
209
|
+
if (code !== undefined) {
|
|
210
|
+
const rebuilt = toolErrorFromCanonicalCode(code, message, { code, failureClass, stderrTail });
|
|
211
|
+
if (rebuilt !== undefined)
|
|
212
|
+
return rebuilt;
|
|
213
|
+
}
|
|
196
214
|
return new SystemError(`external tool '${spec.toolId}' ${label} failed: ${message}`, {
|
|
197
215
|
code: 'SYSTEM.DISPATCH.WORKER_FAILED',
|
|
198
216
|
failureClass,
|
|
@@ -201,6 +219,6 @@ export function dispatchError(spec, message, failureClass, stderrTail) {
|
|
|
201
219
|
}
|
|
202
220
|
/** Convert a worker `error` IPC message into a logged, structured {@link ToolError}. */
|
|
203
221
|
function workerErrorToToolError(spec, msg, stderrTail) {
|
|
204
|
-
return dispatchError(spec, msg.message, msg.failureClass ?? 'ipc_error', stderrTail);
|
|
222
|
+
return dispatchError(spec, msg.message, msg.failureClass ?? 'ipc_error', stderrTail, msg.code);
|
|
205
223
|
}
|
|
206
224
|
//# sourceMappingURL=dispatch-fork-core.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-fork-core.js","sourceRoot":"","sources":["../../src/bootstrap/dispatch-fork-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,WAAW,
|
|
1
|
+
{"version":3,"file":"dispatch-fork-core.js","sourceRoot":"","sources":["../../src/bootstrap/dispatch-fork-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-host-rpc-handler.d.ts","sourceRoot":"","sources":["../../src/bootstrap/dispatch-host-rpc-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"dispatch-host-rpc-handler.d.ts","sourceRoot":"","sources":["../../src/bootstrap/dispatch-host-rpc-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAIV,cAAc,EACd,QAAQ,EACT,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAqJxD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,QAAQ,CAAC,CA4BnB"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* reply (the worker shim re-throws it into the handler) — never an unhandled
|
|
16
16
|
* host crash, never a silent no-op.
|
|
17
17
|
*/
|
|
18
|
+
import { canonicalToolErrorCode, ToolError } from '@opensip-cli/core';
|
|
18
19
|
/**
|
|
19
20
|
* The closed set of seam names the host will dispatch. The IPC `request` crosses
|
|
20
21
|
* a trust boundary (it arrives over the worker's IPC channel), so the host
|
|
@@ -26,6 +27,7 @@ const RECOGNIZED_SEAMS = new Set([
|
|
|
26
27
|
'deliverSignals',
|
|
27
28
|
'writeSarif',
|
|
28
29
|
'writeArtifact',
|
|
30
|
+
'ensureArtifactDir',
|
|
29
31
|
'saveBaseline',
|
|
30
32
|
'compareBaseline',
|
|
31
33
|
'exportBaselineSarif',
|
|
@@ -109,6 +111,9 @@ async function performHostRpc(request, ctx) {
|
|
|
109
111
|
case 'writeArtifact': {
|
|
110
112
|
return ctx.writeArtifact(request.path, request.bytes);
|
|
111
113
|
}
|
|
114
|
+
case 'ensureArtifactDir': {
|
|
115
|
+
return ctx.ensureArtifactDir(request.path);
|
|
116
|
+
}
|
|
112
117
|
case 'saveBaseline': {
|
|
113
118
|
return ctx.saveBaseline(request.tool, request.envelope);
|
|
114
119
|
}
|
|
@@ -171,6 +176,11 @@ export async function handleHostRpc(request, ctx) {
|
|
|
171
176
|
? { code: error.code }
|
|
172
177
|
: {}),
|
|
173
178
|
...(error instanceof Error && error.stack !== undefined ? { stack: error.stack } : {}),
|
|
179
|
+
// Carry the canonical exit-class code for a typed ToolError (e.g. a
|
|
180
|
+
// compareBaseline BASELINE_MISSING rejection → CONFIGURATION_ERROR) so the
|
|
181
|
+
// worker shim re-throws a TYPED error and the exit class survives the
|
|
182
|
+
// boundary instead of degrading to a plain Error → SystemError → exit 1.
|
|
183
|
+
...(error instanceof ToolError ? { toolErrorCode: canonicalToolErrorCode(error) } : {}),
|
|
174
184
|
},
|
|
175
185
|
};
|
|
176
186
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-host-rpc-handler.js","sourceRoot":"","sources":["../../src/bootstrap/dispatch-host-rpc-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"dispatch-host-rpc-handler.js","sourceRoot":"","sources":["../../src/bootstrap/dispatch-host-rpc-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -60,14 +60,16 @@ export async function loadOwningToolCapabilities(options) {
|
|
|
60
60
|
const descriptor = domain.discovery;
|
|
61
61
|
if (descriptor === undefined)
|
|
62
62
|
continue;
|
|
63
|
-
const
|
|
63
|
+
const configuredPreferences = resolveCapabilityPreferences(descriptor, pluginsConfig);
|
|
64
|
+
const explicitlyConfiguredPackages = new Set(configuredPreferences.packages);
|
|
65
|
+
const preferences = augmentBundledCapabilityPreferences(descriptor, configuredPreferences);
|
|
64
66
|
await loadCapabilityDomain({
|
|
65
67
|
registry,
|
|
66
68
|
domainId: domain.id,
|
|
67
69
|
projectDir,
|
|
68
70
|
cliDir,
|
|
69
71
|
preferences,
|
|
70
|
-
shouldLoadPackage: (pkg) => admitCapabilityPackage(descriptor, pkg),
|
|
72
|
+
shouldLoadPackage: (pkg) => admitCapabilityPackage(descriptor, pkg, explicitlyConfiguredPackages),
|
|
71
73
|
onDiagnostic: (diagnostic) => {
|
|
72
74
|
currentScope()?.bootstrapDiagnostics.record(capabilityDiscoveryToCliDiagnostic(diagnostic, domain.id, {
|
|
73
75
|
toolId: owningTool.metadata.id,
|
|
@@ -79,14 +81,19 @@ export async function loadOwningToolCapabilities(options) {
|
|
|
79
81
|
}
|
|
80
82
|
return driven;
|
|
81
83
|
}
|
|
82
|
-
function admitCapabilityPackage(descriptor, pkg) {
|
|
84
|
+
function admitCapabilityPackage(descriptor, pkg, explicitlyConfiguredPackages) {
|
|
83
85
|
if (isBundledCapabilityPack(descriptor, pkg.name)) {
|
|
84
86
|
return capabilityPackProvenancePassthrough(pkg, { admit: true });
|
|
85
87
|
}
|
|
88
|
+
if (explicitlyConfiguredPackages.has(pkg.name)) {
|
|
89
|
+
return capabilityPackProvenancePassthrough(pkg, { admit: true });
|
|
90
|
+
}
|
|
86
91
|
if (isCapabilityPackTrusted(pkg.name)) {
|
|
87
92
|
return capabilityPackProvenancePassthrough(pkg, { admit: true });
|
|
88
93
|
}
|
|
89
|
-
const
|
|
94
|
+
const configuredPackageKey = descriptor.configKeys.packages;
|
|
95
|
+
const configuredPackageHint = configuredPackageKey === undefined ? '' : ` or list it in plugins.${configuredPackageKey}`;
|
|
96
|
+
const reason = `set ${CAPABILITY_PACK_ALLOWLIST_ENV} to '${pkg.name}'${configuredPackageHint}`;
|
|
90
97
|
logger.warn({
|
|
91
98
|
evt: 'cli.capability.trust_denied',
|
|
92
99
|
module: 'cli:capability',
|