opencode-swarm 7.114.7 → 7.114.8
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/.opencode/skills/engineering-conventions/SKILL.md +33 -0
- package/README.md +15 -14
- package/dist/agents/template.d.ts +40 -20
- package/dist/cli/{curator-llm-factory-2xgznxyw.js → curator-llm-factory-ez48eq02.js} +7 -7
- package/dist/cli/{curator-qshyr2tc.js → curator-qj970412.js} +7 -7
- package/dist/cli/{evidence-summary-service-8g594znj.js → evidence-summary-service-fehwj116.js} +1 -1
- package/dist/cli/{guardrail-explain-4t8fnysh.js → guardrail-explain-x2vaxp6s.js} +8 -8
- package/dist/cli/{hive-promoter-5ngbmnrw.js → hive-promoter-ysk5edzw.js} +7 -7
- package/dist/cli/{index-7stsmndb.js → index-6f6y2rbp.js} +3 -3
- package/dist/cli/{index-kjbfry6m.js → index-8f2270hc.js} +1 -1
- package/dist/cli/{index-6ctejje2.js → index-cs5765s2.js} +86 -63
- package/dist/cli/{index-qrnhvhmg.js → index-n18yy0z1.js} +26 -2
- package/dist/cli/{index-91qesget.js → index-rk6qhyng.js} +2 -2
- package/dist/cli/{index-gmjrwz34.js → index-ry8nwsq6.js} +1 -1
- package/dist/cli/{index-vjvdvjd3.js → index-x12hvfpf.js} +3 -3
- package/dist/cli/{index-f6y341yk.js → index-yrrqs4b0.js} +82 -21
- package/dist/cli/{index-z01r5483.js → index-z718bgxe.js} +8 -8
- package/dist/cli/index.d.ts +34 -0
- package/dist/cli/index.js +105 -28
- package/dist/cli/{knowledge-escalator-qn7ew687.js → knowledge-escalator-5gwp1ar8.js} +3 -3
- package/dist/cli/{knowledge-events-k2xsz5bh.js → knowledge-events-m304swh6.js} +1 -1
- package/dist/cli/{knowledge-store-ksa1dr2z.js → knowledge-store-9babt8rd.js} +1 -1
- package/dist/cli/{knowledge-validator-2knz0d2t.js → knowledge-validator-t9sym59g.js} +4 -2
- package/dist/cli/{skill-generator-w6qd9mde.js → skill-generator-tav44xpm.js} +4 -4
- package/dist/config/skill-mirrors.d.ts +12 -0
- package/dist/hooks/adversarial-detector.d.ts +6 -0
- package/dist/hooks/delegation-gate.d.ts +19 -0
- package/dist/hooks/guardrails/index.d.ts +2 -2
- package/dist/hooks/knowledge-validator.d.ts +22 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +74 -70
- package/dist/plan/ledger.d.ts +83 -20
- package/dist/types/delegation.d.ts +24 -0
- package/package.json +1 -1
- package/dist/graph/graph-builder.d.ts +0 -39
- package/dist/graph/graph-query.d.ts +0 -42
- package/dist/graph/graph-store.d.ts +0 -27
- package/dist/graph/import-extractor.d.ts +0 -44
- package/dist/graph/index.d.ts +0 -16
- package/dist/graph/symbol-extractor.d.ts +0 -17
- package/dist/graph/types.d.ts +0 -84
- package/dist/sandbox/win32/restricted-token-executor.d.ts +0 -9
package/dist/cli/index.d.ts
CHANGED
|
@@ -15,6 +15,40 @@ export declare function isSafeCachePath(p: string): boolean;
|
|
|
15
15
|
* grandparent structure validation to prevent misconfigured nested paths.
|
|
16
16
|
*/
|
|
17
17
|
export declare function isSafeLockFilePath(p: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Safety guard for the `uninstall --clean` deletion of PROMPTS_DIR
|
|
20
|
+
* (`<CONFIG_DIR>/opencode-swarm`, a DIRECTORY removed recursively).
|
|
21
|
+
*
|
|
22
|
+
* This is a SEPARATE guard from isSafeCachePath — it is NOT reused because
|
|
23
|
+
* isSafeCachePath's layer-4 requires parent ∈ {packages, node_modules} and
|
|
24
|
+
* grandparent === 'opencode', which the prompts directory (parent basename is
|
|
25
|
+
* the config dir's basename, typically 'opencode') does not satisfy, so
|
|
26
|
+
* isSafeCachePath would false-REJECT a legitimate PROMPTS_DIR.
|
|
27
|
+
*
|
|
28
|
+
* Defense in depth:
|
|
29
|
+
* 1. Canonicalize via safeRealpathSync (realpathSync with ENOENT→fallback)
|
|
30
|
+
* so the path a symlinked leaf actually resolves to is what we validate.
|
|
31
|
+
* 2. Refuse root, home, or shorter-than-home paths.
|
|
32
|
+
* 3. Require ≥ 3 non-empty segments (rejects pathological
|
|
33
|
+
* XDG_CONFIG_HOME='/' which yields '/opencode/opencode-swarm', 2 segments).
|
|
34
|
+
* 4. Require basename === 'opencode-swarm' AND the parent directory's
|
|
35
|
+
* basename to equal the config dir's basename (canonical layout is
|
|
36
|
+
* `<CONFIG_DIR>/opencode-swarm`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function isSafePromptsDir(p: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Safety guard for the `uninstall --clean` deletion of PLUGIN_CONFIG_PATH
|
|
41
|
+
* (`<CONFIG_DIR>/opencode-swarm.json`, a FILE removed with unlinkSync).
|
|
42
|
+
*
|
|
43
|
+
* File-oriented sibling of isSafePromptsDir. isSafePromptsDir would
|
|
44
|
+
* false-REJECT this path because the leaf here is the `.json` FILE, not the
|
|
45
|
+
* `opencode-swarm` directory — hence a dedicated guard.
|
|
46
|
+
*
|
|
47
|
+
* Defense in depth: canonicalize via safeRealpathSync; refuse root/home/
|
|
48
|
+
* shorter-than-home; require basename === 'opencode-swarm.json' AND the
|
|
49
|
+
* parent directory's basename to equal the config dir's basename.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isSafePluginConfigPath(p: string): boolean;
|
|
18
52
|
/**
|
|
19
53
|
* Recursively delete every known opencode plugin cache location for
|
|
20
54
|
* opencode-swarm. Returns paths actually cleared and paths that errored.
|
package/dist/cli/index.js
CHANGED
|
@@ -7,22 +7,22 @@ import {
|
|
|
7
7
|
getPluginLockFilePaths,
|
|
8
8
|
package_default,
|
|
9
9
|
resolveCommand
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-cs5765s2.js";
|
|
11
11
|
import"./index-yfedche9.js";
|
|
12
12
|
import"./index-c8s9a3zh.js";
|
|
13
13
|
import"./index-9bsmzfk3.js";
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_AGENT_CONFIGS
|
|
16
16
|
} from "./index-a45jq4b7.js";
|
|
17
|
-
import"./index-
|
|
17
|
+
import"./index-yrrqs4b0.js";
|
|
18
18
|
import"./index-scww5b77.js";
|
|
19
19
|
import"./index-ga4ta3cr.js";
|
|
20
20
|
import"./index-80jkseqw.js";
|
|
21
|
-
import"./index-
|
|
22
|
-
import"./index-
|
|
23
|
-
import"./index-
|
|
24
|
-
import"./index-
|
|
25
|
-
import"./index-
|
|
21
|
+
import"./index-x12hvfpf.js";
|
|
22
|
+
import"./index-n18yy0z1.js";
|
|
23
|
+
import"./index-6f6y2rbp.js";
|
|
24
|
+
import"./index-8f2270hc.js";
|
|
25
|
+
import"./index-rk6qhyng.js";
|
|
26
26
|
import"./index-bfwt3abw.js";
|
|
27
27
|
import"./index-g40r5d08.js";
|
|
28
28
|
import"./index-vxv732ex.js";
|
|
@@ -49,6 +49,21 @@ import"./index-a76rekgs.js";
|
|
|
49
49
|
import * as fs from "fs";
|
|
50
50
|
import * as os from "os";
|
|
51
51
|
import * as path from "path";
|
|
52
|
+
|
|
53
|
+
// src/tools/repo-graph/safe-realpath.ts
|
|
54
|
+
import { realpathSync } from "fs";
|
|
55
|
+
function safeRealpathSync(targetPath, fallback, realpathResolver = realpathSync) {
|
|
56
|
+
try {
|
|
57
|
+
return realpathResolver(targetPath);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error instanceof Error && error.code === "ENOENT") {
|
|
60
|
+
return fallback;
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/cli/index.ts
|
|
52
67
|
var { version } = package_default;
|
|
53
68
|
var CONFIG_DIR = getPluginConfigDir();
|
|
54
69
|
var OPENCODE_CONFIG_PATH = path.join(CONFIG_DIR, "opencode.json");
|
|
@@ -56,14 +71,17 @@ var PLUGIN_CONFIG_PATH = path.join(CONFIG_DIR, "opencode-swarm.json");
|
|
|
56
71
|
var PROMPTS_DIR = path.join(CONFIG_DIR, "opencode-swarm");
|
|
57
72
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
58
73
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
74
|
+
function segmentDepthBelowRoot(resolved) {
|
|
75
|
+
const { root } = path.parse(resolved);
|
|
76
|
+
return resolved.slice(root.length).split(path.sep).filter((s) => s.length > 0).length;
|
|
77
|
+
}
|
|
59
78
|
function isSafeCachePath(p) {
|
|
60
79
|
const resolved = path.resolve(p);
|
|
61
80
|
const home = path.resolve(os.homedir());
|
|
62
81
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
63
82
|
return false;
|
|
64
83
|
}
|
|
65
|
-
|
|
66
|
-
if (segments.length < 4) {
|
|
84
|
+
if (segmentDepthBelowRoot(resolved) < 4) {
|
|
67
85
|
return false;
|
|
68
86
|
}
|
|
69
87
|
const leaf = path.basename(resolved);
|
|
@@ -86,8 +104,7 @@ function isSafeLockFilePath(p) {
|
|
|
86
104
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
87
105
|
return false;
|
|
88
106
|
}
|
|
89
|
-
|
|
90
|
-
if (segments.length < 4) {
|
|
107
|
+
if (segmentDepthBelowRoot(resolved) < 4) {
|
|
91
108
|
return false;
|
|
92
109
|
}
|
|
93
110
|
const leaf = path.basename(resolved);
|
|
@@ -104,6 +121,48 @@ function isSafeLockFilePath(p) {
|
|
|
104
121
|
}
|
|
105
122
|
return true;
|
|
106
123
|
}
|
|
124
|
+
function isSafePromptsDir(p) {
|
|
125
|
+
const canonical = safeRealpathSync(p, p);
|
|
126
|
+
if (canonical === null) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
const resolved = path.resolve(canonical);
|
|
130
|
+
const home = path.resolve(os.homedir());
|
|
131
|
+
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
if (segmentDepthBelowRoot(resolved) < 3) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if (path.basename(resolved) !== "opencode-swarm") {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (path.basename(path.dirname(resolved)) !== path.basename(CONFIG_DIR)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
function isSafePluginConfigPath(p) {
|
|
146
|
+
const canonical = safeRealpathSync(p, p);
|
|
147
|
+
if (canonical === null) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
const resolved = path.resolve(canonical);
|
|
151
|
+
const home = path.resolve(os.homedir());
|
|
152
|
+
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (segmentDepthBelowRoot(resolved) < 3) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
if (path.basename(resolved) !== "opencode-swarm.json") {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
if (path.basename(path.dirname(resolved)) !== path.basename(CONFIG_DIR)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
107
166
|
function ensureDir(dir) {
|
|
108
167
|
if (!fs.existsSync(dir)) {
|
|
109
168
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -270,15 +329,18 @@ function evictPluginCaches() {
|
|
|
270
329
|
for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
|
|
271
330
|
if (!fs.existsSync(cachePath))
|
|
272
331
|
continue;
|
|
273
|
-
|
|
274
|
-
|
|
332
|
+
const canonical = safeRealpathSync(cachePath, cachePath);
|
|
333
|
+
if (canonical === null || !fs.existsSync(canonical))
|
|
334
|
+
continue;
|
|
335
|
+
if (!isSafeCachePath(canonical)) {
|
|
336
|
+
failed.push(`${canonical} (refused: failed safety check)`);
|
|
275
337
|
continue;
|
|
276
338
|
}
|
|
277
339
|
try {
|
|
278
|
-
fs.rmSync(
|
|
279
|
-
cleared.push(
|
|
340
|
+
fs.rmSync(canonical, { recursive: true, force: true });
|
|
341
|
+
cleared.push(canonical);
|
|
280
342
|
} catch (err) {
|
|
281
|
-
failed.push(`${
|
|
343
|
+
failed.push(`${canonical} (${err instanceof Error ? err.message : String(err)})`);
|
|
282
344
|
}
|
|
283
345
|
}
|
|
284
346
|
return { cleared, failed };
|
|
@@ -289,19 +351,22 @@ function evictLockFiles() {
|
|
|
289
351
|
for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
|
|
290
352
|
if (!fs.existsSync(lockPath))
|
|
291
353
|
continue;
|
|
292
|
-
|
|
293
|
-
|
|
354
|
+
const canonical = safeRealpathSync(lockPath, lockPath);
|
|
355
|
+
if (canonical === null || !fs.existsSync(canonical))
|
|
356
|
+
continue;
|
|
357
|
+
if (!isSafeLockFilePath(canonical)) {
|
|
358
|
+
failed.push(`${canonical} (refused: failed safety check)`);
|
|
294
359
|
continue;
|
|
295
360
|
}
|
|
296
361
|
try {
|
|
297
|
-
fs.unlinkSync(
|
|
298
|
-
cleared.push(
|
|
362
|
+
fs.unlinkSync(canonical);
|
|
363
|
+
cleared.push(canonical);
|
|
299
364
|
} catch (err) {
|
|
300
365
|
const code = err?.code;
|
|
301
366
|
if (code === "EISDIR") {
|
|
302
|
-
failed.push(`${
|
|
367
|
+
failed.push(`${canonical} (path is a directory, not a file)`);
|
|
303
368
|
} else {
|
|
304
|
-
failed.push(`${
|
|
369
|
+
failed.push(`${canonical} (${err instanceof Error ? err.message : String(err)})`);
|
|
305
370
|
}
|
|
306
371
|
}
|
|
307
372
|
}
|
|
@@ -346,14 +411,24 @@ async function uninstall() {
|
|
|
346
411
|
if (process.argv.includes("--clean")) {
|
|
347
412
|
let cleaned = false;
|
|
348
413
|
if (fs.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
414
|
+
const canonical = safeRealpathSync(PLUGIN_CONFIG_PATH, PLUGIN_CONFIG_PATH);
|
|
415
|
+
if (canonical === null || !isSafePluginConfigPath(canonical)) {
|
|
416
|
+
console.log(`\u2717 Refused to remove plugin config (failed safety check): ${canonical ?? PLUGIN_CONFIG_PATH}`);
|
|
417
|
+
} else {
|
|
418
|
+
fs.unlinkSync(canonical);
|
|
419
|
+
console.log(`\u2713 Removed plugin config: ${canonical}`);
|
|
420
|
+
cleaned = true;
|
|
421
|
+
}
|
|
352
422
|
}
|
|
353
423
|
if (fs.existsSync(PROMPTS_DIR)) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
424
|
+
const canonical = safeRealpathSync(PROMPTS_DIR, PROMPTS_DIR);
|
|
425
|
+
if (canonical === null || !isSafePromptsDir(canonical)) {
|
|
426
|
+
console.log(`\u2717 Refused to remove custom prompts (failed safety check): ${canonical ?? PROMPTS_DIR}`);
|
|
427
|
+
} else {
|
|
428
|
+
fs.rmSync(canonical, { recursive: true });
|
|
429
|
+
console.log(`\u2713 Removed custom prompts: ${canonical}`);
|
|
430
|
+
cleaned = true;
|
|
431
|
+
}
|
|
357
432
|
}
|
|
358
433
|
if (!cleaned) {
|
|
359
434
|
console.log("\u2713 No config files to clean up");
|
|
@@ -474,6 +549,8 @@ Valid commands: ${VALID_COMMANDS.join(", ")}`);
|
|
|
474
549
|
}
|
|
475
550
|
export {
|
|
476
551
|
run,
|
|
552
|
+
isSafePromptsDir,
|
|
553
|
+
isSafePluginConfigPath,
|
|
477
554
|
isSafeLockFilePath,
|
|
478
555
|
isSafeCachePath,
|
|
479
556
|
evictPluginCaches,
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
maybeEscalateOnViolation,
|
|
9
9
|
maybeQuarantineOnContradiction,
|
|
10
10
|
readRecentEscalations
|
|
11
|
-
} from "./index-
|
|
12
|
-
import"./index-
|
|
13
|
-
import"./index-
|
|
11
|
+
} from "./index-6f6y2rbp.js";
|
|
12
|
+
import"./index-8f2270hc.js";
|
|
13
|
+
import"./index-rk6qhyng.js";
|
|
14
14
|
import"./index-bfwt3abw.js";
|
|
15
15
|
import"./index-g40r5d08.js";
|
|
16
16
|
import"./index-jtqkh8jf.js";
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveKnowledgeCounterBaselinePath,
|
|
26
26
|
resolveKnowledgeEventsPath,
|
|
27
27
|
resolveLegacyApplicationLogPath
|
|
28
|
-
} from "./index-
|
|
28
|
+
} from "./index-8f2270hc.js";
|
|
29
29
|
import"./index-g40r5d08.js";
|
|
30
30
|
import"./index-zgwm4ryv.js";
|
|
31
31
|
import"./index-0p660a87.js";
|
|
@@ -16,14 +16,15 @@ import {
|
|
|
16
16
|
quarantineEntry,
|
|
17
17
|
resolveUnactionablePath,
|
|
18
18
|
restoreEntry,
|
|
19
|
+
scanContentSafety,
|
|
19
20
|
unarchiveEntry,
|
|
20
21
|
validateActionability,
|
|
21
22
|
validateActionableFields,
|
|
22
23
|
validateLesson,
|
|
23
24
|
validateSkillCandidatePath,
|
|
24
25
|
validateSkillPath
|
|
25
|
-
} from "./index-
|
|
26
|
-
import"./index-
|
|
26
|
+
} from "./index-n18yy0z1.js";
|
|
27
|
+
import"./index-rk6qhyng.js";
|
|
27
28
|
import"./index-bfwt3abw.js";
|
|
28
29
|
import"./index-g40r5d08.js";
|
|
29
30
|
import"./index-jtqkh8jf.js";
|
|
@@ -41,6 +42,7 @@ export {
|
|
|
41
42
|
validateActionableFields,
|
|
42
43
|
validateActionability,
|
|
43
44
|
unarchiveEntry,
|
|
45
|
+
scanContentSafety,
|
|
44
46
|
restoreEntry,
|
|
45
47
|
resolveUnactionablePath,
|
|
46
48
|
quarantineEntry,
|
|
@@ -33,10 +33,10 @@ import {
|
|
|
33
33
|
sanitizeSlug,
|
|
34
34
|
selectCandidateEntries,
|
|
35
35
|
writeEvalStub
|
|
36
|
-
} from "./index-
|
|
37
|
-
import"./index-
|
|
38
|
-
import"./index-
|
|
39
|
-
import"./index-
|
|
36
|
+
} from "./index-x12hvfpf.js";
|
|
37
|
+
import"./index-n18yy0z1.js";
|
|
38
|
+
import"./index-8f2270hc.js";
|
|
39
|
+
import"./index-rk6qhyng.js";
|
|
40
40
|
import"./index-bfwt3abw.js";
|
|
41
41
|
import"./index-g40r5d08.js";
|
|
42
42
|
import"./index-jtqkh8jf.js";
|
|
@@ -88,6 +88,18 @@ export declare const ADDITIONAL_SKILL_MIRROR_CONTRACTS: Array<{
|
|
|
88
88
|
kind: 'identical' | 'divergent' | 'opencode-only';
|
|
89
89
|
canonical?: '.claude' | '.opencode';
|
|
90
90
|
extraIdenticalPaths?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* For `divergent` pairs only: a set of Markdown section headings that must be
|
|
93
|
+
* present in BOTH trees (`.opencode` and `.claude`). Divergence is still
|
|
94
|
+
* allowed for genuinely runtime-specific prose (title line, `effort:`
|
|
95
|
+
* frontmatter, "(Claude Code)" phrasing), but these designated safety
|
|
96
|
+
* sections are parity-enforced by scripts/drift-check.ts so a whole safety
|
|
97
|
+
* guard cannot silently exist in one tree and be absent from the other.
|
|
98
|
+
* Match is a substring test, so a heading may omit a trailing parenthetical.
|
|
99
|
+
* Fixes the M13 skill-mirror safety-drift defect: the divergent branch
|
|
100
|
+
* previously did existence-only checks with no content comparison.
|
|
101
|
+
*/
|
|
102
|
+
sharedSafetyHeadings?: string[];
|
|
91
103
|
reason: string;
|
|
92
104
|
}>;
|
|
93
105
|
/**
|
|
@@ -38,6 +38,12 @@ export declare function handleDebuggingSpiral(match: AdversarialPatternMatch, ta
|
|
|
38
38
|
checkpointCreated: boolean;
|
|
39
39
|
message: string;
|
|
40
40
|
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Test seam: current number of distinct sessions tracked for spiral detection.
|
|
43
|
+
* Used by unit tests to assert the FIFO key-count cap holds; the map itself stays
|
|
44
|
+
* module-private so production callers cannot mutate it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function recentToolCallSessionCount(): number;
|
|
41
47
|
/**
|
|
42
48
|
* Record a tool call for debugging spiral detection.
|
|
43
49
|
* Call this from toolAfter to track repetitive patterns.
|
|
@@ -68,6 +68,25 @@ interface ValidationContext {
|
|
|
68
68
|
* Returns { valid: true } on success, or { valid: false; reason: string } on failure.
|
|
69
69
|
*/
|
|
70
70
|
export declare function validateDelegationEnvelope(envelope: unknown, context: ValidationContext): EnvelopeValidationResult;
|
|
71
|
+
/**
|
|
72
|
+
* M15 advisory-only delegation-envelope check. NON-BLOCKING by contract: it
|
|
73
|
+
* NEVER throws and NEVER rejects a delegation. It runs
|
|
74
|
+
* {@link validateDelegationEnvelope} (previously reachable only from tests) on a
|
|
75
|
+
* delegation prompt that ALREADY parses as a structured `DelegationEnvelope`,
|
|
76
|
+
* and on validation failure appends a concise advisory to
|
|
77
|
+
* `session.pendingAdvisoryMessages` — the existing non-blocking channel.
|
|
78
|
+
*
|
|
79
|
+
* A real, minimal free-text delegation (TASK:/FILE:/... with no structured
|
|
80
|
+
* envelope) is a no-op: {@link parseDelegationEnvelope} returns `null`, so no
|
|
81
|
+
* advisory is produced and nothing is rejected. The new optional `specCriteria`
|
|
82
|
+
* field is OPTIONAL in the validator — a missing field passes silently; only a
|
|
83
|
+
* populated-but-malformed field surfaces an advisory.
|
|
84
|
+
*
|
|
85
|
+
* @returns the validation result when an envelope was parsed, or `null` when the
|
|
86
|
+
* prompt was not a structured envelope. Return value is for tests/telemetry;
|
|
87
|
+
* the side effect (advisory push) is the production purpose.
|
|
88
|
+
*/
|
|
89
|
+
export declare function appendDelegationEnvelopeAdvisory(session: AgentSessionState, promptText: string, context: ValidationContext): EnvelopeValidationResult | null;
|
|
71
90
|
interface MessageInfo {
|
|
72
91
|
role: string;
|
|
73
92
|
agent?: string;
|
|
@@ -38,8 +38,9 @@ export declare function enforceSpecDriftGate(directory: string | undefined, tool
|
|
|
38
38
|
declare function extractErrorSignal(errorContent: unknown): string;
|
|
39
39
|
/**
|
|
40
40
|
* Redacts sensitive values from a shell command string before audit logging.
|
|
41
|
+
* Single-sourced from ./helpers (which additionally redacts home paths).
|
|
41
42
|
*/
|
|
42
|
-
export
|
|
43
|
+
export { redactShellCommand } from './helpers';
|
|
43
44
|
/**
|
|
44
45
|
* Creates guardrails hooks for circuit breaker protection
|
|
45
46
|
* @param directory Working directory from plugin init context (required)
|
|
@@ -80,4 +81,3 @@ export declare function createGuardrailsHooks(directory: string, directoryOrConf
|
|
|
80
81
|
}>;
|
|
81
82
|
}) => Promise<void>;
|
|
82
83
|
};
|
|
83
|
-
export {};
|
|
@@ -12,6 +12,28 @@ export declare const DANGEROUS_COMMAND_PATTERNS: RegExp[];
|
|
|
12
12
|
export declare const SECURITY_DEGRADING_PATTERNS: RegExp[];
|
|
13
13
|
export declare const INVISIBLE_FORMAT_CHARS: RegExp;
|
|
14
14
|
export declare const INJECTION_PATTERNS: RegExp[];
|
|
15
|
+
/**
|
|
16
|
+
* Layer-2 content-safety scan for a single string value. Runs the same
|
|
17
|
+
* *blocking* pattern sets {@link validateLesson}'s Layer-2 block uses —
|
|
18
|
+
* dangerous-command errors, security-degrading instructions, and
|
|
19
|
+
* prompt-injection patterns — over an arbitrary short string (e.g. a
|
|
20
|
+
* directive-action field value such as `triggers` / `required_actions` /
|
|
21
|
+
* `forbidden_actions` / `verification_checks`).
|
|
22
|
+
*
|
|
23
|
+
* Returns a blocking reason string on the first match, or `null` when the value
|
|
24
|
+
* is content-safe. Mirrors validateLesson's normalization exactly: NFKC +
|
|
25
|
+
* invisible-format-char stripping + whitespace collapse + lowercase for the
|
|
26
|
+
* dangerous/security scans, and tests the RAW string for the injection patterns
|
|
27
|
+
* (normalization would strip the very control/invisible characters those
|
|
28
|
+
* patterns are meant to detect).
|
|
29
|
+
*
|
|
30
|
+
* The warning-severity dangerous-command patterns are intentionally NOT applied
|
|
31
|
+
* here: validateLesson treats them as non-blocking warnings (they match benign
|
|
32
|
+
* shell snippets like backticks and `$(...)` that legitimately appear in
|
|
33
|
+
* actionable directives), so promoting them to hard rejections on field values
|
|
34
|
+
* would create false positives without a corresponding safety gain.
|
|
35
|
+
*/
|
|
36
|
+
export declare function scanContentSafety(text: string): string | null;
|
|
15
37
|
/**
|
|
16
38
|
* Extract context words around each occurrence of a target word (single tokens within a window).
|
|
17
39
|
* Context window is 3 words before and after, excluding the target word itself.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { Plugin } from '@opencode-ai/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* FIFO-cap a session-keyed Map to at most `max` entries, evicting oldest first.
|
|
4
|
+
* Values tracked by these maps are plain data (timestamps/usage snapshots), never
|
|
5
|
+
* timer handles, so eviction requires no clearInterval/clearTimeout. Exported for
|
|
6
|
+
* unit testing of the cap invariant; used by the heartbeat throttle path below.
|
|
7
|
+
*/
|
|
8
|
+
export declare function capSessionMap<K, V>(map: Map<K, V>, max: number): void;
|
|
2
9
|
declare const _default: {
|
|
3
10
|
id: "opencode-swarm";
|
|
4
11
|
server: Plugin;
|