opencode-swarm 7.136.3 → 7.136.5
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-g71mz50j.js → config-doctor-n3hatm9d.js} +2 -2
- package/dist/cli/{curation-policy-zhyttjpa.js → curation-policy-c4g08bg1.js} +2 -2
- package/dist/cli/{curator-36dxw38r.js → curator-jc5cc980.js} +12 -12
- package/dist/cli/{curator-llm-factory-k2a7cv41.js → curator-llm-factory-atfnhbn6.js} +12 -12
- package/dist/cli/{guardrail-explain-1k337z5d.js → guardrail-explain-v6f8efve.js} +13 -13
- package/dist/cli/{guardrail-log-xbc9bvdt.js → guardrail-log-0mrq14g9.js} +3 -3
- package/dist/cli/{hive-promoter-daxrn62p.js → hive-promoter-wyejhz8b.js} +12 -12
- package/dist/cli/{index-176zwqcq.js → index-6kd0ezgd.js} +1 -1
- package/dist/cli/{index-mgbpbs1f.js → index-84se71v1.js} +1 -1
- package/dist/cli/{index-zcrvn579.js → index-8f4346kf.js} +1 -1
- package/dist/cli/{index-pff46kfv.js → index-akc6rp3x.js} +2 -2
- package/dist/cli/{index-rtgqy0yg.js → index-bqan4y2y.js} +2 -2
- package/dist/cli/{index-0vq9gnqd.js → index-eeb35dnx.js} +1 -1
- package/dist/cli/{index-n89fdxwg.js → index-f5qs217h.js} +6 -1
- package/dist/cli/{index-brtg922w.js → index-hbzh7yyz.js} +669 -618
- package/dist/cli/{index-68tjkaqk.js → index-j7ja83v5.js} +1 -1
- package/dist/cli/{index-zwh5dewz.js → index-pyz1p8qv.js} +1 -1
- package/dist/cli/{index-wbdxmf1a.js → index-qhbr4h5n.js} +4 -4
- package/dist/cli/{index-kp5h245k.js → index-tr0ctbhq.js} +5 -5
- package/dist/cli/{index-79pgzj9a.js → index-vm05set2.js} +2 -2
- package/dist/cli/{index-g5rtcb1n.js → index-xp2pfbpq.js} +1 -1
- package/dist/cli/{index-g2kpqpvh.js → index-xvcctb2t.js} +14 -14
- package/dist/cli/{index-gj5jerzz.js → index-yj61bped.js} +3 -3
- package/dist/cli/index.js +12 -12
- package/dist/cli/{knowledge-escalator-h7fspgph.js → knowledge-escalator-2xe8z24p.js} +3 -3
- package/dist/cli/{knowledge-events-vkf7an5n.js → knowledge-events-wecrshsx.js} +1 -1
- package/dist/cli/{knowledge-store-s4976v9c.js → knowledge-store-9f74whxw.js} +1 -1
- package/dist/cli/{knowledge-validator-64ppqy4y.js → knowledge-validator-4ng7x9dr.js} +4 -4
- package/dist/cli/{scan-cursor-xbkae12h.js → scan-cursor-yzj9n225.js} +2 -2
- package/dist/cli/{schema-7jm70cab.js → schema-cr1nr1w0.js} +1 -1
- package/dist/cli/{skill-generator-8gtq1ajr.js → skill-generator-ybncj9et.js} +5 -5
- package/dist/hooks/context-budget.d.ts +8 -0
- package/dist/hooks/guardrails/file-authority.d.ts +20 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/message-priority.d.ts +62 -4
- package/dist/index.js +285 -286
- package/dist/memory/index.d.ts +1 -1
- package/dist/memory/local-jsonl-provider.d.ts +4 -1
- package/dist/memory/redaction.d.ts +91 -0
- package/dist/memory/sqlite-provider.d.ts +5 -1
- package/dist/utils/arg-hash.d.ts +113 -0
- package/dist/utils/stable-stringify.d.ts +47 -2
- package/package.json +1 -1
package/dist/memory/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { invalidateMemoryStoreDirCache, isMemoryLinked, MEMORY_LINK_POINTER_FILE
|
|
|
12
12
|
export { buildRecallPromptBlock } from './prompt-block';
|
|
13
13
|
export type { MemoryCompactOptions, MemoryCompactResult, MemoryProposalStore, MemoryProvider, MemoryRecallUsageEvent, MemoryRecallUsageFilter, } from './provider';
|
|
14
14
|
export { buildMemoryRecallPlan, type MemoryRecallPlan, type MemoryRecallPlannerInput, } from './recall-planner';
|
|
15
|
-
export { buildMemoryCohortFingerprintInput, computeMemoryCohortFingerprint, computeRedactionPolicyVersion, findSecrets, redactSecrets, } from './redaction';
|
|
15
|
+
export { buildMemoryCohortFingerprintInput, computeMemoryCohortFingerprint, computeRedactionPolicyVersion, FINGERPRINT_ALGORITHM_VERSION, findSecrets, redactSecrets, } from './redaction';
|
|
16
16
|
export { MEMORY_RECALL_PROFILES, type MemoryRecallProfile, normalizeMemoryAgentRole, resolveMemoryRecallProfile, } from './role-profiles';
|
|
17
17
|
export { appendMemoryRunLog, sanitizeRunId } from './run-log';
|
|
18
18
|
export { computeMemoryContentHash, createBundleId, createMemoryId, createProposalId, isExpired, normalizeMemoryText, validateCuratorMemoryDecision, validateMemoryProposal, validateMemoryRecordRules, } from './schema';
|
|
@@ -55,7 +55,10 @@ export declare class LocalJsonlMemoryProvider implements MemoryProvider, MemoryP
|
|
|
55
55
|
/**
|
|
56
56
|
* #1850 (KC-001 fix): mirror the SQLite provider's fingerprint check. Reads
|
|
57
57
|
* `memory-cohort-config.json` and throws on mismatch. Absent/malformed file
|
|
58
|
-
* is permissive (fail-open never strands memory).
|
|
58
|
+
* is permissive (fail-open never strands memory). #2062 F-012: a file whose
|
|
59
|
+
* `algorithm_version` is not the current one — or is present but
|
|
60
|
+
* uninterpretable — is also permissive, because the digests are not
|
|
61
|
+
* comparable; both warn with a re-link instruction.
|
|
59
62
|
*/
|
|
60
63
|
private assertCohortConfigFingerprint;
|
|
61
64
|
private activeMemory;
|
|
@@ -20,6 +20,97 @@ export interface MemoryCohortFingerprintInput {
|
|
|
20
20
|
embedding_dimension: number;
|
|
21
21
|
embedding_version: string;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* #2062 F-012: version of the cohort-fingerprint ALGORITHM (canonicalization +
|
|
25
|
+
* hash + truncation), persisted alongside the fingerprint in
|
|
26
|
+
* `memory-cohort-config.json` and read back by every consumer.
|
|
27
|
+
*
|
|
28
|
+
* Version 1 is the algorithm below (sorted-key canonical JSON -> sha256 -> first
|
|
29
|
+
* 12 hex chars). Files written before this field existed are treated as
|
|
30
|
+
* version 1, which is exactly correct: they were produced by this same
|
|
31
|
+
* algorithm, so they keep validating with no forced re-link.
|
|
32
|
+
*
|
|
33
|
+
* BUMP THIS whenever a change would alter the digest for an unchanged input —
|
|
34
|
+
* e.g. a different hash, a different truncation length, a change to
|
|
35
|
+
* `stableCanonicalStringify`'s output for a reachable input, or a change to the
|
|
36
|
+
* `MemoryCohortFingerprintInput` shape. Readers compare versions BEFORE
|
|
37
|
+
* comparing fingerprints, so a bump surfaces as "re-run `/swarm memory link`"
|
|
38
|
+
* instead of being misreported as a real provider/embedding config mismatch.
|
|
39
|
+
*/
|
|
40
|
+
export declare const FINGERPRINT_ALGORITHM_VERSION = 1;
|
|
41
|
+
/**
|
|
42
|
+
* #2062 F-012 (R3 fix): the algorithm version implied by a persisted cohort
|
|
43
|
+
* config that has NO `algorithm_version` field. Every file written before the
|
|
44
|
+
* field existed was produced by algorithm version 1, so that is what an absent
|
|
45
|
+
* field means — permanently, whatever `FINGERPRINT_ALGORITHM_VERSION` later
|
|
46
|
+
* becomes.
|
|
47
|
+
*
|
|
48
|
+
* This MUST stay a standalone literal and must never be re-expressed in terms
|
|
49
|
+
* of `FINGERPRINT_ALGORITHM_VERSION`. If it tracked the current version, then
|
|
50
|
+
* the moment that constant is bumped every legacy file already on disk would
|
|
51
|
+
* report itself as current, the version gate could never fire for the very
|
|
52
|
+
* files it exists to protect, and a v1 digest would be byte-compared against a
|
|
53
|
+
* v2 expected value — which `SQLiteMemoryProvider` turns into a hard
|
|
54
|
+
* "config differs" throw. Defaulting to the current version is self-defeating
|
|
55
|
+
* at exactly the moment the mechanism is supposed to help.
|
|
56
|
+
*
|
|
57
|
+
* The explicit `: 1` literal type is the enforcement, not decoration — and it
|
|
58
|
+
* enforces only for as long as it is actually there. No runtime test can catch
|
|
59
|
+
* the aliasing refactor today (while `FINGERPRINT_ALGORITHM_VERSION` is still
|
|
60
|
+
* 1, an alias evaluates to 1 and every assertion passes), so the guard has to
|
|
61
|
+
* fire at the only moment the mistake becomes real: the bump.
|
|
62
|
+
*
|
|
63
|
+
* Both halves of that were measured against this repo with the constant
|
|
64
|
+
* temporarily set to 2, running `bunx tsc --noEmit`:
|
|
65
|
+
*
|
|
66
|
+
* - `LEGACY_…: 1 = FINGERPRINT_ALGORITHM_VERSION` (annotation KEPT)
|
|
67
|
+
* -> exit 2, `TS2322: Type '2' is not assignable to type '1'`. Guard fires.
|
|
68
|
+
* - `LEGACY_… = FINGERPRINT_ALGORITHM_VERSION` (annotation DROPPED)
|
|
69
|
+
* -> exit 0. Guard does NOT fire, and every legacy cohort file is stranded
|
|
70
|
+
* silently.
|
|
71
|
+
*
|
|
72
|
+
* The second form is the one a refactorer actually types, so do NOT rely on
|
|
73
|
+
* `tsc` to catch removal of this annotation — the annotation is the thing
|
|
74
|
+
* being protected, not merely the mechanism. A legitimate bump that leaves
|
|
75
|
+
* this literal alone typechecks cleanly.
|
|
76
|
+
*/
|
|
77
|
+
export declare const LEGACY_FINGERPRINT_ALGORITHM_VERSION: 1;
|
|
78
|
+
/**
|
|
79
|
+
* DI seam for testability (repo convention, cf. `src/utils/logger.ts`). Lets a
|
|
80
|
+
* test simulate a FUTURE bump of `FINGERPRINT_ALGORITHM_VERSION` without
|
|
81
|
+
* hand-editing the constant — the only way to exercise the legacy-file version
|
|
82
|
+
* gate before a real bump ever happens. Production code never mutates this.
|
|
83
|
+
*/
|
|
84
|
+
export declare const _internals: {
|
|
85
|
+
currentAlgorithmVersion: number;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Result of interpreting a persisted `algorithm_version` field:
|
|
89
|
+
* - `comparable` — stored digest was produced by the current algorithm, so a
|
|
90
|
+
* byte comparison is meaningful.
|
|
91
|
+
* - `mismatch` — a known but different algorithm produced it; the digests are
|
|
92
|
+
* not comparable, so callers skip the compare and fail OPEN with a re-link
|
|
93
|
+
* instruction rather than reporting a config difference that does not exist.
|
|
94
|
+
* - `unknown` — the field is present but not a finite number, so the digest
|
|
95
|
+
* cannot be attributed to any algorithm. Callers skip the compare too, but
|
|
96
|
+
* must NOT assume it is current (that would byte-compare on a guess).
|
|
97
|
+
*/
|
|
98
|
+
export type StoredFingerprintAlgorithmVersion = {
|
|
99
|
+
status: 'comparable';
|
|
100
|
+
} | {
|
|
101
|
+
status: 'mismatch';
|
|
102
|
+
storedVersion: number;
|
|
103
|
+
currentVersion: number;
|
|
104
|
+
} | {
|
|
105
|
+
status: 'unknown';
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Single source of truth for the version gate shared by all four readers
|
|
109
|
+
* (SQLite provider, local-jsonl provider, status service, knowledge
|
|
110
|
+
* diagnostics). Keeping it here means a future bump changes one file, and the
|
|
111
|
+
* absent-field semantics cannot silently drift apart across call sites.
|
|
112
|
+
*/
|
|
113
|
+
export declare function classifyStoredFingerprintAlgorithmVersion(rawStoredVersion: unknown, currentVersion?: number): StoredFingerprintAlgorithmVersion;
|
|
23
114
|
export declare function computeMemoryCohortFingerprint(input: MemoryCohortFingerprintInput): string;
|
|
24
115
|
/** Convenience: build the fingerprint input from a memory config subset. */
|
|
25
116
|
export declare function buildMemoryCohortFingerprintInput(config: {
|
|
@@ -148,7 +148,11 @@ export declare class SQLiteMemoryProvider implements MemoryProvider, MemoryPropo
|
|
|
148
148
|
* with this worktree's config (acceptance #10). Absent file = first link
|
|
149
149
|
* (permissive — the linker writes it immediately after migration). A
|
|
150
150
|
* malformed file is also permissive (fail-open never strands memory, but
|
|
151
|
-
* a mismatch is a hard error).
|
|
151
|
+
* a mismatch is a hard error). #2062 F-012: a file whose `algorithm_version`
|
|
152
|
+
* is not the current one — or is present but uninterpretable — is permissive
|
|
153
|
+
* too, because cross-algorithm digests are not comparable. Both warn with a
|
|
154
|
+
* re-link instruction rather than reporting a config mismatch that does not
|
|
155
|
+
* exist.
|
|
152
156
|
*/
|
|
153
157
|
private assertCohortConfigFingerprint;
|
|
154
158
|
private writeMemoryFts;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared primitives for hashing tool-call arguments (issue #2060 follow-ups
|
|
3
|
+
* F-009 / F-010).
|
|
4
|
+
*
|
|
5
|
+
* # Why this exists
|
|
6
|
+
*
|
|
7
|
+
* Two subsystems hash tool arguments to detect "the agent is repeating
|
|
8
|
+
* itself": `hashArgsForSpiral` in `hooks/adversarial-detector.ts` (spiral
|
|
9
|
+
* advisory) and `hashArgs` in `hooks/guardrails/file-authority.ts` (which
|
|
10
|
+
* feeds the consecutive-repetition circuit breaker in
|
|
11
|
+
* `hooks/guardrails/tool-before.ts` — a path that THROWS, not warns).
|
|
12
|
+
*
|
|
13
|
+
* Both need the same two primitives. They live here rather than as two inline
|
|
14
|
+
* copies for the same reason `src/utils/stable-stringify.ts` was extracted: a
|
|
15
|
+
* bug class that exists at two call sites must be fixed once, in one place,
|
|
16
|
+
* and tested once. Keep them here; do not re-inline a copy at a call site.
|
|
17
|
+
*
|
|
18
|
+
* The two call sites differ only in the OUTPUT SHAPE they need — the detector
|
|
19
|
+
* wants a compact base-36 string, file-authority wants a `number` — so
|
|
20
|
+
* `boundedBunHash` returns `bigint` (matching `bunHash`) and each caller
|
|
21
|
+
* formats it.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Cap on the amount of input fed into `bunHash`.
|
|
25
|
+
*
|
|
26
|
+
* Both call sites run synchronously on a per-tool-call hot path, and payloads
|
|
27
|
+
* (patch bodies, file writes) can reach ~1 MB. Node's `bunHash` fallback
|
|
28
|
+
* (djb2, see `bun-compat.ts`) is genuinely reachable in production — the
|
|
29
|
+
* OpenCode plugin host and the Desktop sidecar can run under Node — and is
|
|
30
|
+
* O(n): ~141 ms for a 2 MB input versus ~5 ms for 64 KB. The threat model is
|
|
31
|
+
* "same tool, same args, repeatedly", not adversarial collision resistance,
|
|
32
|
+
* so bounding the hashed input keeps worst-case per-call cost flat.
|
|
33
|
+
*
|
|
34
|
+
* NOTE ON UNITS: this bounds `String.prototype.length`, i.e. UTF-16 code
|
|
35
|
+
* units, not encoded bytes. It is a cost bound, not a byte-exact limit; a
|
|
36
|
+
* non-BMP-heavy string can encode to more bytes than the name suggests. That
|
|
37
|
+
* is fine — the point is a fixed ceiling, and the ceiling is fixed.
|
|
38
|
+
*/
|
|
39
|
+
export declare const HASH_INPUT_CAP_BYTES: number;
|
|
40
|
+
/**
|
|
41
|
+
* Reduces an arbitrarily long string to a bounded, length-prefixed
|
|
42
|
+
* head-and-tail sample suitable as hash input.
|
|
43
|
+
*
|
|
44
|
+
* ## Why not a bare prefix
|
|
45
|
+
*
|
|
46
|
+
* The obvious bound — `input.slice(0, CAP)` — makes every pair of inputs that
|
|
47
|
+
* share a `CAP`-length prefix hash identically. For the circuit-breaker call
|
|
48
|
+
* site that is a false-positive engine: ten consecutive large writes that
|
|
49
|
+
* share a boilerplate header but differ in their (appended) bodies look like
|
|
50
|
+
* ten identical calls and the breaker throws. Sampling the head AND the tail
|
|
51
|
+
* removes the whole append-collision class, and sampling the head removes the
|
|
52
|
+
* prepend-collision class, at exactly the same bounded cost.
|
|
53
|
+
*
|
|
54
|
+
* ## Why the length prefix is load-bearing
|
|
55
|
+
*
|
|
56
|
+
* It is not decoration. Without it the two branches below can collide across
|
|
57
|
+
* the cap boundary: an input of exactly `CAP` characters passes through
|
|
58
|
+
* untransformed, while a longer input produces a `CAP`-character head+tail
|
|
59
|
+
* concatenation — two different inputs, one identical hash input. Prefixing
|
|
60
|
+
* the true length separates the classes. It also makes the under-cap branch
|
|
61
|
+
* injective, so this transform adds ZERO collisions for inputs at or below
|
|
62
|
+
* the cap.
|
|
63
|
+
*
|
|
64
|
+
* ## Residual, accepted lossiness
|
|
65
|
+
*
|
|
66
|
+
* Two inputs longer than the cap collide only if they have the SAME total
|
|
67
|
+
* length AND the same first `CAP/2` characters AND the same last `CAP/2`
|
|
68
|
+
* characters, differing only in the discarded middle. That is unavoidable for
|
|
69
|
+
* any fixed-cost sampler and is the deliberate trade documented on
|
|
70
|
+
* `HASH_INPUT_CAP_BYTES`.
|
|
71
|
+
*
|
|
72
|
+
* Cannot throw: `String.prototype.slice` and template interpolation of a
|
|
73
|
+
* number are total.
|
|
74
|
+
*/
|
|
75
|
+
export declare function sampleForHash(input: string): string;
|
|
76
|
+
/**
|
|
77
|
+
* `bunHash` over a bounded head+tail sample of `input`.
|
|
78
|
+
*
|
|
79
|
+
* Returns `bigint` (the `bunHash` shape) so each caller can format it for its
|
|
80
|
+
* own storage: the detector uses `.toString(36)`, file-authority uses
|
|
81
|
+
* `Number(...)`.
|
|
82
|
+
*
|
|
83
|
+
* Cannot throw for a string input: `sampleForHash` is total and `bunHash`
|
|
84
|
+
* on a string is `TextEncoder.encode` plus BigInt arithmetic (or `Bun.hash`)
|
|
85
|
+
* — no throwing path. Callers rely on this: both use it inside a `catch`
|
|
86
|
+
* block, where a second throw would escape into a hook.
|
|
87
|
+
*/
|
|
88
|
+
export declare function boundedBunHash(input: string): bigint;
|
|
89
|
+
/**
|
|
90
|
+
* Shallow, non-recursive structural summary of a value's own enumerable keys,
|
|
91
|
+
* used only as a fallback discriminator when `stableCanonicalStringify`
|
|
92
|
+
* throws (issue #2060 follow-up F-009).
|
|
93
|
+
*
|
|
94
|
+
* Before this existed, both call sites answered an unstringifiable argument
|
|
95
|
+
* with a CONSTANT ('h:fallback' / `0`). That made every distinct-but-
|
|
96
|
+
* unserializable argument collide, so N consecutive calls with genuinely
|
|
97
|
+
* different arguments looked identical and fired a false positive — a spiral
|
|
98
|
+
* advisory in one case, a thrown circuit breaker in the other.
|
|
99
|
+
*
|
|
100
|
+
* Deliberately shallow (no recursion into nested values) so it cannot itself
|
|
101
|
+
* throw on the very inputs that broke `stableCanonicalStringify`: recursing
|
|
102
|
+
* into a cyclic reference would revisit the cycle, and BigInt values are
|
|
103
|
+
* handled fine by `typeof` / `String()` (unlike `JSON.stringify`, which
|
|
104
|
+
* throws on them). `Object.keys` and `typeof` cannot throw for ordinary
|
|
105
|
+
* objects; the outer try/catch guards only against exotic Proxy traps, and
|
|
106
|
+
* even then identical arguments still collide, so true-positive repetition
|
|
107
|
+
* detection is preserved.
|
|
108
|
+
*
|
|
109
|
+
* This is a DISCRIMINATOR, not an identity function. It is only ever used to
|
|
110
|
+
* break up false collisions on a detection path — never as a fail-closed
|
|
111
|
+
* identity (see the caller guidance on `stableCanonicalStringify`).
|
|
112
|
+
*/
|
|
113
|
+
export declare function coarseObjectDiscriminator(args: unknown): string;
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
* Originally introduced for the adversarial-detector spiral hash
|
|
26
26
|
* (issue #2060) and shared with `file-authority.hashArgs` so both code paths
|
|
27
27
|
* use one correct implementation.
|
|
28
|
+
*
|
|
29
|
+
* This is a canonicalizer for HASH INPUT, not a drop-in `JSON.stringify`
|
|
30
|
+
* replacement — see the "Serialization limits" section on
|
|
31
|
+
* `stableCanonicalStringify` before using it anywhere the output is parsed or
|
|
32
|
+
* shown to a user.
|
|
28
33
|
*/
|
|
29
34
|
/**
|
|
30
35
|
* Recursively produces a canonical JSON string with object keys sorted at
|
|
@@ -39,8 +44,48 @@
|
|
|
39
44
|
* function exists to eliminate. Sorting must be done by rebuilding each object
|
|
40
45
|
* with sorted keys before serialization.
|
|
41
46
|
*
|
|
47
|
+
* ## Serialization limits (#2062 F-008 — deliberate, verified, do not "fix"
|
|
48
|
+
* without re-reading this)
|
|
49
|
+
*
|
|
50
|
+
* - **No `toJSON` support.** `toJSON` is never consulted. A `Date` therefore
|
|
51
|
+
* collapses to `{}` (it has no own enumerable keys) — a genuine divergence
|
|
52
|
+
* from `JSON.stringify`, which emits the ISO string.
|
|
53
|
+
* - **`Map`/`Set` collapse to `{}`.** This MATCHES `JSON.stringify` (neither
|
|
54
|
+
* exposes own enumerable string keys), so it is lossy for both rather than a
|
|
55
|
+
* divergence between them.
|
|
56
|
+
* - **`undefined` serializes as `null`** in object-property AND array-element
|
|
57
|
+
* position, so no bare `undefined` token or sparse-array hole is emitted for
|
|
58
|
+
* it. `JSON.stringify` instead omits an `undefined`-valued property; keeping
|
|
59
|
+
* the key here is deliberate — two objects differing only by a
|
|
60
|
+
* present-but-undefined key must not hash equal. True sparse array *holes*
|
|
61
|
+
* (`[1,,3]`) are NOT covered: `Array.prototype.map` skips holes, so they
|
|
62
|
+
* still render as `[1,,3]`.
|
|
63
|
+
* - **Function and symbol values still emit a bare `undefined` token**, which
|
|
64
|
+
* is not valid JSON. It is deterministic, so it is safe as hash input, but
|
|
65
|
+
* the result is not always `JSON.parse`-able.
|
|
66
|
+
*
|
|
67
|
+
* These limits are safe at every current call site: the cohort fingerprint
|
|
68
|
+
* input is a flat all-primitive struct, and the hook call sites hash tool-call
|
|
69
|
+
* arguments that have already round-tripped through JSON transport, so
|
|
70
|
+
* `Date`/`Map`/`Set`/function values cannot reach them.
|
|
71
|
+
*
|
|
72
|
+
* ## Throwing, and how callers must (and must not) handle it
|
|
73
|
+
*
|
|
42
74
|
* Throws on cyclic structures (infinite recursion) and on values that
|
|
43
|
-
* `JSON.stringify` cannot represent (BigInt)
|
|
44
|
-
*
|
|
75
|
+
* `JSON.stringify` cannot represent (BigInt). Correct caller handling depends
|
|
76
|
+
* on what the hash is FOR:
|
|
77
|
+
*
|
|
78
|
+
* - **Repetition / spiral-detection callers** (`hashArgsForSpiral` in
|
|
79
|
+
* `hooks/adversarial-detector.ts`, `hashArgs` in
|
|
80
|
+
* `hooks/guardrails/file-authority.ts`) SHOULD wrap in try/catch and fall
|
|
81
|
+
* back to a stable coarse hash. There, a fallback only degrades detection
|
|
82
|
+
* sensitivity for the one call that failed.
|
|
83
|
+
* - **Identity / fail-closed comparison callers** (e.g.
|
|
84
|
+
* `computeMemoryCohortFingerprint` in `memory/redaction.ts`) MUST NOT do
|
|
85
|
+
* that. A constant fallback would collapse every failing input to the same
|
|
86
|
+
* fingerprint, so two genuinely incompatible cohort members would compare
|
|
87
|
+
* equal and the fail-closed coherence check would be silently defeated. Let
|
|
88
|
+
* the throw propagate, or rethrow with added context — never return a
|
|
89
|
+
* constant.
|
|
45
90
|
*/
|
|
46
91
|
export declare function stableCanonicalStringify(value: unknown): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.136.
|
|
3
|
+
"version": "7.136.5",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|