@gendigital/sage-opencode 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +255 -74
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +194 -88
- package/dist/mcp-server.cjs.map +4 -4
- package/dist/plugin-discovery.d.ts +1 -0
- package/dist/plugin-discovery.d.ts.map +1 -1
- package/dist/plugin-discovery.js +27 -1
- package/dist/plugin-discovery.js.map +1 -1
- package/dist/startup-scan.d.ts +11 -3
- package/dist/startup-scan.d.ts.map +1 -1
- package/dist/startup-scan.js +59 -21
- package/dist/startup-scan.js.map +1 -1
- package/dist/tool-handler.d.ts +2 -1
- package/dist/tool-handler.d.ts.map +1 -1
- package/dist/tool-handler.js +13 -2
- package/dist/tool-handler.js.map +1 -1
- package/package.json +3 -3
- package/resources/threats/dummy.yaml +22 -17
|
@@ -7,6 +7,7 @@ import type { Branding, Logger, PluginInfo } from "@gendigital/sage-core";
|
|
|
7
7
|
* Discover OpenCode plugins from all sources:
|
|
8
8
|
* 1. NPM packages from config files
|
|
9
9
|
* 2. Local plugin files (global + project)
|
|
10
|
+
* 3. Loose skills (global + project) as pseudo-plugins
|
|
10
11
|
*/
|
|
11
12
|
export declare function discoverOpenCodePlugins(logger: Logger, projectDir?: string, branding?: Branding): Promise<PluginInfo[]>;
|
|
12
13
|
//# sourceMappingURL=plugin-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-discovery.d.ts","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"plugin-discovery.d.ts","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAa,MAAM,uBAAuB,CAAC;AA4CrF;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC5C,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,GAAE,QAA0B,GAClC,OAAO,CAAC,UAAU,EAAE,CAAC,CA6BvB"}
|
package/dist/plugin-discovery.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { readdir, stat } from "node:fs/promises";
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { basename, join } from "node:path";
|
|
8
|
-
import { defaultBranding, getFileContent } from "@gendigital/sage-core";
|
|
8
|
+
import { defaultBranding, discoverLooseSkillsAcrossRoots, getFileContent, getHomeDir, } from "@gendigital/sage-core";
|
|
9
9
|
/** Resolve XDG base directories with fallbacks to homedir defaults */
|
|
10
10
|
function getConfigHome() {
|
|
11
11
|
return process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
|
|
@@ -14,10 +14,31 @@ function getCacheHome() {
|
|
|
14
14
|
return process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache");
|
|
15
15
|
}
|
|
16
16
|
const PROJECT_CONFIG_NAME = "opencode.json";
|
|
17
|
+
/**
|
|
18
|
+
* Loose-skill roots OpenCode loads, at both scopes. Global (personal) skills
|
|
19
|
+
* live under the user profile; project skills live inside the project dir.
|
|
20
|
+
* OpenCode reads its own `opencode` family plus Claude- and agent-compatible
|
|
21
|
+
* families; each is scanned so a malicious skill in any load path is covered.
|
|
22
|
+
* The global `opencode` root is XDG-based (`~/.config/opencode/skills`), not
|
|
23
|
+
* `~/.opencode/skills`. The `scope` key segment keeps a personal and project
|
|
24
|
+
* skill of the same family from colliding in the scan cache.
|
|
25
|
+
*/
|
|
26
|
+
function resolveSkillRoots(projectDir) {
|
|
27
|
+
const roots = [
|
|
28
|
+
{ dir: join(getConfigHome(), "opencode", "skills"), tag: "opencode", scope: "personal" },
|
|
29
|
+
{ dir: join(getHomeDir(), ".claude", "skills"), tag: "claude", scope: "personal" },
|
|
30
|
+
{ dir: join(getHomeDir(), ".agents", "skills"), tag: "agents", scope: "personal" },
|
|
31
|
+
];
|
|
32
|
+
if (projectDir) {
|
|
33
|
+
roots.push({ dir: join(projectDir, ".opencode", "skills"), tag: "opencode", scope: "project" }, { dir: join(projectDir, ".claude", "skills"), tag: "claude", scope: "project" }, { dir: join(projectDir, ".agents", "skills"), tag: "agents", scope: "project" });
|
|
34
|
+
}
|
|
35
|
+
return roots;
|
|
36
|
+
}
|
|
17
37
|
/**
|
|
18
38
|
* Discover OpenCode plugins from all sources:
|
|
19
39
|
* 1. NPM packages from config files
|
|
20
40
|
* 2. Local plugin files (global + project)
|
|
41
|
+
* 3. Loose skills (global + project) as pseudo-plugins
|
|
21
42
|
*/
|
|
22
43
|
export async function discoverOpenCodePlugins(logger, projectDir, branding = defaultBranding) {
|
|
23
44
|
logger.debug(`${branding.name} plugin discovery: scanning OpenCode plugins`);
|
|
@@ -35,6 +56,11 @@ export async function discoverOpenCodePlugins(logger, projectDir, branding = def
|
|
|
35
56
|
const projectPlugins = await discoverLocalPlugins(projectPluginsDir, "project", logger);
|
|
36
57
|
plugins.push(...projectPlugins);
|
|
37
58
|
}
|
|
59
|
+
// 4. Discover loose skills as pseudo-plugins (deduped by resolved path,
|
|
60
|
+
// fails open per root) so the scan pipeline covers skills installed outside
|
|
61
|
+
// any plugin.
|
|
62
|
+
const skills = await discoverLooseSkillsAcrossRoots(resolveSkillRoots(projectDir));
|
|
63
|
+
plugins.push(...skills);
|
|
38
64
|
logger.debug(`${branding.name} plugin discovery: found ${plugins.length} plugin(s)`);
|
|
39
65
|
return plugins;
|
|
40
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-discovery.js","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,
|
|
1
|
+
{"version":3,"file":"plugin-discovery.js","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/startup-scan.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Startup and session scan handlers for OpenCode.
|
|
3
|
-
*
|
|
3
|
+
* Runs core's session scan and hands back the structured findings so the
|
|
4
|
+
* connector can build its own TUI popup (rather than a formatted string).
|
|
4
5
|
*/
|
|
5
|
-
import { type Branding, type Logger } from "@gendigital/sage-core";
|
|
6
|
-
export declare function
|
|
6
|
+
import { type Branding, type Logger, type PluginScanResult } from "@gendigital/sage-core";
|
|
7
|
+
export declare function resolveSkillUploadWorkerPath(): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Build a session-scan runner. Discovers OpenCode plugins/skills (minus Sage
|
|
10
|
+
* itself), runs the core session scan — which populates the verdict cache and
|
|
11
|
+
* spawns the skill-upload worker — and passes the structured results to
|
|
12
|
+
* `onResults`. Fails open: any error is logged and the handler resolves.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSessionScanHandler(logger: Logger, projectDir?: string, onResults?: (results: PluginScanResult[]) => void, branding?: Branding, onNotices?: (noticeIds: string[]) => void): () => Promise<void>;
|
|
7
15
|
//# sourceMappingURL=startup-scan.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-scan.d.ts","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"startup-scan.d.ts","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACN,KAAK,QAAQ,EAEb,KAAK,MAAM,EACX,KAAK,gBAAgB,EAErB,MAAM,uBAAuB,CAAC;AAqB/B,wBAAgB,4BAA4B,IAAI,MAAM,GAAG,SAAS,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,IAAI,EACjD,QAAQ,GAAE,QAA0B,EACpC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,IAAI,GACvC,MAAM,OAAO,CAAC,IAAI,CAAC,CAuCrB"}
|
package/dist/startup-scan.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Startup and session scan handlers for OpenCode.
|
|
3
|
-
*
|
|
3
|
+
* Runs core's session scan and hands back the structured findings so the
|
|
4
|
+
* connector can build its own TUI popup (rather than a formatted string).
|
|
4
5
|
*/
|
|
5
6
|
import { createRequire } from "node:module";
|
|
6
|
-
import {
|
|
7
|
+
import { defaultBranding, runSessionStart, } from "@gendigital/sage-core";
|
|
7
8
|
import { getBundledDataDirs, getSageVersion } from "./bundled-dirs.js";
|
|
8
9
|
import { discoverOpenCodePlugins } from "./plugin-discovery.js";
|
|
10
|
+
const SELF_PREFIX = "@gendigital/sage-opencode@";
|
|
9
11
|
/**
|
|
10
|
-
* OpenCode is published as an unbundled ESM plugin (tsc only). The
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* OpenCode is published as an unbundled ESM plugin (tsc only). The detached
|
|
13
|
+
* workers therefore live in the `@gendigital/sage-core` package under
|
|
14
|
+
* `dist/`. Resolve via `require.resolve` so we pick them up wherever
|
|
15
|
+
* pnpm/node placed them.
|
|
14
16
|
*/
|
|
15
17
|
function resolveModelDownloadWorkerPath() {
|
|
16
18
|
try {
|
|
@@ -21,22 +23,58 @@ function resolveModelDownloadWorkerPath() {
|
|
|
21
23
|
return undefined;
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
|
-
export function
|
|
26
|
+
export function resolveSkillUploadWorkerPath() {
|
|
27
|
+
try {
|
|
28
|
+
const req = createRequire(import.meta.url);
|
|
29
|
+
return req.resolve("@gendigital/sage-core/dist/skill-upload-worker.js");
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Build a session-scan runner. Discovers OpenCode plugins/skills (minus Sage
|
|
37
|
+
* itself), runs the core session scan — which populates the verdict cache and
|
|
38
|
+
* spawns the skill-upload worker — and passes the structured results to
|
|
39
|
+
* `onResults`. Fails open: any error is logged and the handler resolves.
|
|
40
|
+
*/
|
|
41
|
+
export function createSessionScanHandler(logger, projectDir, onResults, branding = defaultBranding, onNotices) {
|
|
25
42
|
const { threatsDir, trustedDomainsDir } = getBundledDataDirs();
|
|
26
43
|
const version = getSageVersion();
|
|
27
|
-
return
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
return async () => {
|
|
45
|
+
try {
|
|
46
|
+
const discovered = await discoverOpenCodePlugins(logger, projectDir, branding);
|
|
47
|
+
const plugins = discovered.filter((p) => !p.key.startsWith(SELF_PREFIX));
|
|
48
|
+
const { scanResults, notices } = await runSessionStart({
|
|
49
|
+
plugins,
|
|
50
|
+
threatsDir,
|
|
51
|
+
trustedDomainsDir,
|
|
52
|
+
version,
|
|
53
|
+
logger,
|
|
54
|
+
agentRuntime: "opencode",
|
|
55
|
+
// No agentRuntimeVersion: the OpenCode SDK exposes no host version synchronously.
|
|
56
|
+
modelDownloadWorkerPath: resolveModelDownloadWorkerPath(),
|
|
57
|
+
skillUploadWorkerPath: resolveSkillUploadWorkerPath(),
|
|
58
|
+
});
|
|
59
|
+
const findingsCount = scanResults.reduce((n, r) => n + r.findings.length, 0);
|
|
60
|
+
logger.debug(`${branding.name} session scan complete`, {
|
|
61
|
+
agentRuntime: "opencode",
|
|
62
|
+
pluginsCount: plugins.length,
|
|
63
|
+
resultsWithFindings: scanResults.length,
|
|
64
|
+
findingsCount,
|
|
65
|
+
});
|
|
66
|
+
// Surface the one-time notice BEFORE the finding toasts. The toast queue
|
|
67
|
+
// is FIFO, so enqueuing notices first shows the "new feature" info ahead
|
|
68
|
+
// of any malware findings.
|
|
69
|
+
if (notices && notices.length > 0)
|
|
70
|
+
onNotices?.(notices);
|
|
71
|
+
onResults?.(scanResults);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
logger.error(`${branding.name} session scan failed (fail-open)`, {
|
|
75
|
+
error: String(error),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
41
79
|
}
|
|
42
80
|
//# sourceMappingURL=startup-scan.js.map
|
package/dist/startup-scan.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup-scan.js","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"startup-scan.js","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAEN,eAAe,EAGf,eAAe,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,GAAG,4BAA4B,CAAC;AAEjD;;;;;GAKG;AACH,SAAS,8BAA8B;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC3C,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CACvC,MAAc,EACd,UAAmB,EACnB,SAAiD,EACjD,WAAqB,eAAe,EACpC,SAAyC;IAEzC,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAC/D,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IAEjC,OAAO,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACJ,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC/E,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC;YAEzE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,eAAe,CAAC;gBACtD,OAAO;gBACP,UAAU;gBACV,iBAAiB;gBACjB,OAAO;gBACP,MAAM;gBACN,YAAY,EAAE,UAAU;gBACxB,kFAAkF;gBAClF,uBAAuB,EAAE,8BAA8B,EAAE;gBACzD,qBAAqB,EAAE,4BAA4B,EAAE;aACrD,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAC7E,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,IAAI,wBAAwB,EAAE;gBACtD,YAAY,EAAE,UAAU;gBACxB,YAAY,EAAE,OAAO,CAAC,MAAM;gBAC5B,mBAAmB,EAAE,WAAW,CAAC,MAAM;gBACvC,aAAa;aACb,CAAC,CAAC;YACH,yEAAyE;YACzE,yEAAyE;YACzE,2BAA2B;YAC3B,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC;YACxD,SAAS,EAAE,CAAC,WAAW,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,IAAI,kCAAkC,EAAE;gBAChE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;aACpB,CAAC,CAAC;QACJ,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
|
package/dist/tool-handler.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type ApprovalStore, type Branding, type Logger } from "@gendigital/sage-core";
|
|
1
|
+
import { type ApprovalStore, type Branding, type CanonicalToolType, type Logger } from "@gendigital/sage-core";
|
|
2
|
+
export declare const OPENCODE_TOOL_MAP: Record<string, CanonicalToolType>;
|
|
2
3
|
export interface ToolHandlerOptions {
|
|
3
4
|
showToast?: (msg: string, variant: "info" | "success" | "warning" | "error") => void;
|
|
4
5
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,iBAAiB,EAOtB,KAAK,MAAM,EAEX,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAc/D,CAAC;AA+BF,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;CACrF;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,MAAM,EACzB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,QAAQ,GAAE,QAA0B;mCAG5B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAClD;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KACvC,OAAO,CAAC,IAAI,CAAC;EAyIhB"}
|
package/dist/tool-handler.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { canonicalizeToolName, defaultBranding, formatDenyMessage, guardToolCall, summarizeArtifacts, } from "@gendigital/sage-core";
|
|
2
|
-
const OPENCODE_TOOL_MAP = {
|
|
1
|
+
import { canonicalizeToolName, captureEnabled, captureHookInput, defaultBranding, formatDenyMessage, guardToolCall, summarizeArtifacts, } from "@gendigital/sage-core";
|
|
2
|
+
export const OPENCODE_TOOL_MAP = {
|
|
3
3
|
bash: "Bash",
|
|
4
4
|
webfetch: "WebFetch",
|
|
5
5
|
write: "Write",
|
|
@@ -59,6 +59,17 @@ export function createToolHandlers(logger, approvalStore, threatsDir, trustedDom
|
|
|
59
59
|
});
|
|
60
60
|
try {
|
|
61
61
|
const args = output.args ?? {};
|
|
62
|
+
// E2E payload-drift capture (drift loop). OpenCode is an in-process
|
|
63
|
+
// ESM plugin (not MCP, not a CJS hook), so the "raw wire" payload is the
|
|
64
|
+
// in-proc tool-call shape OpenCode hands us. Namespaced opencode-* so it
|
|
65
|
+
// can't collide with other agents sharing SAGE_E2E_CAPTURE_DIR. Inert in
|
|
66
|
+
// production (env unset); fail-open inside captureHookInput.
|
|
67
|
+
if (captureEnabled()) {
|
|
68
|
+
await captureHookInput("PreToolUse", { tool: input.tool, sessionID: input.sessionID, callID: input.callID, args }, {
|
|
69
|
+
toolName: canonicalizeToolName(OPENCODE_TOOL_MAP, input.tool),
|
|
70
|
+
toolInput: normalizeToolInput(input.tool, args),
|
|
71
|
+
}, { filePrefix: "opencode-" });
|
|
72
|
+
}
|
|
62
73
|
const artifacts = extractFromOpenCodeTool(input.tool, args);
|
|
63
74
|
if (!artifacts || artifacts.length === 0) {
|
|
64
75
|
completeHook("skipped", { skippedReason: "no_artifacts" });
|
package/dist/tool-handler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,oBAAoB,EACpB,eAAe,EACf,iBAAiB,EACjB,aAAa,EAEb,kBAAkB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,iBAAiB,GAAsC;
|
|
1
|
+
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.12.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"description": "Safety for Agents - ADR layer for OpenCode",
|
|
10
10
|
"homepage": "https://github.com/gendigitalinc/sage",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@opencode-ai/plugin": "^1.14.48",
|
|
35
|
-
"@gendigital/sage-
|
|
36
|
-
"@gendigital/sage-
|
|
35
|
+
"@gendigital/sage-mcp": "0.12.0",
|
|
36
|
+
"@gendigital/sage-core": "0.12.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.0.0",
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
# Author: Test — NOT real threats
|
|
3
3
|
#
|
|
4
4
|
# Canary rules that match completely harmless, highly-specific marker strings.
|
|
5
|
-
# The
|
|
6
|
-
#
|
|
5
|
+
# The markers are deliberately OPAQUE (e.g. "diagmark_cmd_a75bf229", not
|
|
6
|
+
# "__sage_test_deny_cmd_..."): a self-describing name reads as a security probe, and
|
|
7
|
+
# a safety-trained model given security context (e.g. OpenCode, which injects Sage's
|
|
8
|
+
# scan findings into the prompt) will REFUSE to run it — so the artifact never
|
|
9
|
+
# reaches Sage and the E2E deny/ask test can't fire. Opaque markers run as rote yet
|
|
10
|
+
# stay unique random strings, so false positives are essentially impossible. The
|
|
11
|
+
# rule id/title carry the human-readable meaning; the hex suffix aids traceability.
|
|
7
12
|
#
|
|
8
13
|
# Coverage matrix:
|
|
9
14
|
# Tool match_on block(deny) require_approval(ask) log(allow)
|
|
@@ -24,7 +29,7 @@
|
|
|
24
29
|
category: testing
|
|
25
30
|
severity: critical
|
|
26
31
|
confidence: 0.95
|
|
27
|
-
pattern: "
|
|
32
|
+
pattern: "diagmark_cmd_a75bf229"
|
|
28
33
|
match_on: command
|
|
29
34
|
title: "[TEST] Canary deny command (alpha)"
|
|
30
35
|
expires_at: null
|
|
@@ -34,7 +39,7 @@
|
|
|
34
39
|
category: testing
|
|
35
40
|
severity: critical
|
|
36
41
|
confidence: 0.95
|
|
37
|
-
pattern: "
|
|
42
|
+
pattern: "diagmark_run_c3d91e4a"
|
|
38
43
|
match_on: command
|
|
39
44
|
title: "[TEST] Canary deny command (bravo)"
|
|
40
45
|
expires_at: null
|
|
@@ -44,7 +49,7 @@
|
|
|
44
49
|
category: testing
|
|
45
50
|
severity: warning
|
|
46
51
|
confidence: 0.60
|
|
47
|
-
pattern: "
|
|
52
|
+
pattern: "diagmark_cmd_8f2e6b71"
|
|
48
53
|
match_on: command
|
|
49
54
|
title: "[TEST] Canary approval command (alpha)"
|
|
50
55
|
expires_at: null
|
|
@@ -54,7 +59,7 @@
|
|
|
54
59
|
category: testing
|
|
55
60
|
severity: warning
|
|
56
61
|
confidence: 0.60
|
|
57
|
-
pattern: "
|
|
62
|
+
pattern: "diagmark_run_d4a09c53"
|
|
58
63
|
match_on: command
|
|
59
64
|
title: "[TEST] Canary approval command (bravo)"
|
|
60
65
|
expires_at: null
|
|
@@ -64,7 +69,7 @@
|
|
|
64
69
|
category: testing
|
|
65
70
|
severity: info
|
|
66
71
|
confidence: 0.10
|
|
67
|
-
pattern: "
|
|
72
|
+
pattern: "diagmark_cmd_1b7e3f82"
|
|
68
73
|
match_on: command
|
|
69
74
|
title: "[TEST] Canary log-only command"
|
|
70
75
|
expires_at: null
|
|
@@ -77,7 +82,7 @@
|
|
|
77
82
|
category: testing
|
|
78
83
|
severity: critical
|
|
79
84
|
confidence: 0.95
|
|
80
|
-
pattern: "
|
|
85
|
+
pattern: "diagmark_file_e6c4a918"
|
|
81
86
|
match_on: file_path
|
|
82
87
|
title: "[TEST] Canary deny file path"
|
|
83
88
|
expires_at: null
|
|
@@ -87,7 +92,7 @@
|
|
|
87
92
|
category: testing
|
|
88
93
|
severity: warning
|
|
89
94
|
confidence: 0.60
|
|
90
|
-
pattern: "
|
|
95
|
+
pattern: "diagmark_file_52fd7b36"
|
|
91
96
|
match_on: file_path
|
|
92
97
|
title: "[TEST] Canary approval file path"
|
|
93
98
|
expires_at: null
|
|
@@ -97,7 +102,7 @@
|
|
|
97
102
|
category: testing
|
|
98
103
|
severity: info
|
|
99
104
|
confidence: 0.10
|
|
100
|
-
pattern: "
|
|
105
|
+
pattern: "diagmark_file_9a13de74"
|
|
101
106
|
match_on: file_path
|
|
102
107
|
title: "[TEST] Canary log-only file path"
|
|
103
108
|
expires_at: null
|
|
@@ -110,7 +115,7 @@
|
|
|
110
115
|
category: testing
|
|
111
116
|
severity: critical
|
|
112
117
|
confidence: 0.95
|
|
113
|
-
pattern: "
|
|
118
|
+
pattern: "diagmark_content_3c8f15b7"
|
|
114
119
|
match_on: content
|
|
115
120
|
title: "[TEST] Canary deny content"
|
|
116
121
|
expires_at: null
|
|
@@ -120,7 +125,7 @@
|
|
|
120
125
|
category: testing
|
|
121
126
|
severity: warning
|
|
122
127
|
confidence: 0.60
|
|
123
|
-
pattern: "
|
|
128
|
+
pattern: "diagmark_content_7d4ea2c9"
|
|
124
129
|
match_on: content
|
|
125
130
|
title: "[TEST] Canary approval content"
|
|
126
131
|
expires_at: null
|
|
@@ -130,7 +135,7 @@
|
|
|
130
135
|
category: testing
|
|
131
136
|
severity: info
|
|
132
137
|
confidence: 0.10
|
|
133
|
-
pattern: "
|
|
138
|
+
pattern: "diagmark_content_f0b683d1"
|
|
134
139
|
match_on: content
|
|
135
140
|
title: "[TEST] Canary log-only content"
|
|
136
141
|
expires_at: null
|
|
@@ -144,7 +149,7 @@
|
|
|
144
149
|
category: testing
|
|
145
150
|
severity: critical
|
|
146
151
|
confidence: 0.95
|
|
147
|
-
pattern: "
|
|
152
|
+
pattern: "diaghost-4e91ca37\\.test"
|
|
148
153
|
match_on: url
|
|
149
154
|
title: "[TEST] Canary deny URL"
|
|
150
155
|
expires_at: null
|
|
@@ -154,7 +159,7 @@
|
|
|
154
159
|
category: testing
|
|
155
160
|
severity: warning
|
|
156
161
|
confidence: 0.60
|
|
157
|
-
pattern: "
|
|
162
|
+
pattern: "diaghost-b26d80f5\\.test"
|
|
158
163
|
match_on: url
|
|
159
164
|
title: "[TEST] Canary approval URL"
|
|
160
165
|
expires_at: null
|
|
@@ -164,7 +169,7 @@
|
|
|
164
169
|
category: testing
|
|
165
170
|
severity: info
|
|
166
171
|
confidence: 0.10
|
|
167
|
-
pattern: "
|
|
172
|
+
pattern: "diaghost-65f3d7a4\\.test"
|
|
168
173
|
match_on: url
|
|
169
174
|
title: "[TEST] Canary log-only URL"
|
|
170
175
|
expires_at: null
|
|
@@ -177,7 +182,7 @@
|
|
|
177
182
|
category: testing
|
|
178
183
|
severity: critical
|
|
179
184
|
confidence: 0.95
|
|
180
|
-
pattern: "
|
|
185
|
+
pattern: "diaghost-0c82eb16\\.test"
|
|
181
186
|
match_on: domain
|
|
182
187
|
title: "[TEST] Canary deny domain"
|
|
183
188
|
expires_at: null
|