@kb-labs/agent-cli 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/README.md +56 -0
  2. package/dist/cli/commands/diff.d.ts +17 -0
  3. package/dist/cli/commands/diff.js +182 -0
  4. package/dist/cli/commands/diff.js.map +1 -0
  5. package/dist/cli/commands/history.d.ts +16 -0
  6. package/dist/cli/commands/history.js +216 -0
  7. package/dist/cli/commands/history.js.map +1 -0
  8. package/dist/cli/commands/quality-report.d.ts +21 -0
  9. package/dist/cli/commands/quality-report.js +457 -0
  10. package/dist/cli/commands/quality-report.js.map +1 -0
  11. package/dist/cli/commands/rollback.d.ts +27 -0
  12. package/dist/cli/commands/rollback.js +109 -0
  13. package/dist/cli/commands/rollback.js.map +1 -0
  14. package/dist/cli/commands/run.d.ts +42 -0
  15. package/dist/cli/commands/run.js +923 -0
  16. package/dist/cli/commands/run.js.map +1 -0
  17. package/dist/cli/commands/trace-context.d.ts +22 -0
  18. package/dist/cli/commands/trace-context.js +131 -0
  19. package/dist/cli/commands/trace-context.js.map +1 -0
  20. package/dist/cli/commands/trace-diagnose.d.ts +20 -0
  21. package/dist/cli/commands/trace-diagnose.js +434 -0
  22. package/dist/cli/commands/trace-diagnose.js.map +1 -0
  23. package/dist/cli/commands/trace-event-normalizer.d.ts +13 -0
  24. package/dist/cli/commands/trace-event-normalizer.js +39 -0
  25. package/dist/cli/commands/trace-event-normalizer.js.map +1 -0
  26. package/dist/cli/commands/trace-filter.d.ts +19 -0
  27. package/dist/cli/commands/trace-filter.js +153 -0
  28. package/dist/cli/commands/trace-filter.js.map +1 -0
  29. package/dist/cli/commands/trace-iteration.d.ts +18 -0
  30. package/dist/cli/commands/trace-iteration.js +192 -0
  31. package/dist/cli/commands/trace-iteration.js.map +1 -0
  32. package/dist/cli/commands/trace-stats.d.ts +17 -0
  33. package/dist/cli/commands/trace-stats.js +247 -0
  34. package/dist/cli/commands/trace-stats.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +473 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/manifest.d.ts +184 -0
  39. package/dist/manifest.js +473 -0
  40. package/dist/manifest.js.map +1 -0
  41. package/dist/rest/handlers/approve-handler.d.ts +15 -0
  42. package/dist/rest/handlers/approve-handler.js +60 -0
  43. package/dist/rest/handlers/approve-handler.js.map +1 -0
  44. package/dist/rest/handlers/approve-session-plan-handler.d.ts +10 -0
  45. package/dist/rest/handlers/approve-session-plan-handler.js +52 -0
  46. package/dist/rest/handlers/approve-session-plan-handler.js.map +1 -0
  47. package/dist/rest/handlers/correct-handler.d.ts +7 -0
  48. package/dist/rest/handlers/correct-handler.js +326 -0
  49. package/dist/rest/handlers/correct-handler.js.map +1 -0
  50. package/dist/rest/handlers/create-session-handler.d.ts +7 -0
  51. package/dist/rest/handlers/create-session-handler.js +25 -0
  52. package/dist/rest/handlers/create-session-handler.js.map +1 -0
  53. package/dist/rest/handlers/execute-session-plan-handler.d.ts +10 -0
  54. package/dist/rest/handlers/execute-session-plan-handler.js +635 -0
  55. package/dist/rest/handlers/execute-session-plan-handler.js.map +1 -0
  56. package/dist/rest/handlers/generate-spec-handler.d.ts +10 -0
  57. package/dist/rest/handlers/generate-spec-handler.js +389 -0
  58. package/dist/rest/handlers/generate-spec-handler.js.map +1 -0
  59. package/dist/rest/handlers/get-file-diff-handler.d.ts +24 -0
  60. package/dist/rest/handlers/get-file-diff-handler.js +44 -0
  61. package/dist/rest/handlers/get-file-diff-handler.js.map +1 -0
  62. package/dist/rest/handlers/get-session-handler.d.ts +10 -0
  63. package/dist/rest/handlers/get-session-handler.js +23 -0
  64. package/dist/rest/handlers/get-session-handler.js.map +1 -0
  65. package/dist/rest/handlers/get-session-plan-handler.d.ts +10 -0
  66. package/dist/rest/handlers/get-session-plan-handler.js +53 -0
  67. package/dist/rest/handlers/get-session-plan-handler.js.map +1 -0
  68. package/dist/rest/handlers/get-session-turns-handler.d.ts +16 -0
  69. package/dist/rest/handlers/get-session-turns-handler.js +35 -0
  70. package/dist/rest/handlers/get-session-turns-handler.js.map +1 -0
  71. package/dist/rest/handlers/get-spec-handler.d.ts +10 -0
  72. package/dist/rest/handlers/get-spec-handler.js +39 -0
  73. package/dist/rest/handlers/get-spec-handler.js.map +1 -0
  74. package/dist/rest/handlers/list-file-changes-handler.d.ts +13 -0
  75. package/dist/rest/handlers/list-file-changes-handler.js +34 -0
  76. package/dist/rest/handlers/list-file-changes-handler.js.map +1 -0
  77. package/dist/rest/handlers/list-sessions-handler.d.ts +7 -0
  78. package/dist/rest/handlers/list-sessions-handler.js +23 -0
  79. package/dist/rest/handlers/list-sessions-handler.js.map +1 -0
  80. package/dist/rest/handlers/rollback-handler.d.ts +22 -0
  81. package/dist/rest/handlers/rollback-handler.js +91 -0
  82. package/dist/rest/handlers/rollback-handler.js.map +1 -0
  83. package/dist/rest/handlers/run-handler.d.ts +7 -0
  84. package/dist/rest/handlers/run-handler.js +516 -0
  85. package/dist/rest/handlers/run-handler.js.map +1 -0
  86. package/dist/rest/handlers/sessions-handler.d.ts +18 -0
  87. package/dist/rest/handlers/sessions-handler.js +56 -0
  88. package/dist/rest/handlers/sessions-handler.js.map +1 -0
  89. package/dist/rest/handlers/status-handler.d.ts +7 -0
  90. package/dist/rest/handlers/status-handler.js +313 -0
  91. package/dist/rest/handlers/status-handler.js.map +1 -0
  92. package/dist/rest/handlers/stop-handler.d.ts +7 -0
  93. package/dist/rest/handlers/stop-handler.js +317 -0
  94. package/dist/rest/handlers/stop-handler.js.map +1 -0
  95. package/dist/widgets/220.js +446 -0
  96. package/dist/widgets/220.js.map +1 -0
  97. package/dist/widgets/331.js +2 -0
  98. package/dist/widgets/331.js.map +1 -0
  99. package/dist/widgets/403.js +2 -0
  100. package/dist/widgets/403.js.map +1 -0
  101. package/dist/widgets/406.js +35 -0
  102. package/dist/widgets/406.js.map +1 -0
  103. package/dist/widgets/455.js +2 -0
  104. package/dist/widgets/455.js.map +1 -0
  105. package/dist/widgets/482.js +2 -0
  106. package/dist/widgets/482.js.map +1 -0
  107. package/dist/widgets/485.js +2 -0
  108. package/dist/widgets/485.js.map +1 -0
  109. package/dist/widgets/527.js +2 -0
  110. package/dist/widgets/527.js.map +1 -0
  111. package/dist/widgets/628.js +2 -0
  112. package/dist/widgets/628.js.map +1 -0
  113. package/dist/widgets/694.js +2 -0
  114. package/dist/widgets/694.js.map +1 -0
  115. package/dist/widgets/712.js +2 -0
  116. package/dist/widgets/712.js.map +1 -0
  117. package/dist/widgets/866.js +2 -0
  118. package/dist/widgets/866.js.map +1 -0
  119. package/dist/widgets/915.js +39 -0
  120. package/dist/widgets/915.js.map +1 -0
  121. package/dist/widgets/957.js +10 -0
  122. package/dist/widgets/957.js.map +1 -0
  123. package/dist/widgets/983.js +2 -0
  124. package/dist/widgets/983.js.map +1 -0
  125. package/dist/widgets/@mf-types.d.ts +3 -0
  126. package/dist/widgets/@mf-types.zip +0 -0
  127. package/dist/widgets/__federation_expose_AgentsPage.js +2 -0
  128. package/dist/widgets/__federation_expose_AgentsPage.js.map +1 -0
  129. package/dist/widgets/mf-manifest.json +260 -0
  130. package/dist/widgets/mf-stats.json +305 -0
  131. package/dist/widgets/remoteEntry.js +7 -0
  132. package/dist/widgets/remoteEntry.js.map +1 -0
  133. package/dist/ws/session-stream-handler.d.ts +8 -0
  134. package/dist/ws/session-stream-handler.js +409 -0
  135. package/dist/ws/session-stream-handler.js.map +1 -0
  136. package/package.json +83 -0
