@kisev/agentomatic 11.0.2-dev.85.gb47f85ffc092 → 11.0.2-dev.87.g5a92e74c6754
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 +10 -8
- package/README.ru.md +11 -8
- package/dist/agent-profiles.js +33 -48
- package/dist/assets/agents/architect.md +4 -4
- package/dist/assets/agents/critic.md +10 -11
- package/dist/assets/agents/manager.md +11 -12
- package/dist/assets/agents/mapper.md +4 -4
- package/dist/assets/agents/review.md +11 -12
- package/dist/assets/agents/worker.md +29 -32
- package/dist/assets/commands/rtk-stats.md +1 -1
- package/dist/cli.js +5 -4
- package/dist/config-setup.d.ts +1 -6
- package/dist/config-setup.js +69 -51
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +32 -52
- package/dist/index.d.ts +2 -128
- package/dist/index.js +93 -169
- package/dist/jsonc.d.ts +12 -1
- package/dist/jsonc.js +82 -5
- package/dist/opencode-config.d.ts +9 -0
- package/dist/opencode-config.js +136 -0
- package/dist/plugins/events.d.ts +20 -0
- package/dist/plugins/events.js +48 -0
- package/dist/plugins/rtk.d.ts +4 -17
- package/dist/plugins/rtk.js +15 -7
- package/dist/plugins/rules-injector.d.ts +15 -28
- package/dist/plugins/rules-injector.js +38 -33
- package/dist/plugins/zed-bell.d.ts +2 -13
- package/dist/plugins/zed-bell.js +5 -4
- package/dist/registry.js +1 -1
- package/dist/routing.js +1 -1
- package/package.json +2 -7
- package/dist/plugins/compatibility.d.ts +0 -30
- package/dist/plugins/compatibility.js +0 -87
package/dist/plugins/rtk.d.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode/plugin";
|
|
2
|
-
type
|
|
3
|
-
tool: string;
|
|
4
|
-
args?: {
|
|
5
|
-
command?: unknown;
|
|
6
|
-
};
|
|
7
|
-
};
|
|
8
|
-
type HookOutput = {
|
|
9
|
-
output?: unknown;
|
|
10
|
-
};
|
|
2
|
+
import { type ToolAfter } from "./events.js";
|
|
11
3
|
export type RtkMethod = "compressed-rtk" | "truncated-head-tail" | "rtk-unavailable" | "ineligible" | "below-threshold";
|
|
12
4
|
export type RtkStats = {
|
|
13
5
|
schema_version: 1;
|
|
@@ -35,17 +27,12 @@ export declare function rtkCharsSaved(stats: RtkStats): number;
|
|
|
35
27
|
export declare function rtkTokensSavedEstimate(stats: RtkStats): number;
|
|
36
28
|
export declare function readRtkStats(path?: string): Promise<RtkStats | undefined>;
|
|
37
29
|
export declare function rtk(options?: RtkOptions): Promise<{
|
|
38
|
-
"
|
|
30
|
+
"execute.after"?: undefined;
|
|
39
31
|
} | {
|
|
40
|
-
"
|
|
32
|
+
"execute.after": (input: ToolAfter) => Promise<void>;
|
|
41
33
|
}>;
|
|
42
34
|
declare const _default: {
|
|
43
35
|
id: string;
|
|
44
|
-
|
|
45
|
-
"tool.execute.after"?: undefined;
|
|
46
|
-
} | {
|
|
47
|
-
"tool.execute.after": (input: HookInput, output: HookOutput) => Promise<void>;
|
|
48
|
-
}>;
|
|
49
|
-
setup(ctx: Plugin.Context): Promise<(() => Promise<void>) | undefined>;
|
|
36
|
+
setup(ctx: Plugin.Context): Promise<void>;
|
|
50
37
|
};
|
|
51
38
|
export default _default;
|
package/dist/plugins/rtk.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resultText, replaceResultText, toolInput } from "./events.js";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -138,26 +138,33 @@ export async function rtk(options = {}) {
|
|
|
138
138
|
((selected, input) => external(options.bin ?? "rtk", selected, input));
|
|
139
139
|
const statsPath = options.statsPath === null ? undefined : (options.statsPath ?? rtkStatsPath());
|
|
140
140
|
return {
|
|
141
|
-
"
|
|
141
|
+
"execute.after": async (input) => {
|
|
142
|
+
if (input.status !== "completed")
|
|
143
|
+
return;
|
|
144
|
+
const output = { output: resultText(input.result) };
|
|
142
145
|
try {
|
|
143
146
|
if (input.tool === "edit" &&
|
|
144
147
|
typeof output.output === "string" &&
|
|
145
148
|
/oldString (not found|found multiple times|and newString must be different)/i.test(output.output))
|
|
146
149
|
output.output = `${output.output}\nSTOP. Read the file before retrying Edit.`;
|
|
147
|
-
if (input.tool !== "
|
|
150
|
+
if (input.tool !== "shell" ||
|
|
148
151
|
typeof output.output !== "string" ||
|
|
149
152
|
output.output.length < (options.threshold ?? THRESHOLD)) {
|
|
150
|
-
if (input.tool === "
|
|
153
|
+
if (input.tool === "shell" && typeof output.output === "string" && statsPath)
|
|
151
154
|
await recordStats(statsPath, "below-threshold", output.output.length, output.output.length);
|
|
155
|
+
if (output.output !== undefined)
|
|
156
|
+
input.result = replaceResultText(input.result, output.output);
|
|
152
157
|
return;
|
|
153
158
|
}
|
|
154
|
-
const
|
|
159
|
+
const command = toolInput(input.input).command;
|
|
160
|
+
const selected = typeof command === "string" ? filter(command) : undefined;
|
|
155
161
|
const compressed = selected ? await run(selected, output.output) : undefined;
|
|
156
162
|
const result = compressed && compressed.length < output.output.length
|
|
157
163
|
? compressed
|
|
158
164
|
: truncate(output.output);
|
|
159
165
|
const originalSize = output.output.length;
|
|
160
166
|
output.output = `${result}\n[rtk: compressed method=${result === compressed ? `rtk/${selected}` : "head+tail"}; sizes=${originalSize}->${result.length}; evidence_complete=false; loss=possible]`;
|
|
167
|
+
input.result = replaceResultText(input.result, output.output);
|
|
161
168
|
if (statsPath) {
|
|
162
169
|
const method = result === compressed
|
|
163
170
|
? "compressed-rtk"
|
|
@@ -177,8 +184,9 @@ export async function rtk(options = {}) {
|
|
|
177
184
|
}
|
|
178
185
|
export default {
|
|
179
186
|
id: "agentomatic.rtk",
|
|
180
|
-
server: async (_input, options = {}) => rtk(options),
|
|
181
187
|
async setup(ctx) {
|
|
182
|
-
|
|
188
|
+
const hooks = await rtk(ctx.options);
|
|
189
|
+
if (hooks["execute.after"])
|
|
190
|
+
await ctx.tool.hook("execute.after", hooks["execute.after"]);
|
|
183
191
|
},
|
|
184
192
|
};
|
|
@@ -1,45 +1,32 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode/plugin";
|
|
2
|
+
import { type ToolAfter } from "./events.js";
|
|
2
3
|
export type RulesInjectorOptions = {
|
|
3
4
|
budget?: number;
|
|
4
5
|
cwd?: string;
|
|
5
6
|
enabled?: boolean;
|
|
6
7
|
};
|
|
7
8
|
export declare function rulesInjector(options?: RulesInjectorOptions): Promise<{
|
|
8
|
-
"
|
|
9
|
+
"execute.after"?: undefined;
|
|
9
10
|
event?: undefined;
|
|
10
|
-
|
|
11
|
+
context?: undefined;
|
|
11
12
|
} | {
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
"execute.after": (input: ToolAfter & {
|
|
14
|
+
directory?: string;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
event: (event: {
|
|
17
|
+
type: string;
|
|
18
|
+
data?: unknown;
|
|
18
19
|
}) => Promise<void>;
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
context: (input: {
|
|
21
|
+
sessionID: string;
|
|
22
|
+
system: Array<{
|
|
23
|
+
type: "text";
|
|
24
|
+
text: string;
|
|
25
|
+
}>;
|
|
21
26
|
}) => Promise<void>;
|
|
22
27
|
}>;
|
|
23
28
|
declare const _default: {
|
|
24
29
|
id: string;
|
|
25
|
-
server: (input: {
|
|
26
|
-
directory?: string;
|
|
27
|
-
}, options?: RulesInjectorOptions) => Promise<{
|
|
28
|
-
"tool.execute.after"?: undefined;
|
|
29
|
-
event?: undefined;
|
|
30
|
-
"experimental.chat.system.transform"?: undefined;
|
|
31
|
-
} | {
|
|
32
|
-
"tool.execute.after": (input: unknown, result: unknown) => Promise<void>;
|
|
33
|
-
event: ({ event, }: {
|
|
34
|
-
event?: {
|
|
35
|
-
type?: string;
|
|
36
|
-
properties?: Record<string, unknown>;
|
|
37
|
-
};
|
|
38
|
-
}) => Promise<void>;
|
|
39
|
-
"experimental.chat.system.transform": (input: unknown, result: {
|
|
40
|
-
system?: unknown[];
|
|
41
|
-
}) => Promise<void>;
|
|
42
|
-
}>;
|
|
43
30
|
setup(ctx: Plugin.Context): Promise<(() => Promise<void>) | undefined>;
|
|
44
31
|
};
|
|
45
32
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resultText, replaceResultText, subscribeEvents, toolInput, } from "./events.js";
|
|
2
2
|
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, resolve } from "node:path";
|
|
@@ -10,20 +10,6 @@ function sessionID(value) {
|
|
|
10
10
|
return item[key];
|
|
11
11
|
return undefined;
|
|
12
12
|
}
|
|
13
|
-
function pathOf(input, output) {
|
|
14
|
-
for (const value of [input, output]) {
|
|
15
|
-
const args = value?.args;
|
|
16
|
-
for (const key of ["filePath", "file_path", "path"])
|
|
17
|
-
if (typeof args?.[key] === "string")
|
|
18
|
-
return args[key];
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
function output(value, text) {
|
|
23
|
-
const item = value;
|
|
24
|
-
if (typeof item?.output === "string")
|
|
25
|
-
item.output = `${item.output}\n${text}`;
|
|
26
|
-
}
|
|
27
13
|
function marker(rule) {
|
|
28
14
|
return `[rules-injector source=${rule.path} revision=${rule.revision}]`;
|
|
29
15
|
}
|
|
@@ -45,16 +31,19 @@ export async function rulesInjector(options = {}) {
|
|
|
45
31
|
}
|
|
46
32
|
return item;
|
|
47
33
|
};
|
|
48
|
-
const inject = async (input
|
|
49
|
-
|
|
50
|
-
if (call?.tool !== "read" && call?.tool !== "edit")
|
|
34
|
+
const inject = async (input) => {
|
|
35
|
+
if (input.status !== "completed" || (input.tool !== "read" && input.tool !== "edit"))
|
|
51
36
|
return;
|
|
52
|
-
const identifier = sessionID
|
|
53
|
-
const target =
|
|
54
|
-
|
|
37
|
+
const identifier = input.sessionID;
|
|
38
|
+
const target = toolInput(input.input).path;
|
|
39
|
+
const original = resultText(input.result);
|
|
40
|
+
if (!identifier || typeof target !== "string" || original === undefined)
|
|
55
41
|
return;
|
|
42
|
+
const output = (text) => {
|
|
43
|
+
input.result = replaceResultText(input.result, `${original}\n${text}`);
|
|
44
|
+
};
|
|
56
45
|
try {
|
|
57
|
-
const native =
|
|
46
|
+
const native = input.directory ?? cwd;
|
|
58
47
|
const paths = [];
|
|
59
48
|
let current = dirname(resolve(native, target));
|
|
60
49
|
while (true) {
|
|
@@ -104,35 +93,51 @@ export async function rulesInjector(options = {}) {
|
|
|
104
93
|
}
|
|
105
94
|
}
|
|
106
95
|
if (additions.length)
|
|
107
|
-
output(
|
|
96
|
+
output(additions.join("\n\n"));
|
|
108
97
|
}
|
|
109
98
|
catch (error) {
|
|
110
|
-
output(
|
|
99
|
+
output(`[rules-injector warning] cannot read AGENTS.md: ${String(error)}`);
|
|
111
100
|
}
|
|
112
101
|
};
|
|
113
102
|
return {
|
|
114
|
-
"
|
|
115
|
-
event: async (
|
|
116
|
-
if (event
|
|
117
|
-
const identifier = sessionID(event.
|
|
103
|
+
"execute.after": inject,
|
|
104
|
+
event: async (event) => {
|
|
105
|
+
if (event.type === "session.compacted" || event.type.includes("compaction")) {
|
|
106
|
+
const identifier = sessionID(event.data);
|
|
118
107
|
if (identifier)
|
|
119
108
|
state(identifier).replay = true;
|
|
120
109
|
}
|
|
121
110
|
},
|
|
122
|
-
|
|
111
|
+
context: async (input) => {
|
|
123
112
|
const identifier = sessionID(input);
|
|
124
|
-
if (!identifier || !state(identifier).replay
|
|
113
|
+
if (!identifier || !state(identifier).replay)
|
|
125
114
|
return;
|
|
126
115
|
for (const rule of state(identifier).loaded.values())
|
|
127
|
-
|
|
116
|
+
input.system.push({ type: "text", text: block(rule) });
|
|
128
117
|
state(identifier).replay = false;
|
|
129
118
|
},
|
|
130
119
|
};
|
|
131
120
|
}
|
|
132
121
|
export default {
|
|
133
122
|
id: "agentomatic.rules-injector",
|
|
134
|
-
server: async (input, options = {}) => rulesInjector({ ...options, cwd: options.cwd ?? input.directory }),
|
|
135
123
|
async setup(ctx) {
|
|
136
|
-
|
|
124
|
+
const hooks = await rulesInjector({ ...ctx.options, cwd: ctx.location.directory });
|
|
125
|
+
if (hooks["execute.after"])
|
|
126
|
+
await ctx.tool.hook("execute.after", async (event) => {
|
|
127
|
+
if (event.status !== "completed" || (event.tool !== "read" && event.tool !== "edit"))
|
|
128
|
+
return;
|
|
129
|
+
const session = await ctx.session
|
|
130
|
+
.get({ sessionID: event.sessionID })
|
|
131
|
+
.catch(() => undefined);
|
|
132
|
+
if (session) {
|
|
133
|
+
const scoped = { ...event, directory: session.location.directory };
|
|
134
|
+
await hooks["execute.after"](scoped);
|
|
135
|
+
event.result = scoped.result;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
if (hooks.context)
|
|
139
|
+
await ctx.session.hook("context", hooks.context);
|
|
140
|
+
if (hooks.event)
|
|
141
|
+
return subscribeEvents(ctx, hooks.event);
|
|
137
142
|
},
|
|
138
143
|
};
|
|
@@ -5,23 +5,12 @@ export type ZedBellOptions = {
|
|
|
5
5
|
export declare function zedBell(options?: ZedBellOptions): Promise<{
|
|
6
6
|
event?: undefined;
|
|
7
7
|
} | {
|
|
8
|
-
event: (
|
|
9
|
-
|
|
10
|
-
type?: string;
|
|
11
|
-
};
|
|
8
|
+
event: (event: {
|
|
9
|
+
type: string;
|
|
12
10
|
}) => Promise<void>;
|
|
13
11
|
}>;
|
|
14
12
|
declare const _default: {
|
|
15
13
|
id: string;
|
|
16
|
-
server: (_input: unknown, options?: ZedBellOptions) => Promise<{
|
|
17
|
-
event?: undefined;
|
|
18
|
-
} | {
|
|
19
|
-
event: ({ event }: {
|
|
20
|
-
event: {
|
|
21
|
-
type?: string;
|
|
22
|
-
};
|
|
23
|
-
}) => Promise<void>;
|
|
24
|
-
}>;
|
|
25
14
|
setup(ctx: Plugin.Context): Promise<(() => Promise<void>) | undefined>;
|
|
26
15
|
};
|
|
27
16
|
export default _default;
|
package/dist/plugins/zed-bell.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { subscribeEvents } from "./events.js";
|
|
2
2
|
export async function zedBell(options = {}) {
|
|
3
3
|
if (!options.enabled)
|
|
4
4
|
return {};
|
|
5
5
|
return {
|
|
6
|
-
event: async (
|
|
6
|
+
event: async (event) => {
|
|
7
7
|
if (event.type !== "session.idle" && event.type !== "permission.asked")
|
|
8
8
|
return;
|
|
9
9
|
const acp = process.env.OPENCODE_CLIENT === "acp" || process.argv.includes("acp");
|
|
@@ -14,8 +14,9 @@ export async function zedBell(options = {}) {
|
|
|
14
14
|
}
|
|
15
15
|
export default {
|
|
16
16
|
id: "agentomatic.zed-bell",
|
|
17
|
-
server: async (_input, options = {}) => zedBell(options),
|
|
18
17
|
async setup(ctx) {
|
|
19
|
-
|
|
18
|
+
const hooks = await zedBell(ctx.options);
|
|
19
|
+
if (hooks.event)
|
|
20
|
+
return subscribeEvents(ctx, hooks.event);
|
|
20
21
|
},
|
|
21
22
|
};
|
package/dist/registry.js
CHANGED
|
@@ -57,7 +57,7 @@ const COMMANDS = [
|
|
|
57
57
|
"Show the RTK output-compression observability summary for this host.",
|
|
58
58
|
`Run \`npx --yes @kisev/agentomatic@${requirePackageVersion()} doctor --json\` and render the \`rtk.observability\` check as a short human summary: wrapper status, rtk binary availability, event counters, characters saved, and the token estimate.`,
|
|
59
59
|
"When the doctor command is unavailable, read the stats file directly: `$XDG_STATE_HOME/opencode/skills/rtk/stats.json`, or `~/.local/state/opencode/skills/rtk/stats.json` when that variable is unset.",
|
|
60
|
-
"Zero counters with an active wrapper mean no verbose
|
|
60
|
+
"Zero counters with an active wrapper mean no verbose shell output has been compressed yet.",
|
|
61
61
|
"The `/rtk` command still loads the portable rtk skill and is unaffected by this summary.",
|
|
62
62
|
],
|
|
63
63
|
},
|
package/dist/routing.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kisev/agentomatic",
|
|
3
|
-
"version": "11.0.2-dev.
|
|
3
|
+
"version": "11.0.2-dev.87.g5a92e74c6754",
|
|
4
4
|
"description": "OpenCode integration and opt-in installer for portable Agent Skills.",
|
|
5
5
|
"homepage": "https://github.com/kisev/skills#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -46,24 +46,19 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@clack/prompts": "^1.8.1",
|
|
49
|
-
"@kisev/safe-fs": "1.0.0-dev.
|
|
49
|
+
"@kisev/safe-fs": "1.0.0-dev.87.g5a92e74c6754",
|
|
50
50
|
"commander": "15.0.0",
|
|
51
51
|
"zod": "4.1.8"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@opencode-ai/plugin": "1.18.32",
|
|
55
54
|
"@opencode/plugin": "2.0.19",
|
|
56
55
|
"@types/node": "22.15.30",
|
|
57
56
|
"typescript": "7.0.2"
|
|
58
57
|
},
|
|
59
58
|
"peerDependencies": {
|
|
60
|
-
"@opencode-ai/plugin": ">=1.18.0 <1.19.0",
|
|
61
59
|
"@opencode/plugin": ">=2.0.0 <2.1.0"
|
|
62
60
|
},
|
|
63
61
|
"peerDependenciesMeta": {
|
|
64
|
-
"@opencode-ai/plugin": {
|
|
65
|
-
"optional": true
|
|
66
|
-
},
|
|
67
62
|
"@opencode/plugin": {
|
|
68
63
|
"optional": true
|
|
69
64
|
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from "@opencode/plugin";
|
|
2
|
-
type Input = {
|
|
3
|
-
tool: string;
|
|
4
|
-
sessionID: string;
|
|
5
|
-
args: Record<string, unknown>;
|
|
6
|
-
directory?: string;
|
|
7
|
-
};
|
|
8
|
-
type Hooks = {
|
|
9
|
-
"tool.execute.before"?: (input: Input, output: {
|
|
10
|
-
args: unknown;
|
|
11
|
-
}) => Promise<void>;
|
|
12
|
-
"tool.execute.after"?: (input: Input, output: {
|
|
13
|
-
output: string;
|
|
14
|
-
}) => Promise<void>;
|
|
15
|
-
event?: (input: {
|
|
16
|
-
event: {
|
|
17
|
-
type: string;
|
|
18
|
-
properties?: Record<string, unknown>;
|
|
19
|
-
};
|
|
20
|
-
}) => Promise<void>;
|
|
21
|
-
"experimental.chat.system.transform"?: (input: {
|
|
22
|
-
sessionID: string;
|
|
23
|
-
}, output: {
|
|
24
|
-
system: string[];
|
|
25
|
-
}) => Promise<void>;
|
|
26
|
-
};
|
|
27
|
-
export declare function registerV2Hooks(ctx: Plugin.Context, hooks: Hooks, options?: {
|
|
28
|
-
sessionDirectory?: boolean;
|
|
29
|
-
}): Promise<(() => Promise<void>) | undefined>;
|
|
30
|
-
export {};
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
function toolName(name) {
|
|
2
|
-
return name === "shell" ? "bash" : name === "subagent" ? "task" : name;
|
|
3
|
-
}
|
|
4
|
-
function args(value) {
|
|
5
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
6
|
-
? value
|
|
7
|
-
: {};
|
|
8
|
-
}
|
|
9
|
-
function text(result) {
|
|
10
|
-
if (typeof result.content === "string")
|
|
11
|
-
return result.content;
|
|
12
|
-
if (Array.isArray(result.content))
|
|
13
|
-
return result.content
|
|
14
|
-
.filter((part) => part.type === "text")
|
|
15
|
-
.map((part) => part.text)
|
|
16
|
-
.join("\n");
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
function replaceText(result, output) {
|
|
20
|
-
if (!Array.isArray(result.content))
|
|
21
|
-
return { ...result, content: output };
|
|
22
|
-
let replaced = false;
|
|
23
|
-
return {
|
|
24
|
-
...result,
|
|
25
|
-
content: result.content.flatMap((part) => {
|
|
26
|
-
if (part.type !== "text")
|
|
27
|
-
return [part];
|
|
28
|
-
if (replaced)
|
|
29
|
-
return [];
|
|
30
|
-
replaced = true;
|
|
31
|
-
return [{ type: "text", text: output }];
|
|
32
|
-
}),
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
export async function registerV2Hooks(ctx, hooks, options = {}) {
|
|
36
|
-
if (hooks["tool.execute.before"])
|
|
37
|
-
await ctx.tool.hook("execute.before", async (event) => {
|
|
38
|
-
const output = { args: event.input };
|
|
39
|
-
await hooks["tool.execute.before"]({ ...event, tool: toolName(event.tool), args: args(event.input) }, output);
|
|
40
|
-
event.input = output.args;
|
|
41
|
-
});
|
|
42
|
-
if (hooks["tool.execute.after"])
|
|
43
|
-
await ctx.tool.hook("execute.after", async (event) => {
|
|
44
|
-
if (event.status !== "completed")
|
|
45
|
-
return;
|
|
46
|
-
const original = text(event.result);
|
|
47
|
-
if (original === undefined)
|
|
48
|
-
return;
|
|
49
|
-
const output = { output: original };
|
|
50
|
-
let directory = ctx.location.directory;
|
|
51
|
-
if (options.sessionDirectory && (event.tool === "read" || event.tool === "edit")) {
|
|
52
|
-
const session = await ctx.session
|
|
53
|
-
.get({ sessionID: event.sessionID })
|
|
54
|
-
.catch(() => undefined);
|
|
55
|
-
if (!session)
|
|
56
|
-
return;
|
|
57
|
-
directory = session.location.directory;
|
|
58
|
-
}
|
|
59
|
-
await hooks["tool.execute.after"]({ ...event, tool: toolName(event.tool), args: args(event.input), directory }, output);
|
|
60
|
-
if (output.output !== original)
|
|
61
|
-
event.result = replaceText(event.result, output.output);
|
|
62
|
-
});
|
|
63
|
-
if (hooks["experimental.chat.system.transform"])
|
|
64
|
-
await ctx.session.hook("context", async (event) => {
|
|
65
|
-
const output = { system: [] };
|
|
66
|
-
await hooks["experimental.chat.system.transform"]({ sessionID: event.sessionID }, output);
|
|
67
|
-
event.system.push(...output.system.map((text) => ({ type: "text", text })));
|
|
68
|
-
});
|
|
69
|
-
if (!hooks.event)
|
|
70
|
-
return;
|
|
71
|
-
const controller = new AbortController();
|
|
72
|
-
const subscription = (async () => {
|
|
73
|
-
try {
|
|
74
|
-
for await (const event of ctx.event.subscribe({ signal: controller.signal })) {
|
|
75
|
-
await hooks.event({ event: { type: event.type, properties: args(event.data) } });
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
catch (error) {
|
|
79
|
-
if (!controller.signal.aborted)
|
|
80
|
-
console.error("agentomatic event subscription failed", error);
|
|
81
|
-
}
|
|
82
|
-
})();
|
|
83
|
-
return async () => {
|
|
84
|
-
controller.abort();
|
|
85
|
-
await subscription;
|
|
86
|
-
};
|
|
87
|
-
}
|