@intutic/gate 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/actions.d.ts +86 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +239 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/client.d.ts +94 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +207 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/dsh.d.ts +162 -0
  12. package/dist/dsh.d.ts.map +1 -0
  13. package/dist/dsh.js +189 -0
  14. package/dist/dsh.js.map +1 -0
  15. package/dist/errors.d.ts +41 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +53 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/eve.d.ts +425 -0
  20. package/dist/eve.d.ts.map +1 -0
  21. package/dist/eve.js +378 -0
  22. package/dist/eve.js.map +1 -0
  23. package/dist/gate.d.ts +113 -0
  24. package/dist/gate.d.ts.map +1 -0
  25. package/dist/gate.js +274 -0
  26. package/dist/gate.js.map +1 -0
  27. package/dist/harness.d.ts +482 -0
  28. package/dist/harness.d.ts.map +1 -0
  29. package/dist/harness.js +504 -0
  30. package/dist/harness.js.map +1 -0
  31. package/dist/headers.d.ts +26 -0
  32. package/dist/headers.d.ts.map +1 -0
  33. package/dist/headers.js +30 -0
  34. package/dist/headers.js.map +1 -0
  35. package/dist/imagecheck.d.ts +93 -0
  36. package/dist/imagecheck.d.ts.map +1 -0
  37. package/dist/imagecheck.js +286 -0
  38. package/dist/imagecheck.js.map +1 -0
  39. package/dist/index.d.ts +26 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +19 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/managedAgents.d.ts +375 -0
  44. package/dist/managedAgents.d.ts.map +1 -0
  45. package/dist/managedAgents.js +446 -0
  46. package/dist/managedAgents.js.map +1 -0
  47. package/dist/mastra.d.ts +175 -0
  48. package/dist/mastra.d.ts.map +1 -0
  49. package/dist/mastra.js +161 -0
  50. package/dist/mastra.js.map +1 -0
  51. package/dist/openai.d.ts +392 -0
  52. package/dist/openai.d.ts.map +1 -0
  53. package/dist/openai.js +658 -0
  54. package/dist/openai.js.map +1 -0
  55. package/dist/shlex.d.ts +16 -0
  56. package/dist/shlex.d.ts.map +1 -0
  57. package/dist/shlex.js +78 -0
  58. package/dist/shlex.js.map +1 -0
  59. package/dist/snapshot.d.ts +111 -0
  60. package/dist/snapshot.d.ts.map +1 -0
  61. package/dist/snapshot.js +243 -0
  62. package/dist/snapshot.js.map +1 -0
  63. package/dist/soprules.d.ts +88 -0
  64. package/dist/soprules.d.ts.map +1 -0
  65. package/dist/soprules.js +176 -0
  66. package/dist/soprules.js.map +1 -0
  67. package/dist/trueforge.d.ts +191 -0
  68. package/dist/trueforge.d.ts.map +1 -0
  69. package/dist/trueforge.js +184 -0
  70. package/dist/trueforge.js.map +1 -0
  71. package/dist/vercel.d.ts +174 -0
  72. package/dist/vercel.d.ts.map +1 -0
  73. package/dist/vercel.js +157 -0
  74. package/dist/vercel.js.map +1 -0
  75. package/dist/workflow.d.ts +209 -0
  76. package/dist/workflow.d.ts.map +1 -0
  77. package/dist/workflow.js +254 -0
  78. package/dist/workflow.js.map +1 -0
  79. package/dist/wrapTools.d.ts +68 -0
  80. package/dist/wrapTools.d.ts.map +1 -0
  81. package/dist/wrapTools.js +95 -0
  82. package/dist/wrapTools.js.map +1 -0
  83. package/package.json +123 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * HTTP client for the Intutic control plane's gate endpoints.
