patchwork-os 0.2.0-alpha.34 → 0.2.0-alpha.36
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 +202 -93
- package/deploy/bootstrap-new-vps.sh +12 -12
- package/deploy/bootstrap-vps.sh +6 -3
- package/deploy/deploy-landing.sh +59 -2
- package/dist/activityLog.d.ts +49 -0
- package/dist/activityLog.js +78 -0
- package/dist/activityLog.js.map +1 -1
- package/dist/approvalHttp.d.ts +25 -0
- package/dist/approvalHttp.js +74 -18
- package/dist/approvalHttp.js.map +1 -1
- package/dist/approvalInsights.d.ts +49 -0
- package/dist/approvalInsights.js +97 -0
- package/dist/approvalInsights.js.map +1 -0
- package/dist/approvalQueue.d.ts +11 -0
- package/dist/approvalQueue.js +80 -1
- package/dist/approvalQueue.js.map +1 -1
- package/dist/approvalSignals.d.ts +124 -0
- package/dist/approvalSignals.js +512 -0
- package/dist/approvalSignals.js.map +1 -0
- package/dist/automation.d.ts +37 -0
- package/dist/automation.js +105 -61
- package/dist/automation.js.map +1 -1
- package/dist/automationSuggestions.d.ts +79 -0
- package/dist/automationSuggestions.js +150 -0
- package/dist/automationSuggestions.js.map +1 -0
- package/dist/bridge.js +78 -1
- package/dist/bridge.js.map +1 -1
- package/dist/ccPermissions.d.ts +15 -0
- package/dist/ccPermissions.js +15 -0
- package/dist/ccPermissions.js.map +1 -1
- package/dist/claudeDriver.js +74 -16
- package/dist/claudeDriver.js.map +1 -1
- package/dist/commands/patchworkInit.d.ts +8 -0
- package/dist/commands/patchworkInit.js +41 -5
- package/dist/commands/patchworkInit.js.map +1 -1
- package/dist/commands/recipe.d.ts +20 -0
- package/dist/commands/recipe.js +212 -6
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.d.ts +79 -1
- package/dist/commands/recipeInstall.js +333 -16
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/commands/tracesExport.d.ts +83 -0
- package/dist/commands/tracesExport.js +269 -0
- package/dist/commands/tracesExport.js.map +1 -0
- package/dist/commands/tracesImport.d.ts +56 -0
- package/dist/commands/tracesImport.js +161 -0
- package/dist/commands/tracesImport.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/connectorRoutes.d.ts +43 -0
- package/dist/connectorRoutes.js +1023 -0
- package/dist/connectorRoutes.js.map +1 -0
- package/dist/connectors/asana.d.ts +198 -0
- package/dist/connectors/asana.js +679 -0
- package/dist/connectors/asana.js.map +1 -0
- package/dist/connectors/baseConnector.d.ts +36 -0
- package/dist/connectors/baseConnector.js +151 -28
- package/dist/connectors/baseConnector.js.map +1 -1
- package/dist/connectors/discord.d.ts +150 -0
- package/dist/connectors/discord.js +543 -0
- package/dist/connectors/discord.js.map +1 -0
- package/dist/connectors/github.js +11 -4
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gitlab.d.ts +180 -0
- package/dist/connectors/gitlab.js +582 -0
- package/dist/connectors/gitlab.js.map +1 -0
- package/dist/connectors/gmail.js +50 -10
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleCalendar.js +36 -10
- package/dist/connectors/googleCalendar.js.map +1 -1
- package/dist/connectors/googleDrive.d.ts +34 -0
- package/dist/connectors/googleDrive.js +321 -0
- package/dist/connectors/googleDrive.js.map +1 -0
- package/dist/connectors/linear.js +23 -4
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/mcpOAuth.js +26 -2
- package/dist/connectors/mcpOAuth.js.map +1 -1
- package/dist/connectors/oauthStateStore.d.ts +31 -0
- package/dist/connectors/oauthStateStore.js +52 -0
- package/dist/connectors/oauthStateStore.js.map +1 -0
- package/dist/connectors/pagerduty.d.ts +160 -0
- package/dist/connectors/pagerduty.js +464 -0
- package/dist/connectors/pagerduty.js.map +1 -0
- package/dist/connectors/slack.d.ts +16 -1
- package/dist/connectors/slack.js +57 -5
- package/dist/connectors/slack.js.map +1 -1
- package/dist/connectors/tokenStorage.js +27 -2
- package/dist/connectors/tokenStorage.js.map +1 -1
- package/dist/connectors/zendesk.js +19 -1
- package/dist/connectors/zendesk.js.map +1 -1
- package/dist/cors.d.ts +10 -0
- package/dist/cors.js +29 -0
- package/dist/cors.js.map +1 -0
- package/dist/decisionReplay.d.ts +72 -0
- package/dist/decisionReplay.js +92 -0
- package/dist/decisionReplay.js.map +1 -0
- package/dist/decisionTraceLog.d.ts +6 -0
- package/dist/decisionTraceLog.js +54 -2
- package/dist/decisionTraceLog.js.map +1 -1
- package/dist/featureFlags.d.ts +17 -11
- package/dist/featureFlags.js +52 -47
- package/dist/featureFlags.js.map +1 -1
- package/dist/fp/automationInterpreter.js +25 -21
- package/dist/fp/automationInterpreter.js.map +1 -1
- package/dist/fp/automationState.js +4 -1
- package/dist/fp/automationState.js.map +1 -1
- package/dist/fp/policyParser.js +4 -1
- package/dist/fp/policyParser.js.map +1 -1
- package/dist/inboxRoutes.d.ts +22 -0
- package/dist/inboxRoutes.js +114 -0
- package/dist/inboxRoutes.js.map +1 -0
- package/dist/index.js +734 -144
- package/dist/index.js.map +1 -1
- package/dist/mcpRoutes.d.ts +37 -0
- package/dist/mcpRoutes.js +76 -0
- package/dist/mcpRoutes.js.map +1 -0
- package/dist/oauth.d.ts +3 -0
- package/dist/oauth.js +151 -26
- package/dist/oauth.js.map +1 -1
- package/dist/oauthRoutes.d.ts +32 -0
- package/dist/oauthRoutes.js +124 -0
- package/dist/oauthRoutes.js.map +1 -0
- package/dist/orchestrator/orchestratorBridge.js +2 -2
- package/dist/orchestrator/orchestratorBridge.js.map +1 -1
- package/dist/patchworkConfig.d.ts +7 -0
- package/dist/patchworkConfig.js.map +1 -1
- package/dist/pluginLoader.d.ts +12 -0
- package/dist/pluginLoader.js +43 -4
- package/dist/pluginLoader.js.map +1 -1
- package/dist/pluginWatcher.js +8 -3
- package/dist/pluginWatcher.js.map +1 -1
- package/dist/preToolUseHook.d.ts +12 -0
- package/dist/preToolUseHook.js +23 -0
- package/dist/preToolUseHook.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +8 -0
- package/dist/recipeOrchestration.js +320 -39
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipeRoutes.d.ts +154 -0
- package/dist/recipeRoutes.js +1098 -0
- package/dist/recipeRoutes.js.map +1 -0
- package/dist/recipes/captureForRunlog.d.ts +27 -0
- package/dist/recipes/captureForRunlog.js +128 -0
- package/dist/recipes/captureForRunlog.js.map +1 -0
- package/dist/recipes/chainedRunner.d.ts +54 -3
- package/dist/recipes/chainedRunner.js +256 -36
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/compiler.js +3 -3
- package/dist/recipes/compiler.js.map +1 -1
- package/dist/recipes/detectSilentFail.d.ts +34 -0
- package/dist/recipes/detectSilentFail.js +105 -0
- package/dist/recipes/detectSilentFail.js.map +1 -0
- package/dist/recipes/installer.js +3 -3
- package/dist/recipes/installer.js.map +1 -1
- package/dist/recipes/manifest.js +21 -6
- package/dist/recipes/manifest.js.map +1 -1
- package/dist/recipes/migrationWarnings.d.ts +12 -0
- package/dist/recipes/migrationWarnings.js +44 -0
- package/dist/recipes/migrationWarnings.js.map +1 -0
- package/dist/recipes/replayRun.d.ts +62 -0
- package/dist/recipes/replayRun.js +97 -0
- package/dist/recipes/replayRun.js.map +1 -0
- package/dist/recipes/resolveRecipePath.d.ts +69 -0
- package/dist/recipes/resolveRecipePath.js +202 -0
- package/dist/recipes/resolveRecipePath.js.map +1 -0
- package/dist/recipes/scheduler.js +102 -11
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schemaGenerator.js +3 -3
- package/dist/recipes/schemaGenerator.js.map +1 -1
- package/dist/recipes/toolRegistry.d.ts +5 -0
- package/dist/recipes/toolRegistry.js +9 -0
- package/dist/recipes/toolRegistry.js.map +1 -1
- package/dist/recipes/tools/asana.d.ts +16 -0
- package/dist/recipes/tools/asana.js +524 -0
- package/dist/recipes/tools/asana.js.map +1 -0
- package/dist/recipes/tools/discord.d.ts +18 -0
- package/dist/recipes/tools/discord.js +254 -0
- package/dist/recipes/tools/discord.js.map +1 -0
- package/dist/recipes/tools/file.d.ts +6 -0
- package/dist/recipes/tools/file.js +12 -8
- package/dist/recipes/tools/file.js.map +1 -1
- package/dist/recipes/tools/github.js +29 -4
- package/dist/recipes/tools/github.js.map +1 -1
- package/dist/recipes/tools/gitlab.d.ts +11 -0
- package/dist/recipes/tools/gitlab.js +285 -0
- package/dist/recipes/tools/gitlab.js.map +1 -0
- package/dist/recipes/tools/gmail.d.ts +1 -1
- package/dist/recipes/tools/gmail.js +230 -6
- package/dist/recipes/tools/gmail.js.map +1 -1
- package/dist/recipes/tools/googleDrive.d.ts +1 -0
- package/dist/recipes/tools/googleDrive.js +55 -0
- package/dist/recipes/tools/googleDrive.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +8 -0
- package/dist/recipes/tools/index.js +8 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/tools/jira.d.ts +14 -0
- package/dist/recipes/tools/jira.js +369 -0
- package/dist/recipes/tools/jira.js.map +1 -0
- package/dist/recipes/tools/linear.d.ts +2 -1
- package/dist/recipes/tools/linear.js +227 -3
- package/dist/recipes/tools/linear.js.map +1 -1
- package/dist/recipes/tools/meetingNotes.d.ts +21 -0
- package/dist/recipes/tools/meetingNotes.js +701 -0
- package/dist/recipes/tools/meetingNotes.js.map +1 -0
- package/dist/recipes/tools/pagerduty.d.ts +15 -0
- package/dist/recipes/tools/pagerduty.js +451 -0
- package/dist/recipes/tools/pagerduty.js.map +1 -0
- package/dist/recipes/tools/sentry.d.ts +12 -0
- package/dist/recipes/tools/sentry.js +73 -0
- package/dist/recipes/tools/sentry.js.map +1 -0
- package/dist/recipes/tools/slack.js +15 -5
- package/dist/recipes/tools/slack.js.map +1 -1
- package/dist/recipes/validation.js +83 -14
- package/dist/recipes/validation.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +30 -2
- package/dist/recipes/yamlRunner.js +369 -70
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +76 -1
- package/dist/recipesHttp.js +474 -12
- package/dist/recipesHttp.js.map +1 -1
- package/dist/runLog.d.ts +78 -2
- package/dist/runLog.js +204 -6
- package/dist/runLog.js.map +1 -1
- package/dist/schemas/dry-run-plan.v1.json +139 -0
- package/dist/schemas/recipe.v1.json +684 -0
- package/dist/server.d.ts +79 -10
- package/dist/server.js +366 -1384
- package/dist/server.js.map +1 -1
- package/dist/ssrfGuard.d.ts +54 -0
- package/dist/ssrfGuard.js +122 -0
- package/dist/ssrfGuard.js.map +1 -0
- package/dist/streamableHttp.d.ts +39 -1
- package/dist/streamableHttp.js +126 -17
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/getDocumentSymbols.d.ts +24 -0
- package/dist/tools/getDocumentSymbols.js +74 -8
- package/dist/tools/getDocumentSymbols.js.map +1 -1
- package/dist/tools/getSecurityAdvisories.js +10 -1
- package/dist/tools/getSecurityAdvisories.js.map +1 -1
- package/dist/tools/getSessionUsage.d.ts +3 -0
- package/dist/tools/getSessionUsage.js +3 -0
- package/dist/tools/getSessionUsage.js.map +1 -1
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +32 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/slackPostMessage.js +1 -1
- package/dist/tools/slackPostMessage.js.map +1 -1
- package/dist/tools/transaction.d.ts +19 -0
- package/dist/tools/transaction.js +29 -0
- package/dist/tools/transaction.js.map +1 -1
- package/dist/traceEncryption.d.ts +46 -0
- package/dist/traceEncryption.js +124 -0
- package/dist/traceEncryption.js.map +1 -0
- package/dist/transport.d.ts +39 -0
- package/dist/transport.js +88 -8
- package/dist/transport.js.map +1 -1
- package/package.json +22 -5
- package/templates/policies/README.md +72 -0
- package/templates/policies/conservative.json +14 -0
- package/templates/policies/developer.json +14 -0
- package/templates/policies/headless-ci.json +24 -0
- package/templates/policies/personal-assistant.json +15 -0
- package/templates/policies/regulated-industry.json +18 -0
- package/templates/recipes/project-health-check.yaml +1 -1
- package/templates/recipes/webhook/README.md +70 -0
- package/templates/recipes/webhook/capture-thought.yaml +26 -0
- package/templates/recipes/webhook/customer-escalation.yaml +49 -0
- package/templates/recipes/webhook/incident-intake.yaml +46 -0
- package/templates/recipes/webhook/meeting-prep.yaml +48 -0
- package/templates/recipes/webhook/morning-brief.yaml +57 -0
package/dist/approvalQueue.js
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
|
-
import { randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
1
|
+
import { createHash, randomBytes, randomUUID, timingSafeEqual, } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* Stable canonical JSON used to compute the `inflightKey`. Sorts object
|
|
4
|
+
* keys at every level so logically-identical params with different key
|
|
5
|
+
* order hash the same. Returns "[uncloneable]" if input contains circular
|
|
6
|
+
* references — those won't dedup, but the queue still works.
|
|
7
|
+
*/
|
|
8
|
+
function canonicalJson(value) {
|
|
9
|
+
const seen = new WeakSet();
|
|
10
|
+
const stringify = (v) => {
|
|
11
|
+
if (v === null || typeof v !== "object")
|
|
12
|
+
return v;
|
|
13
|
+
if (seen.has(v))
|
|
14
|
+
return "[circular]";
|
|
15
|
+
seen.add(v);
|
|
16
|
+
if (Array.isArray(v))
|
|
17
|
+
return v.map(stringify);
|
|
18
|
+
const obj = v;
|
|
19
|
+
const out = {};
|
|
20
|
+
for (const k of Object.keys(obj).sort())
|
|
21
|
+
out[k] = stringify(obj[k]);
|
|
22
|
+
return out;
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
return JSON.stringify(stringify(value));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return "[uncloneable]";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
2
31
|
export class ApprovalQueue {
|
|
3
32
|
entries = new Map();
|
|
33
|
+
/** inflightKey → callId, for dedup lookup on `request()`. */
|
|
34
|
+
inflight = new Map();
|
|
4
35
|
ttlMs;
|
|
5
36
|
listeners = new Set();
|
|
6
37
|
constructor(opts = {}) {
|
|
@@ -22,6 +53,34 @@ export class ApprovalQueue {
|
|
|
22
53
|
}
|
|
23
54
|
}
|
|
24
55
|
request(input, opts = {}) {
|
|
56
|
+
// Dedup: if an identical (sessionId, toolName, params) request is already
|
|
57
|
+
// queued, return its existing promise instead of allocating a fresh
|
|
58
|
+
// callId + push notification. Prevents a buggy/malicious agent that
|
|
59
|
+
// spams the same call N times from generating N prompts.
|
|
60
|
+
const inflightKey = createHash("sha256")
|
|
61
|
+
.update(input.sessionId ?? "")
|
|
62
|
+
.update("\0")
|
|
63
|
+
.update(input.toolName)
|
|
64
|
+
.update("\0")
|
|
65
|
+
.update(canonicalJson(input.params))
|
|
66
|
+
.digest("hex");
|
|
67
|
+
const existingCallId = this.inflight.get(inflightKey);
|
|
68
|
+
if (existingCallId) {
|
|
69
|
+
const existing = this.entries.get(existingCallId);
|
|
70
|
+
if (existing) {
|
|
71
|
+
const promise = new Promise((res) => {
|
|
72
|
+
existing.pendingPromises.push(res);
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
callId: existing.callId,
|
|
76
|
+
approvalToken: existing.approvalToken,
|
|
77
|
+
promise,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// Stale inflight entry pointing at a callId that no longer exists —
|
|
81
|
+
// fall through and create a fresh request.
|
|
82
|
+
this.inflight.delete(inflightKey);
|
|
83
|
+
}
|
|
25
84
|
const callId = randomUUID();
|
|
26
85
|
const requestedAt = Date.now();
|
|
27
86
|
const approvalToken = opts.withToken
|
|
@@ -36,7 +95,10 @@ export class ApprovalQueue {
|
|
|
36
95
|
if (!entry)
|
|
37
96
|
return;
|
|
38
97
|
this.entries.delete(callId);
|
|
98
|
+
this.inflight.delete(entry.inflightKey);
|
|
39
99
|
entry.resolve("expired");
|
|
100
|
+
for (const r of entry.pendingPromises)
|
|
101
|
+
r("expired");
|
|
40
102
|
this.notify();
|
|
41
103
|
}, this.ttlMs);
|
|
42
104
|
if (typeof timer === "object" && "unref" in timer)
|
|
@@ -47,8 +109,11 @@ export class ApprovalQueue {
|
|
|
47
109
|
resolve: resolveFn,
|
|
48
110
|
timer,
|
|
49
111
|
approvalToken,
|
|
112
|
+
inflightKey,
|
|
113
|
+
pendingPromises: [],
|
|
50
114
|
...input,
|
|
51
115
|
});
|
|
116
|
+
this.inflight.set(inflightKey, callId);
|
|
52
117
|
this.notify();
|
|
53
118
|
return { callId, approvalToken, promise };
|
|
54
119
|
}
|
|
@@ -85,6 +150,7 @@ export class ApprovalQueue {
|
|
|
85
150
|
sessionId: e.sessionId,
|
|
86
151
|
summary: e.summary,
|
|
87
152
|
riskSignals: e.riskSignals,
|
|
153
|
+
personalSignals: e.personalSignals,
|
|
88
154
|
// approvalToken intentionally omitted from list — never expose to untrusted callers
|
|
89
155
|
}));
|
|
90
156
|
}
|
|
@@ -96,8 +162,17 @@ export class ApprovalQueue {
|
|
|
96
162
|
for (const entry of this.entries.values()) {
|
|
97
163
|
clearTimeout(entry.timer);
|
|
98
164
|
entry.resolve("expired");
|
|
165
|
+
// Wake up any duplicate callers who joined this entry via dedup —
|
|
166
|
+
// their promises would otherwise hang forever after shutdown /
|
|
167
|
+
// resetApprovalQueueForTests.
|
|
168
|
+
for (const r of entry.pendingPromises)
|
|
169
|
+
r("expired");
|
|
99
170
|
}
|
|
100
171
|
this.entries.clear();
|
|
172
|
+
// Drain dedup map. Stale entries are self-healing on the next request,
|
|
173
|
+
// but leaving them around leaks memory across shutdown cycles and is
|
|
174
|
+
// the wrong invariant for `clear()`.
|
|
175
|
+
this.inflight.clear();
|
|
101
176
|
}
|
|
102
177
|
resolveEntry(callId, decision) {
|
|
103
178
|
const entry = this.entries.get(callId);
|
|
@@ -105,7 +180,11 @@ export class ApprovalQueue {
|
|
|
105
180
|
return false;
|
|
106
181
|
clearTimeout(entry.timer);
|
|
107
182
|
this.entries.delete(callId);
|
|
183
|
+
this.inflight.delete(entry.inflightKey);
|
|
108
184
|
entry.resolve(decision);
|
|
185
|
+
// Wake up any duplicate callers who joined this entry via dedup.
|
|
186
|
+
for (const r of entry.pendingPromises)
|
|
187
|
+
r(decision);
|
|
109
188
|
this.notify();
|
|
110
189
|
return true;
|
|
111
190
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approvalQueue.js","sourceRoot":"","sources":["../src/approvalQueue.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"approvalQueue.js","sourceRoot":"","sources":["../src/approvalQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* approvalSignals — passive risk personalization for the approval queue.
|
|
3
|
+
*
|
|
4
|
+
* Computes user-specific signals based on past approval / activity history.
|
|
5
|
+
* These supplement (not replace) the policy-engine `riskSignals` which are
|
|
6
|
+
* computed from the call's CONTENT (params shape, destructive flags, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Personal signals describe the user's RELATIONSHIP to this tool/call:
|
|
9
|
+
* "you approved this 27 times" is a different signal class from "this
|
|
10
|
+
* command contains rm -rf". Both should reach the approval modal.
|
|
11
|
+
*
|
|
12
|
+
* Catalog (from docs/strategic/2026-05-02/memory-ecosystem-report.md §5):
|
|
13
|
+
* three of the twelve heuristics shipped here. Heuristics 4-12 follow.
|
|
14
|
+
*
|
|
15
|
+
* 1. "You approved similar actions N times" — past allow on same tool
|
|
16
|
+
* 2. "You rejected this tool before" — past deny on same tool
|
|
17
|
+
* 3. "First use of this connector" — connector namespace ∩ activity log
|
|
18
|
+
* 5. "Last called T days ago" — gap since most recent call (heuristic 4
|
|
19
|
+
* from the catalog is satisfied by the first_connector_use kind above)
|
|
20
|
+
* 7. "Risk tier escalation" — current tier exceeds the user's typical
|
|
21
|
+
* approved tier across recent decisions
|
|
22
|
+
* 6. "Mirrors a recipe step you trust" — primary param matches a step
|
|
23
|
+
* from a successful past recipe run
|
|
24
|
+
* 8. "Often runs alongside X" — co-occurrence pairing in recent activity
|
|
25
|
+
* 9. "Workspace mismatch" — call from a workspace that has never
|
|
26
|
+
* approved this tool before
|
|
27
|
+
* 10. "Time-of-day anomaly" — call hour outside the user's usual window
|
|
28
|
+
* for this tool (opt-in: gate via `enableTimeOfDayAnomaly`)
|
|
29
|
+
* 11. "Param novelty" — primary param (command/url/pattern) prefix never
|
|
30
|
+
* seen on prior approvals of this tool
|
|
31
|
+
* 12. "Cooldown breach" — same tool fired N+ times in a short window
|
|
32
|
+
*
|
|
33
|
+
* The signals are **transparent**: every signal has a `source` enum so a
|
|
34
|
+
* future "why is this signal here?" UI can link back to the rows that
|
|
35
|
+
* produced it. We do not infer; we count and match. No model, no
|
|
36
|
+
* fine-tuning. Honesty is the value proposition.
|
|
37
|
+
*
|
|
38
|
+
* Privacy: signals are computed locally over local logs. They flow into
|
|
39
|
+
* the approval queue's PendingApproval shape, which is exposed via
|
|
40
|
+
* GET /approvals (bearer-auth-gated) and the SSE stream (same auth).
|
|
41
|
+
* Nothing leaves the machine.
|
|
42
|
+
*/
|
|
43
|
+
import type { ActivityLog } from "./activityLog.js";
|
|
44
|
+
import type { RiskTier } from "./riskTier.js";
|
|
45
|
+
export interface PersonalSignal {
|
|
46
|
+
kind: "prior_approvals" | "prior_rejection" | "first_connector_use" | "first_tool_use" | "stale_tool_use" | "tier_escalation" | "cooccurrence_pattern" | "cooldown_breach" | "workspace_mismatch" | "time_of_day_anomaly" | "param_novelty" | "recipe_step_trust";
|
|
47
|
+
/** Human-facing label suitable for an approval modal line. */
|
|
48
|
+
label: string;
|
|
49
|
+
/** Severity controls visual weight. low = informational, high = warning. */
|
|
50
|
+
severity: "low" | "medium" | "high";
|
|
51
|
+
/** Source identifier so the UI can link the signal back to its evidence. */
|
|
52
|
+
source: "approval_history" | "activity_history" | "tool_registry" | "recipe_run_log";
|
|
53
|
+
/** Optional numeric backing the label, surfaced in tooltips / counts. */
|
|
54
|
+
count?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Minimal querier surface for h6. Accepting the narrow interface (rather
|
|
58
|
+
* than the full `RecipeRunLog` class) lets tests inject canned runs
|
|
59
|
+
* without instantiating the disk-backed log, and keeps the dependency
|
|
60
|
+
* graph small.
|
|
61
|
+
*/
|
|
62
|
+
export interface RecipeRunQuerier {
|
|
63
|
+
query(q: {
|
|
64
|
+
status?: string;
|
|
65
|
+
limit?: number;
|
|
66
|
+
}): Array<{
|
|
67
|
+
recipeName: string;
|
|
68
|
+
status: string;
|
|
69
|
+
stepResults?: Array<{
|
|
70
|
+
id: string;
|
|
71
|
+
tool?: string;
|
|
72
|
+
status: "ok" | "skipped" | "error";
|
|
73
|
+
resolvedParams?: unknown;
|
|
74
|
+
}>;
|
|
75
|
+
}>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Compute the personal-signal set for an incoming approval request.
|
|
79
|
+
*
|
|
80
|
+
* Pure function over the activity log; no I/O of its own. Tested in
|
|
81
|
+
* isolation by feeding a mock ActivityLog. The activityLog argument is
|
|
82
|
+
* passed positionally rather than wired through deps so the surface
|
|
83
|
+
* stays inspectable.
|
|
84
|
+
*/
|
|
85
|
+
export declare function computePersonalSignals(input: {
|
|
86
|
+
toolName: string;
|
|
87
|
+
activityLog: ActivityLog;
|
|
88
|
+
/**
|
|
89
|
+
* Risk tier of the *current* call, used by heuristic 7. Optional —
|
|
90
|
+
* pre-#126 callers and the test fixtures that omit it simply skip
|
|
91
|
+
* tier-escalation evaluation.
|
|
92
|
+
*/
|
|
93
|
+
currentTier?: RiskTier;
|
|
94
|
+
/**
|
|
95
|
+
* Absolute workspace path of the *current* call, used by heuristic 9
|
|
96
|
+
* (workspace mismatch). Optional — when omitted, h9 is skipped.
|
|
97
|
+
* Approval-decision rows persisted before workspace was captured on
|
|
98
|
+
* the lifecycle metadata also degrade gracefully (treated as having
|
|
99
|
+
* no baseline).
|
|
100
|
+
*/
|
|
101
|
+
currentWorkspace?: string;
|
|
102
|
+
/**
|
|
103
|
+
* Opt-in switch for heuristic 10 (time-of-day anomaly). The catalog
|
|
104
|
+
* flags this as medium-FP — noisy for power users with irregular
|
|
105
|
+
* schedules — so the default is off. Bridge wires it on when the
|
|
106
|
+
* user enables the corresponding setting.
|
|
107
|
+
*/
|
|
108
|
+
enableTimeOfDayAnomaly?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Params of the *current* call, used by heuristic 11 (param novelty).
|
|
111
|
+
* Optional — when omitted, h11 is skipped. The bridge passes the same
|
|
112
|
+
* (un-redacted) params used elsewhere in the approval flow; the
|
|
113
|
+
* heuristic extracts only the primary key (command / url / pattern)
|
|
114
|
+
* and never logs or returns the value.
|
|
115
|
+
*/
|
|
116
|
+
currentParams?: Record<string, unknown>;
|
|
117
|
+
/**
|
|
118
|
+
* Optional recipe-run querier for heuristic 6 (recipe-step trust). When
|
|
119
|
+
* present, h6 scans recent successful runs for a step that matches
|
|
120
|
+
* this tool + the current call's primary param prefix and surfaces
|
|
121
|
+
* the recipe name. Skipped when omitted.
|
|
122
|
+
*/
|
|
123
|
+
recipeRunLog?: RecipeRunQuerier;
|
|
124
|
+
}): PersonalSignal[];
|