@gendigital/sage-opencode 0.13.0 → 0.15.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.
@@ -13,26 +13,40 @@ export const OPENCODE_TOOL_MAP = {
13
13
  question: "Question",
14
14
  task: "Task",
15
15
  read_lines: "ReadLines",
16
+ // OpenCode v2 tool names
17
+ shell: "Bash",
18
+ patch: "ApplyPatch",
19
+ subagent: "Task",
16
20
  };
17
21
  import { SageVerdictBlockError, SageVerdictError } from "./error.js";
18
- import { extractFromOpenCodeTool } from "./extractors.js";
22
+ import { extractFromOpenCodeTool, openCodeFilePath, openCodePatchTexts } from "./extractors.js";
19
23
  function asString(value) {
20
24
  return typeof value === "string" ? value : undefined;
21
25
  }
22
- function normalizeToolInput(toolName, args) {
26
+ /**
27
+ * Map OpenCode argument names onto the Claude-style keys core reads
28
+ * (`file_path`, `new_string`, and `patch` for ApplyPatch AMSI scans and
29
+ * content snapshots).
30
+ */
31
+ export function normalizeToolInput(toolName, args) {
23
32
  switch (toolName) {
24
33
  case "write":
25
34
  return {
26
35
  ...args,
27
- file_path: asString(args.filePath) ?? asString(args.file_path) ?? "",
36
+ file_path: openCodeFilePath(args) || (asString(args.file_path) ?? ""),
28
37
  content: asString(args.content) ?? "",
29
38
  };
30
39
  case "edit":
31
40
  return {
32
41
  ...args,
33
- file_path: asString(args.filePath) ?? asString(args.file_path) ?? "",
42
+ file_path: openCodeFilePath(args) || (asString(args.file_path) ?? ""),
34
43
  new_string: asString(args.newString) ?? asString(args.new_string) ?? "",
35
44
  };
45
+ case "patch":
46
+ return {
47
+ ...args,
48
+ patch: asString(args.patch) ?? asString(args.patchText) ?? "",
49
+ };
36
50
  default:
37
51
  return args;
38
52
  }
@@ -59,6 +73,10 @@ export function createToolHandlers(logger, approvalStore, threatsDir, trustedDom
59
73
  });
60
74
  try {
61
75
  const args = output.args ?? {};
76
+ if (input.tool === "patch" && openCodePatchTexts(args).length > 1) {
77
+ completeHook("blocked", { skippedReason: "conflicting_patch_fields" });
78
+ throw new SageVerdictBlockError(`${branding.name} blocked this patch: patchText and patch contain different content.`);
79
+ }
62
80
  // E2E payload-drift capture (drift loop). OpenCode is an in-process
63
81
  // ESM plugin (not MCP, not a CJS hook), so the "raw wire" payload is the
64
82
  // in-proc tool-call shape OpenCode hands us. Namespaced opencode-* so it
@@ -1 +1 @@
1
- {"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Local structural types for the OpenCode v2 plugin API.
3
+ *
4
+ * Structural subset of the OpenCode v2 Promise plugin API, checked against
5
+ * the 2.1.4 server plugin documentation. Declared locally so the package can
6
+ * retain its v1 SDK dependency. Re-check these shapes when updating v2 support.
7
+ */
8
+ /** OpenCode v2 version these types were last checked against. */
9
+ export declare const V2_SDK_TYPES_VERSION = "2.1.4";
10
+ export interface V2Registration {
11
+ readonly dispose: () => Promise<void>;
12
+ }
13
+ /** Subset of v2 `ToolContext` passed to tool `execute`. */
14
+ export interface V2ToolContext {
15
+ readonly sessionID: string;
16
+ readonly agent: string;
17
+ readonly messageID: string;
18
+ readonly id: string;
19
+ readonly [key: string]: unknown;
20
+ }
21
+ export interface V2ToolResult {
22
+ content?: unknown;
23
+ metadata?: Record<string, unknown>;
24
+ }
25
+ export interface V2PermissionEvaluation {
26
+ readonly action: string;
27
+ effect: "allow" | "ask" | "deny";
28
+ }
29
+ export interface V2PermissionAssertInput {
30
+ readonly sessionID: string;
31
+ readonly agent: string;
32
+ readonly source: {
33
+ readonly type: "tool";
34
+ readonly messageID: string;
35
+ readonly id: string;
36
+ };
37
+ readonly action: string;
38
+ readonly resources: readonly string[];
39
+ readonly save: readonly string[];
40
+ }
41
+ export interface V2ToolInfo {
42
+ readonly name?: string;
43
+ readonly description: string;
44
+ readonly input: unknown;
45
+ readonly options?: {
46
+ readonly codemode?: boolean;
47
+ };
48
+ readonly execute: (input: unknown, context: V2ToolContext) => Promise<V2ToolResult>;
49
+ }
50
+ export interface V2ToolEditor {
51
+ get(id: string): V2ToolInfo | undefined;
52
+ add(tool: V2ToolInfo): void;
53
+ }
54
+ export interface V2McpEditor {
55
+ get(name: string): unknown;
56
+ set(name: string, config: Record<string, unknown>): void;
57
+ }
58
+ export interface V2ToolExecuteBefore {
59
+ tool: string;
60
+ readonly sessionID: string;
61
+ readonly id: string;
62
+ input: unknown;
63
+ }
64
+ /** Structural subset of the v2 promise plugin `Context` Sage relies on. */
65
+ export interface V2PluginContext {
66
+ readonly location?: {
67
+ readonly directory?: string;
68
+ };
69
+ readonly tool: {
70
+ readonly transform: (callback: (editor: V2ToolEditor) => void) => Promise<V2Registration>;
71
+ readonly hook: (name: "execute.before", callback: (event: V2ToolExecuteBefore) => Promise<void> | void) => Promise<V2Registration>;
72
+ };
73
+ readonly permission: {
74
+ readonly assert: (input: V2PermissionAssertInput) => Promise<void>;
75
+ readonly hook: (name: "evaluate", callback: (event: V2PermissionEvaluation) => Promise<void> | void) => Promise<V2Registration>;
76
+ };
77
+ readonly mcp?: {
78
+ readonly transform: (callback: (editor: V2McpEditor) => void) => Promise<V2Registration>;
79
+ };
80
+ readonly session?: {
81
+ readonly hook: (name: "prompt", callback: (event: {
82
+ readonly sessionID: string;
83
+ }) => Promise<void> | void) => Promise<V2Registration>;
84
+ };
85
+ /** Not part of the v2 server context today; used if a future host exposes it. */
86
+ readonly toast?: {
87
+ show(options: {
88
+ title?: string;
89
+ message: string;
90
+ variant?: string;
91
+ duration?: number;
92
+ }): void;
93
+ };
94
+ }
95
+ //# sourceMappingURL=v2-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-types.d.ts","sourceRoot":"","sources":["../src/v2-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACnD,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,YAAY;IAC5B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IACxC,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACzD;AAED,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;CACf;AAED,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,QAAQ,CAAC,IAAI,EAAE;QACd,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;QAC1F,QAAQ,CAAC,IAAI,EAAE,CACd,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KAC1D,OAAO,CAAC,cAAc,CAAC,CAAC;KAC7B,CAAC;IACF,QAAQ,CAAC,UAAU,EAAE;QACpB,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACnE,QAAQ,CAAC,IAAI,EAAE,CACd,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KAC7D,OAAO,CAAC,cAAc,CAAC,CAAC;KAC7B,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,EAAE;QACd,QAAQ,CAAC,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;KACzF,CAAC;IACF,QAAQ,CAAC,OAAO,CAAC,EAAE;QAClB,QAAQ,CAAC,IAAI,EAAE,CACd,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,CAAC,KAAK,EAAE;YAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KACrE,OAAO,CAAC,cAAc,CAAC,CAAC;KAC7B,CAAC;IACF,iFAAiF;IACjF,QAAQ,CAAC,KAAK,CAAC,EAAE;QAChB,IAAI,CAAC,OAAO,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;KAC9F,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Local structural types for the OpenCode v2 plugin API.
3
+ *
4
+ * Structural subset of the OpenCode v2 Promise plugin API, checked against
5
+ * the 2.1.4 server plugin documentation. Declared locally so the package can
6
+ * retain its v1 SDK dependency. Re-check these shapes when updating v2 support.
7
+ */
8
+ /** OpenCode v2 version these types were last checked against. */
9
+ export const V2_SDK_TYPES_VERSION = "2.1.4";
10
+ //# sourceMappingURL=v2-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2-types.js","sourceRoot":"","sources":["../src/v2-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC"}
package/dist/v2.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * OpenCode v2 (opencode2 / `@opencode-ai/core`) adapter.
3
+ *
4
+ * v2 loads the package's default export as `{ id, setup }` and calls
5
+ * `setup(context)` with domain APIs instead of v1's hooks object. This adapter
6
+ * maps those domains onto the shared Sage controller:
7
+ * - `tool.hook("execute.before")` → Sage tool interception. Throwing from the
8
+ * hook fails just that tool call with the thrown message (the turn continues),
9
+ * which is the v1 block semantics, so the same `SageVerdictBlockError` works.
10
+ * - `tool.transform` → registers `sage_approve`, which requests a native
11
+ * permission prompt through `permission.assert`.
12
+ * - `permission.hook("evaluate")` → forces Sage approval requests to ask.
13
+ * - `mcp.transform` → registers the Sage MCP server unless `sage` exists.
14
+ * - `session.hook("prompt")` → per-session plugin/skill scan.
15
+ *
16
+ * The v2 API types live in `v2-types.ts` (see there for the SDK version they
17
+ * mirror); every payload is validated before use (fail open).
18
+ */
19
+ import type { V2PluginContext } from "./v2-types.js";
20
+ export type { V2McpEditor, V2PluginContext, V2ToolContext, V2ToolEditor, V2ToolExecuteBefore, V2ToolInfo, V2ToolResult, } from "./v2-types.js";
21
+ export declare const SAGE_APPROVE_TOOL = "sage_approve";
22
+ /** OpenCode v2 plugin `setup`. Returns a cleanup that disposes registrations. */
23
+ export declare function setupV2(context: V2PluginContext): Promise<() => Promise<void>>;
24
+ //# sourceMappingURL=v2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../src/v2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH,OAAO,KAAK,EAAE,eAAe,EAA8B,MAAM,eAAe,CAAC;AAEjF,YAAY,EACX,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,UAAU,EACV,YAAY,GACZ,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AA0ChD,iFAAiF;AACjF,wBAAsB,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAuGpF"}
package/dist/v2.js ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * OpenCode v2 (opencode2 / `@opencode-ai/core`) adapter.
3
+ *
4
+ * v2 loads the package's default export as `{ id, setup }` and calls
5
+ * `setup(context)` with domain APIs instead of v1's hooks object. This adapter
6
+ * maps those domains onto the shared Sage controller:
7
+ * - `tool.hook("execute.before")` → Sage tool interception. Throwing from the
8
+ * hook fails just that tool call with the thrown message (the turn continues),
9
+ * which is the v1 block semantics, so the same `SageVerdictBlockError` works.
10
+ * - `tool.transform` → registers `sage_approve`, which requests a native
11
+ * permission prompt through `permission.assert`.
12
+ * - `permission.hook("evaluate")` → forces Sage approval requests to ask.
13
+ * - `mcp.transform` → registers the Sage MCP server unless `sage` exists.
14
+ * - `session.hook("prompt")` → per-session plugin/skill scan.
15
+ *
16
+ * The v2 API types live in `v2-types.ts` (see there for the SDK version they
17
+ * mirror); every payload is validated before use (fail open).
18
+ */
19
+ import { ApprovalUnavailableError, approvalPatterns, createSageController, SAGE_MCP_SERVER_NAME, sageMcpServerConfig, } from "./shared.js";
20
+ export const SAGE_APPROVE_TOOL = "sage_approve";
21
+ const SAGE_APPROVAL_ACTION = "sage_approval";
22
+ function isRecord(value) {
23
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24
+ }
25
+ function createApproveTool(sage, plugin) {
26
+ return {
27
+ name: SAGE_APPROVE_TOOL,
28
+ description: sage.approveToolDescription,
29
+ input: {
30
+ type: "object",
31
+ properties: {
32
+ actionId: { type: "string", description: sage.approveArgDescription },
33
+ },
34
+ required: ["actionId"],
35
+ additionalProperties: false,
36
+ },
37
+ // The approval dialog must be driven by the model directly, not from a
38
+ // code-mode script.
39
+ options: { codemode: false },
40
+ async execute(input, context) {
41
+ const actionId = isRecord(input) && typeof input.actionId === "string" ? input.actionId : "";
42
+ const result = await sage.resolveApproval(actionId, async (pending) => {
43
+ if (!plugin.permission || typeof plugin.permission.assert !== "function") {
44
+ throw new ApprovalUnavailableError("OpenCode v2 permission API is unavailable");
45
+ }
46
+ await plugin.permission.assert({
47
+ sessionID: context.sessionID,
48
+ agent: context.agent,
49
+ source: { type: "tool", messageID: context.messageID, id: context.id },
50
+ action: SAGE_APPROVAL_ACTION,
51
+ resources: [`${actionId}: ${approvalPatterns(pending).join(", ")}`],
52
+ save: [],
53
+ });
54
+ });
55
+ return { content: result };
56
+ },
57
+ };
58
+ }
59
+ /** OpenCode v2 plugin `setup`. Returns a cleanup that disposes registrations. */
60
+ export async function setupV2(context) {
61
+ const toast = context.toast;
62
+ const createNotifier = toast && typeof toast.show === "function"
63
+ ? (branding) => (message, variant, duration) => {
64
+ try {
65
+ toast.show({ title: branding.name, message, variant, duration });
66
+ }
67
+ catch {
68
+ // Notifications are best-effort
69
+ }
70
+ }
71
+ : undefined;
72
+ const sage = await createSageController({
73
+ directory: context.location?.directory ?? process.cwd(),
74
+ createNotifier,
75
+ host: "v2",
76
+ });
77
+ const registrations = [];
78
+ if (!context.permission || typeof context.permission.hook !== "function") {
79
+ throw new Error("OpenCode v2 permission hook is required for Sage approvals");
80
+ }
81
+ registrations.push(await context.permission.hook("evaluate", (event) => {
82
+ if (event.action === SAGE_APPROVAL_ACTION && event.effect === "allow")
83
+ event.effect = "ask";
84
+ }));
85
+ registrations.push(await context.tool.hook("execute.before", async (event) => {
86
+ // Unexpected shapes fail open: Sage never blocks a call it can't read.
87
+ if (!isRecord(event) || typeof event.tool !== "string")
88
+ return;
89
+ let args;
90
+ let unrecognizedReason = "not_an_object";
91
+ if (isRecord(event.input)) {
92
+ args = event.input;
93
+ }
94
+ else if (typeof event.input === "string") {
95
+ try {
96
+ const parsed = JSON.parse(event.input);
97
+ if (isRecord(parsed))
98
+ args = parsed;
99
+ else
100
+ unrecognizedReason = "json_not_an_object";
101
+ }
102
+ catch {
103
+ unrecognizedReason = "invalid_json";
104
+ }
105
+ }
106
+ if (!args) {
107
+ sage.logger.warn("OpenCode v2 tool input has unrecognized shape", {
108
+ tool: event.tool,
109
+ sessionID: event.sessionID,
110
+ callID: event.id,
111
+ inputType: Array.isArray(event.input)
112
+ ? "array"
113
+ : event.input === null
114
+ ? "null"
115
+ : typeof event.input,
116
+ reason: unrecognizedReason,
117
+ });
118
+ }
119
+ await sage.beforeToolUse({
120
+ tool: event.tool,
121
+ sessionID: typeof event.sessionID === "string" ? event.sessionID : "unknown",
122
+ callID: typeof event.id === "string" ? event.id : "",
123
+ }, { args: args ?? {} });
124
+ }));
125
+ registrations.push(await context.tool.transform((editor) => {
126
+ if (!editor.get(SAGE_APPROVE_TOOL)) {
127
+ editor.add(createApproveTool(sage, context));
128
+ }
129
+ }));
130
+ if (context.mcp) {
131
+ registrations.push(await context.mcp.transform((editor) => {
132
+ // Never clobber a user-supplied `sage` server.
133
+ if (editor.get(SAGE_MCP_SERVER_NAME) !== undefined)
134
+ return;
135
+ editor.set(SAGE_MCP_SERVER_NAME, sageMcpServerConfig());
136
+ }));
137
+ }
138
+ if (context.session) {
139
+ registrations.push(await context.session.hook("prompt", (event) => {
140
+ const sessionID = isRecord(event) && typeof event.sessionID === "string" ? event.sessionID : "";
141
+ // Don't hold up the prompt on the scan.
142
+ void sage.scanSession(sessionID).catch((error) => {
143
+ sage.logger.debug("Session scan failed", { error: String(error) });
144
+ });
145
+ }));
146
+ }
147
+ return async () => {
148
+ await Promise.allSettled(registrations.map((r) => r.dispose()));
149
+ };
150
+ }
151
+ //# sourceMappingURL=v2.js.map
package/dist/v2.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"v2.js","sourceRoot":"","sources":["../src/v2.ts"],"names":[],"mappings":"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"}
package/index.js ADDED
@@ -0,0 +1,3 @@
1
+ // OpenCode v2's local-directory loader looks for an index or server module at
2
+ // the directory root. The published package and OpenCode v1 still use dist/index.js.
3
+ export { default, SagePlugin } from "./dist/index.js";
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.13.0",
7
+ "version": "0.15.0",
8
8
  "type": "module",
9
9
  "description": "Safety for Agents - ADR layer for OpenCode",
10
10
  "homepage": "https://github.com/gendigitalinc/sage",
@@ -24,6 +24,7 @@
24
24
  }
25
25
  },
