opencode-swarm 7.150.0 → 7.151.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/dist/cli/{config-doctor-96qyv31a.js → config-doctor-08zmx89c.js} +2 -2
- package/dist/cli/{core-xx0x5tfv.js → core-w0gjhw5q.js} +1 -1
- package/dist/cli/{curation-policy-nck9g765.js → curation-policy-fmvccdrg.js} +6 -6
- package/dist/cli/{curator-llm-factory-b83jsg02.js → curator-llm-factory-jmx72zhc.js} +28 -28
- package/dist/cli/{curator-frrehxxe.js → curator-twqjxden.js} +28 -28
- package/dist/cli/{evidence-summary-service-dv4bt2bx.js → evidence-summary-service-py66zgn4.js} +12 -12
- package/dist/cli/{gate-evidence-dkvs7aez.js → gate-evidence-ynhyzwsw.js} +6 -6
- package/dist/cli/{guardrail-explain-1zbk21fq.js → guardrail-explain-j9h5r8gh.js} +29 -29
- package/dist/cli/{guardrail-log-d20jewtr.js → guardrail-log-7995v5q5.js} +5 -5
- package/dist/cli/{guardrail-reset-wb3ba243.js → guardrail-reset-seextj6h.js} +28 -28
- package/dist/cli/{hive-promoter-10zv1b45.js → hive-promoter-a6xtvynw.js} +28 -28
- package/dist/cli/{index-k2sm9677.js → index-0q2mjxp2.js} +1 -1
- package/dist/cli/{index-bhg6brtw.js → index-1z7kx41f.js} +745 -8
- package/dist/cli/index-2xfffkk0.js +149 -0
- package/dist/cli/{index-mef0trex.js → index-4y7n76bn.js} +2 -1
- package/dist/cli/{index-htqs4p52.js → index-5jwbepcr.js} +1 -1
- package/dist/cli/{index-1wmd5wn1.js → index-5sh0kqf5.js} +4 -4
- package/dist/cli/{index-exn0ztsv.js → index-6zkm4p7p.js} +1 -1
- package/dist/cli/{index-x3pt7d0b.js → index-7w2b1z4j.js} +2 -2
- package/dist/cli/{index-s0xz2520.js → index-9d9p7bv2.js} +3 -3
- package/dist/cli/{index-prxrmc3b.js → index-9wpr1p2g.js} +2 -2
- package/dist/cli/{index-t54jt9cs.js → index-a2phfdsv.js} +1 -1
- package/dist/cli/{index-an922xj4.js → index-akef15kb.js} +7 -7
- package/dist/cli/{index-xggpmtfx.js → index-aw492hpn.js} +57 -40
- package/dist/cli/{index-dtmgt2xn.js → index-dvycdkhj.js} +1 -0
- package/dist/cli/{index-4sdhbxgq.js → index-f73px21b.js} +1 -1
- package/dist/cli/{index-0tn1kxej.js → index-fbj6wvew.js} +7 -7
- package/dist/cli/{index-apwcvfjt.js → index-frp2hwdg.js} +2 -2
- package/dist/cli/{index-zyv56em5.js → index-gqss5zbr.js} +3 -3
- package/dist/cli/{index-8cn6545x.js → index-hw93dwd0.js} +30 -30
- package/dist/cli/{index-n99s022c.js → index-jjpppdvb.js} +1 -1
- package/dist/cli/{index-qqs44wcp.js → index-kzdv0g9e.js} +79 -66
- package/dist/cli/{index-mnhagjvn.js → index-n35866rr.js} +4 -4
- package/dist/cli/{index-ma1p1w05.js → index-npzmqk01.js} +6 -6
- package/dist/cli/{index-w9pb72vg.js → index-qmwed766.js} +2 -2
- package/dist/cli/{index-g75rbw3e.js → index-t9h95vjd.js} +5 -5
- package/dist/cli/{index-1rpjd5na.js → index-twhhwe74.js} +1 -1
- package/dist/cli/{index-m8dn0qnm.js → index-txbd25bc.js} +1 -1
- package/dist/cli/{index-jb9tb1sd.js → index-v3gshkpz.js} +1 -1
- package/dist/cli/{index-r5djc1cc.js → index-xtyxnxf4.js} +5 -5
- package/dist/cli/{index-reknv4f9.js → index-xysb3ed7.js} +2 -2
- package/dist/cli/{index-1rww5k9e.js → index-z09fmg67.js} +4 -4
- package/dist/cli/{index-vy6q9d8j.js → index-z4bg1hv8.js} +1 -1
- package/dist/cli/index.js +28 -28
- package/dist/cli/{knowledge-escalator-pc7smwrd.js → knowledge-escalator-bqnkq3k7.js} +11 -11
- package/dist/cli/{knowledge-events-jmb3jm84.js → knowledge-events-rz3mt7gf.js} +9 -9
- package/dist/cli/{knowledge-link-mzn8x0qd.js → knowledge-link-v7hj1h8m.js} +5 -5
- package/dist/cli/{knowledge-store-wd6zh05h.js → knowledge-store-1m74b90j.js} +6 -6
- package/dist/cli/{knowledge-validator-2v6ar1wk.js → knowledge-validator-hfvhpkgk.js} +8 -8
- package/dist/cli/{pending-delegations-qzy6rnvw.js → pending-delegations-a2nmssr1.js} +3 -3
- package/dist/cli/{pr-subscriptions-q862pvz1.js → pr-subscriptions-7879nq5k.js} +3 -3
- package/dist/cli/{runner-1aygs98c.js → runner-7znestx4.js} +6 -6
- package/dist/cli/{scan-cursor-hr8e3jqj.js → scan-cursor-b36bzxkt.js} +7 -7
- package/dist/cli/{schema-g44y7s0w.js → schema-sc332es3.js} +1 -1
- package/dist/cli/{scope-persistence-0n2cv4kn.js → scope-persistence-phkj8438.js} +8 -8
- package/dist/cli/{skill-generator-0gmpxwgk.js → skill-generator-2d005nr6.js} +13 -13
- package/dist/cli/{telemetry-5deacb7w.js → telemetry-52pw5xac.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-9v8e0dz7.js → worktree-collision-ownership-p31zm5k0.js} +3 -3
- package/dist/cli/{worktree-isolation-pcr5zv0c.js → worktree-isolation-zpgkd71h.js} +28 -28
- package/dist/commands/close.d.ts +1 -0
- package/dist/commands/registry.d.ts +2 -2
- package/dist/hooks/guardrails/audit-log.d.ts +70 -19
- package/dist/hooks/guardrails/helpers.d.ts +16 -1
- package/dist/hooks/guardrails/shell-audit-store.d.ts +211 -0
- package/dist/hooks/guardrails/tool-before.d.ts +0 -2
- package/dist/index.js +339 -319
- package/dist/observability/catalog.d.ts +7 -5
- package/dist/services/guardrail-log-service.d.ts +4 -0
- package/dist/telemetry.d.ts +22 -1
- package/package.json +2 -1
- package/dist/cli/index-ggs716fj.js +0 -110
|
@@ -2,22 +2,30 @@
|
|
|
2
2
|
* Unified Guardrail Decision Audit Log
|
|
3
3
|
*
|
|
4
4
|
* Additive JSONL schema for guardrail decisions. Each append writes one
|
|
5
|
-
* validated JSON line to the
|
|
5
|
+
* validated, redacted, size-bounded JSON line to the canonical
|
|
6
|
+
* `.swarm/session/shell-audit.jsonl` store (issue #2040). Persistence itself
|
|
7
|
+
* — locking, framing, retention, compaction — is owned by
|
|
8
|
+
* `./shell-audit-store.ts`; this module owns entry validation, write-time
|
|
9
|
+
* redaction/minimization, and line shaping.
|
|
6
10
|
*
|
|
7
11
|
* The existing shell audit entry shape is preserved byte-for-byte when
|
|
8
12
|
* `type: 'shell'` is used (fields: ts, sessionID, agent, tool, command).
|
|
9
13
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* Write-time minimization (issue #2040 requirement 4/5):
|
|
15
|
+
* - Commands are redacted FIRST via `redactShellCommand` (secrets, home
|
|
16
|
+
* paths) — redaction sees the full command — then truncated to
|
|
17
|
+
* SHELL_AUDIT_LIMITS.maxCommandChars with an explicit `…[truncated]`
|
|
18
|
+
* marker. Callers cannot opt out. Redacting first keeps the correlation
|
|
19
|
+
* hash on the persisted form and minimizes secrets anywhere in the
|
|
20
|
+
* command before any bytes are selected for persistence.
|
|
21
|
+
* - Paths are redacted via `redactPath`; free-text reasons embed
|
|
22
|
+
* home-profile paths via `redactEmbeddedPaths`.
|
|
23
|
+
* - Typed command-bearing entries additionally persist `commandHash` (a
|
|
24
|
+
* 16-hex sha256 digest of the FINAL redacted command) so correlation and
|
|
25
|
+
* duplicate detection survive without reversible content. Legacy
|
|
26
|
+
* `shell` entries stay EXACTLY five fields (SC-119 pinned contract) and
|
|
27
|
+
* never carry the hash.
|
|
15
28
|
*/
|
|
16
|
-
import * as fs from 'node:fs/promises';
|
|
17
|
-
export declare const _internals: {
|
|
18
|
-
mkdir: typeof fs.mkdir;
|
|
19
|
-
appendFile: typeof fs.appendFile;
|
|
20
|
-
};
|
|
21
29
|
/**
|
|
22
30
|
* Discriminated union of guardrail decision types.
|
|
23
31
|
*
|
|
@@ -86,29 +94,72 @@ export interface SandboxSkipDecision {
|
|
|
86
94
|
skipReason: string;
|
|
87
95
|
}
|
|
88
96
|
export type GuardrailDecisionEntry = ShellDecision | FileWriteDecision | ScopeViolationDecision | DestructiveBlockDecision | SandboxWrapDecision | SandboxSkipDecision;
|
|
97
|
+
/**
|
|
98
|
+
* Redaction/content class of every persisted audit field. SINGLE SOURCE OF
|
|
99
|
+
* TRUTH: the ratchet test (`tests/unit/hooks/shell-audit-field-classes.test.ts`)
|
|
100
|
+
* enumerates the union's fields against this map — adding a decision field
|
|
101
|
+
* without declaring its class fails CI. Classes:
|
|
102
|
+
*
|
|
103
|
+
* - `timestamp` — ISO-8601 string, no free content.
|
|
104
|
+
* - `identifier` — opaque session/agent/tool identity string.
|
|
105
|
+
* - `decision-type` — closed enum discriminator.
|
|
106
|
+
* - `redacted-command` — shell command text after truncation + redaction.
|
|
107
|
+
* - `redacted-path` — filesystem path after home-profile redaction.
|
|
108
|
+
* - `enum` — closed per-type classification string.
|
|
109
|
+
* - `free-text-redacted` — producer free text after bounded truncation +
|
|
110
|
+
* embedded-path redaction.
|
|
111
|
+
* - `content-hash` — one-way digest of redacted content (correlation
|
|
112
|
+
* only; never rendered, never reversible).
|
|
113
|
+
*/
|
|
114
|
+
export type ShellAuditFieldClass = 'timestamp' | 'identifier' | 'decision-type' | 'redacted-command' | 'redacted-path' | 'enum' | 'free-text-redacted' | 'content-hash';
|
|
115
|
+
export declare const SHELL_AUDIT_FIELD_CLASSES: Readonly<Record<string, ShellAuditFieldClass>>;
|
|
116
|
+
/** 16-hex sha256 digest of the final redacted command — correlation without
|
|
117
|
+
* reversible content. Deterministic: identical redacted commands hash
|
|
118
|
+
* identically (issue #2040 edge-case: deterministic-enough-for-correlation). */
|
|
119
|
+
export declare function hashRedactedCommand(redacted: string): string;
|
|
89
120
|
/**
|
|
90
121
|
* Best-effort path redaction for audit logs.
|
|
91
122
|
*
|
|
92
123
|
* Replaces leading home/profile segments with a tilde placeholder so
|
|
93
|
-
* absolute paths do not leak user-specific directory names
|
|
124
|
+
* absolute paths do not leak user-specific directory names (POSIX
|
|
125
|
+
* `/home/<name>`, macOS `/Users/<name>`, Windows drive profiles
|
|
126
|
+
* `C:\Users\<name>` case-insensitive, and UNC profile shares).
|
|
94
127
|
*
|
|
95
|
-
* This is intentionally minimal —
|
|
96
|
-
*
|
|
128
|
+
* This is intentionally minimal on non-home paths — ordinary project paths
|
|
129
|
+
* are diagnostic content and are preserved (over-redaction guards pin it).
|
|
97
130
|
*/
|
|
98
131
|
export declare function redactPath(filePath: string): string;
|
|
132
|
+
declare function redactEmbeddedPaths(text: string): string;
|
|
133
|
+
export { redactEmbeddedPaths };
|
|
134
|
+
/**
|
|
135
|
+
* Archive-boundary re-redaction (issue #2040 requirement 4 / review round
|
|
136
|
+
* F4): re-apply the CURRENT redaction policy to one persisted decision line
|
|
137
|
+
* before the close pipeline archives it. Legacy pre-#2040 lines written with
|
|
138
|
+
* weaker redaction are normalized here so no legacy record can bypass
|
|
139
|
+
* current policy in the archived cut. Parse-safe passthrough: an
|
|
140
|
+
* unparseable line is returned unchanged (the store's corrupt accounting
|
|
141
|
+
* owns it).
|
|
142
|
+
*/
|
|
143
|
+
export declare function redactDecisionLineForArchive(line: string): string;
|
|
99
144
|
export interface AppendGuardrailDecisionOptions {
|
|
100
|
-
|
|
145
|
+
/** Project root; the store resolves `.swarm/session/shell-audit.jsonl`. */
|
|
146
|
+
directory: string;
|
|
101
147
|
enabled: boolean;
|
|
102
148
|
}
|
|
103
149
|
/**
|
|
104
|
-
* Append a validated guardrail decision entry to the JSONL audit
|
|
150
|
+
* Append a validated guardrail decision entry to the JSONL audit store.
|
|
105
151
|
*
|
|
106
|
-
* - Writes exactly one JSON line per call (`JSON.stringify(entry) + '\n'`).
|
|
107
152
|
* - Skips silently when `enabled` is false.
|
|
108
153
|
* - Skips malformed entries after debug logging; never throws.
|
|
109
|
-
* -
|
|
154
|
+
* - Truncates + redacts content at line-shaping time (caller-independent
|
|
155
|
+
* minimization); typed command entries carry a correlation hash.
|
|
156
|
+
* - Delegates persistence (lock, framing, retention, compaction) to the
|
|
157
|
+
* bounded store; store failures (locked, oversize, I/O) are caught and
|
|
158
|
+
* logged — audit failures NEVER block tool execution (issue #2040
|
|
159
|
+
* requirement 6: a guardrail block still blocks when logging fails).
|
|
160
|
+
* - `.swarm/` containment is enforced by the store's path resolution.
|
|
110
161
|
*
|
|
111
162
|
* @param entry Decision entry to persist.
|
|
112
|
-
* @param ctx Audit destination and enablement flag.
|
|
163
|
+
* @param ctx Audit destination (project root) and enablement flag.
|
|
113
164
|
*/
|
|
114
165
|
export declare function appendGuardrailDecision(entry: GuardrailDecisionEntry, ctx: AppendGuardrailDecisionOptions): Promise<void>;
|
|
@@ -33,6 +33,21 @@ export declare function hasTraversalSegments(filePath: string): boolean;
|
|
|
33
33
|
export declare function isInDeclaredScope(filePath: string, scopeEntries: string[], cwd?: string): boolean;
|
|
34
34
|
/**
|
|
35
35
|
* Redacts sensitive values from a shell command string before audit logging.
|
|
36
|
-
*
|
|
36
|
+
*
|
|
37
|
+
* Covers env-var assignments (POSIX/PowerShell `$env:`/cmd `set`), CLI flags
|
|
38
|
+
* (sensitive names, both `=`-joined and space-separated), Bearer/Basic auth,
|
|
39
|
+
* `-H` header flags, URL credentials (`scheme://user:pass@host`), well-known
|
|
40
|
+
* token VALUE shapes (OpenAI/GitHub/AWS/Slack/Google — content-based, so they
|
|
41
|
+
* fire regardless of the surrounding flag name), and long base64-like payload
|
|
42
|
+
* runs (≥80 chars with mixed case + digit — the encoded-wrapper/heredoc
|
|
43
|
+
* minimization class from issue #2040; plain hex SHAs and short payloads are
|
|
44
|
+
* deliberately NOT matched). Sensitive values are consumed through closing
|
|
45
|
+
* quotes when quoted (`KEY="two words"` redacts the whole value, not just the
|
|
46
|
+
* first word). UNC profile material (`\\server\share\user\…`) is minimized
|
|
47
|
+
* like the other home-profile families.
|
|
48
|
+
*
|
|
49
|
+
* Deterministic: identical inputs always redact identically (correlation via
|
|
50
|
+
* the audit `commandHash` relies on it). No pattern retains any reversible
|
|
51
|
+
* secret material.
|
|
37
52
|
*/
|
|
38
53
|
export declare function redactShellCommand(cmd: string): string;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shell-audit bounded store — the single append seam and bounded store for
|
|
3
|
+
* `.swarm/session/shell-audit.jsonl` (issue #2040, Observability PR 12/23).
|
|
4
|
+
*
|
|
5
|
+
* HISTORY: the guardrail decision audit was a fire-and-forget append-only
|
|
6
|
+
* JSONL with NO byte/age/count ceiling, no locking, no torn-tail handling,
|
|
7
|
+
* and one whole-file reader (`/swarm guardrail-log` read the entire file
|
|
8
|
+
* before filtering) — unbounded growth and unbounded read memory in long
|
|
9
|
+
* sessions.
|
|
10
|
+
*
|
|
11
|
+
* NOW it is a BOUNDED single-file store in the `src/events/core-events.ts`
|
|
12
|
+
* (#2039) house pattern, with SECURITY-AUDIT retention defined separately
|
|
13
|
+
* from general events (issue #2040 requirement 1):
|
|
14
|
+
*
|
|
15
|
+
* Line 1: `swarm-shell-audit-manifest` header carrying the size-bounded
|
|
16
|
+
* FOLDED aggregate (decisions compacted away: lifetime total,
|
|
17
|
+
* per-type counts ≤16 keys + "other", corrupt/dropped counters).
|
|
18
|
+
* Line 2+: raw decision JSONL — the RECENT retained window, byte-for-byte
|
|
19
|
+
* preserved (the store never normalizes producer lines; legacy
|
|
20
|
+
* 5-field shell entries stay legacy).
|
|
21
|
+
*
|
|
22
|
+
* DECISION-CLASS PRIORITY (issue #2040 requirement 2):
|
|
23
|
+
* - SECURITY class — every typed entry (file_write, scope_violation,
|
|
24
|
+
* destructive_block, sandbox_wrap, sandbox_skip): never AGE-folded.
|
|
25
|
+
* - ALLOWED class — legacy no-`type` shell entries: age-folded past
|
|
26
|
+
* allowedAgeMaxMs and held to their own tighter count cap.
|
|
27
|
+
* - The byte ceiling (activeMaxBytes) is SOVEREIGN over both classes:
|
|
28
|
+
* when it binds, the oldest lines fold regardless of class, disclosed
|
|
29
|
+
* via the folded per-type counts and shell_audit_health. Retention
|
|
30
|
+
* NEVER alters guardrail authorization — this store is write-only
|
|
31
|
+
* telemetry; enforcement decisions are computed and thrown by the
|
|
32
|
+
* guardrail hooks independently of any append succeeding.
|
|
33
|
+
*
|
|
34
|
+
* CONCURRENCY: every write (append, fold, finalize) holds the exclusive
|
|
35
|
+
* `.swarm/session/shell-audit.lock` (`wx` create, stale-broken after
|
|
36
|
+
* 5 minutes) — there are no lockless writes.
|
|
37
|
+
*
|
|
38
|
+
* LEGACY MIGRATION: header-less files are read as-is (the manifest is
|
|
39
|
+
* stripped only when line 1 parses as one); the first throttled maintenance
|
|
40
|
+
* fold rewrites them manifest-first in bounded compactMaxBytes passes;
|
|
41
|
+
* close finalize drains to convergence. A crash mid-migration leaves either
|
|
42
|
+
* form, both readable.
|
|
43
|
+
*
|
|
44
|
+
* All functions are synchronous (house pattern). The `_internals` DI seam
|
|
45
|
+
* lets tests override filesystem operations and limits without `mock.module`
|
|
46
|
+
* (AGENTS.md invariant 7). State lives exclusively under `.swarm/session/`
|
|
47
|
+
* (invariant 4) — every function takes an explicit project-root `directory`.
|
|
48
|
+
* No `bun:` imports — Node-ESM-loadable (invariant 2).
|
|
49
|
+
*/
|
|
50
|
+
import * as fs from 'node:fs';
|
|
51
|
+
export interface ShellAuditLimits {
|
|
52
|
+
/** Hard ceiling on the retained window (manifest line + decision lines). */
|
|
53
|
+
activeMaxBytes: number;
|
|
54
|
+
/** Hard ceiling on retained SECURITY-class (typed) decision lines. */
|
|
55
|
+
securityMaxEntries: number;
|
|
56
|
+
/** Hard ceiling on retained ALLOWED-class (legacy shell) decision lines. */
|
|
57
|
+
allowedMaxEntries: number;
|
|
58
|
+
/** ALLOWED-class retention age; older allowed decisions fold into the header. */
|
|
59
|
+
allowedAgeMaxMs: number;
|
|
60
|
+
/** Bounded fold work per maintenance pass (bytes of folded lines). */
|
|
61
|
+
compactMaxBytes: number;
|
|
62
|
+
/** Hard documented read bound for public reads, independent of history. */
|
|
63
|
+
readMaxBytes: number;
|
|
64
|
+
/** Appends between throttled maintenance checks. */
|
|
65
|
+
checkInterval: number;
|
|
66
|
+
/** Disk-pressure/failure warning cooldown. */
|
|
67
|
+
warnCooldownMs: number;
|
|
68
|
+
/** Upper bound for a serialized manifest header (single line). */
|
|
69
|
+
headerMaxBytes: number;
|
|
70
|
+
/** Serialized single-decision bound; larger appends fail with a typed error. */
|
|
71
|
+
maxLineBytes: number;
|
|
72
|
+
/** Raw command truncation bound applied at line-shaping time. */
|
|
73
|
+
maxCommandChars: number;
|
|
74
|
+
/** Free-text (reason) truncation bound applied at line-shaping time. */
|
|
75
|
+
maxReasonChars: number;
|
|
76
|
+
/**
|
|
77
|
+
* Hard bound on any single whole-file store read. A legacy header-less
|
|
78
|
+
* file larger than this migrates through the bounded STREAMING reader
|
|
79
|
+
* (chunked line folding) instead of being materialized whole (review
|
|
80
|
+
* round RC-2: the legacy path is exactly the file that lacks the
|
|
81
|
+
* activeMaxBytes ceiling).
|
|
82
|
+
*/
|
|
83
|
+
migrationMaxBytes: number;
|
|
84
|
+
}
|
|
85
|
+
export declare const SHELL_AUDIT_LIMITS: ShellAuditLimits;
|
|
86
|
+
export type ShellAuditDecisionClass = 'security' | 'allowed';
|
|
87
|
+
/** Size-bounded folded aggregate persisted in the manifest header. FOLDED-ONLY:
|
|
88
|
+
* decisions compacted/cut away from the retained window. Retained decisions
|
|
89
|
+
* are NOT in here. Lifetime totals = folded + retained. */
|
|
90
|
+
export interface ShellAuditFolded {
|
|
91
|
+
totalDecisions: number;
|
|
92
|
+
/** Per-discriminator counts, capped at 16 distinct keys + "other". */
|
|
93
|
+
byType: Record<string, number>;
|
|
94
|
+
corrupt: number;
|
|
95
|
+
dropped: number;
|
|
96
|
+
oldestTimestamp: string | null;
|
|
97
|
+
newestTimestamp: string | null;
|
|
98
|
+
}
|
|
99
|
+
export interface ShellAuditManifest {
|
|
100
|
+
v: 1;
|
|
101
|
+
type: 'swarm-shell-audit-manifest';
|
|
102
|
+
schemaVersion: number;
|
|
103
|
+
folded: ShellAuditFolded;
|
|
104
|
+
updatedAt: string;
|
|
105
|
+
}
|
|
106
|
+
export declare const _internals: {
|
|
107
|
+
readonly appendFileSync: typeof fs.appendFileSync;
|
|
108
|
+
readonly readFileSync: typeof fs.readFileSync;
|
|
109
|
+
readonly existsSync: typeof fs.existsSync;
|
|
110
|
+
readonly mkdirSync: typeof fs.mkdirSync;
|
|
111
|
+
readonly statSync: fs.StatSyncFn;
|
|
112
|
+
readonly renameSync: typeof fs.renameSync;
|
|
113
|
+
readonly writeFileSync: typeof fs.writeFileSync;
|
|
114
|
+
readonly unlinkSync: typeof fs.unlinkSync;
|
|
115
|
+
readonly openSync: typeof fs.openSync;
|
|
116
|
+
readonly closeSync: typeof fs.closeSync;
|
|
117
|
+
readonly readSync: typeof fs.readSync;
|
|
118
|
+
readonly now: () => number;
|
|
119
|
+
readonly limits: ShellAuditLimits;
|
|
120
|
+
readonly emitHealth: typeof emitShellAuditHealth;
|
|
121
|
+
};
|
|
122
|
+
export declare function shellAuditFilePath(directory: string): string;
|
|
123
|
+
export type ShellAuditCoverage = 'complete' | 'truncated' | 'empty';
|
|
124
|
+
/** The bounded view of the retained window. `text` is manifest-stripped
|
|
125
|
+
* decision lines in append order (never starting mid-line). */
|
|
126
|
+
export interface ShellAuditReadResult {
|
|
127
|
+
text: string;
|
|
128
|
+
truncated: boolean;
|
|
129
|
+
coverage: ShellAuditCoverage;
|
|
130
|
+
}
|
|
131
|
+
export interface ShellAuditStoreLock {
|
|
132
|
+
/** Release the lock (idempotent). */
|
|
133
|
+
release: () => void;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Acquire the exclusive store lock with a brief bounded retry, then run `fn`
|
|
137
|
+
* while holding it. Returns null when the lock stays contended for the whole
|
|
138
|
+
* retry window — callers map that onto their existing error contract (the
|
|
139
|
+
* audit append path is fail-open: catch + debug log, never block the tool).
|
|
140
|
+
*/
|
|
141
|
+
export declare function withShellAuditStoreLock<T>(directory: string, fn: () => T): T | null;
|
|
142
|
+
/** Test seam (AGENTS.md invariant 7): reset module-scoped maintenance
|
|
143
|
+
* counters between tests. Restore by calling in `afterEach`. */
|
|
144
|
+
export declare function _resetMaintenanceCounters(): void;
|
|
145
|
+
/**
|
|
146
|
+
* Bounded read of the retained window: the newest `readMaxBytes` of decision
|
|
147
|
+
* lines, manifest-stripped, in append order. `truncated` means older history
|
|
148
|
+
* exists beyond the read bound (a legacy header-less file larger than the
|
|
149
|
+
* bound, or a store mid-drain) — callers disclose it, never silently treat
|
|
150
|
+
* the window as complete history.
|
|
151
|
+
*/
|
|
152
|
+
export declare function readShellAuditTail(directory: string, maxBytes?: number): ShellAuditReadResult;
|
|
153
|
+
/** Manifest folded summary via a header-only bounded read (null when the file
|
|
154
|
+
* is absent or still header-less/legacy). */
|
|
155
|
+
export declare function getShellAuditFoldedSummary(directory: string): ShellAuditFolded | null;
|
|
156
|
+
/** Typed store-busy error — the audit append path maps it onto its existing
|
|
157
|
+
* fail-open contract (catch + debug log; never block the tool call). */
|
|
158
|
+
export declare const SHELL_AUDIT_STORE_LOCKED = "SHELL_AUDIT_STORE_LOCKED";
|
|
159
|
+
export declare const SHELL_AUDIT_LINE_TOO_LARGE = "SHELL_AUDIT_LINE_TOO_LARGE";
|
|
160
|
+
/**
|
|
161
|
+
* Append one serialized decision line to the store through the canonical
|
|
162
|
+
* seam. The caller (audit-log.ts) has already validated the entry shape and
|
|
163
|
+
* applied write-time redaction; this function owns framing, locking, and
|
|
164
|
+
* retention.
|
|
165
|
+
*
|
|
166
|
+
* - Holds the store lock for the write; re-establishes line framing when a
|
|
167
|
+
* prior crash tore the tail (newline prefix).
|
|
168
|
+
* - First write on a fresh store is atomic (manifest + one line) so a crash
|
|
169
|
+
* can never leave a torn header at line 1.
|
|
170
|
+
* - A legacy header-less file is appended to as-is; the throttled maintenance
|
|
171
|
+
* pass migrates it manifest-first in bounded passes.
|
|
172
|
+
* - Runs throttled maintenance (bounded compaction / legacy drain) every
|
|
173
|
+
* `checkInterval` appends, after the lock is released.
|
|
174
|
+
*
|
|
175
|
+
* Throws `SHELL_AUDIT_STORE_LOCKED` after bounded lock retry, or
|
|
176
|
+
* `SHELL_AUDIT_LINE_TOO_LARGE` for oversized lines — the audit append path
|
|
177
|
+
* catches both and logs non-fatally (logging failure never blocks a tool).
|
|
178
|
+
*/
|
|
179
|
+
export declare function appendShellAuditLineSync(directory: string, line: string): void;
|
|
180
|
+
/** External compaction trigger. Fail-open. */
|
|
181
|
+
export declare function compactShellAudit(directory: string): void;
|
|
182
|
+
/**
|
|
183
|
+
* Close finalize (issue #2040 requirement 7): under one lock acquisition,
|
|
184
|
+
* drain any legacy header-less file to convergence and fold the remaining
|
|
185
|
+
* window into a defined, VALIDATED cut (the atomicReplace pre-rename
|
|
186
|
+
* validation), which `/swarm close` then archives as part of the session
|
|
187
|
+
* directory copy. Fail-open: never throws to the close pipeline. Releasing
|
|
188
|
+
* the lock also unlinks it, so a stale lock file is never archived.
|
|
189
|
+
*
|
|
190
|
+
* `options.lineTransform` (review round F4): when provided, every retained
|
|
191
|
+
* decision line is passed through it before the final validated rewrite —
|
|
192
|
+
* the close pipeline supplies the CURRENT redaction policy so a legacy
|
|
193
|
+
* record with weaker pre-#2040 redaction cannot bypass it in the archived
|
|
194
|
+
* cut ("re-redact at the archive boundary").
|
|
195
|
+
*/
|
|
196
|
+
export declare function finalizeShellAuditForClose(directory: string, options?: {
|
|
197
|
+
lineTransform?: (line: string) => string;
|
|
198
|
+
}): void;
|
|
199
|
+
declare function emitShellAuditHealth(directory: string, payload: {
|
|
200
|
+
trigger: 'compaction' | 'close';
|
|
201
|
+
accepted: number;
|
|
202
|
+
compacted: number;
|
|
203
|
+
retained: number;
|
|
204
|
+
dropped: number;
|
|
205
|
+
corrupt: number;
|
|
206
|
+
oldest: string | null;
|
|
207
|
+
newest: string | null;
|
|
208
|
+
bytes: number;
|
|
209
|
+
limitBytes: number;
|
|
210
|
+
}): void;
|
|
211
|
+
export {};
|
|
@@ -23,8 +23,6 @@ export interface ToolBeforeContext {
|
|
|
23
23
|
precomputedAuthorityRules: Record<string, AgentRule>;
|
|
24
24
|
/** Global deny prefixes — apply to all agents regardless of per-agent rules */
|
|
25
25
|
universalDenyPrefixes: string[];
|
|
26
|
-
/** Shell audit log path */
|
|
27
|
-
shellAuditPath: string;
|
|
28
26
|
/** Whether shell audit logging is enabled */
|
|
29
27
|
shellAuditEnabled: boolean;
|
|
30
28
|
/** Agents allowed to use bash/shell interpreter (undefined = all allowed) */
|