@code-yeongyu/senpi 2026.6.28-4 → 2026.6.30
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/CHANGELOG.md +15 -0
- package/README.md +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +17 -4
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/builtin/hooks/command-runner.d.ts +25 -0
- package/dist/core/extensions/builtin/hooks/command-runner.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/command-runner.js +152 -0
- package/dist/core/extensions/builtin/hooks/command-runner.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/command.d.ts +11 -0
- package/dist/core/extensions/builtin/hooks/command.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/command.js +180 -0
- package/dist/core/extensions/builtin/hooks/command.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/config-loader.d.ts +19 -0
- package/dist/core/extensions/builtin/hooks/config-loader.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/config-loader.js +125 -0
- package/dist/core/extensions/builtin/hooks/config-loader.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/diagnostics.d.ts +10 -0
- package/dist/core/extensions/builtin/hooks/diagnostics.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/diagnostics.js +14 -0
- package/dist/core/extensions/builtin/hooks/diagnostics.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/dispatcher.d.ts +60 -0
- package/dist/core/extensions/builtin/hooks/dispatcher.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/dispatcher.js +161 -0
- package/dist/core/extensions/builtin/hooks/dispatcher.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/handler.d.ts +12 -0
- package/dist/core/extensions/builtin/hooks/handler.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/handler.js +128 -0
- package/dist/core/extensions/builtin/hooks/handler.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/index.d.ts +6 -0
- package/dist/core/extensions/builtin/hooks/index.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/index.js +216 -0
- package/dist/core/extensions/builtin/hooks/index.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/lifecycle-adapter.d.ts +29 -0
- package/dist/core/extensions/builtin/hooks/lifecycle-adapter.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/lifecycle-adapter.js +276 -0
- package/dist/core/extensions/builtin/hooks/lifecycle-adapter.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/matcher.d.ts +7 -0
- package/dist/core/extensions/builtin/hooks/matcher.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/matcher.js +109 -0
- package/dist/core/extensions/builtin/hooks/matcher.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/output-bounds.d.ts +29 -0
- package/dist/core/extensions/builtin/hooks/output-bounds.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/output-bounds.js +47 -0
- package/dist/core/extensions/builtin/hooks/output-bounds.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/output-parser.d.ts +27 -0
- package/dist/core/extensions/builtin/hooks/output-parser.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/output-parser.js +168 -0
- package/dist/core/extensions/builtin/hooks/output-parser.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/plugin-loader.d.ts +11 -0
- package/dist/core/extensions/builtin/hooks/plugin-loader.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/plugin-loader.js +138 -0
- package/dist/core/extensions/builtin/hooks/plugin-loader.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/plugin-manifest.d.ts +47 -0
- package/dist/core/extensions/builtin/hooks/plugin-manifest.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/plugin-manifest.js +86 -0
- package/dist/core/extensions/builtin/hooks/plugin-manifest.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/prompt-adapter.d.ts +30 -0
- package/dist/core/extensions/builtin/hooks/prompt-adapter.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/prompt-adapter.js +59 -0
- package/dist/core/extensions/builtin/hooks/prompt-adapter.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/safety.d.ts +14 -0
- package/dist/core/extensions/builtin/hooks/safety.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/safety.js +179 -0
- package/dist/core/extensions/builtin/hooks/safety.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/schema.d.ts +3 -0
- package/dist/core/extensions/builtin/hooks/schema.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/schema.js +94 -0
- package/dist/core/extensions/builtin/hooks/schema.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/stop-adapter.d.ts +18 -0
- package/dist/core/extensions/builtin/hooks/stop-adapter.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/stop-adapter.js +282 -0
- package/dist/core/extensions/builtin/hooks/stop-adapter.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/tool-adapter.d.ts +11 -0
- package/dist/core/extensions/builtin/hooks/tool-adapter.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/tool-adapter.js +158 -0
- package/dist/core/extensions/builtin/hooks/tool-adapter.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-storage.d.ts +24 -0
- package/dist/core/extensions/builtin/hooks/trust-storage.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust-storage.js +102 -0
- package/dist/core/extensions/builtin/hooks/trust-storage.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust.d.ts +34 -0
- package/dist/core/extensions/builtin/hooks/trust.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/trust.js +194 -0
- package/dist/core/extensions/builtin/hooks/trust.js.map +1 -0
- package/dist/core/extensions/builtin/hooks/types.d.ts +134 -0
- package/dist/core/extensions/builtin/hooks/types.d.ts.map +1 -0
- package/dist/core/extensions/builtin/hooks/types.js +36 -0
- package/dist/core/extensions/builtin/hooks/types.js.map +1 -0
- package/dist/core/extensions/builtin/index.d.ts.map +1 -1
- package/dist/core/extensions/builtin/index.js +2 -0
- package/dist/core/extensions/builtin/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +20 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +17 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +14 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +14 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +38 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +2 -2
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/version-check.d.ts +1 -0
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +7 -0
- package/dist/utils/version-check.js.map +1 -1
- package/docs/extensions.md +450 -0
- package/docs/index.md +1 -1
- package/docs/packages.md +9 -6
- package/examples/extensions/README.md +1 -0
- package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +17 -24
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts +17 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js +17 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +0 -24
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +16 -35
- package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js +12 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js +12 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js +12 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js +15 -15
- package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +3 -0
- package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/npm-shrinkwrap.json +9 -9
- package/package.json +4 -4
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import lockfile from "proper-lockfile";
|
|
4
|
+
import { CONFIG_DIR_NAME, getAgentDir } from "../../../../config.js";
|
|
5
|
+
import { emptyHookTrustState, readHookTrustStateJson } from "./trust.js";
|
|
6
|
+
export class FileHookStateStorage {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
const agentDir = options.agentDir ?? getAgentDir();
|
|
9
|
+
this.globalStatePath = join(agentDir, "hooks-state.json");
|
|
10
|
+
this.projectStatePath = join(options.cwd, CONFIG_DIR_NAME, "hooks-state.json");
|
|
11
|
+
}
|
|
12
|
+
read(scope) {
|
|
13
|
+
return withHookStateFileLock(statePathForScope(scope, this.globalStatePath, this.projectStatePath), (path) => readHookTrustStateJson(existsSync(path) ? readFileSync(path, "utf-8") : undefined));
|
|
14
|
+
}
|
|
15
|
+
update(scope, updater) {
|
|
16
|
+
return withHookStateFileLock(statePathForScope(scope, this.globalStatePath, this.projectStatePath), (path) => {
|
|
17
|
+
const current = readHookTrustStateJson(existsSync(path) ? readFileSync(path, "utf-8") : undefined);
|
|
18
|
+
const next = updater(current);
|
|
19
|
+
writeFileSync(path, serializeHookTrustState(next), "utf-8");
|
|
20
|
+
return next;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class InMemoryHookStateStorage {
|
|
25
|
+
constructor() {
|
|
26
|
+
this.globalState = emptyHookTrustState();
|
|
27
|
+
this.projectState = emptyHookTrustState();
|
|
28
|
+
}
|
|
29
|
+
read(scope) {
|
|
30
|
+
return scope === "global" ? this.globalState : this.projectState;
|
|
31
|
+
}
|
|
32
|
+
update(scope, updater) {
|
|
33
|
+
const next = updater(this.read(scope));
|
|
34
|
+
if (scope === "global") {
|
|
35
|
+
this.globalState = next;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.projectState = next;
|
|
39
|
+
}
|
|
40
|
+
return next;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function statePathForScope(scope, globalStatePath, projectStatePath) {
|
|
44
|
+
return scope === "global" ? globalStatePath : projectStatePath;
|
|
45
|
+
}
|
|
46
|
+
function serializeHookTrustState(state) {
|
|
47
|
+
const sortedHooks = {};
|
|
48
|
+
for (const key of Object.keys(state.hooks).sort()) {
|
|
49
|
+
const entry = state.hooks[key];
|
|
50
|
+
if (entry !== undefined) {
|
|
51
|
+
sortedHooks[key] = entry;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return `${JSON.stringify({ version: 1, hooks: sortedHooks }, null, 2)}\n`;
|
|
55
|
+
}
|
|
56
|
+
function acquireHookStateLockSync(path) {
|
|
57
|
+
const stateDir = dirname(path);
|
|
58
|
+
mkdirSync(stateDir, { recursive: true });
|
|
59
|
+
const maxAttempts = 10;
|
|
60
|
+
const delayMs = 20;
|
|
61
|
+
let lastError;
|
|
62
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
63
|
+
try {
|
|
64
|
+
return lockfile.lockSync(stateDir, { realpath: false, lockfilePath: `${path}.lock` });
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const code = errorCode(error);
|
|
68
|
+
if (code !== "ELOCKED" || attempt === maxAttempts) {
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
lastError = error;
|
|
72
|
+
const start = Date.now();
|
|
73
|
+
while (Date.now() - start < delayMs) {
|
|
74
|
+
Date.now();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (lastError instanceof Error) {
|
|
79
|
+
throw lastError;
|
|
80
|
+
}
|
|
81
|
+
throw new Error("Failed to acquire hook state lock");
|
|
82
|
+
}
|
|
83
|
+
function errorCode(error) {
|
|
84
|
+
if (!isRecord(error)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const code = error.code;
|
|
88
|
+
return typeof code === "string" ? code : undefined;
|
|
89
|
+
}
|
|
90
|
+
function isRecord(value) {
|
|
91
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
92
|
+
}
|
|
93
|
+
function withHookStateFileLock(path, fn) {
|
|
94
|
+
const release = acquireHookStateLockSync(path);
|
|
95
|
+
try {
|
|
96
|
+
return fn(path);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
release();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=trust-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust-storage.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/hooks/trust-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAA8B,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAarG,MAAM,OAAO,oBAAoB;IAIhC,YAAY,OAAoC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC;QACnD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QAC1D,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,EAAE,kBAAkB,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,KAA4B;QAChC,OAAO,qBAAqB,CAAC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAC5G,sBAAsB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAClF,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAA4B,EAAE,OAAoD;QACxF,OAAO,qBAAqB,CAAC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5G,MAAM,OAAO,GAAG,sBAAsB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACnG,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YAC9B,aAAa,CAAC,IAAI,EAAE,uBAAuB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC;QACb,CAAC,CAAC,CAAC;IACJ,CAAC;CACD;AAED,MAAM,OAAO,wBAAwB;IAArC;QACS,gBAAW,GAAmB,mBAAmB,EAAE,CAAC;QACpD,iBAAY,GAAmB,mBAAmB,EAAE,CAAC;IAe9D,CAAC;IAbA,IAAI,CAAC,KAA4B;QAChC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC;IAClE,CAAC;IAED,MAAM,CAAC,KAA4B,EAAE,OAAoD;QACxF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACvC,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACzB,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAED,SAAS,iBAAiB,CAAC,KAA4B,EAAE,eAAuB,EAAE,gBAAwB;IACzG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAChE,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAqB;IACrD,MAAM,WAAW,GAAmC,EAAE,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC1B,CAAC;IACF,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,SAAS,wBAAwB,CAAC,IAAY;IAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,EAAE,CAAC;IACnB,IAAI,SAAkB,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACzD,IAAI,CAAC;YACJ,OAAO,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC,CAAC;QACvF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAC9B,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBACnD,MAAM,KAAK,CAAC;YACb,CAAC;YACD,SAAS,GAAG,KAAK,CAAC;YAClB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,OAAO,EAAE,CAAC;gBACrC,IAAI,CAAC,GAAG,EAAE,CAAC;YACZ,CAAC;QACF,CAAC;IACF,CAAC;IAED,IAAI,SAAS,YAAY,KAAK,EAAE,CAAC;QAChC,MAAM,SAAS,CAAC;IACjB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAChC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,qBAAqB,CAAI,IAAY,EAAE,EAAuB;IACtE,MAAM,OAAO,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC;QACJ,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;YAAS,CAAC;QACV,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport lockfile from \"proper-lockfile\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../../../../config.ts\";\nimport { emptyHookTrustState, type HookTrustStorageScope, readHookTrustStateJson } from \"./trust.ts\";\nimport type { HookTrustEntry, HookTrustState } from \"./types.ts\";\n\nexport interface HookStateStorage {\n\tread(scope: HookTrustStorageScope): HookTrustState;\n\tupdate(scope: HookTrustStorageScope, updater: (current: HookTrustState) => HookTrustState): HookTrustState;\n}\n\nexport type FileHookStateStorageOptions = {\n\treadonly agentDir?: string;\n\treadonly cwd: string;\n};\n\nexport class FileHookStateStorage implements HookStateStorage {\n\tprivate readonly globalStatePath: string;\n\tprivate readonly projectStatePath: string;\n\n\tconstructor(options: FileHookStateStorageOptions) {\n\t\tconst agentDir = options.agentDir ?? getAgentDir();\n\t\tthis.globalStatePath = join(agentDir, \"hooks-state.json\");\n\t\tthis.projectStatePath = join(options.cwd, CONFIG_DIR_NAME, \"hooks-state.json\");\n\t}\n\n\tread(scope: HookTrustStorageScope): HookTrustState {\n\t\treturn withHookStateFileLock(statePathForScope(scope, this.globalStatePath, this.projectStatePath), (path) =>\n\t\t\treadHookTrustStateJson(existsSync(path) ? readFileSync(path, \"utf-8\") : undefined),\n\t\t);\n\t}\n\n\tupdate(scope: HookTrustStorageScope, updater: (current: HookTrustState) => HookTrustState): HookTrustState {\n\t\treturn withHookStateFileLock(statePathForScope(scope, this.globalStatePath, this.projectStatePath), (path) => {\n\t\t\tconst current = readHookTrustStateJson(existsSync(path) ? readFileSync(path, \"utf-8\") : undefined);\n\t\t\tconst next = updater(current);\n\t\t\twriteFileSync(path, serializeHookTrustState(next), \"utf-8\");\n\t\t\treturn next;\n\t\t});\n\t}\n}\n\nexport class InMemoryHookStateStorage implements HookStateStorage {\n\tprivate globalState: HookTrustState = emptyHookTrustState();\n\tprivate projectState: HookTrustState = emptyHookTrustState();\n\n\tread(scope: HookTrustStorageScope): HookTrustState {\n\t\treturn scope === \"global\" ? this.globalState : this.projectState;\n\t}\n\n\tupdate(scope: HookTrustStorageScope, updater: (current: HookTrustState) => HookTrustState): HookTrustState {\n\t\tconst next = updater(this.read(scope));\n\t\tif (scope === \"global\") {\n\t\t\tthis.globalState = next;\n\t\t} else {\n\t\t\tthis.projectState = next;\n\t\t}\n\t\treturn next;\n\t}\n}\n\nfunction statePathForScope(scope: HookTrustStorageScope, globalStatePath: string, projectStatePath: string): string {\n\treturn scope === \"global\" ? globalStatePath : projectStatePath;\n}\n\nfunction serializeHookTrustState(state: HookTrustState): string {\n\tconst sortedHooks: Record<string, HookTrustEntry> = {};\n\tfor (const key of Object.keys(state.hooks).sort()) {\n\t\tconst entry = state.hooks[key];\n\t\tif (entry !== undefined) {\n\t\t\tsortedHooks[key] = entry;\n\t\t}\n\t}\n\treturn `${JSON.stringify({ version: 1, hooks: sortedHooks }, null, 2)}\\n`;\n}\n\nfunction acquireHookStateLockSync(path: string): () => void {\n\tconst stateDir = dirname(path);\n\tmkdirSync(stateDir, { recursive: true });\n\tconst maxAttempts = 10;\n\tconst delayMs = 20;\n\tlet lastError: unknown;\n\n\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\ttry {\n\t\t\treturn lockfile.lockSync(stateDir, { realpath: false, lockfilePath: `${path}.lock` });\n\t\t} catch (error) {\n\t\t\tconst code = errorCode(error);\n\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tlastError = error;\n\t\t\tconst start = Date.now();\n\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\tDate.now();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (lastError instanceof Error) {\n\t\tthrow lastError;\n\t}\n\tthrow new Error(\"Failed to acquire hook state lock\");\n}\n\nfunction errorCode(error: unknown): string | undefined {\n\tif (!isRecord(error)) {\n\t\treturn undefined;\n\t}\n\tconst code = error.code;\n\treturn typeof code === \"string\" ? code : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction withHookStateFileLock<T>(path: string, fn: (path: string) => T): T {\n\tconst release = acquireHookStateLockSync(path);\n\ttry {\n\t\treturn fn(path);\n\t} finally {\n\t\trelease();\n\t}\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ExecutableHookHandler, HookSourceScope, HookTrustEntry, HookTrustState } from "./types.ts";
|
|
2
|
+
export type HookTrustPlatform = NodeJS.Platform;
|
|
3
|
+
export type HookTrustStorageScope = "global" | "project";
|
|
4
|
+
export type HookTrustOptions = {
|
|
5
|
+
readonly platform?: HookTrustPlatform;
|
|
6
|
+
};
|
|
7
|
+
export type HookTrustStorageOptions = {
|
|
8
|
+
readonly projectTrusted: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type HookTrustRecord = {
|
|
11
|
+
readonly id: string;
|
|
12
|
+
readonly currentHash: string;
|
|
13
|
+
readonly enabled: boolean;
|
|
14
|
+
readonly trusted: boolean;
|
|
15
|
+
readonly executable: boolean;
|
|
16
|
+
readonly scope: HookSourceScope;
|
|
17
|
+
readonly sourcePath: string;
|
|
18
|
+
readonly matcher?: string;
|
|
19
|
+
readonly commandPreview: string;
|
|
20
|
+
readonly entry?: HookTrustEntry;
|
|
21
|
+
};
|
|
22
|
+
export declare function emptyHookTrustState(): HookTrustState;
|
|
23
|
+
export declare function hookTrustId(handler: ExecutableHookHandler): string;
|
|
24
|
+
export declare function buildHookTrustRecord(handler: ExecutableHookHandler, options?: HookTrustOptions): HookTrustRecord;
|
|
25
|
+
export declare function createHookTrustEntry(handler: ExecutableHookHandler, options?: HookTrustOptions & {
|
|
26
|
+
readonly updatedAt?: string;
|
|
27
|
+
}): HookTrustEntry;
|
|
28
|
+
export declare function hashCommandHook(handler: ExecutableHookHandler, options?: HookTrustOptions): string;
|
|
29
|
+
export declare function isCommandHookTrusted(handler: ExecutableHookHandler, state: HookTrustState, options?: HookTrustOptions): boolean;
|
|
30
|
+
export declare function listHookTrustRecords(handlers: readonly ExecutableHookHandler[], state: HookTrustState, options?: HookTrustOptions): readonly HookTrustRecord[];
|
|
31
|
+
export declare function filterExecutableTrustedHooks(handlers: readonly ExecutableHookHandler[], state: HookTrustState, options?: HookTrustOptions): readonly ExecutableHookHandler[];
|
|
32
|
+
export declare function readHookTrustStateJson(input: string | undefined): HookTrustState;
|
|
33
|
+
export declare function hookTrustStorageScope(handler: ExecutableHookHandler, options: HookTrustStorageOptions): HookTrustStorageScope | undefined;
|
|
34
|
+
//# sourceMappingURL=trust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/hooks/trust.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,qBAAqB,EAErB,eAAe,EACf,cAAc,EACd,cAAc,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,QAAQ,CAAC;AAChD,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACrC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC;CAChC,CAAC;AAYF,wBAAgB,mBAAmB,IAAI,cAAc,CAEpD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAElE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,EAAE,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAepH;AAED,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,GAAE,gBAAgB,GAAG;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D,cAAc,CAWhB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,qBAAqB,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAkBtG;AAED,wBAAgB,oBAAoB,CACnC,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,gBAAqB,GAC5B,OAAO,CAGT;AAED,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,SAAS,qBAAqB,EAAE,EAC1C,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,gBAAqB,GAC5B,SAAS,eAAe,EAAE,CAE5B;AAED,wBAAgB,4BAA4B,CAC3C,QAAQ,EAAE,SAAS,qBAAqB,EAAE,EAC1C,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,gBAAqB,GAC5B,SAAS,qBAAqB,EAAE,CAElC;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,cAAc,CAYhF;AAED,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,qBAAqB,EAC9B,OAAO,EAAE,uBAAuB,GAC9B,qBAAqB,GAAG,SAAS,CAKnC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { DEFAULT_HOOK_TIMEOUT_SECONDS, isValidHookTimeoutSeconds } from "./safety.js";
|
|
3
|
+
const HOOK_STATE_VERSION = 1;
|
|
4
|
+
export function emptyHookTrustState() {
|
|
5
|
+
return { version: HOOK_STATE_VERSION, hooks: {} };
|
|
6
|
+
}
|
|
7
|
+
export function hookTrustId(handler) {
|
|
8
|
+
return `hk_${sourceKeyHash(handler.source)}_${handler.event}_${handler.groupIndex}_${handler.handlerIndex}`;
|
|
9
|
+
}
|
|
10
|
+
export function buildHookTrustRecord(handler, options = {}) {
|
|
11
|
+
const id = hookTrustId(handler);
|
|
12
|
+
const currentHash = hashCommandHook(handler, options);
|
|
13
|
+
const commandPreview = selectedCommand(handler, options.platform ?? process.platform);
|
|
14
|
+
return {
|
|
15
|
+
id,
|
|
16
|
+
currentHash,
|
|
17
|
+
enabled: true,
|
|
18
|
+
trusted: false,
|
|
19
|
+
executable: false,
|
|
20
|
+
scope: handler.source.scope,
|
|
21
|
+
sourcePath: handler.source.sourcePath,
|
|
22
|
+
...(handler.matcher === undefined ? {} : { matcher: handler.matcher }),
|
|
23
|
+
commandPreview,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function createHookTrustEntry(handler, options = {}) {
|
|
27
|
+
const commandPreview = selectedCommand(handler, options.platform ?? process.platform);
|
|
28
|
+
return {
|
|
29
|
+
enabled: true,
|
|
30
|
+
trustedHash: hashCommandHook(handler, options),
|
|
31
|
+
scope: handler.source.scope,
|
|
32
|
+
sourcePath: handler.source.sourcePath,
|
|
33
|
+
...(handler.matcher === undefined ? {} : { matcher: handler.matcher }),
|
|
34
|
+
commandPreview,
|
|
35
|
+
updatedAt: options.updatedAt ?? new Date().toISOString(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function hashCommandHook(handler, options = {}) {
|
|
39
|
+
const platform = options.platform ?? process.platform;
|
|
40
|
+
const hook = {
|
|
41
|
+
async: false,
|
|
42
|
+
command: handler.config.command,
|
|
43
|
+
commandWindows: handler.config.commandWindows,
|
|
44
|
+
platformCommand: selectedCommand(handler, platform),
|
|
45
|
+
statusMessage: handler.config.statusMessage,
|
|
46
|
+
timeout: normalizedTimeout(handler.config.timeout),
|
|
47
|
+
type: "command",
|
|
48
|
+
};
|
|
49
|
+
const identity = {
|
|
50
|
+
event: handler.event,
|
|
51
|
+
hook,
|
|
52
|
+
matcher: handler.matcher,
|
|
53
|
+
sourceKeyHash: sourceKeyHash(handler.source),
|
|
54
|
+
};
|
|
55
|
+
return `sha256:${sha256Hex(JSON.stringify(canonicalJson(identity)))}`;
|
|
56
|
+
}
|
|
57
|
+
export function isCommandHookTrusted(handler, state, options = {}) {
|
|
58
|
+
const record = buildStatefulHookTrustRecord(handler, state, options);
|
|
59
|
+
return record.executable;
|
|
60
|
+
}
|
|
61
|
+
export function listHookTrustRecords(handlers, state, options = {}) {
|
|
62
|
+
return handlers.map((handler) => buildStatefulHookTrustRecord(handler, state, options));
|
|
63
|
+
}
|
|
64
|
+
export function filterExecutableTrustedHooks(handlers, state, options = {}) {
|
|
65
|
+
return handlers.filter((handler) => buildStatefulHookTrustRecord(handler, state, options).executable);
|
|
66
|
+
}
|
|
67
|
+
export function readHookTrustStateJson(input) {
|
|
68
|
+
if (input === undefined || input.trim() === "") {
|
|
69
|
+
return emptyHookTrustState();
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
return parseHookTrustState(JSON.parse(input));
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error instanceof Error) {
|
|
76
|
+
return emptyHookTrustState();
|
|
77
|
+
}
|
|
78
|
+
return emptyHookTrustState();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function hookTrustStorageScope(handler, options) {
|
|
82
|
+
if (handler.source.scope === "project") {
|
|
83
|
+
return options.projectTrusted ? "project" : undefined;
|
|
84
|
+
}
|
|
85
|
+
return "global";
|
|
86
|
+
}
|
|
87
|
+
function buildStatefulHookTrustRecord(handler, state, options) {
|
|
88
|
+
const base = buildHookTrustRecord(handler, options);
|
|
89
|
+
const entry = state.hooks[base.id];
|
|
90
|
+
const enabled = entry?.enabled ?? true;
|
|
91
|
+
const trusted = entry?.trustedHash === base.currentHash;
|
|
92
|
+
return {
|
|
93
|
+
...base,
|
|
94
|
+
enabled,
|
|
95
|
+
trusted,
|
|
96
|
+
executable: enabled && trusted,
|
|
97
|
+
...(entry === undefined ? {} : { entry }),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function parseHookTrustState(input) {
|
|
101
|
+
if (!isRecord(input) || input.version !== HOOK_STATE_VERSION || !isRecord(input.hooks)) {
|
|
102
|
+
return emptyHookTrustState();
|
|
103
|
+
}
|
|
104
|
+
const hooks = {};
|
|
105
|
+
for (const [id, entry] of Object.entries(input.hooks)) {
|
|
106
|
+
const parsed = parseHookTrustEntry(entry);
|
|
107
|
+
if (parsed !== undefined) {
|
|
108
|
+
hooks[id] = parsed;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { version: HOOK_STATE_VERSION, hooks };
|
|
112
|
+
}
|
|
113
|
+
function parseHookTrustEntry(input) {
|
|
114
|
+
if (!isRecord(input)) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const enabled = input.enabled;
|
|
118
|
+
const trustedHash = input.trustedHash;
|
|
119
|
+
const scope = input.scope;
|
|
120
|
+
const sourcePath = input.sourcePath;
|
|
121
|
+
const matcher = input.matcher;
|
|
122
|
+
const commandPreview = input.commandPreview;
|
|
123
|
+
const updatedAt = input.updatedAt;
|
|
124
|
+
if (typeof enabled !== "boolean" ||
|
|
125
|
+
(trustedHash !== undefined && typeof trustedHash !== "string") ||
|
|
126
|
+
!isHookSourceScope(scope) ||
|
|
127
|
+
typeof sourcePath !== "string" ||
|
|
128
|
+
(matcher !== undefined && typeof matcher !== "string") ||
|
|
129
|
+
typeof commandPreview !== "string" ||
|
|
130
|
+
typeof updatedAt !== "string") {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
enabled,
|
|
135
|
+
...(trustedHash === undefined ? {} : { trustedHash }),
|
|
136
|
+
scope,
|
|
137
|
+
sourcePath,
|
|
138
|
+
...(matcher === undefined ? {} : { matcher }),
|
|
139
|
+
commandPreview,
|
|
140
|
+
updatedAt,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function selectedCommand(handler, platform) {
|
|
144
|
+
if (platform === "win32" && handler.config.commandWindows !== undefined) {
|
|
145
|
+
return handler.config.commandWindows;
|
|
146
|
+
}
|
|
147
|
+
return handler.config.command;
|
|
148
|
+
}
|
|
149
|
+
function normalizedTimeout(timeout) {
|
|
150
|
+
if (timeout === undefined) {
|
|
151
|
+
return DEFAULT_HOOK_TIMEOUT_SECONDS;
|
|
152
|
+
}
|
|
153
|
+
if (!isValidHookTimeoutSeconds(timeout)) {
|
|
154
|
+
throw new Error("Invalid command hook timeout reached trust hashing.");
|
|
155
|
+
}
|
|
156
|
+
return timeout;
|
|
157
|
+
}
|
|
158
|
+
function sourceKeyHash(source) {
|
|
159
|
+
return sha256Hex([source.scope, source.sourcePath, source.pluginRoot ?? "", source.manifestPath ?? ""].join("\0")).slice(0, 12);
|
|
160
|
+
}
|
|
161
|
+
function sha256Hex(value) {
|
|
162
|
+
return createHash("sha256").update(value).digest("hex");
|
|
163
|
+
}
|
|
164
|
+
function canonicalJson(value) {
|
|
165
|
+
if (Array.isArray(value)) {
|
|
166
|
+
return value.map(canonicalJson);
|
|
167
|
+
}
|
|
168
|
+
if (!isJsonRecord(value)) {
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
const result = {};
|
|
172
|
+
for (const key of Object.keys(value).sort()) {
|
|
173
|
+
const child = value[key];
|
|
174
|
+
if (child !== undefined) {
|
|
175
|
+
result[key] = canonicalJson(child);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
function isRecord(value) {
|
|
181
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
182
|
+
}
|
|
183
|
+
function isJsonRecord(value) {
|
|
184
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
185
|
+
}
|
|
186
|
+
function isHookSourceScope(value) {
|
|
187
|
+
return (value === "global" ||
|
|
188
|
+
value === "project" ||
|
|
189
|
+
value === "plugin" ||
|
|
190
|
+
value === "runtime" ||
|
|
191
|
+
value === "cli" ||
|
|
192
|
+
value === "managed");
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=trust.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trust.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/hooks/trust.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,4BAA4B,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAyCtF,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAE7B,MAAM,UAAU,mBAAmB;IAClC,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAA8B;IACzD,OAAO,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;AAC7G,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAA8B,EAAE,OAAO,GAAqB,EAAE;IAClG,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACtD,MAAM,cAAc,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtF,OAAO;QACN,EAAE;QACF,WAAW;QACX,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,KAAK;QACjB,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK;QAC3B,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU;QACrC,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACtE,cAAc;KACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,OAA8B,EAC9B,OAAO,GAAuD,EAAE;IAEhE,MAAM,cAAc,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtF,OAAO;QACN,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC;QAC9C,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,KAAK;QAC3B,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU;QACrC,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QACtE,cAAc;QACd,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACxD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAA8B,EAAE,OAAO,GAAqB,EAAE;IAC7F,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACtD,MAAM,IAAI,GAA6C;QACtD,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO;QAC/B,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc;QAC7C,eAAe,EAAE,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC;QACnD,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa;QAC3C,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;QAClD,IAAI,EAAE,SAAS;KACf,CAAC;IACF,MAAM,QAAQ,GAA6C;QAC1D,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,IAAI;QACJ,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,aAAa,EAAE,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC;KAC5C,CAAC;IACF,OAAO,UAAU,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,OAA8B,EAC9B,KAAqB,EACrB,OAAO,GAAqB,EAAE;IAE9B,MAAM,MAAM,GAAG,4BAA4B,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC,UAAU,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,QAA0C,EAC1C,KAAqB,EACrB,OAAO,GAAqB,EAAE;IAE9B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,4BAA4B,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC3C,QAA0C,EAC1C,KAAqB,EACrB,OAAO,GAAqB,EAAE;IAE9B,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,4BAA4B,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC;AACvG,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAyB;IAC/D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,OAAO,mBAAmB,EAAE,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC;QACJ,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC5B,OAAO,mBAAmB,EAAE,CAAC;QAC9B,CAAC;QACD,OAAO,mBAAmB,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,qBAAqB,CACpC,OAA8B,EAC9B,OAAgC;IAEhC,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACxC,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACvD,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,SAAS,4BAA4B,CACpC,OAA8B,EAC9B,KAAqB,EACrB,OAAyB;IAEzB,MAAM,IAAI,GAAG,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC;IACvC,MAAM,OAAO,GAAG,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,WAAW,CAAC;IACxD,OAAO;QACN,GAAG,IAAI;QACP,OAAO;QACP,OAAO;QACP,UAAU,EAAE,OAAO,IAAI,OAAO;QAC9B,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KACzC,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IAC1C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,KAAK,kBAAkB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACxF,OAAO,mBAAmB,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,KAAK,GAAmC,EAAE,CAAC;IACjD,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,KAAK,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC;QACpB,CAAC;IACF,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IAC1C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACpC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,IACC,OAAO,OAAO,KAAK,SAAS;QAC5B,CAAC,WAAW,KAAK,SAAS,IAAI,OAAO,WAAW,KAAK,QAAQ,CAAC;QAC9D,CAAC,iBAAiB,CAAC,KAAK,CAAC;QACzB,OAAO,UAAU,KAAK,QAAQ;QAC9B,CAAC,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC;QACtD,OAAO,cAAc,KAAK,QAAQ;QAClC,OAAO,SAAS,KAAK,QAAQ,EAC5B,CAAC;QACF,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO;QACN,OAAO;QACP,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;QACrD,KAAK;QACL,UAAU;QACV,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;QAC7C,cAAc;QACd,SAAS;KACT,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,OAA8B,EAAE,QAA2B;IACnF,IAAI,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACzE,OAAO,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;IACtC,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;AAC/B,CAAC;AAED,SAAS,iBAAiB,CAAC,OAA2B;IACrD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,4BAA4B,CAAC;IACrC,CAAC;IACD,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,MAA0B;IAChD,OAAO,SAAS,CACf,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAChG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC/B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,aAAa,CAAC,KAAgB;IACtC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC/B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,YAAY,CAAC,KAAgB;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACxC,OAAO,CACN,KAAK,KAAK,QAAQ;QAClB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,QAAQ;QAClB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,KAAK;QACf,KAAK,KAAK,SAAS,CACnB,CAAC;AACH,CAAC","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { DEFAULT_HOOK_TIMEOUT_SECONDS, isValidHookTimeoutSeconds } from \"./safety.ts\";\nimport type {\n\tExecutableHookHandler,\n\tHookSourceMetadata,\n\tHookSourceScope,\n\tHookTrustEntry,\n\tHookTrustState,\n} from \"./types.ts\";\n\nexport type HookTrustPlatform = NodeJS.Platform;\nexport type HookTrustStorageScope = \"global\" | \"project\";\n\nexport type HookTrustOptions = {\n\treadonly platform?: HookTrustPlatform;\n};\n\nexport type HookTrustStorageOptions = {\n\treadonly projectTrusted: boolean;\n};\n\nexport type HookTrustRecord = {\n\treadonly id: string;\n\treadonly currentHash: string;\n\treadonly enabled: boolean;\n\treadonly trusted: boolean;\n\treadonly executable: boolean;\n\treadonly scope: HookSourceScope;\n\treadonly sourcePath: string;\n\treadonly matcher?: string;\n\treadonly commandPreview: string;\n\treadonly entry?: HookTrustEntry;\n};\n\ntype JsonValue =\n\t| null\n\t| boolean\n\t| number\n\t| string\n\t| readonly JsonValue[]\n\t| { readonly [key: string]: JsonValue | undefined };\n\nconst HOOK_STATE_VERSION = 1;\n\nexport function emptyHookTrustState(): HookTrustState {\n\treturn { version: HOOK_STATE_VERSION, hooks: {} };\n}\n\nexport function hookTrustId(handler: ExecutableHookHandler): string {\n\treturn `hk_${sourceKeyHash(handler.source)}_${handler.event}_${handler.groupIndex}_${handler.handlerIndex}`;\n}\n\nexport function buildHookTrustRecord(handler: ExecutableHookHandler, options: HookTrustOptions = {}): HookTrustRecord {\n\tconst id = hookTrustId(handler);\n\tconst currentHash = hashCommandHook(handler, options);\n\tconst commandPreview = selectedCommand(handler, options.platform ?? process.platform);\n\treturn {\n\t\tid,\n\t\tcurrentHash,\n\t\tenabled: true,\n\t\ttrusted: false,\n\t\texecutable: false,\n\t\tscope: handler.source.scope,\n\t\tsourcePath: handler.source.sourcePath,\n\t\t...(handler.matcher === undefined ? {} : { matcher: handler.matcher }),\n\t\tcommandPreview,\n\t};\n}\n\nexport function createHookTrustEntry(\n\thandler: ExecutableHookHandler,\n\toptions: HookTrustOptions & { readonly updatedAt?: string } = {},\n): HookTrustEntry {\n\tconst commandPreview = selectedCommand(handler, options.platform ?? process.platform);\n\treturn {\n\t\tenabled: true,\n\t\ttrustedHash: hashCommandHook(handler, options),\n\t\tscope: handler.source.scope,\n\t\tsourcePath: handler.source.sourcePath,\n\t\t...(handler.matcher === undefined ? {} : { matcher: handler.matcher }),\n\t\tcommandPreview,\n\t\tupdatedAt: options.updatedAt ?? new Date().toISOString(),\n\t};\n}\n\nexport function hashCommandHook(handler: ExecutableHookHandler, options: HookTrustOptions = {}): string {\n\tconst platform = options.platform ?? process.platform;\n\tconst hook: { [key: string]: JsonValue | undefined } = {\n\t\tasync: false,\n\t\tcommand: handler.config.command,\n\t\tcommandWindows: handler.config.commandWindows,\n\t\tplatformCommand: selectedCommand(handler, platform),\n\t\tstatusMessage: handler.config.statusMessage,\n\t\ttimeout: normalizedTimeout(handler.config.timeout),\n\t\ttype: \"command\",\n\t};\n\tconst identity: { [key: string]: JsonValue | undefined } = {\n\t\tevent: handler.event,\n\t\thook,\n\t\tmatcher: handler.matcher,\n\t\tsourceKeyHash: sourceKeyHash(handler.source),\n\t};\n\treturn `sha256:${sha256Hex(JSON.stringify(canonicalJson(identity)))}`;\n}\n\nexport function isCommandHookTrusted(\n\thandler: ExecutableHookHandler,\n\tstate: HookTrustState,\n\toptions: HookTrustOptions = {},\n): boolean {\n\tconst record = buildStatefulHookTrustRecord(handler, state, options);\n\treturn record.executable;\n}\n\nexport function listHookTrustRecords(\n\thandlers: readonly ExecutableHookHandler[],\n\tstate: HookTrustState,\n\toptions: HookTrustOptions = {},\n): readonly HookTrustRecord[] {\n\treturn handlers.map((handler) => buildStatefulHookTrustRecord(handler, state, options));\n}\n\nexport function filterExecutableTrustedHooks(\n\thandlers: readonly ExecutableHookHandler[],\n\tstate: HookTrustState,\n\toptions: HookTrustOptions = {},\n): readonly ExecutableHookHandler[] {\n\treturn handlers.filter((handler) => buildStatefulHookTrustRecord(handler, state, options).executable);\n}\n\nexport function readHookTrustStateJson(input: string | undefined): HookTrustState {\n\tif (input === undefined || input.trim() === \"\") {\n\t\treturn emptyHookTrustState();\n\t}\n\ttry {\n\t\treturn parseHookTrustState(JSON.parse(input));\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\treturn emptyHookTrustState();\n\t\t}\n\t\treturn emptyHookTrustState();\n\t}\n}\n\nexport function hookTrustStorageScope(\n\thandler: ExecutableHookHandler,\n\toptions: HookTrustStorageOptions,\n): HookTrustStorageScope | undefined {\n\tif (handler.source.scope === \"project\") {\n\t\treturn options.projectTrusted ? \"project\" : undefined;\n\t}\n\treturn \"global\";\n}\n\nfunction buildStatefulHookTrustRecord(\n\thandler: ExecutableHookHandler,\n\tstate: HookTrustState,\n\toptions: HookTrustOptions,\n): HookTrustRecord {\n\tconst base = buildHookTrustRecord(handler, options);\n\tconst entry = state.hooks[base.id];\n\tconst enabled = entry?.enabled ?? true;\n\tconst trusted = entry?.trustedHash === base.currentHash;\n\treturn {\n\t\t...base,\n\t\tenabled,\n\t\ttrusted,\n\t\texecutable: enabled && trusted,\n\t\t...(entry === undefined ? {} : { entry }),\n\t};\n}\n\nfunction parseHookTrustState(input: unknown): HookTrustState {\n\tif (!isRecord(input) || input.version !== HOOK_STATE_VERSION || !isRecord(input.hooks)) {\n\t\treturn emptyHookTrustState();\n\t}\n\n\tconst hooks: Record<string, HookTrustEntry> = {};\n\tfor (const [id, entry] of Object.entries(input.hooks)) {\n\t\tconst parsed = parseHookTrustEntry(entry);\n\t\tif (parsed !== undefined) {\n\t\t\thooks[id] = parsed;\n\t\t}\n\t}\n\treturn { version: HOOK_STATE_VERSION, hooks };\n}\n\nfunction parseHookTrustEntry(input: unknown): HookTrustEntry | undefined {\n\tif (!isRecord(input)) {\n\t\treturn undefined;\n\t}\n\tconst enabled = input.enabled;\n\tconst trustedHash = input.trustedHash;\n\tconst scope = input.scope;\n\tconst sourcePath = input.sourcePath;\n\tconst matcher = input.matcher;\n\tconst commandPreview = input.commandPreview;\n\tconst updatedAt = input.updatedAt;\n\tif (\n\t\ttypeof enabled !== \"boolean\" ||\n\t\t(trustedHash !== undefined && typeof trustedHash !== \"string\") ||\n\t\t!isHookSourceScope(scope) ||\n\t\ttypeof sourcePath !== \"string\" ||\n\t\t(matcher !== undefined && typeof matcher !== \"string\") ||\n\t\ttypeof commandPreview !== \"string\" ||\n\t\ttypeof updatedAt !== \"string\"\n\t) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tenabled,\n\t\t...(trustedHash === undefined ? {} : { trustedHash }),\n\t\tscope,\n\t\tsourcePath,\n\t\t...(matcher === undefined ? {} : { matcher }),\n\t\tcommandPreview,\n\t\tupdatedAt,\n\t};\n}\n\nfunction selectedCommand(handler: ExecutableHookHandler, platform: HookTrustPlatform): string {\n\tif (platform === \"win32\" && handler.config.commandWindows !== undefined) {\n\t\treturn handler.config.commandWindows;\n\t}\n\treturn handler.config.command;\n}\n\nfunction normalizedTimeout(timeout: number | undefined): number {\n\tif (timeout === undefined) {\n\t\treturn DEFAULT_HOOK_TIMEOUT_SECONDS;\n\t}\n\tif (!isValidHookTimeoutSeconds(timeout)) {\n\t\tthrow new Error(\"Invalid command hook timeout reached trust hashing.\");\n\t}\n\treturn timeout;\n}\n\nfunction sourceKeyHash(source: HookSourceMetadata): string {\n\treturn sha256Hex(\n\t\t[source.scope, source.sourcePath, source.pluginRoot ?? \"\", source.manifestPath ?? \"\"].join(\"\\0\"),\n\t).slice(0, 12);\n}\n\nfunction sha256Hex(value: string): string {\n\treturn createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction canonicalJson(value: JsonValue): JsonValue {\n\tif (Array.isArray(value)) {\n\t\treturn value.map(canonicalJson);\n\t}\n\tif (!isJsonRecord(value)) {\n\t\treturn value;\n\t}\n\tconst result: { [key: string]: JsonValue } = {};\n\tfor (const key of Object.keys(value).sort()) {\n\t\tconst child = value[key];\n\t\tif (child !== undefined) {\n\t\t\tresult[key] = canonicalJson(child);\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isJsonRecord(value: JsonValue): value is { readonly [key: string]: JsonValue | undefined } {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isHookSourceScope(value: unknown): value is HookSourceScope {\n\treturn (\n\t\tvalue === \"global\" ||\n\t\tvalue === \"project\" ||\n\t\tvalue === \"plugin\" ||\n\t\tvalue === \"runtime\" ||\n\t\tvalue === \"cli\" ||\n\t\tvalue === \"managed\"\n\t);\n}\n"]}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
export declare const SUPPORTED_HOOK_EVENTS: readonly ["PreToolUse", "PostToolUse", "UserPromptSubmit", "SessionStart", "PreCompact", "PostCompact", "Stop"];
|
|
2
|
+
export declare const UNSUPPORTED_KNOWN_HOOK_EVENTS: readonly ["PermissionRequest", "PermissionDenied", "SubagentStart", "SubagentStop", "Notification", "Setup", "UserPromptExpansion", "PostToolUseFailure", "PostToolBatch", "TaskCreated", "TaskCompleted", "StopFailure", "TeammateIdle", "InstructionsLoaded", "ConfigChange", "CwdChanged", "FileChanged", "WorktreeCreate", "WorktreeRemove", "MessageDisplay", "SessionEnd", "Elicitation", "ElicitationResult"];
|
|
3
|
+
export declare const UNSUPPORTED_HANDLER_TYPES: readonly ["prompt", "agent", "http", "mcp_tool"];
|
|
4
|
+
export type SupportedHookEvent = (typeof SUPPORTED_HOOK_EVENTS)[number];
|
|
5
|
+
export type UnsupportedKnownHookEvent = (typeof UNSUPPORTED_KNOWN_HOOK_EVENTS)[number];
|
|
6
|
+
export type HookSourceScope = "global" | "project" | "plugin" | "runtime" | "cli" | "managed";
|
|
7
|
+
export type HookDiscoveryTiming = "pre-session" | "runtime";
|
|
8
|
+
export type HookSourceMetadata = {
|
|
9
|
+
readonly scope: HookSourceScope;
|
|
10
|
+
readonly sourcePath: string;
|
|
11
|
+
readonly displayOrder: number;
|
|
12
|
+
readonly discoveredAt: HookDiscoveryTiming;
|
|
13
|
+
readonly pluginRoot?: string;
|
|
14
|
+
readonly manifestPath?: string;
|
|
15
|
+
};
|
|
16
|
+
export type CommandHookConfig = {
|
|
17
|
+
readonly type: "command";
|
|
18
|
+
readonly command: string;
|
|
19
|
+
readonly commandWindows?: string;
|
|
20
|
+
readonly timeout?: number;
|
|
21
|
+
readonly statusMessage?: string;
|
|
22
|
+
};
|
|
23
|
+
export type ExecutableHookHandler = {
|
|
24
|
+
readonly event: SupportedHookEvent;
|
|
25
|
+
readonly matcher?: string;
|
|
26
|
+
readonly groupIndex: number;
|
|
27
|
+
readonly handlerIndex: number;
|
|
28
|
+
readonly config: CommandHookConfig;
|
|
29
|
+
readonly source: HookSourceMetadata;
|
|
30
|
+
};
|
|
31
|
+
export type HookDiagnosticCode = "invalid_root" | "invalid_hooks" | "invalid_event_config" | "invalid_matcher" | "invalid_handler_group" | "invalid_handler_list" | "invalid_handler" | "invalid_command" | "invalid_command_windows" | "invalid_command_target" | "missing_command_target" | "invalid_timeout" | "invalid_status_message" | "unknown_event" | "unsupported_event" | "unsupported_field" | "unsupported_handler_type" | "unsupported_async_handler" | "unsupported_command_variant";
|
|
32
|
+
export type HookDiagnostic = {
|
|
33
|
+
readonly code: HookDiagnosticCode;
|
|
34
|
+
readonly severity: "error" | "warning";
|
|
35
|
+
readonly message: string;
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly source: HookSourceMetadata;
|
|
38
|
+
readonly event?: string;
|
|
39
|
+
};
|
|
40
|
+
export type ParsedHookConfig = {
|
|
41
|
+
readonly executableHandlers: readonly ExecutableHookHandler[];
|
|
42
|
+
readonly diagnostics: readonly HookDiagnostic[];
|
|
43
|
+
};
|
|
44
|
+
export type HookTrustEntry = {
|
|
45
|
+
readonly enabled: boolean;
|
|
46
|
+
readonly trustedHash?: string;
|
|
47
|
+
readonly scope: HookSourceScope;
|
|
48
|
+
readonly sourcePath: string;
|
|
49
|
+
readonly matcher?: string;
|
|
50
|
+
readonly commandPreview: string;
|
|
51
|
+
readonly updatedAt: string;
|
|
52
|
+
};
|
|
53
|
+
export type HookTrustState = {
|
|
54
|
+
readonly version: 1;
|
|
55
|
+
readonly hooks: Readonly<Record<string, HookTrustEntry>>;
|
|
56
|
+
};
|
|
57
|
+
export type HookRuntimeState = {
|
|
58
|
+
readonly parsed: ParsedHookConfig;
|
|
59
|
+
readonly trust: HookTrustState;
|
|
60
|
+
};
|
|
61
|
+
export type HookInputWire = {
|
|
62
|
+
readonly event: "SessionStart";
|
|
63
|
+
readonly sessionId: string;
|
|
64
|
+
readonly cwd: string;
|
|
65
|
+
readonly hook_event_name?: "SessionStart";
|
|
66
|
+
readonly reason?: string;
|
|
67
|
+
readonly session_id?: string;
|
|
68
|
+
readonly transcript_path?: string;
|
|
69
|
+
} | {
|
|
70
|
+
readonly event: "UserPromptSubmit";
|
|
71
|
+
readonly prompt: string;
|
|
72
|
+
readonly cwd: string;
|
|
73
|
+
readonly session_id?: string;
|
|
74
|
+
readonly permission_mode?: string;
|
|
75
|
+
readonly transcript_path?: string;
|
|
76
|
+
} | {
|
|
77
|
+
readonly event: "PreToolUse";
|
|
78
|
+
readonly toolName: string;
|
|
79
|
+
readonly toolInput: unknown;
|
|
80
|
+
readonly cwd: string;
|
|
81
|
+
readonly session_id?: string;
|
|
82
|
+
readonly hook_event_name?: "PreToolUse";
|
|
83
|
+
readonly tool_name?: string;
|
|
84
|
+
readonly tool_input?: unknown;
|
|
85
|
+
readonly tool_use_id?: string;
|
|
86
|
+
} | {
|
|
87
|
+
readonly event: "PostToolUse";
|
|
88
|
+
readonly toolName: string;
|
|
89
|
+
readonly toolInput: unknown;
|
|
90
|
+
readonly toolOutput: unknown;
|
|
91
|
+
readonly cwd: string;
|
|
92
|
+
readonly session_id?: string;
|
|
93
|
+
readonly hook_event_name?: "PostToolUse";
|
|
94
|
+
readonly tool_name?: string;
|
|
95
|
+
readonly tool_input?: unknown;
|
|
96
|
+
readonly tool_response?: unknown;
|
|
97
|
+
readonly tool_use_id?: string;
|
|
98
|
+
} | {
|
|
99
|
+
readonly event: "PreCompact";
|
|
100
|
+
readonly reason: string;
|
|
101
|
+
readonly cwd: string;
|
|
102
|
+
readonly custom_instructions?: string;
|
|
103
|
+
readonly hook_event_name?: "PreCompact";
|
|
104
|
+
readonly request_id?: string;
|
|
105
|
+
readonly session_id?: string;
|
|
106
|
+
readonly transcript_path?: string;
|
|
107
|
+
readonly will_retry?: boolean;
|
|
108
|
+
} | {
|
|
109
|
+
readonly event: "PostCompact";
|
|
110
|
+
readonly reason: string;
|
|
111
|
+
readonly cwd: string;
|
|
112
|
+
readonly accepted?: boolean;
|
|
113
|
+
readonly hook_event_name?: "PostCompact";
|
|
114
|
+
readonly request_id?: string;
|
|
115
|
+
readonly session_id?: string;
|
|
116
|
+
readonly transcript_path?: string;
|
|
117
|
+
readonly will_retry?: boolean;
|
|
118
|
+
} | {
|
|
119
|
+
readonly event: "Stop";
|
|
120
|
+
readonly stopReason?: string;
|
|
121
|
+
readonly cwd: string;
|
|
122
|
+
readonly hook_event_name?: "Stop";
|
|
123
|
+
readonly session_id?: string;
|
|
124
|
+
readonly transcript_path?: string;
|
|
125
|
+
};
|
|
126
|
+
export type HookOutputWire = {
|
|
127
|
+
readonly decision?: "approve" | "block" | "deny" | "ask";
|
|
128
|
+
readonly reason?: string;
|
|
129
|
+
readonly additionalContext?: string;
|
|
130
|
+
readonly updatedInput?: unknown;
|
|
131
|
+
readonly updatedToolOutput?: unknown;
|
|
132
|
+
readonly continue?: boolean;
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/hooks/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export const SUPPORTED_HOOK_EVENTS = [
|
|
2
|
+
"PreToolUse",
|
|
3
|
+
"PostToolUse",
|
|
4
|
+
"UserPromptSubmit",
|
|
5
|
+
"SessionStart",
|
|
6
|
+
"PreCompact",
|
|
7
|
+
"PostCompact",
|
|
8
|
+
"Stop",
|
|
9
|
+
];
|
|
10
|
+
export const UNSUPPORTED_KNOWN_HOOK_EVENTS = [
|
|
11
|
+
"PermissionRequest",
|
|
12
|
+
"PermissionDenied",
|
|
13
|
+
"SubagentStart",
|
|
14
|
+
"SubagentStop",
|
|
15
|
+
"Notification",
|
|
16
|
+
"Setup",
|
|
17
|
+
"UserPromptExpansion",
|
|
18
|
+
"PostToolUseFailure",
|
|
19
|
+
"PostToolBatch",
|
|
20
|
+
"TaskCreated",
|
|
21
|
+
"TaskCompleted",
|
|
22
|
+
"StopFailure",
|
|
23
|
+
"TeammateIdle",
|
|
24
|
+
"InstructionsLoaded",
|
|
25
|
+
"ConfigChange",
|
|
26
|
+
"CwdChanged",
|
|
27
|
+
"FileChanged",
|
|
28
|
+
"WorktreeCreate",
|
|
29
|
+
"WorktreeRemove",
|
|
30
|
+
"MessageDisplay",
|
|
31
|
+
"SessionEnd",
|
|
32
|
+
"Elicitation",
|
|
33
|
+
"ElicitationResult",
|
|
34
|
+
];
|
|
35
|
+
export const UNSUPPORTED_HANDLER_TYPES = ["prompt", "agent", "http", "mcp_tool"];
|
|
36
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/hooks/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACpC,YAAY;IACZ,aAAa;IACb,kBAAkB;IAClB,cAAc;IACd,YAAY;IACZ,aAAa;IACb,MAAM;CACG,CAAC;AAEX,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC5C,mBAAmB;IACnB,kBAAkB;IAClB,eAAe;IACf,cAAc;IACd,cAAc;IACd,OAAO;IACP,qBAAqB;IACrB,oBAAoB;IACpB,eAAe;IACf,aAAa;IACb,eAAe;IACf,aAAa;IACb,cAAc;IACd,oBAAoB;IACpB,cAAc;IACd,YAAY;IACZ,aAAa;IACb,gBAAgB;IAChB,gBAAgB;IAChB,gBAAgB;IAChB,YAAY;IACZ,aAAa;IACb,mBAAmB;CACV,CAAC;AAEX,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC","sourcesContent":["export const SUPPORTED_HOOK_EVENTS = [\n\t\"PreToolUse\",\n\t\"PostToolUse\",\n\t\"UserPromptSubmit\",\n\t\"SessionStart\",\n\t\"PreCompact\",\n\t\"PostCompact\",\n\t\"Stop\",\n] as const;\n\nexport const UNSUPPORTED_KNOWN_HOOK_EVENTS = [\n\t\"PermissionRequest\",\n\t\"PermissionDenied\",\n\t\"SubagentStart\",\n\t\"SubagentStop\",\n\t\"Notification\",\n\t\"Setup\",\n\t\"UserPromptExpansion\",\n\t\"PostToolUseFailure\",\n\t\"PostToolBatch\",\n\t\"TaskCreated\",\n\t\"TaskCompleted\",\n\t\"StopFailure\",\n\t\"TeammateIdle\",\n\t\"InstructionsLoaded\",\n\t\"ConfigChange\",\n\t\"CwdChanged\",\n\t\"FileChanged\",\n\t\"WorktreeCreate\",\n\t\"WorktreeRemove\",\n\t\"MessageDisplay\",\n\t\"SessionEnd\",\n\t\"Elicitation\",\n\t\"ElicitationResult\",\n] as const;\n\nexport const UNSUPPORTED_HANDLER_TYPES = [\"prompt\", \"agent\", \"http\", \"mcp_tool\"] as const;\n\nexport type SupportedHookEvent = (typeof SUPPORTED_HOOK_EVENTS)[number];\nexport type UnsupportedKnownHookEvent = (typeof UNSUPPORTED_KNOWN_HOOK_EVENTS)[number];\nexport type HookSourceScope = \"global\" | \"project\" | \"plugin\" | \"runtime\" | \"cli\" | \"managed\";\nexport type HookDiscoveryTiming = \"pre-session\" | \"runtime\";\n\nexport type HookSourceMetadata = {\n\treadonly scope: HookSourceScope;\n\treadonly sourcePath: string;\n\treadonly displayOrder: number;\n\treadonly discoveredAt: HookDiscoveryTiming;\n\treadonly pluginRoot?: string;\n\treadonly manifestPath?: string;\n};\n\nexport type CommandHookConfig = {\n\treadonly type: \"command\";\n\treadonly command: string;\n\treadonly commandWindows?: string;\n\treadonly timeout?: number;\n\treadonly statusMessage?: string;\n};\n\nexport type ExecutableHookHandler = {\n\treadonly event: SupportedHookEvent;\n\treadonly matcher?: string;\n\treadonly groupIndex: number;\n\treadonly handlerIndex: number;\n\treadonly config: CommandHookConfig;\n\treadonly source: HookSourceMetadata;\n};\n\nexport type HookDiagnosticCode =\n\t| \"invalid_root\"\n\t| \"invalid_hooks\"\n\t| \"invalid_event_config\"\n\t| \"invalid_matcher\"\n\t| \"invalid_handler_group\"\n\t| \"invalid_handler_list\"\n\t| \"invalid_handler\"\n\t| \"invalid_command\"\n\t| \"invalid_command_windows\"\n\t| \"invalid_command_target\"\n\t| \"missing_command_target\"\n\t| \"invalid_timeout\"\n\t| \"invalid_status_message\"\n\t| \"unknown_event\"\n\t| \"unsupported_event\"\n\t| \"unsupported_field\"\n\t| \"unsupported_handler_type\"\n\t| \"unsupported_async_handler\"\n\t| \"unsupported_command_variant\";\n\nexport type HookDiagnostic = {\n\treadonly code: HookDiagnosticCode;\n\treadonly severity: \"error\" | \"warning\";\n\treadonly message: string;\n\treadonly path: string;\n\treadonly source: HookSourceMetadata;\n\treadonly event?: string;\n};\n\nexport type ParsedHookConfig = {\n\treadonly executableHandlers: readonly ExecutableHookHandler[];\n\treadonly diagnostics: readonly HookDiagnostic[];\n};\n\nexport type HookTrustEntry = {\n\treadonly enabled: boolean;\n\treadonly trustedHash?: string;\n\treadonly scope: HookSourceScope;\n\treadonly sourcePath: string;\n\treadonly matcher?: string;\n\treadonly commandPreview: string;\n\treadonly updatedAt: string;\n};\n\nexport type HookTrustState = {\n\treadonly version: 1;\n\treadonly hooks: Readonly<Record<string, HookTrustEntry>>;\n};\n\nexport type HookRuntimeState = {\n\treadonly parsed: ParsedHookConfig;\n\treadonly trust: HookTrustState;\n};\n\nexport type HookInputWire =\n\t| {\n\t\t\treadonly event: \"SessionStart\";\n\t\t\treadonly sessionId: string;\n\t\t\treadonly cwd: string;\n\t\t\treadonly hook_event_name?: \"SessionStart\";\n\t\t\treadonly reason?: string;\n\t\t\treadonly session_id?: string;\n\t\t\treadonly transcript_path?: string;\n\t }\n\t| {\n\t\t\treadonly event: \"UserPromptSubmit\";\n\t\t\treadonly prompt: string;\n\t\t\treadonly cwd: string;\n\t\t\treadonly session_id?: string;\n\t\t\treadonly permission_mode?: string;\n\t\t\treadonly transcript_path?: string;\n\t }\n\t| {\n\t\t\treadonly event: \"PreToolUse\";\n\t\t\treadonly toolName: string;\n\t\t\treadonly toolInput: unknown;\n\t\t\treadonly cwd: string;\n\t\t\treadonly session_id?: string;\n\t\t\treadonly hook_event_name?: \"PreToolUse\";\n\t\t\treadonly tool_name?: string;\n\t\t\treadonly tool_input?: unknown;\n\t\t\treadonly tool_use_id?: string;\n\t }\n\t| {\n\t\t\treadonly event: \"PostToolUse\";\n\t\t\treadonly toolName: string;\n\t\t\treadonly toolInput: unknown;\n\t\t\treadonly toolOutput: unknown;\n\t\t\treadonly cwd: string;\n\t\t\treadonly session_id?: string;\n\t\t\treadonly hook_event_name?: \"PostToolUse\";\n\t\t\treadonly tool_name?: string;\n\t\t\treadonly tool_input?: unknown;\n\t\t\treadonly tool_response?: unknown;\n\t\t\treadonly tool_use_id?: string;\n\t }\n\t| {\n\t\t\treadonly event: \"PreCompact\";\n\t\t\treadonly reason: string;\n\t\t\treadonly cwd: string;\n\t\t\treadonly custom_instructions?: string;\n\t\t\treadonly hook_event_name?: \"PreCompact\";\n\t\t\treadonly request_id?: string;\n\t\t\treadonly session_id?: string;\n\t\t\treadonly transcript_path?: string;\n\t\t\treadonly will_retry?: boolean;\n\t }\n\t| {\n\t\t\treadonly event: \"PostCompact\";\n\t\t\treadonly reason: string;\n\t\t\treadonly cwd: string;\n\t\t\treadonly accepted?: boolean;\n\t\t\treadonly hook_event_name?: \"PostCompact\";\n\t\t\treadonly request_id?: string;\n\t\t\treadonly session_id?: string;\n\t\t\treadonly transcript_path?: string;\n\t\t\treadonly will_retry?: boolean;\n\t }\n\t| {\n\t\t\treadonly event: \"Stop\";\n\t\t\treadonly stopReason?: string;\n\t\t\treadonly cwd: string;\n\t\t\treadonly hook_event_name?: \"Stop\";\n\t\t\treadonly session_id?: string;\n\t\t\treadonly transcript_path?: string;\n\t };\n\nexport type HookOutputWire = {\n\treadonly decision?: \"approve\" | \"block\" | \"deny\" | \"ask\";\n\treadonly reason?: string;\n\treadonly additionalContext?: string;\n\treadonly updatedInput?: unknown;\n\treadonly updatedToolOutput?: unknown;\n\treadonly continue?: boolean;\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKpD,OAAO,aAAa,MAAM,WAAW,CAAC;AACtC,OAAO,cAAc,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAKpD,OAAO,aAAa,MAAM,WAAW,CAAC;AACtC,OAAO,cAAc,MAAM,YAAY,CAAC;AAUxC,OAAO,wBAAwB,MAAM,wBAAwB,CAAC;AAO9D,OAAO,YAAY,MAAM,UAAU,CAAC;AAIpC,MAAM,WAAW,uBAAuB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,gBAAgB,CAAC;CAC1B;AAED,eAAO,MAAM,yBAAyB,YAAI,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,KAAK,CAAU,CAAC;AAEhG,eAAO,MAAM,+BAA+B;;;;;CAKoC,CAAC;AAEjF,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAsBtD,CAAC"}
|
|
@@ -7,6 +7,7 @@ import filesExtension from "./files.js";
|
|
|
7
7
|
import goalExtension from "./goal/index.js";
|
|
8
8
|
import gptApplyPatchExtension from "./gpt-apply-patch/index.js";
|
|
9
9
|
import historySearchExtension from "./history-search/index.js";
|
|
10
|
+
import hooksExtension from "./hooks/index.js";
|
|
10
11
|
import nestedAgentsMdExtension from "./nested-agents-md/index.js";
|
|
11
12
|
import openaiWebSearchExtension from "./openai-web-search/index.js";
|
|
12
13
|
import permissionSystemExtension from "./permission-system/index.js";
|
|
@@ -30,6 +31,7 @@ export const globalDefaultExtensionFactories = {
|
|
|
30
31
|
tps: tpsExtension,
|
|
31
32
|
};
|
|
32
33
|
export const builtinExtensions = [
|
|
34
|
+
{ id: "hooks", factory: hooksExtension },
|
|
33
35
|
{ id: "permission-system", factory: permissionSystemExtension },
|
|
34
36
|
{ id: "gpt-apply-patch", factory: gptApplyPatchExtension },
|
|
35
37
|
{ id: "prompt-preset", factory: promptPresetExtension },
|