26
26
  "files": [
27
+ "index.js",
27
28
  "dist/**",
28
29
  "resources/**",
29
30
  "package.json",
@@ -32,8 +33,8 @@
32
33
  ],
33
34
  "dependencies": {
34
35
  "@opencode-ai/plugin": "^1.14.48",
35
- "@gendigital/sage-core": "0.13.0",
36
- "@gendigital/sage-mcp": "0.13.0"
36
+ "@gendigital/sage-core": "0.15.0",
37
+ "@gendigital/sage-mcp": "0.15.0"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/node": "^22.0.0",
@@ -9,7 +9,7 @@
9
9
  category: secrets
10
10
  severity: critical
11
11
  confidence: 0.80
12
- pattern: "(sk-[a-zA-Z0-9_-]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|ghp_[0-9a-zA-Z]{36}|gho_[0-9a-zA-Z]{36}|glpat-[0-9a-zA-Z_-]{20,}|xox[baprs]-[0-9a-zA-Z-]+)"
12
+ pattern: "\\b(sk-[a-zA-Z0-9_-]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|ghp_[0-9a-zA-Z]{36}|gho_[0-9a-zA-Z]{36}|glpat-[0-9a-zA-Z_-]{20,}|xox[baprs]-[0-9a-zA-Z-]+)"
13
13
  match_on: [command, content]
14
14
  title: "Known API key prefix detected"
15
15
  expires_at: null
@@ -19,6 +19,9 @@
19
19
  # WebFetch/Bash url ✓ ✓ ✓
20
20
  # WebFetch/Bash domain ✓ — —
21
21
  #
22
+ # Submit-only (flags: ["submit_only"], allow + capped non-blocking telemetry):
23
+ # Bash (command), Write/Edit/Read (file_path)
24
+ #
22
25
  # The file_path rules also cover Read, Delete, Glob, and LS tools
23
26
  # (they produce the same artifact type).
24
27
  # The url rules also cover URLs embedded in Bash commands and file content.
@@ -84,7 +87,6 @@
84
87
  title: "[TEST] Canary log-only command"
85
88
  expires_at: null
86
89
  revoked: false
87
- flags: ["report"]
88
90
 
89
91
  # ─── File-path patterns (Write / Edit / Read / Delete tools) ────────
90
92
 
@@ -123,7 +125,6 @@
123
125
  title: "[TEST] Canary log-only file path"
124
126
  expires_at: null
125
127
  revoked: false
126
- flags: ["report"]
127
128
 
128
129
  # ─── Content patterns (Write / Edit tools — file body) ──────────────
129
130
 
@@ -162,7 +163,6 @@
162
163
  title: "[TEST] Canary log-only content"
163
164
  expires_at: null
164
165
  revoked: false
165
- flags: ["report"]
166
166
 
167
167
  # ─── URL patterns (WebFetch / Bash / Write content) ─────────────────
168
168
  # Uses .test TLD (RFC 2606 reserved, never resolves) for safety.
@@ -202,7 +202,6 @@
202
202
  title: "[TEST] Canary log-only URL"
203
203
  expires_at: null
204
204
  revoked: false
205
- flags: ["report"]
206
205
 
207
206
  # ─── Domain pattern (verifies domain→url routing in heuristics) ─────
208
207
 
@@ -217,3 +216,37 @@
217
216
  title: "[TEST] Canary deny domain"
218
217
  expires_at: null
219
218
  revoked: false
219
+
220
+ # ─── Submit-only patterns (telemetry, never block) ──────────────────
221
+ #
222
+ # `flags: ["submit_only"]` removes the rule from the verdict entirely and
223
+ # instead submits a non-blocking event to /v2/heuristic, capped at one submit
224
+ # per rule per client per 24h (packages/core/src/submit-limits.ts). The
225
+ # confidence is deliberately deny-level so a regression that lets the flag
226
+ # leak into the verdict shows up as a deny.
227
+
228
+ - id: "DUMMY-CMD-SUBMIT-001"
229
+ version: 1
230
+ detection_name: "CMD:SageTestCommandSubmit-A [Tst]"
231
+ category: testing
232
+ severity: critical
233
+ confidence: 0.95
234
+ pattern: "diagmark_cmd_d7e7127e"
235
+ match_on: command
236
+ title: "[TEST] Canary submit-only command"
237
+ expires_at: null
238
+ revoked: false
239
+ flags: ["submit_only"]
240
+
241
+ - id: "DUMMY-FILE-SUBMIT-001"
242
+ version: 1
243
+ detection_name: "FN:SageTestFileSubmit-A [Tst]"
244
+ category: testing
245
+ severity: critical
246
+ confidence: 0.95
247
+ pattern: "diagmark_file_57871281"
248
+ match_on: file_path
249
+ title: "[TEST] Canary submit-only file path"
250
+ expires_at: null
251
+ revoked: false
252
+ flags: ["submit_only"]
@@ -440,3 +440,16 @@
440
440
  expires_at: null
441
441
  revoked: false
442
442
  # Source: ATR-2026-00097 (pattern unchanged from upstream). Covers zh-CN, zh-TW, ja, ko.
443
+
444
+ - id: "CLT-PI-094"
445
+ version: 1
446
+ detection_name: "Other:SagePromptInjection-CP [Heur]"
447
+ category: prompt_injection
448
+ severity: warning
449
+ confidence: 0.70
450
+ case_insensitive: true
451
+ pattern: "\\b(?:disregard|ignore|forget|override)\\s+(?:all\\s+|any\\s+)?(?:your|the|my)\\s+system\\s+(?:prompt|message|instructions?)\\b"
452
+ match_on: content
453
+ title: "Instruction override: disregard system prompt"
454
+ expires_at: null
455
+ revoked: false