@@ -0,0 +1,25 @@
1
+ import { defineHandler } from '@kb-labs/sdk';
2
+ import { SessionManager } from '@kb-labs/agent-core';
3
+
4
+ // src/rest/handlers/create-session-handler.ts
5
+ var create_session_handler_default = defineHandler({
6
+ async execute(ctx, input) {
7
+ const body = input.body;
8
+ if (!body?.agentId) {
9
+ throw new Error("Agent ID is required");
10
+ }
11
+ const sessionManager = new SessionManager(ctx.cwd);
12
+ const session = await sessionManager.createSession({
13
+ mode: "execute",
14
+ task: body.task ?? "",
15
+ agentId: body.agentId,
16
+ name: body.name
17
+ });
18
+ ctx.platform.logger.info(`[create-session] Created session ${session.id} for agent ${body.agentId}`);
19
+ return { session };
20
+ }
21
+ });
22
+
23
+ export { create_session_handler_default as default };
24
+ //# sourceMappingURL=create-session-handler.js.map
25
+ //# sourceMappingURL=create-session-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/rest/handlers/create-session-handler.ts"],"names":[],"mappings":";;;;AAQA,IAAO,iCAAQ,aAAA,CAAc;AAAA,EAC3B,MAAM,OAAA,CACJ,GAAA,EACA,KAAA,EACgC;AAChC,IAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AAEnB,IAAA,IAAI,CAAC,MAAM,OAAA,EAAS;AAClB,MAAA,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAAA,IACxC;AAEA,IAAA,MAAM,cAAA,GAAiB,IAAI,cAAA,CAAe,GAAA,CAAI,GAAG,CAAA;AAEjD,IAAA,MAAM,OAAA,GAAU,MAAM,cAAA,CAAe,aAAA,CAAc;AAAA,MACjD,IAAA,EAAM,SAAA;AAAA,MACN,IAAA,EAAM,KAAK,IAAA,IAAQ,EAAA;AAAA,MACnB,SAAS,IAAA,CAAK,OAAA;AAAA,MACd,MAAM,IAAA,CAAK;AAAA,KACZ,CAAA;AAED,IAAA,GAAA,CAAI,QAAA,CAAS,OAAO,IAAA,CAAK,CAAA,iCAAA,EAAoC,QAAQ,EAAE,CAAA,WAAA,EAAc,IAAA,CAAK,OAAO,CAAA,CAAE,CAAA;AAEnG,IAAA,OAAO,EAAE,OAAA,EAAQ;AAAA,EACnB;AACF,CAAC","file":"create-session-handler.js","sourcesContent":["/**\n * POST /sessions - Create a new session\n */\n\nimport { defineHandler, type RestInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { SessionManager } from '@kb-labs/agent-core';\nimport type { CreateSessionRequest, CreateSessionResponse } from '@kb-labs/agent-contracts';\n\nexport default defineHandler({\n async execute(\n ctx: PluginContextV3,\n input: RestInput<CreateSessionRequest>\n ): Promise<CreateSessionResponse> {\n const body = input.body as CreateSessionRequest | undefined;\n\n if (!body?.agentId) {\n throw new Error('Agent ID is required');\n }\n\n const sessionManager = new SessionManager(ctx.cwd);\n\n const session = await sessionManager.createSession({\n mode: 'execute',\n task: body.task ?? '',\n agentId: body.agentId,\n name: body.name,\n });\n\n ctx.platform.logger.info(`[create-session] Created session ${session.id} for agent ${body.agentId}`);\n\n return { session };\n },\n});\n"]}
@@ -0,0 +1,10 @@
1
+ import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
2
+ import { RestInput } from '@kb-labs/sdk';
3
+ import { ExecuteSessionPlanRequest, ExecuteSessionPlanResponse } from '@kb-labs/agent-contracts';
4
+
5
+ interface ExecutePlanRouteParams {
6
+ sessionId?: string;
7
+ }
8
+ declare const _default: _kb_labs_shared_command_kit.Handler<unknown, RestInput<ExecuteSessionPlanRequest, unknown, ExecutePlanRouteParams>, ExecuteSessionPlanResponse>;
9
+
10
+ export { _default as default };
@@ -0,0 +1,635 @@
1
+ import { defineHandler, useAnalytics, useCache, useConfig, usePlatform } from '@kb-labs/sdk';
2
+ import { bootstrapAgentSDK, SessionManager, createSessionMemoryBridge, createCoreToolPack, PlanDocumentService } from '@kb-labs/agent-core';
3
+ import fs, { promises } from 'fs';
4
+ import { createDefaultResponseRequirementsSelector } from '@kb-labs/agent-runtime';
5
+ import { IncrementalTraceWriter } from '@kb-labs/agent-tracing';
6
+ import { AgentSDK } from '@kb-labs/agent-sdk';
7
+ import { createToolRegistry } from '@kb-labs/agent-tools';
8
+ import path from 'path';
9
+ import { AGENT_ANALYTICS_EVENTS, AGENTS_WS_CHANNELS, AGENTS_WS_BASE_PATH } from '@kb-labs/agent-contracts';
10
+
11
+ // src/rest/handlers/execute-session-plan-handler.ts
12
+ var CACHE_PREFIX = "agent:run:";
13
+ var EVENT_TOPIC_PREFIX = "agent:events:";
14
+ var CACHE_TTL = 36e5;
15
+ var RunManagerImpl = class {
16
+ /** Live agents and listeners (not cacheable) */
17
+ activeRuns = /* @__PURE__ */ new Map();
18
+ /** Session-level listeners: sessionId → Set<callback> — receive events from ALL runs in session */
19
+ sessionListeners = /* @__PURE__ */ new Map();
20
+ /** sessionId per runId — set when run is registered */
21
+ runSessionMap = /* @__PURE__ */ new Map();
22
+ /**
23
+ * Generate unique run ID
24
+ */
25
+ generateRunId() {
26
+ return `run-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
27
+ }
28
+ /**
29
+ * Register a new run
30
+ */
31
+ async register(runId, task, agent, sessionManager, sessionId) {
32
+ const now = (/* @__PURE__ */ new Date()).toISOString();
33
+ const run = {
34
+ runId,
35
+ task,
36
+ status: "pending",
37
+ agent,
38
+ sessionManager,
39
+ startedAt: now,
40
+ listeners: /* @__PURE__ */ new Set(),
41
+ lastSeq: 0,
42
+ eventBuffer: []
43
+ };
44
+ this.activeRuns.set(runId, run);
45
+ if (sessionId) {
46
+ this.runSessionMap.set(runId, sessionId);
47
+ }
48
+ await this.saveToCache(run);
49
+ return run;
50
+ }
51
+ /**
52
+ * Get run by ID (from memory first, then cache for state)
53
+ */
54
+ get(runId) {
55
+ return this.activeRuns.get(runId);
56
+ }
57
+ /**
58
+ * Check if run exists (in memory or cache)
59
+ */
60
+ async exists(runId) {
61
+ if (this.activeRuns.has(runId)) {
62
+ return true;
63
+ }
64
+ const state = await this.getState(runId);
65
+ return state !== null;
66
+ }
67
+ /**
68
+ * Get run state from cache (for completed runs or cross-process access)
69
+ */
70
+ async getState(runId) {
71
+ const cache = useCache();
72
+ if (!cache) {
73
+ return null;
74
+ }
75
+ return cache.get(`${CACHE_PREFIX}${runId}`);
76
+ }
77
+ /**
78
+ * Update run status
79
+ */
80
+ async updateStatus(runId, status, extra) {
81
+ const run = this.activeRuns.get(runId);
82
+ if (run) {
83
+ run.status = status;
84
+ if (extra) {
85
+ Object.assign(run, extra);
86
+ }
87
+ await this.saveToCache(run);
88
+ }
89
+ }
90
+ /**
91
+ * Save run state to cache
92
+ */
93
+ async saveToCache(run) {
94
+ const cache = useCache();
95
+ if (!cache) {
96
+ return;
97
+ }
98
+ const state = {
99
+ runId: run.runId,
100
+ task: run.task,
101
+ status: run.status,
102
+ startedAt: run.startedAt,
103
+ completedAt: run.completedAt,
104
+ durationMs: run.durationMs,
105
+ summary: run.summary,
106
+ error: run.error
107
+ };
108
+ await cache.set(`${CACHE_PREFIX}${run.runId}`, state, CACHE_TTL);
109
+ }
110
+ /** Track subscriptions for cleanup */
111
+ subscriptions = /* @__PURE__ */ new Map();
112
+ /**
113
+ * Add event listener to run (uses eventBus for cross-process)
114
+ */
115
+ addListener(runId, callback) {
116
+ const platform = usePlatform();
117
+ if (!platform?.eventBus) {
118
+ const run2 = this.activeRuns.get(runId);
119
+ if (run2) {
120
+ run2.listeners.add(callback);
121
+ return true;
122
+ }
123
+ return false;
124
+ }
125
+ const topic = `${EVENT_TOPIC_PREFIX}${runId}`;
126
+ const unsubscribe = platform.eventBus.subscribe(topic, async (event) => {
127
+ try {
128
+ callback(event);
129
+ } catch {
130
+ }
131
+ });
132
+ if (!this.subscriptions.has(runId)) {
133
+ this.subscriptions.set(runId, /* @__PURE__ */ new Map());
134
+ }
135
+ this.subscriptions.get(runId).set(callback, unsubscribe);
136
+ const run = this.activeRuns.get(runId);
137
+ if (run) {
138
+ run.listeners.add(callback);
139
+ }
140
+ return true;
141
+ }
142
+ /**
143
+ * Remove event listener from run
144
+ */
145
+ removeListener(runId, callback) {
146
+ const runSubs = this.subscriptions.get(runId);
147
+ if (runSubs) {
148
+ const unsubscribe = runSubs.get(callback);
149
+ if (unsubscribe) {
150
+ unsubscribe();
151
+ runSubs.delete(callback);
152
+ }
153
+ if (runSubs.size === 0) {
154
+ this.subscriptions.delete(runId);
155
+ }
156
+ }
157
+ const run = this.activeRuns.get(runId);
158
+ if (run) {
159
+ run.listeners.delete(callback);
160
+ }
161
+ }
162
+ /**
163
+ * Broadcast event to all listeners of a run (uses eventBus for cross-process)
164
+ * Assigns monotonic sequence number for reliable ordering
165
+ * @returns The event with seq assigned (for persistence)
166
+ */
167
+ broadcast(runId, event) {
168
+ const platform = usePlatform();
169
+ const run = this.activeRuns.get(runId);
170
+ let seqEvent = event;
171
+ if (run) {
172
+ run.lastSeq++;
173
+ seqEvent = { ...event, seq: run.lastSeq, runId };
174
+ run.eventBuffer.push(seqEvent);
175
+ }
176
+ if (platform?.eventBus) {
177
+ const topic = `${EVENT_TOPIC_PREFIX}${runId}`;
178
+ platform.eventBus.publish(topic, seqEvent).catch(() => {
179
+ });
180
+ }
181
+ if (run) {
182
+ for (const listener of run.listeners) {
183
+ try {
184
+ listener(seqEvent);
185
+ } catch {
186
+ }
187
+ }
188
+ }
189
+ const sessionId = this.runSessionMap.get(runId);
190
+ if (sessionId) {
191
+ const sListeners = this.sessionListeners.get(sessionId);
192
+ if (sListeners) {
193
+ for (const listener of sListeners) {
194
+ try {
195
+ listener(seqEvent);
196
+ } catch {
197
+ }
198
+ }
199
+ }
200
+ }
201
+ return seqEvent;
202
+ }
203
+ /**
204
+ * Add a session-level listener — receives events from ALL runs in this session.
205
+ */
206
+ addSessionListener(sessionId, callback) {
207
+ if (!this.sessionListeners.has(sessionId)) {
208
+ this.sessionListeners.set(sessionId, /* @__PURE__ */ new Set());
209
+ }
210
+ this.sessionListeners.get(sessionId).add(callback);
211
+ }
212
+ /**
213
+ * Remove a session-level listener.
214
+ */
215
+ removeSessionListener(sessionId, callback) {
216
+ const listeners = this.sessionListeners.get(sessionId);
217
+ if (listeners) {
218
+ listeners.delete(callback);
219
+ if (listeners.size === 0) {
220
+ this.sessionListeners.delete(sessionId);
221
+ }
222
+ }
223
+ }
224
+ /**
225
+ * Get replay buffer for a run (all events emitted since start).
226
+ * Used by WS handler to send missed events on late connection.
227
+ * Optionally filter by afterSeq to only get events the client hasn't seen.
228
+ */
229
+ getEventBuffer(runId, afterSeq) {
230
+ const run = this.activeRuns.get(runId);
231
+ if (!run) {
232
+ return [];
233
+ }
234
+ if (afterSeq != null) {
235
+ return run.eventBuffer.filter((e) => e.seq != null && e.seq > afterSeq);
236
+ }
237
+ return [...run.eventBuffer];
238
+ }
239
+ /**
240
+ * List all active runs
241
+ */
242
+ listActive() {
243
+ return Array.from(this.activeRuns.values()).map((r) => ({
244
+ runId: r.runId,
245
+ task: r.task,
246
+ status: r.status,
247
+ startedAt: r.startedAt
248
+ }));
249
+ }
250
+ /**
251
+ * Request graceful stop of a running agent (and its child agents via propagated AbortSignal).
252
+ * Agent finishes its current tool call then exits at the next iteration boundary.
253
+ */
254
+ requestStop(runId) {
255
+ const run = this.activeRuns.get(runId);
256
+ if (!run || run.status !== "running" || !run.agent) {
257
+ return false;
258
+ }
259
+ run.agent.requestStop();
260
+ return true;
261
+ }
262
+ /**
263
+ * Clean up completed runs from memory (cache handles its own TTL)
264
+ */
265
+ cleanup() {
266
+ for (const [runId, run] of this.activeRuns) {
267
+ if (run.status === "completed" || run.status === "failed" || run.status === "stopped") {
268
+ this.activeRuns.delete(runId);
269
+ }
270
+ }
271
+ }
272
+ };
273
+ var GLOBAL_KEY = "__kb_agent_run_manager__";
274
+ if (!globalThis[GLOBAL_KEY]) {
275
+ globalThis[GLOBAL_KEY] = new RunManagerImpl();
276
+ }
277
+ var RunManager = globalThis[GLOBAL_KEY];
278
+
279
+ // src/rest/handlers/run-handler.ts
280
+ bootstrapAgentSDK();
281
+ var FOLLOW_UP_SCOPE_RE = /\b(глубже|подробнее|детал|слишком поверхност|deeper|more depth|details?)\b/i;
282
+ function isLikelyFollowUpScopeTask(task) {
283
+ return FOLLOW_UP_SCOPE_RE.test(task);
284
+ }
285
+ function pathExists(dir) {
286
+ try {
287
+ return fs.existsSync(dir);
288
+ } catch {
289
+ return false;
290
+ }
291
+ }
292
+ function scoreRepoFromToolPath(rawPath, scores) {
293
+ const p = rawPath.replace(/\\/g, "/");
294
+ const explicit = p.match(/(^|\/)(kb-labs-[^/]+)\//);
295
+ if (explicit?.[2]) {
296
+ scores.set(explicit[2], (scores.get(explicit[2]) ?? 0) + 5);
297
+ }
298
+ if (p.startsWith("packages/")) {
299
+ if (/packages\/agent[-/]/.test(p) || /agent-core|agent-tools|agent-cli|agent-task-runner/.test(p)) {
300
+ scores.set("kb-labs-agents", (scores.get("kb-labs-agents") ?? 0) + 4);
301
+ }
302
+ if (/packages\/mind[-/]/.test(p) || /mind-engine|mind-core/.test(p)) {
303
+ scores.set("kb-labs-mind", (scores.get("kb-labs-mind") ?? 0) + 4);
304
+ }
305
+ }
306
+ }
307
+ async function inferFollowUpWorkingDir(sessionManager, sessionId, baseWorkingDir) {
308
+ const events = await sessionManager.getSessionEvents(sessionId);
309
+ if (!events.length) {
310
+ return null;
311
+ }
312
+ const completedRuns = /* @__PURE__ */ new Set();
313
+ for (const event of events) {
314
+ if (event.type === "agent:end" && event.runId) {
315
+ completedRuns.add(event.runId);
316
+ }
317
+ }
318
+ const lastRunId = Array.from(completedRuns).at(-1);
319
+ if (!lastRunId) {
320
+ return null;
321
+ }
322
+ const repoScores = /* @__PURE__ */ new Map();
323
+ for (const event of events) {
324
+ if (event.runId !== lastRunId) {
325
+ continue;
326
+ }
327
+ if (event.type === "tool:start") {
328
+ const input = event.data?.input ?? {};
329
+ const p1 = input.path;
330
+ const p2 = input.directory;
331
+ if (typeof p1 === "string") {
332
+ scoreRepoFromToolPath(p1, repoScores);
333
+ }
334
+ if (typeof p2 === "string") {
335
+ scoreRepoFromToolPath(p2, repoScores);
336
+ }
337
+ }
338
+ if (event.type === "tool:end") {
339
+ const metadata = event.data?.metadata ?? {};
340
+ const p = metadata.path;
341
+ if (typeof p === "string") {
342
+ scoreRepoFromToolPath(p, repoScores);
343
+ }
344
+ }
345
+ }
346
+ const ranked = Array.from(repoScores.entries()).sort((a, b) => b[1] - a[1]);
347
+ const top = ranked[0];
348
+ if (!top || top[1] < 4) {
349
+ return null;
350
+ }
351
+ const inferredDir = path.join(baseWorkingDir, top[0]);
352
+ return pathExists(inferredDir) ? inferredDir : null;
353
+ }
354
+ var run_handler_default = defineHandler({
355
+ async execute(ctx, input) {
356
+ const body = input.body;
357
+ if (!body?.task) {
358
+ throw new Error("Task is required");
359
+ }
360
+ const analytics = useAnalytics();
361
+ const runId = RunManager.generateRunId();
362
+ const startTime = Date.now();
363
+ let sessionId = body.sessionId;
364
+ let workingDir = body.workingDir || ctx.cwd;
365
+ let sessionManager = new SessionManager(workingDir);
366
+ if (!sessionId) {
367
+ const session = await sessionManager.createSession({
368
+ mode: "execute",
369
+ task: body.task,
370
+ agentId: body.agentId ?? "orchestrator"
371
+ });
372
+ sessionId = session.id;
373
+ ctx.platform.logger.info(`[run-handler] Created new session ${sessionId}`);
374
+ } else {
375
+ const existingSession = await sessionManager.loadSession(sessionId);
376
+ let resolvedSession = existingSession;
377
+ if (!resolvedSession && pathExists(ctx.cwd)) {
378
+ const fallbackManager = new SessionManager(ctx.cwd);
379
+ const fallbackSession = await fallbackManager.loadSession(sessionId);
380
+ if (fallbackSession) {
381
+ sessionManager = fallbackManager;
382
+ resolvedSession = fallbackSession;
383
+ }
384
+ }
385
+ if (!resolvedSession) {
386
+ throw new Error(`Session not found: ${sessionId} (cwd=${ctx.cwd})`);
387
+ }
388
+ workingDir = body.workingDir || resolvedSession.workingDir || workingDir;
389
+ if (!body.workingDir && isLikelyFollowUpScopeTask(body.task)) {
390
+ const inferred = await inferFollowUpWorkingDir(sessionManager, sessionId, resolvedSession.workingDir || ctx.cwd);
391
+ if (inferred && inferred !== workingDir) {
392
+ ctx.platform.logger.info(`[run-handler] Follow-up scope inferred: ${workingDir} -> ${inferred}`);
393
+ workingDir = inferred;
394
+ }
395
+ }
396
+ sessionManager = new SessionManager(workingDir);
397
+ ctx.platform.logger.info(`[run-handler] Continuing session ${sessionId} (workingDir=${workingDir})`);
398
+ }
399
+ ctx.platform.logger.info(`[run-handler] Starting run ${runId} for task: ${body.task}`);
400
+ await sessionManager.createUserTurn(sessionId, body.task, runId);
401
+ await analytics?.track(AGENT_ANALYTICS_EVENTS.RUN_STARTED, {
402
+ runId,
403
+ sessionId,
404
+ taskLength: body.task.length,
405
+ tier: body.tier ?? "medium",
406
+ enableEscalation: body.enableEscalation ?? true,
407
+ responseMode: body.responseMode ?? "auto",
408
+ verbose: body.verbose ?? false
409
+ });
410
+ const sessionMemory = createSessionMemoryBridge(workingDir, sessionId);
411
+ const responseRequirementsSelector = createDefaultResponseRequirementsSelector();
412
+ const toolRegistry = createToolRegistry({
413
+ workingDir,
414
+ currentTask: body.task,
415
+ sessionId,
416
+ verbose: body.verbose,
417
+ cache: useCache(),
418
+ sessionMemory,
419
+ responseRequirementsResolver: async ({ task, kernel }) => responseRequirementsSelector.select({
420
+ state: kernel,
421
+ messages: [],
422
+ task: task ?? body.task
423
+ })
424
+ });
425
+ const agentsConfig = await useConfig();
426
+ const finalSessionId = sessionId;
427
+ const traceDir = path.join(workingDir, ".kb", "traces", "incremental");
428
+ const traceWriter = new IncrementalTraceWriter(runId, {}, traceDir);
429
+ const agent = new AgentSDK().register(createCoreToolPack(toolRegistry)).createRunner({
430
+ sessionId: finalSessionId,
431
+ workingDir,
432
+ maxIterations: 50,
433
+ temperature: 0.1,
434
+ tier: body.tier ?? "medium",
435
+ tokenBudget: agentsConfig?.tokenBudget,
436
+ onEvent: (event) => {
437
+ const seqEvent = RunManager.broadcast(runId, event);
438
+ void sessionManager.addEvent(finalSessionId, {
439
+ ...seqEvent,
440
+ sessionId: finalSessionId,
441
+ runId,
442
+ metadata: {
443
+ ...seqEvent.metadata,
444
+ sessionId: finalSessionId,
445
+ runId,
446
+ workingDir
447
+ }
448
+ });
449
+ }
450
+ });
451
+ const run = await RunManager.register(runId, body.task, agent, sessionManager, finalSessionId);
452
+ await RunManager.updateStatus(runId, "running");
453
+ void (async () => {
454
+ try {
455
+ const result = await agent.execute(body.task);
456
+ const durationMs = Date.now() - startTime;
457
+ const detailedTrace = traceWriter.getEntries();
458
+ await traceWriter.finalize?.();
459
+ if (detailedTrace.length > 0) {
460
+ await sessionManager.storeTraceArtifacts(finalSessionId, runId, detailedTrace);
461
+ }
462
+ if (result.fileChanges && result.fileChanges.length > 0) {
463
+ await sessionManager.attachFileChangesToTurn(finalSessionId, runId, result.fileChanges);
464
+ }
465
+ await RunManager.updateStatus(runId, result.success ? "completed" : "failed", {
466
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
467
+ durationMs,
468
+ summary: result.summary,
469
+ error: result.error
470
+ });
471
+ await analytics?.track(
472
+ result.success ? AGENT_ANALYTICS_EVENTS.RUN_COMPLETED : AGENT_ANALYTICS_EVENTS.RUN_FAILED,
473
+ {
474
+ runId,
475
+ durationMs,
476
+ success: result.success,
477
+ summary: result.summary?.slice(0, 200)
478
+ }
479
+ );
480
+ ctx.platform.logger.info(`[run-handler] Run ${runId} completed: ${result.success}`);
481
+ } catch (error) {
482
+ const errorMsg = error instanceof Error ? error.message : String(error);
483
+ const durationMs = Date.now() - startTime;
484
+ const detailedTrace = traceWriter.getEntries();
485
+ await traceWriter.finalize?.();
486
+ if (detailedTrace.length > 0) {
487
+ await sessionManager.storeTraceArtifacts(finalSessionId, runId, detailedTrace);
488
+ }
489
+ await RunManager.updateStatus(runId, "failed", {
490
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
491
+ durationMs,
492
+ error: errorMsg
493
+ });
494
+ await analytics?.track(AGENT_ANALYTICS_EVENTS.RUN_FAILED, {
495
+ runId,
496
+ durationMs,
497
+ error: errorMsg.slice(0, 200)
498
+ });
499
+ ctx.platform.logger.error(`[run-handler] Run ${runId} failed: ${errorMsg}`);
500
+ }
501
+ })();
502
+ const wsPath = AGENTS_WS_CHANNELS.SESSION_STREAM.replace(":sessionId", finalSessionId);
503
+ const eventsPath = `${AGENTS_WS_BASE_PATH}${wsPath}`;
504
+ return {
505
+ runId,
506
+ sessionId: finalSessionId,
507
+ eventsPath,
508
+ status: "started",
509
+ startedAt: run.startedAt
510
+ };
511
+ }
512
+ });
513
+
514
+ // src/rest/handlers/execute-session-plan-handler.ts
515
+ async function loadPlan(planPath) {
516
+ const content = await promises.readFile(planPath, "utf-8");
517
+ return JSON.parse(content);
518
+ }
519
+ function buildExecutionTask(plan) {
520
+ const phaseLines = plan.phases.map((phase, idx) => {
521
+ const steps = phase.steps.map((step, stepIdx) => {
522
+ const tool = step.tool || "n/a";
523
+ return ` ${stepIdx + 1}. ${step.action} [tool: ${tool}]`;
524
+ }).join("\n");
525
+ return `${idx + 1}. ${phase.name}
526
+ ${steps || " (no steps)"}`;
527
+ }).join("\n");
528
+ return [
529
+ `Execute the approved implementation plan for task: ${plan.task}`,
530
+ "",
531
+ "Follow phase order and dependencies. Update progress with concrete results.",
532
+ "",
533
+ `Plan ID: ${plan.id}`,
534
+ `Complexity: ${plan.complexity}`,
535
+ `Estimated Duration: ${plan.estimatedDuration || "Unknown"}`,
536
+ "",
537
+ "Phases:",
538
+ phaseLines,
539
+ "",
540
+ "Requirements:",
541
+ "- Execute plan steps pragmatically; adapt only when blocked.",
542
+ "- Keep outputs concrete: changed files, commands run, verification results."
543
+ ].join("\n");
544
+ }
545
+ function buildExecutionTaskWithSpec(plan, spec) {
546
+ return [
547
+ `Execute the approved implementation plan for task: ${plan.task}`,
548
+ "",
549
+ `Plan ID: ${plan.id}`,
550
+ `Complexity: ${plan.complexity}`,
551
+ "",
552
+ "## DETAILED SPECIFICATION (exact changes)",
553
+ "",
554
+ "A detailed spec was generated and verified. Apply these exact changes:",
555
+ "",
556
+ spec.markdown || "(no spec markdown available)",
557
+ "",
558
+ "Requirements:",
559
+ "- Apply the before/after diffs from the spec as precisely as possible.",
560
+ "- Verify each change after applying it.",
561
+ "- If the spec code doesn't match the current file (file was modified since spec), adapt minimally.",
562
+ "- Keep outputs concrete: changed files, commands run, verification results."
563
+ ].join("\n");
564
+ }
565
+ var execute_session_plan_handler_default = defineHandler({
566
+ async execute(ctx, input) {
567
+ const params = input.params;
568
+ const sessionId = params?.sessionId;
569
+ const body = input.body ?? {};
570
+ if (!sessionId) {
571
+ throw new Error("Session ID is required");
572
+ }
573
+ const baseManager = new SessionManager(ctx.cwd);
574
+ const session = await baseManager.loadSession(sessionId);
575
+ if (!session) {
576
+ throw new Error(`Session not found: ${sessionId}`);
577
+ }
578
+ const workingDir = session.workingDir || ctx.cwd;
579
+ const sessionManager = new SessionManager(workingDir);
580
+ const planPath = sessionManager.getSessionPlanPath(sessionId);
581
+ let plan;
582
+ try {
583
+ plan = await loadPlan(planPath);
584
+ } catch {
585
+ throw new Error(`Plan not found for session ${sessionId}`);
586
+ }
587
+ if (plan.status !== "approved" && plan.status !== "spec_ready") {
588
+ throw new Error(`Plan must be approved before execution (current status: ${plan.status})`);
589
+ }
590
+ let spec = null;
591
+ try {
592
+ const specPath = sessionManager.getSessionSpecPath(sessionId);
593
+ const specContent = await promises.readFile(specPath, "utf-8");
594
+ spec = JSON.parse(specContent);
595
+ } catch {
596
+ }
597
+ const executionTask = spec?.markdown ? buildExecutionTaskWithSpec(plan, spec) : buildExecutionTask(plan);
598
+ const runInput = {
599
+ body: {
600
+ task: executionTask,
601
+ sessionId,
602
+ workingDir,
603
+ tier: body.tier,
604
+ responseMode: body.responseMode,
605
+ verbose: body.verbose,
606
+ enableEscalation: body.enableEscalation
607
+ }
608
+ };
609
+ const runResponse = await run_handler_default.execute(ctx, runInput);
610
+ const inProgressPlan = {
611
+ ...plan,
612
+ status: "in_progress",
613
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
614
+ };
615
+ await promises.writeFile(planPath, JSON.stringify(inProgressPlan, null, 2), "utf-8");
616
+ const documentService = new PlanDocumentService(workingDir);
617
+ const markdownPath = documentService.getPlanPath(plan);
618
+ await documentService.appendExecutionLog(
619
+ markdownPath,
620
+ `- ${(/* @__PURE__ */ new Date()).toISOString()}: Execution started (runId: ${runResponse.runId}).`
621
+ );
622
+ return {
623
+ sessionId,
624
+ planId: plan.id,
625
+ runId: runResponse.runId,
626
+ eventsPath: runResponse.eventsPath,
627
+ status: runResponse.status,
628
+ startedAt: runResponse.startedAt
629
+ };
630
+ }
631
+ });
632
+
633
+ export { execute_session_plan_handler_default as default };
634
+ //# sourceMappingURL=execute-session-plan-handler.js.map
635
+ //# sourceMappingURL=execute-session-plan-handler.js.map