@hanhnd/agent-kit 1.0.18 → 1.0.20
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/dist/kit-server.js +31 -9
- package/dist/tools/agent.js +19 -3
- package/dist/tools/core.js +17 -5
- package/package.json +1 -1
package/dist/kit-server.js
CHANGED
|
@@ -21051,20 +21051,30 @@ function registerCoreTools(server2) {
|
|
|
21051
21051
|
"kit_save_handoff",
|
|
21052
21052
|
"Save a brainstorm, plan, or ticket handoff artifact to .agent-kit/handoffs/. Returns the saved file path to use in next-step instructions.",
|
|
21053
21053
|
{
|
|
21054
|
-
type: external_exports.enum(["brainstorm", "plan", "ticket"]).describe("Handoff type"),
|
|
21054
|
+
type: external_exports.enum(["brainstorm", "plan", "ticket", "research"]).describe("Handoff type"),
|
|
21055
21055
|
content: external_exports.string().describe("Full markdown content to save"),
|
|
21056
|
-
slug: external_exports.string().describe(
|
|
21056
|
+
slug: external_exports.string().describe(
|
|
21057
|
+
'Short identifier for the filename, e.g. "user-auth" or "PROJ-123". Do NOT append version numbers (v2, v3, etc); the tool will automatically update the existing file if it exists.'
|
|
21058
|
+
)
|
|
21057
21059
|
},
|
|
21058
21060
|
async ({ type, content, slug }) => {
|
|
21059
21061
|
try {
|
|
21060
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
21061
21062
|
const safeSlug = slug.replace(/[^a-zA-Z0-9-_]/g, "-").toLowerCase();
|
|
21062
|
-
const filename = `${type}-${timestamp}-${safeSlug}.md`;
|
|
21063
21063
|
const handoffDir = path.join(getWorkspaceRoot(), ".agent-kit", "handoffs", `${type}s`);
|
|
21064
21064
|
if (!fs.existsSync(handoffDir)) {
|
|
21065
21065
|
fs.mkdirSync(handoffDir, { recursive: true });
|
|
21066
21066
|
}
|
|
21067
|
-
const
|
|
21067
|
+
const files = fs.readdirSync(handoffDir);
|
|
21068
|
+
const slugPattern = new RegExp(`^${type}-([0-9T-]{19}-)?${safeSlug}\\.md$`);
|
|
21069
|
+
const existingFile = files.filter((f) => slugPattern.test(f)).sort().pop();
|
|
21070
|
+
let filePath;
|
|
21071
|
+
if (existingFile) {
|
|
21072
|
+
filePath = path.join(handoffDir, existingFile);
|
|
21073
|
+
} else {
|
|
21074
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
21075
|
+
const filename = `${type}-${timestamp}-${safeSlug}.md`;
|
|
21076
|
+
filePath = path.join(handoffDir, filename);
|
|
21077
|
+
}
|
|
21068
21078
|
fs.writeFileSync(filePath, content, "utf8");
|
|
21069
21079
|
return mcpText(`\u2705 Saved to: ${filePath}`);
|
|
21070
21080
|
} catch (error2) {
|
|
@@ -21212,20 +21222,32 @@ function registerAgentTools(server2) {
|
|
|
21212
21222
|
const jobId = randomUUID();
|
|
21213
21223
|
const child = spawn(usedAgent, agentArgs, {
|
|
21214
21224
|
cwd: workspaceRoot,
|
|
21215
|
-
env: { ...process.env, GEMINI_WORKSPACE: workspaceRoot }
|
|
21225
|
+
env: { ...process.env, GEMINI_WORKSPACE: workspaceRoot },
|
|
21226
|
+
detached: process.platform !== "win32"
|
|
21216
21227
|
});
|
|
21228
|
+
const killTree = (sig) => {
|
|
21229
|
+
if (process.platform !== "win32" && child.pid) {
|
|
21230
|
+
try {
|
|
21231
|
+
process.kill(-child.pid, sig);
|
|
21232
|
+
} catch {
|
|
21233
|
+
child.kill(sig);
|
|
21234
|
+
}
|
|
21235
|
+
} else {
|
|
21236
|
+
child.kill(sig);
|
|
21237
|
+
}
|
|
21238
|
+
};
|
|
21217
21239
|
job = {
|
|
21218
21240
|
agent: usedAgent,
|
|
21219
21241
|
process: child,
|
|
21220
21242
|
startedAt: /* @__PURE__ */ new Date(),
|
|
21221
21243
|
chunks: [],
|
|
21222
21244
|
logStream,
|
|
21223
|
-
timeoutHandle: setTimeout(() =>
|
|
21245
|
+
timeoutHandle: setTimeout(() => killTree("SIGTERM"), AGENT_TIMEOUT)
|
|
21224
21246
|
};
|
|
21225
21247
|
jobRegistry.set(jobId, job);
|
|
21226
21248
|
killChild = () => {
|
|
21227
|
-
|
|
21228
|
-
setTimeout(() =>
|
|
21249
|
+
killTree("SIGTERM");
|
|
21250
|
+
setTimeout(() => killTree("SIGKILL"), 5e3).unref();
|
|
21229
21251
|
};
|
|
21230
21252
|
if (extra.signal.aborted) killChild();
|
|
21231
21253
|
else extra.signal.addEventListener("abort", killChild);
|
package/dist/tools/agent.js
CHANGED
|
@@ -86,23 +86,39 @@ export function registerAgentTools(server) {
|
|
|
86
86
|
const { logPath: lp, logStream } = initAgentLog(workspaceRoot, taskSlug(task), usedAgent);
|
|
87
87
|
logPath = lp;
|
|
88
88
|
const jobId = randomUUID();
|
|
89
|
+
// detached=true on Unix creates a new process group so we can kill the
|
|
90
|
+
// entire tree (CLI + its sub-agents) with process.kill(-pid, signal).
|
|
89
91
|
const child = spawn(usedAgent, agentArgs, {
|
|
90
92
|
cwd: workspaceRoot,
|
|
91
93
|
env: { ...process.env, GEMINI_WORKSPACE: workspaceRoot },
|
|
94
|
+
detached: process.platform !== 'win32',
|
|
92
95
|
});
|
|
96
|
+
const killTree = (sig) => {
|
|
97
|
+
if (process.platform !== 'win32' && child.pid) {
|
|
98
|
+
try {
|
|
99
|
+
process.kill(-child.pid, sig);
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
child.kill(sig);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
child.kill(sig);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
93
109
|
job = {
|
|
94
110
|
agent: usedAgent,
|
|
95
111
|
process: child,
|
|
96
112
|
startedAt: new Date(),
|
|
97
113
|
chunks: [],
|
|
98
114
|
logStream,
|
|
99
|
-
timeoutHandle: setTimeout(() =>
|
|
115
|
+
timeoutHandle: setTimeout(() => killTree('SIGTERM'), AGENT_TIMEOUT),
|
|
100
116
|
};
|
|
101
117
|
jobRegistry.set(jobId, job);
|
|
102
118
|
// Kill child if the MCP request is cancelled (e.g. user presses ESC)
|
|
103
119
|
killChild = () => {
|
|
104
|
-
|
|
105
|
-
setTimeout(() =>
|
|
120
|
+
killTree('SIGTERM');
|
|
121
|
+
setTimeout(() => killTree('SIGKILL'), 5000).unref();
|
|
106
122
|
};
|
|
107
123
|
if (extra.signal.aborted)
|
|
108
124
|
killChild();
|
package/dist/tools/core.js
CHANGED
|
@@ -16,21 +16,33 @@ export function registerCoreTools(server) {
|
|
|
16
16
|
// Returns the saved file path for use in next-step instructions
|
|
17
17
|
// ═══════════════════════════════════════════════════════════════
|
|
18
18
|
server.tool('kit_save_handoff', 'Save a brainstorm, plan, or ticket handoff artifact to .agent-kit/handoffs/. Returns the saved file path to use in next-step instructions.', {
|
|
19
|
-
type: z.enum(['brainstorm', 'plan', 'ticket']).describe('Handoff type'),
|
|
19
|
+
type: z.enum(['brainstorm', 'plan', 'ticket', 'research']).describe('Handoff type'),
|
|
20
20
|
content: z.string().describe('Full markdown content to save'),
|
|
21
21
|
slug: z
|
|
22
22
|
.string()
|
|
23
|
-
.describe('Short identifier for the filename, e.g. "user-auth" or "PROJ-123"'),
|
|
23
|
+
.describe('Short identifier for the filename, e.g. "user-auth" or "PROJ-123". Do NOT append version numbers (v2, v3, etc); the tool will automatically update the existing file if it exists.'),
|
|
24
24
|
}, async ({ type, content, slug }) => {
|
|
25
25
|
try {
|
|
26
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
27
26
|
const safeSlug = slug.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();
|
|
28
|
-
const filename = `${type}-${timestamp}-${safeSlug}.md`;
|
|
29
27
|
const handoffDir = path.join(getWorkspaceRoot(), '.agent-kit', 'handoffs', `${type}s`);
|
|
30
28
|
if (!fs.existsSync(handoffDir)) {
|
|
31
29
|
fs.mkdirSync(handoffDir, { recursive: true });
|
|
32
30
|
}
|
|
33
|
-
const
|
|
31
|
+
const files = fs.readdirSync(handoffDir);
|
|
32
|
+
const slugPattern = new RegExp(`^${type}-([0-9T-]{19}-)?${safeSlug}\\.md$`);
|
|
33
|
+
const existingFile = files
|
|
34
|
+
.filter((f) => slugPattern.test(f))
|
|
35
|
+
.sort()
|
|
36
|
+
.pop();
|
|
37
|
+
let filePath;
|
|
38
|
+
if (existingFile) {
|
|
39
|
+
filePath = path.join(handoffDir, existingFile);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
43
|
+
const filename = `${type}-${timestamp}-${safeSlug}.md`;
|
|
44
|
+
filePath = path.join(handoffDir, filename);
|
|
45
|
+
}
|
|
34
46
|
fs.writeFileSync(filePath, content, 'utf8');
|
|
35
47
|
return mcpText(`✅ Saved to: ${filePath}`);
|
|
36
48
|
}
|