3
+ *
4
+ * Port of `packages/intutic-clawde/intutic_clawde/gate/client.py`.
5
+ *
6
+ * Endpoints used:
7
+ *
8
+ * POST /api/v1/hook-gate synchronous allow/deny -> {allowed, reason, incidentId?}
9
+ * POST /api/v1/hook-events batched telemetry -> creates governance_incidents rows
10
+ *
11
+ * Two behaviours that must not be "improved":
12
+ *
13
+ * * The hook-gate SERVER fails OPEN on its own error paths — it returns
14
+ * `{allowed:true}` on malformed input, schema mismatch, or DB error,
15
+ * because blocking a developer over a bad payload teaches people to
16
+ * disable the hook. This CLIENT, by contrast, defaults to FAIL-CLOSED
17
+ * (`failClosed=true`) for blocking decisions: a transport error or
18
+ * non-2xx response means we have no verdict at all to defer to, so
19
+ * `hookGate` reports `allowed=false`. Set `failClosed=false` to treat the
20
+ * tier as advisory, mirroring the server's own posture.
21
+ * * `emit` NEVER throws. Telemetry that can break a run is worse than no
22
+ * telemetry.
23
+ */
24
+ export interface GateResponse {
25
+ allowed: boolean;
26
+ reason: string;
27
+ incidentId?: string | undefined;
28
+ /** False when the call failed and `failClosed` decided the verdict. */
29
+ reached: boolean;
30
+ }
31
+ export interface GateClientOptions {
32
+ baseUrl?: string;
33
+ apiKey?: string;
34
+ workspaceId?: string;
35
+ sessionId?: string;
36
+ /**
37
+ * Attributes incidents to the right adapter. Sent as `harnessType` on every
38
+ * gate call and event.
39
+ */
40
+ harness?: string;
41
+ failClosed?: boolean;
42
+ timeoutMs?: number;
43
+ }
44
+ /**
45
+ * Control-plane client for the pre-execution gate.
46
+ *
47
+ * `harness` defaults to `"generic"` and is sent as `harnessType` on every
48
+ * gate call and event, so incidents attribute to the right adapter. Override
49
+ * it when wrapping a specific framework (`mastra`, `vercel-ai`,
50
+ * `langchainjs`, `dsh`, ...).
51
+ */
52
+ export declare class GateClient {
53
+ readonly baseUrl: string;
54
+ readonly apiKey: string;
55
+ readonly workspaceId: string;
56
+ readonly sessionId: string;
57
+ readonly harness: string;
58
+ readonly failClosed: boolean;
59
+ readonly timeoutMs: number;
60
+ constructor(opts?: GateClientOptions);
61
+ private post;
62
+ /**
63
+ * Synchronous allow/deny for one tool call.
64
+ *
65
+ * The endpoint matches ~19 DLP regexes against the serialised toolInput,
66
+ * plus SOP rules. It is defence in depth on top of the local tiers, not a
67
+ * replacement for them.
68
+ *
69
+ * When the call itself fails (transport error, non-2xx), the verdict is
70
+ * decided by `failClosed`: true (the default) reports BLOCK, because a
71
+ * client with no verdict has nothing to defer to; false reports allow,
72
+ * mirroring the server's own fail-open error paths.
73
+ */
74
+ hookGate(toolName: string, toolInput: unknown): Promise<GateResponse>;
75
+ /**
76
+ * Fire-and-forget telemetry. Never throws.
77
+ *
78
+ * A `tool_blocked` event creates a `governance_incidents` row whose
79
+ * description embeds the reason verbatim.
80
+ */
81
+ emit(event: string, toolName: string, reason?: string, toolInput?: unknown, incidentId?: string, filePath?: string): Promise<boolean>;
82
+ /**
83
+ * Build a client from the environment, falling back to CLI credentials.
84
+ *
85
+ * Reading `~/.intutic/credentials.json` means the gate works with whatever
86
+ * workspace `intutic login` already bound, instead of duplicating the key.
87
+ */
88
+ static fromEnv(opts?: {
89
+ sessionId?: string;
90
+ harness?: string;
91
+ failClosed?: boolean;
92
+ }): GateClient;
93
+ }
94
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAyBH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;gBAEd,IAAI,GAAE,iBAAsB;YAa1B,IAAI;IAsBlB;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAoC3E;;;;;OAKG;IACG,IAAI,CACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,SAAK,EACX,SAAS,CAAC,EAAE,OAAO,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAsBnB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,GAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,UAAU;CAoCtG"}
package/dist/client.js ADDED
@@ -0,0 +1,207 @@
1
+ /**
2
+ * HTTP client for the Intutic control plane's gate endpoints.
3
+ *
4
+ * Port of `packages/intutic-clawde/intutic_clawde/gate/client.py`.
5
+ *
6
+ * Endpoints used:
7
+ *
8
+ * POST /api/v1/hook-gate synchronous allow/deny -> {allowed, reason, incidentId?}
9
+ * POST /api/v1/hook-events batched telemetry -> creates governance_incidents rows
10
+ *
11
+ * Two behaviours that must not be "improved":
12
+ *
13
+ * * The hook-gate SERVER fails OPEN on its own error paths — it returns
14
+ * `{allowed:true}` on malformed input, schema mismatch, or DB error,
15
+ * because blocking a developer over a bad payload teaches people to
16
+ * disable the hook. This CLIENT, by contrast, defaults to FAIL-CLOSED
17
+ * (`failClosed=true`) for blocking decisions: a transport error or
18
+ * non-2xx response means we have no verdict at all to defer to, so
19
+ * `hookGate` reports `allowed=false`. Set `failClosed=false` to treat the
20
+ * tier as advisory, mirroring the server's own posture.
21
+ * * `emit` NEVER throws. Telemetry that can break a run is worse than no
22
+ * telemetry.
23
+ */
24
+ import { readFileSync } from 'node:fs';
25
+ import { homedir } from 'node:os';
26
+ import { join } from 'node:path';
27
+ const DEFAULT_TIMEOUT_MS = 2_000;
28
+ const EVENT_TIMEOUT_MS = 2_000;
29
+ const REASON_MAX = 512; // control plane truncates at 512; do it here so logs match
30
+ // Mirrors HookEventSchema in services/control-plane/src/routes/hookEvents.ts.
31
+ const VALID_EVENTS = new Set([
32
+ 'tool_blocked',
33
+ 'tool_allowed',
34
+ 'tool_flagged',
35
+ 'tool_would_block',
36
+ 'config_tamper',
37
+ 'network_bypass',
38
+ 'guards_disabled',
39
+ 'snapshot_absent',
40
+ 'snapshot_stale',
41
+ 'snapshot_invalid',
42
+ 'snapshot_empty',
43
+ ]);
44
+ /**
45
+ * Control-plane client for the pre-execution gate.
46
+ *
47
+ * `harness` defaults to `"generic"` and is sent as `harnessType` on every
48
+ * gate call and event, so incidents attribute to the right adapter. Override
49
+ * it when wrapping a specific framework (`mastra`, `vercel-ai`,
50
+ * `langchainjs`, `dsh`, ...).
51
+ */
52
+ export class GateClient {
53
+ baseUrl;
54
+ apiKey;
55
+ workspaceId;
56
+ sessionId;
57
+ harness;
58
+ failClosed;
59
+ timeoutMs;
60
+ constructor(opts = {}) {
61
+ this.baseUrl = (opts.baseUrl || process.env.INTUTIC_CONTROL_PLANE_URL || 'https://api.intutic.ai').replace(/\/$/, '');
62
+ this.apiKey = opts.apiKey ?? '';
63
+ this.workspaceId = opts.workspaceId ?? '';
64
+ this.sessionId = opts.sessionId ?? '';
65
+ this.harness = opts.harness ?? 'generic';
66
+ this.failClosed = opts.failClosed ?? true;
67
+ this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
68
+ }
69
+ async post(path, body, timeoutMs) {
70
+ const controller = new AbortController();
71
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
72
+ try {
73
+ const res = await fetch(this.baseUrl + path, {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ Authorization: `Bearer ${this.apiKey}`,
78
+ 'X-Workspace-Id': this.workspaceId,
79
+ },
80
+ body: JSON.stringify(body),
81
+ signal: controller.signal,
82
+ });
83
+ if (!res.ok)
84
+ throw new Error(`HTTP ${res.status} from ${path}`);
85
+ const text = await res.text();
86
+ return text ? JSON.parse(text) : {};
87
+ }
88
+ finally {
89
+ clearTimeout(timer);
90
+ }
91
+ }
92
+ /**
93
+ * Synchronous allow/deny for one tool call.
94
+ *
95
+ * The endpoint matches ~19 DLP regexes against the serialised toolInput,
96
+ * plus SOP rules. It is defence in depth on top of the local tiers, not a
97
+ * replacement for them.
98
+ *
99
+ * When the call itself fails (transport error, non-2xx), the verdict is
100
+ * decided by `failClosed`: true (the default) reports BLOCK, because a
101
+ * client with no verdict has nothing to defer to; false reports allow,
102
+ * mirroring the server's own fail-open error paths.
103
+ */
104
+ async hookGate(toolName, toolInput) {
105
+ try {
106
+ const d = await this.post('/api/v1/hook-gate', {
107
+ toolName,
108
+ toolInput,
109
+ workspaceId: this.workspaceId,
110
+ sessionId: this.sessionId,
111
+ harnessType: this.harness,
112
+ }, this.timeoutMs);
113
+ return {
114
+ allowed: Boolean(d.allowed ?? true),
115
+ reason: String(d.reason ?? ''),
116
+ incidentId: typeof d.incidentId === 'string' ? d.incidentId : undefined,
117
+ reached: true,
118
+ };
119
+ }
120
+ catch (exc) {
121
+ const name = exc instanceof Error ? exc.constructor.name : 'Error';
122
+ if (this.failClosed) {
123
+ return {
124
+ allowed: false,
125
+ reason: `hook-gate unreachable (${name}) — failing closed (failClosed=true)`,
126
+ reached: false,
127
+ };
128
+ }
129
+ return {
130
+ allowed: true,
131
+ reason: `hook-gate unreachable (${name}) — failing open (failClosed=false)`,
132
+ reached: false,
133
+ };
134
+ }
135
+ }
136
+ /**
137
+ * Fire-and-forget telemetry. Never throws.
138
+ *
139
+ * A `tool_blocked` event creates a `governance_incidents` row whose
140
+ * description embeds the reason verbatim.
141
+ */
142
+ async emit(event, toolName, reason = '', toolInput, incidentId, filePath) {
143
+ if (!VALID_EVENTS.has(event))
144
+ return false;
145
+ const ev = {
146
+ event,
147
+ toolName,
148
+ reason: (reason || '').slice(0, REASON_MAX),
149
+ workspaceId: this.workspaceId,
150
+ sessionId: this.sessionId,
151
+ harnessType: this.harness,
152
+ timestamp: new Date().toISOString(),
153
+ };
154
+ if (toolInput !== undefined)
155
+ ev.toolInput = toolInput;
156
+ if (incidentId)
157
+ ev.incidentId = incidentId;
158
+ if (filePath)
159
+ ev.filePath = filePath.slice(0, 512);
160
+ try {
161
+ await this.post('/api/v1/hook-events', { events: [ev] }, EVENT_TIMEOUT_MS);
162
+ return true;
163
+ }
164
+ catch {
165
+ return false;
166
+ }
167
+ }
168
+ /**
169
+ * Build a client from the environment, falling back to CLI credentials.
170
+ *
171
+ * Reading `~/.intutic/credentials.json` means the gate works with whatever
172
+ * workspace `intutic login` already bound, instead of duplicating the key.
173
+ */
174
+ static fromEnv(opts = {}) {
175
+ const base = process.env.INTUTIC_CONTROL_PLANE_URL || 'https://api.intutic.ai';
176
+ let key = process.env.INTUTIC_API_KEY || '';
177
+ let ws = process.env.INTUTIC_WORKSPACE_ID || '';
178
+ if (!key || !ws) {
179
+ try {
180
+ const credPath = join(homedir(), '.intutic', 'credentials.json');
181
+ const c = JSON.parse(readFileSync(credPath, 'utf-8'));
182
+ key = key || String(c.apiKey ?? '');
183
+ ws = ws || String(c.workspaceId ?? '');
184
+ }
185
+ catch {
186
+ // No credentials file — fall through with whatever env supplied.
187
+ }
188
+ }
189
+ const sess = opts.sessionId || process.env.INTUTIC_SESSION_ID || '';
190
+ if (!sess) {
191
+ // The proxy defaults an unset x-session-id to the literal "unknown",
192
+ // which collapses every run onto one dashboard row. Refuse instead.
193
+ throw new Error('No session id. Set INTUTIC_SESSION_ID or pass sessionId — an unset x-session-id ' +
194
+ "becomes the literal 'unknown' in the proxy and merges every run into a single " +
195
+ 'dashboard session.');
196
+ }
197
+ return new GateClient({
198
+ baseUrl: base,
199
+ apiKey: key,
200
+ workspaceId: ws,
201
+ sessionId: sess,
202
+ harness: opts.harness ?? 'generic',
203
+ failClosed: opts.failClosed ?? true,
204
+ });
205
+ }
206
+ }
207
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/dsh.d.ts ADDED
@@ -0,0 +1,162 @@
1
+ /**
2
+ * dsh.ts — Cordis plugin adapter for DeepSeek's "dsh" harness.
3
+ *
4
+ * Published as the `@intutic/gate/dsh` subpath (see README.md's "Subpath
5
+ * convention for later phases"). `services/sync-daemon/src/harness/dshHooks.ts`
6
+ * merge-writes a row naming this module (`name: '@intutic/gate/dsh'`) into a
7
+ * dsh profile's `cordis.patch.yml`; dsh's own Cordis loader resolves that name
8
+ * with a plain dynamic `import()` and mounts the exported plugin
9
+ * (`{ name, inject, apply }`) the same way it mounts every other bundle row.
10
+ *
11
+ * ## The veto mechanism — CONFIRMED against a real install, not assumed
12
+ *
13
+ * dsh is a developer preview (`@deepseek-ai/dsh`, first published 2026-08-13)
14
+ * built on DeepSeek's own "Cordis" plugin framework (`@deepseek-ai/cordis`,
15
+ * `@deepseek-ai/dsh-tools`, `@deepseek-ai/dsh-app-boot`, ...). Both are public
16
+ * on the npm registry, and this module was authored against a real
17
+ * `npm pack`/inspection of them (see the TD entry this phase filed for exactly
18
+ * what was checked and what still had to be assumed) — NOT solely from the
19
+ * phase brief's prior guess, which named a different event (`agent/pre-step`)
20
+ * and a different decision shape (`{kind:'reject',...}`). Both turned out to
21
+ * be close but not exact:
22
+ *
23
+ * - The real per-tool veto point is `tools/pre-execute` (declared by
24
+ * `@deepseek-ai/dsh-tools`), not `agent/pre-step` (`@deepseek-ai/dsh-agent`'s
25
+ * per-turn/step event — a coarser boundary that batches a driver step
26
+ * rather than one tool call, and the wrong extension point for a
27
+ * per-tool-call gate).
28
+ * - It is a genuine Cordis `waterfall`: `(exec: ToolExecution, next: () =>
29
+ * Promise<PreToolDecision>) => Promise<PreToolDecision>`. Cordis's own
30
+ * waterfall contract (confirmed by reading `@deepseek-ai/cordis`'s
31
+ * `events.d.ts`) composes listeners around a `next()` continuation —
32
+ * "a listener that does not call next() vetoes the rest of the chain,
33
+ * including the built-in behavior" — so this listener calls `next()` on
34
+ * ALLOW (to preserve whatever later listener or built-in behaviour — e.g.
35
+ * dsh's own `ask`/approval flow — would otherwise run) and returns its own
36
+ * `{kind:'deny',...}` WITHOUT calling `next()` to veto.
37
+ * - The decision shape is `PreToolDecision = {kind:'allow'} | {kind:'deny',
38
+ * reason} | {kind:'ask', reason?}` (confirmed from
39
+ * `@deepseek-ai/dsh-tools`'s shipped `.d.ts`) — `'deny'`, not the phase
40
+ * brief's guessed `'reject'`.
41
+ *
42
+ * `ctx.tools.guard()` (a separate, monotonic, explicitly SYNCHRONOUS
43
+ * mechanism dsh also exposes) was considered and rejected: `@intutic/gate`'s
44
+ * `Gate.guard()` is async (network-backed SOP-rule fetch and `/hook-gate`
45
+ * POST — see gate.ts's module doc), and a synchronous `ToolGuard` cannot
46
+ * `await` it. `tools/pre-execute` is the only one of dsh's two extension
47
+ * points this package's async contract fits.
48
+ *
49
+ * ## What this module does NOT import
50
+ *
51
+ * Deliberately no dependency on `@deepseek-ai/cordis` or `@deepseek-ai/dsh-tools`
52
+ * at runtime — `CordisLikeContext`/`DshToolExecution`/`DshPreToolDecision`
53
+ * below are narrow structural types capturing only the shape this plugin
54
+ * actually touches, matching Cordis's own duck-typed plugin contract (a
55
+ * plain `{ name?, inject?, apply(ctx, config) }` object — confirmed against
56
+ * both `@deepseek-ai/cordis`'s README quick-start and dsh's own in-product
57
+ * "cordis-plugin-development" skill doc, which returns `{ apply(ctx) {...} }`
58
+ * with no import of anything). Adding a hard dependency on a fast-moving
59
+ * preview product's framework package to `@intutic/gate`'s dsh subpath would
60
+ * make every OTHER subpath's install pull it in too (or need a peerDependency
61
+ * carve-out) for a shape simple enough to describe locally. The real
62
+ * `@deepseek-ai/cordis` package is used only as a devDependency, in this
63
+ * module's own test file, to exercise the real waterfall dispatch mechanics
64
+ * against the genuine `Context` class rather than a hand-rolled stand-in.
65
+ *
66
+ * @module
67
+ */
68
+ import { Gate } from './gate.js';
69
+ import type { GateConfig } from './gate.js';
70
+ /** The Cordis Plugin id this module registers as. Shown in dsh's own plugin
71
+ * diagnostics/`--dump-config` output. */
72
+ export declare const PLUGIN_NAME = "intutic-governance";
73
+ /**
74
+ * The slice of dsh's real `tools/pre-execute` payload (`ToolExecution`, from
75
+ * `@deepseek-ai/dsh-tools`) this plugin reads. `arguments` is documented as
76
+ * "losslessly JSON-serializable parsed arguments (tools validate their own
77
+ * schema)" — an `unknown`, not necessarily an object, hence
78
+ * {@link renderDshToolInput} below.
79
+ */
80
+ export interface DshToolExecution {
81
+ readonly name: string;
82
+ readonly arguments: unknown;
83
+ }
84
+ /** The confirmed real `PreToolDecision` union from `@deepseek-ai/dsh-tools`. */
85
+ export type DshPreToolDecision = {
86
+ kind: 'allow';
87
+ } | {
88
+ kind: 'deny';
89
+ reason: string;
90
+ } | {
91
+ kind: 'ask';
92
+ reason?: string;
93
+ };
94
+ /**
95
+ * Structural stand-in for the Cordis `Context` this plugin needs — see the
96
+ * module doc for why the real `@deepseek-ai/cordis` package is not imported.
97
+ */
98
+ export interface CordisLikeContext {
99
+ on(event: 'tools/pre-execute', listener: (exec: DshToolExecution, next: () => Promise<DshPreToolDecision>) => Promise<DshPreToolDecision>): () => boolean;
100
+ }
101
+ /** `cordis.patch.yml` row config for this plugin. Extends the core
102
+ * {@link GateConfig} with the one dsh-specific knob: an explicit session id,
103
+ * since dsh has no single "the session" this plugin can read off `exec` (a
104
+ * `ToolExecution` carries an `agent?`, not a raw session/conversation id) —
105
+ * see {@link resolveSessionId}. */
106
+ export interface DshGateConfig extends GateConfig {
107
+ /** Overrides the generated-per-process session id. Mirrors
108
+ * `INTUTIC_SESSION_ID` for callers that already have one to hand. */
109
+ sessionId?: string;
110
+ }
111
+ /** Cordis Plugins declare their hard dependencies here; the loader defers
112
+ * activation until every named service exists and reactivates on restart.
113
+ * `tools` is `@deepseek-ai/dsh-tools`'s `ToolRegistry` service — the thing
114
+ * that actually dispatches `tools/pre-execute`. */
115
+ export declare const inject: string[];
116
+ /**
117
+ * Build the `tools/pre-execute` listener for a given {@link Gate}.
118
+ *
119
+ * Factored out of {@link apply} so a test can exercise the exact listener
120
+ * `apply()` registers — event extraction, the refusal-to-decision mapping,
121
+ * the fail-closed default, and the waterfall `next()`-calling on allow —
122
+ * against a controllable fake `Gate`, without needing a real dsh install or
123
+ * network access to construct a `GateClient`.
124
+ *
125
+ * Never throws: every path returns a {@link DshPreToolDecision}. A crash
126
+ * inside `gate.guard()` that is not an {@link IntuticGateRefusal} — a bug in
127
+ * this gate, or an unexpected throw from a tier it calls into — is treated
128
+ * as "cannot evaluate" and denied rather than allowed to escape the
129
+ * waterfall or fall through to an allow; see gate.ts's own module doc for why
130
+ * every tier in this package takes that direction on failure.
131
+ */
132
+ export declare function createPreExecuteListener(gate: Gate): (exec: DshToolExecution, next: () => Promise<DshPreToolDecision>) => Promise<DshPreToolDecision>;
133
+ /**
134
+ * Mount the Intutic governance gate on a dsh profile.
135
+ *
136
+ * Builds one {@link Gate} for the lifetime of this plugin instance (not per
137
+ * call — Tier A1/A2/A3 all cache within a `Gate`, see gate.ts) and installs it
138
+ * as the process-wide default too (`install()`), so a hand-authored
139
+ * `wrapTool`/`wrapTools` call elsewhere in the same dsh process picks up the
140
+ * identical instance rather than constructing a second one with independent
141
+ * caches.
142
+ *
143
+ * Never throws out of `apply()` itself: a `GateClient.fromEnv` failure (e.g.
144
+ * credentials genuinely unreadable) degrades to a client-less `Gate` — Tier B
145
+ * and Tier A3 inactive, Tier A1/A2 (local, load-bearing) unaffected — rather
146
+ * than taking down the whole dsh profile boot over a governance layer that is
147
+ * additive by design.
148
+ */
149
+ export declare function apply(ctx: CordisLikeContext, config?: DshGateConfig): void;
150
+ /** Default export — the whole Plugin object, for `name: '@intutic/gate/dsh'`
151
+ * cordis.patch.yml rows that resolve this module and pass it directly to
152
+ * `ctx.plugin()` (dsh's loader unwraps a default export the same way it
153
+ * unwraps a named one — see `dsh-app-boot`'s `unwrapExports`). Named exports
154
+ * (`apply`, `inject`, `PLUGIN_NAME`) are also available for a caller that
155
+ * imports this subpath directly rather than through the loader. */
156
+ declare const _default: {
157
+ name: string;
158
+ inject: string[];
159
+ apply: typeof apply;
160
+ };
161
+ export default _default;
162
+ //# sourceMappingURL=dsh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dsh.d.ts","sourceRoot":"","sources":["../src/dsh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AAGH,OAAO,EAAE,IAAI,EAAW,MAAM,WAAW,CAAA;AACzC,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,WAAW,CAAA;AAItD;0CAC0C;AAC1C,eAAO,MAAM,WAAW,uBAAuB,CAAA;AAE/C;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,gFAAgF;AAChF,MAAM,MAAM,kBAAkB,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAExH;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,CACA,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,KAAK,OAAO,CAAC,kBAAkB,CAAC,GACzG,MAAM,OAAO,CAAA;CACjB;AAED;;;;oCAIoC;AACpC,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;0EACsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;oDAGoD;AACpD,eAAO,MAAM,MAAM,UAAY,CAAA;AAwC/B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,IAAI,GACT,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAoBlG;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,GAAE,aAAkB,GAAG,IAAI,CAY9E;AAED;;;;;oEAKoE;;;;;;AACpE,wBAAmD"}