@agimon-ai/po-task 0.0.0-alpha.7 → 0.0.0-alpha.71

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 (93) hide show
  1. package/LICENSE +149 -21
  2. package/README.md +12 -2
  3. package/dist/apiContracts.cjs +1 -0
  4. package/dist/apiContracts.cjs.map +1 -1
  5. package/dist/apiContracts.mjs +1 -0
  6. package/dist/apiContracts.mjs.map +1 -1
  7. package/dist/{delegation-Dsqf7fUM.mjs → delegation-5TOl_dEq.mjs} +4 -3
  8. package/dist/delegation-5TOl_dEq.mjs.map +1 -0
  9. package/dist/{delegation-frvEXhIz.cjs → delegation-BJtAUTVg.cjs} +4 -3
  10. package/dist/delegation-BJtAUTVg.cjs.map +1 -0
  11. package/dist/delegationManager.cjs +1 -1
  12. package/dist/delegationManager.d.mts +1 -1
  13. package/dist/delegationManager.mjs +1 -1
  14. package/dist/extensions/mcp.cjs +60 -61
  15. package/dist/extensions/mcp.cjs.map +1 -1
  16. package/dist/extensions/mcp.mjs +60 -61
  17. package/dist/extensions/mcp.mjs.map +1 -1
  18. package/dist/extensions/native.mjs +420 -315
  19. package/dist/extensions/native.mjs.map +1 -1
  20. package/dist/extensions/server.cjs +398 -136
  21. package/dist/extensions/server.cjs.map +1 -1
  22. package/dist/extensions/server.d.mts +2 -2
  23. package/dist/extensions/server.d.mts.map +1 -1
  24. package/dist/extensions/server.mjs +397 -135
  25. package/dist/extensions/server.mjs.map +1 -1
  26. package/dist/extensions/web.mjs +254 -206
  27. package/dist/extensions/web.mjs.map +1 -1
  28. package/dist/{index-DlmXKyhQ.d.mts → index-CdJx5tdI.d.mts} +2 -2
  29. package/dist/{index-DlmXKyhQ.d.mts.map → index-CdJx5tdI.d.mts.map} +1 -1
  30. package/dist/{index-B1JPJdpZ.d.mts → index-DrE00rrP.d.mts} +3 -3
  31. package/dist/{index-B1JPJdpZ.d.mts.map → index-DrE00rrP.d.mts.map} +1 -1
  32. package/dist/{index-qQGWsPum.d.mts → index-DuT-Lbxy.d.mts} +2 -3
  33. package/dist/index-DuT-Lbxy.d.mts.map +1 -0
  34. package/dist/{index-CUWCvh-E.d.mts → index-nx0ueNkm.d.mts} +2 -2
  35. package/dist/{index-CUWCvh-E.d.mts.map → index-nx0ueNkm.d.mts.map} +1 -1
  36. package/dist/{index-B9QNwUBr.d.mts → index-sahNy7Hg.d.mts} +3 -3
  37. package/dist/{index-B9QNwUBr.d.mts.map → index-sahNy7Hg.d.mts.map} +1 -1
  38. package/dist/{index-CA4Opp4r.d.mts → index-tAu1TIyi.d.mts} +4 -6
  39. package/dist/index-tAu1TIyi.d.mts.map +1 -0
  40. package/dist/index.cjs +3 -5
  41. package/dist/index.d.mts +10 -10
  42. package/dist/index.mjs +4 -4
  43. package/dist/{logSinkTelemetry-BhbKdn-x.mjs → logSinkTelemetry-3GMazFYa.mjs} +2 -2
  44. package/dist/logSinkTelemetry-3GMazFYa.mjs.map +1 -0
  45. package/dist/{logSinkTelemetry-BGb8WQBz.cjs → logSinkTelemetry-DhzIQMsV.cjs} +3 -3
  46. package/dist/logSinkTelemetry-DhzIQMsV.cjs.map +1 -0
  47. package/dist/logSinkTelemetry.cjs +1 -1
  48. package/dist/logSinkTelemetry.d.mts +1 -1
  49. package/dist/logSinkTelemetry.mjs +1 -1
  50. package/dist/{paths-P-XvOUuH.cjs → paths-CWVDY8Yd.cjs} +12 -78
  51. package/dist/paths-CWVDY8Yd.cjs.map +1 -0
  52. package/dist/{paths-DajceJig.mjs → paths-CjATVpi8.mjs} +12 -66
  53. package/dist/paths-CjATVpi8.mjs.map +1 -0
  54. package/dist/storeInvariants.d.mts +1 -1
  55. package/dist/storePaths.cjs +1 -3
  56. package/dist/storePaths.d.mts +2 -2
  57. package/dist/storePaths.mjs +1 -1
  58. package/dist/storeReconcile.d.mts +1 -1
  59. package/dist/storeReducer.d.mts +1 -1
  60. package/dist/storeTaskGraph.d.mts +1 -1
  61. package/dist/storeTaskStore.cjs +1 -1
  62. package/dist/storeTaskStore.d.mts +1 -1
  63. package/dist/storeTaskStore.mjs +1 -1
  64. package/dist/storeTypes.d.mts +1 -1
  65. package/dist/{task-4HeGAS8o.d.mts → task--hlnpS7L.d.mts} +2 -2
  66. package/dist/{task-4HeGAS8o.d.mts.map → task--hlnpS7L.d.mts.map} +1 -1
  67. package/dist/task-CXF9VULl.cjs.map +1 -1
  68. package/dist/{task-DJpTteeJ.d.mts → task-DdTKZNtU.d.mts} +3 -1
  69. package/dist/task-DdTKZNtU.d.mts.map +1 -0
  70. package/dist/task-giCbpKzV.mjs.map +1 -1
  71. package/dist/{taskGraph-D0zFHF2p.d.mts → taskGraph-CB8ffMCz.d.mts} +2 -2
  72. package/dist/{taskGraph-D0zFHF2p.d.mts.map → taskGraph-CB8ffMCz.d.mts.map} +1 -1
  73. package/dist/{taskStore-C4vcUOzA.cjs → taskStore-B-BbY2Ci.cjs} +30 -36
  74. package/dist/taskStore-B-BbY2Ci.cjs.map +1 -0
  75. package/dist/{taskStore-BAi54FKL.mjs → taskStore-wuXXFCZT.mjs} +29 -35
  76. package/dist/taskStore-wuXXFCZT.mjs.map +1 -0
  77. package/dist/toolResponseEnvelope.d.mts +1 -1
  78. package/dist/toolSchema.d.mts +1 -1
  79. package/llms.txt +11 -0
  80. package/package.json +18 -17
  81. package/src/prompts/codemode-how-to-task/SKILL.md +40 -0
  82. package/src/types/webTasks.ts +1 -0
  83. package/dist/delegation-Dsqf7fUM.mjs.map +0 -1
  84. package/dist/delegation-frvEXhIz.cjs.map +0 -1
  85. package/dist/index-CA4Opp4r.d.mts.map +0 -1
  86. package/dist/index-qQGWsPum.d.mts.map +0 -1
  87. package/dist/logSinkTelemetry-BGb8WQBz.cjs.map +0 -1
  88. package/dist/logSinkTelemetry-BhbKdn-x.mjs.map +0 -1
  89. package/dist/paths-DajceJig.mjs.map +0 -1
  90. package/dist/paths-P-XvOUuH.cjs.map +0 -1
  91. package/dist/task-DJpTteeJ.d.mts.map +0 -1
  92. package/dist/taskStore-BAi54FKL.mjs.map +0 -1
  93. package/dist/taskStore-C4vcUOzA.cjs.map +0 -1
@@ -2,27 +2,28 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_paths = require("../paths-P-XvOUuH.cjs");
5
+ const require_paths = require("../paths-CWVDY8Yd.cjs");
6
6
  const require_config = require("../config-BC-bztyx.cjs");
7
7
  const require_taskGraph = require("../taskGraph-BskRslrr.cjs");
8
8
  const require_telemetry = require("../telemetry-x3JxCA5K.cjs");
9
- const require_delegation = require("../delegation-frvEXhIz.cjs");
9
+ const require_delegation = require("../delegation-BJtAUTVg.cjs");
10
10
  const require_taskResult = require("../taskResult-D2G7b4w-.cjs");
11
11
  const require_task = require("../task-UvW877Ez.cjs");
12
12
  const require_reducer = require("../reducer-BV0YIZ2o.cjs");
13
- const require_taskStore = require("../taskStore-C4vcUOzA.cjs");
14
- const require_logSinkTelemetry = require("../logSinkTelemetry-BGb8WQBz.cjs");
13
+ const require_taskStore = require("../taskStore-B-BbY2Ci.cjs");
14
+ const require_logSinkTelemetry = require("../logSinkTelemetry-DhzIQMsV.cjs");
15
15
  let _agimon_ai_po_core_delegation = require("@agimon-ai/po-core/delegation");
16
16
  let node_path = require("node:path");
17
17
  node_path = require_paths.__toESM(node_path, 1);
18
- let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
18
+ let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
19
19
  let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
20
20
  let _agimon_ai_po_core_backgroundWork = require("@agimon-ai/po-core/backgroundWork");
21
+ let _agimon_ai_po_core_codemode = require("@agimon-ai/po-core/codemode");
21
22
  let _agimon_ai_po_core_contextContributions = require("@agimon-ai/po-core/contextContributions");
22
23
  let _agimon_ai_po_core_readiness = require("@agimon-ai/po-core/readiness");
23
24
  let node_crypto = require("node:crypto");
24
- let _agimon_ai_po_core_hubChannel = require("@agimon-ai/po-core/hubChannel");
25
25
  let typebox_value = require("typebox/value");
26
+ let _agimon_ai_po_core_hubChannel = require("@agimon-ai/po-core/hubChannel");
26
27
  //#region src/services/contextContribution/index.ts
27
28
  const TASK_CONTEXT_CONTRIBUTION_SOURCE = "@agimon-ai/po-task";
28
29
  const TASK_CONTEXT_CONTRIBUTION_ID = "active-tasks";
@@ -82,6 +83,315 @@ function createNodeDelegationPlatform(environment = process.env) {
82
83
  };
83
84
  }
84
85
  //#endregion
86
+ //#region src/services/taskTool/index.ts
87
+ function output(value) {
88
+ if (typeof value === "object" && value !== null && "content" in value) return value;
89
+ return {
90
+ content: [{
91
+ type: "text",
92
+ text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
93
+ }],
94
+ details: value
95
+ };
96
+ }
97
+ function failure(error) {
98
+ return {
99
+ content: [{
100
+ type: "text",
101
+ text: error instanceof Error ? error.message : String(error)
102
+ }],
103
+ isError: true
104
+ };
105
+ }
106
+ async function reducerAction(store, action, params, maxTasks) {
107
+ const { document, value } = await store.mutate((current) => {
108
+ const result = require_reducer.applyTaskMutation(current, action, params, void 0, maxTasks);
109
+ return {
110
+ ...require_reducer.isCommittingOp(result.op) ? { document: result.document } : {},
111
+ value: result
112
+ };
113
+ });
114
+ if (value.op.kind === "error") throw new Error(value.op.message);
115
+ return require_taskResult.buildToolResult(action, params, document, value.op);
116
+ }
117
+ async function assignmentBatch(manager, assignments, signal) {
118
+ const result = [];
119
+ for (const [index, assignment] of assignments.entries()) try {
120
+ const outcome = await manager.assign(assignment.id, {
121
+ agent: assignment.agent,
122
+ inlineAgent: assignment.inlineAgent,
123
+ instructions: assignment.instructions,
124
+ relevantFiles: assignment.relevantFiles,
125
+ priorFindings: assignment.priorFindings,
126
+ model: assignment.model,
127
+ ...assignment.context === "fork" || assignment.context === "fresh" ? { context: assignment.context } : {},
128
+ signal
129
+ });
130
+ result.push({
131
+ index,
132
+ id: assignment.id,
133
+ agent: assignment.agent,
134
+ ...outcome
135
+ });
136
+ } catch (error) {
137
+ result.push({
138
+ index,
139
+ id: assignment.id,
140
+ agent: assignment.agent,
141
+ ok: false,
142
+ message: String(error)
143
+ });
144
+ }
145
+ return result;
146
+ }
147
+ /** One task action against the session store, shared by the `task` tool and the `tasks` code-mode namespace. */
148
+ async function runTaskAction(store, manager, maxTasks, rawParams, signal, onUpdate) {
149
+ if (!(0, typebox_value.Check)(require_task.TaskParamsSchema, rawParams)) {
150
+ const [first] = (0, typebox_value.Errors)(require_task.TaskParamsSchema, rawParams);
151
+ return failure(`Invalid task parameters${first ? `: ${first.instancePath || "/"} ${first.message}` : ""}.`);
152
+ }
153
+ const params = rawParams;
154
+ try {
155
+ if ((params.action === "assign" || params.action === "cancel") && !manager) throw new Error("Delegation is not available on this connection.");
156
+ if (params.action === "assign") {
157
+ if (!params.assignments?.length) throw new Error("assign requires a non-empty assignments[] array");
158
+ onUpdate?.(output(`Delegating ${params.assignments.length} task${params.assignments.length === 1 ? "" : "s"}...`));
159
+ const items = await assignmentBatch(manager, params.assignments, signal);
160
+ const assigned = items.filter((item) => item.ok).map((item) => item.id);
161
+ const text = require_taskResult.formatAssignmentResults(items);
162
+ if (assigned.length === 0) throw new Error(text);
163
+ return require_taskResult.buildAssignmentResult(params, store.snapshot, text, {
164
+ assigned,
165
+ failed: items.length - assigned.length
166
+ });
167
+ }
168
+ if (params.action === "cancel") {
169
+ const outcome = await manager.cancel(params.id ?? NaN);
170
+ if (!outcome.ok) throw new Error(outcome.message);
171
+ return require_taskResult.buildTextResult("cancel", params, store.snapshot, outcome.message);
172
+ }
173
+ return reducerAction(store, params.action, params, maxTasks);
174
+ } catch (error) {
175
+ return failure(error);
176
+ }
177
+ }
178
+ function createHeadlessTaskTool(store, manager, maxTasks) {
179
+ return {
180
+ name: "task",
181
+ label: "Task",
182
+ description: "Maintain a persistent task graph and delegate ready tasks to background agents.",
183
+ parameters: require_task.TaskParamsSchema,
184
+ promptSnippet: "Track complex work persistently and delegate ready tasks",
185
+ executionMode: "serial",
186
+ execute: (_toolCallId, rawParams, signal, onUpdate) => runTaskAction(store, manager, maxTasks, rawParams, signal, onUpdate)
187
+ };
188
+ }
189
+ //#endregion
190
+ //#region src/services/taskNamespace/index.ts
191
+ const DECLARATIONS = `type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'deleted';
192
+
193
+ type DelegationState = 'requested' | 'running' | 'completed' | 'failed' | 'cancelled';
194
+
195
+ interface DelegationResult {
196
+ status: string;
197
+ output?: string;
198
+ outputPath?: string;
199
+ sessionFile?: string;
200
+ error?: string;
201
+ durationMs?: number;
202
+ toolCount?: number;
203
+ }
204
+
205
+ interface TaskDelegation {
206
+ requestId: string;
207
+ agent: string;
208
+ identity?: string;
209
+ state: DelegationState;
210
+ sessionId?: string;
211
+ pid?: number;
212
+ runId?: string;
213
+ model?: string;
214
+ startedAt?: string;
215
+ endedAt?: string;
216
+ result?: DelegationResult;
217
+ }
218
+
219
+ interface Task {
220
+ id: number;
221
+ subject: string;
222
+ description?: string;
223
+ activeForm?: string;
224
+ status: TaskStatus;
225
+ blockedBy?: number[];
226
+ owner?: string;
227
+ metadata?: Record<string, unknown>;
228
+ createdAt?: string;
229
+ updatedAt?: string;
230
+ delegation?: TaskDelegation;
231
+ }
232
+
233
+ interface TaskDocument {
234
+ version: number;
235
+ rev: number;
236
+ nextId: number;
237
+ tasks: Task[];
238
+ }
239
+ interface TaskItem {
240
+ /** Existing task id to change. Omit to create; an unknown id fails only that entry. */
241
+ id?: number;
242
+ /** Temporary name so a LATER entry in the same call can list it in blockedBy. Never stored. */
243
+ ref?: string;
244
+ /** Short and imperative. Required when creating. */
245
+ subject?: string;
246
+ /** The durable brief handed to a subagent on assign. */
247
+ description?: string;
248
+ /** Present-continuous label shown while in_progress, such as 'writing tests'. */
249
+ activeForm?: string;
250
+ status?: TaskStatus;
251
+ /** For a NEW entry: task ids or earlier refs. */
252
+ blockedBy?: (number | string)[];
253
+ /** For an entry with an id: dependencies to add or remove. */
254
+ addBlockedBy?: (number | string)[];
255
+ removeBlockedBy?: (number | string)[];
256
+ owner?: string;
257
+ /** Merged into the task; a null value deletes that key. */
258
+ metadata?: Record<string, unknown>;
259
+ }
260
+
261
+ interface TaskAssignment {
262
+ /** A pending, unblocked task. */
263
+ id: number;
264
+ /** Exact name from subagent({ action: 'agents' }). */
265
+ agent: string;
266
+ instructions?: string;
267
+ /** Only files you actually read or located. */
268
+ relevantFiles?: string[];
269
+ /** Only verified facts, not directives. */
270
+ priorFindings?: string;
271
+ model?: string;
272
+ context?: 'fresh' | 'fork';
273
+ }
274
+
275
+ /** What a write returns: the text the task tool would print, and the graph after the write. */
276
+ interface TaskWrite {
277
+ message: string;
278
+ document: TaskDocument;
279
+ /** upsert only: ids that landed and how many entries failed. Nothing landing throws; a partial failure does not. */
280
+ applied?: number[];
281
+ failed?: number;
282
+ }
283
+ declare const tasks: {
284
+ /** The whole task graph, tombstones included. Filter it in the script. */
285
+ snapshot(): Promise<TaskDocument>;
286
+ /**
287
+ * Create or change tasks, applied in array order. Never mark a task completed while tests fail or the
288
+ * work is partial: use failed, or keep it in_progress and add a task for the blocker in the same call.
289
+ * Status flow is pending, in_progress, completed. failed is recoverable and deleted is a tombstone.
290
+ */
291
+ upsert(tasks: TaskItem[]): Promise<TaskWrite>;
292
+ /** Tombstone one task. Refused while it has a running delegation. */
293
+ delete(id: number): Promise<TaskWrite>;
294
+ /** Remove every task. Refused while a delegation is running. */
295
+ clear(): Promise<TaskWrite>;
296
+ /** Hand ready tasks to background subagents. Batch independent tasks in one call. */
297
+ assign(assignments: TaskAssignment[]): Promise<TaskWrite>;
298
+ /** Cancel a task's running delegation. */
299
+ cancel(id: number): Promise<TaskWrite>;
300
+ };`;
301
+ /** The owning session's task graph: `snapshot` reads without locking, the rest write through the same store as the `task` tool. */
302
+ function createTaskNamespace(options) {
303
+ return {
304
+ name: "tasks",
305
+ summary: "The session task graph: tasks.snapshot() reads it, tasks.upsert/delete/clear change it, tasks.assign/cancel hand tasks to background subagents. Use it to track multi-step work.",
306
+ declarations: DECLARATIONS,
307
+ bind(run) {
308
+ if (run.sessionId !== options.sessionId) throw new Error("Tasks namespace belongs to another session.");
309
+ let disposed = false;
310
+ run.onDispose(() => {
311
+ disposed = true;
312
+ });
313
+ const assertAvailable = () => {
314
+ run.signal.throwIfAborted();
315
+ if (disposed) throw new Error("Tasks namespace run is disposed.");
316
+ options.assertAvailable();
317
+ };
318
+ const members = Object.create(null);
319
+ members.snapshot = async () => {
320
+ assertAvailable();
321
+ const storePath = options.store.storePath;
322
+ const errors = [];
323
+ const document = await options.store.readAsync(() => false, (error) => errors.push(error));
324
+ assertAvailable();
325
+ if (options.store.storePath !== storePath) throw new Error("Task store path changed during snapshot.");
326
+ if (errors.length > 0) throw new Error("Task snapshot read failed.", { cause: errors[0] });
327
+ return JSON.parse(JSON.stringify(document));
328
+ };
329
+ const write = async (params) => {
330
+ assertAvailable();
331
+ const started = Date.now();
332
+ const result = await runTaskAction(options.store, options.manager, options.maxTasks, params, run.signal);
333
+ assertAvailable();
334
+ const message = result.content.flatMap((part) => part.type === "text" ? [part.text] : []).join("\n");
335
+ const upsert = result.details?.upsert;
336
+ const failure = result.isError || upsert && upsert.applied.length === 0 && upsert.failed > 0 ? message : void 0;
337
+ run.record?.({
338
+ name: `tasks.${String(params.action)}`,
339
+ tool: "task",
340
+ args: params,
341
+ ok: failure === void 0,
342
+ ms: Date.now() - started,
343
+ ...failure === void 0 ? {} : { error: failure },
344
+ result: {
345
+ content: result.content,
346
+ details: result.details
347
+ }
348
+ });
349
+ if (failure !== void 0) throw new Error(failure);
350
+ return {
351
+ message,
352
+ document: JSON.parse(JSON.stringify(options.store.snapshot)),
353
+ ...upsert ? {
354
+ applied: upsert.applied,
355
+ failed: upsert.failed
356
+ } : {}
357
+ };
358
+ };
359
+ members.upsert = (tasks) => write({
360
+ action: "upsert",
361
+ tasks: entriesWithIds(tasks)
362
+ });
363
+ members.list = members.snapshot;
364
+ members.delete = (id) => write({
365
+ action: "delete",
366
+ id: taskId(id)
367
+ });
368
+ members.clear = () => write({ action: "clear" });
369
+ members.assign = (assignments) => write({
370
+ action: "assign",
371
+ assignments: entriesWithIds(assignments)
372
+ });
373
+ members.cancel = (id) => write({
374
+ action: "cancel",
375
+ id: taskId(id)
376
+ });
377
+ return members;
378
+ }
379
+ };
380
+ }
381
+ /** `'3'` becomes `3`, as the `task` tool's argument coercion does; anything else is left for validation to reject. */
382
+ function taskId(value) {
383
+ return typeof value === "string" && /^\d+$/.test(value) ? Number(value) : value;
384
+ }
385
+ /** One entry becomes a list, and each entry's id goes through `taskId`. The caller's objects are not changed. */
386
+ function entriesWithIds(value) {
387
+ const entries = value !== null && typeof value === "object" && !Array.isArray(value) ? [value] : value;
388
+ if (!Array.isArray(entries)) return entries;
389
+ return entries.map((entry) => entry !== null && typeof entry === "object" && "id" in entry ? {
390
+ ...entry,
391
+ id: taskId(entry.id)
392
+ } : entry);
393
+ }
394
+ //#endregion
85
395
  //#region src/types/webTasks.ts
86
396
  /** Browser-safe task view published by the cockpit hub channel. */
87
397
  const TASKS_CHANNEL_TYPE = "task_graph";
@@ -95,7 +405,7 @@ function headlineOf(content) {
95
405
  const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ host: serverHost, agent: host, signal: pluginSignal }) => {
96
406
  if (!host) throw new Error("Task session requires the headless host.");
97
407
  const execution = host.context;
98
- if (serverHost.context.directEvents === void 0) throw new Error("Task headless facet requires the session direct event bus.");
408
+ if (serverHost.context.directEvents === void 0) throw new Error("Task server plugin requires the session direct event bus.");
99
409
  const directEvents = serverHost.context.directEvents;
100
410
  const reporter = require_logSinkTelemetry.createTaskErrorReporter({
101
411
  cwd: execution.cwd,
@@ -180,6 +490,25 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ host: serverHos
180
490
  },
181
491
  services: [(serviceContextOwner) => {
182
492
  serviceContext = serviceContextOwner;
493
+ const namespace = createTaskNamespace({
494
+ store,
495
+ manager,
496
+ maxTasks,
497
+ sessionId: execution.sessionId,
498
+ assertAvailable: () => {
499
+ if (!active || disposed || pluginSignal?.aborted) throw new Error("Task session is unavailable.");
500
+ }
501
+ });
502
+ serviceContextOwner.inject([_agimon_ai_po_core_codemode.PO_CODEMODE_SERVICE], (context) => {
503
+ const codemode = (0, _agimon_ai_po_core_codemode.readPoCodemode)(context);
504
+ if (!codemode) return void 0;
505
+ const registration = codemode.register(SOURCE, namespace);
506
+ const restriction = host.registerToolRestriction({ excludedTools: ["task"] });
507
+ return () => {
508
+ restriction.dispose();
509
+ registration.dispose();
510
+ };
511
+ });
183
512
  serviceContextOwner.inject([_agimon_ai_po_core_contextContributions.PO_CONTEXT_CONTRIBUTIONS_SERVICE], (context) => {
184
513
  const registration = (0, _agimon_ai_po_core_contextContributions.requirePoContextContributions)(context).register(createTaskContextContribution(() => active && !disposed ? store.snapshot.tasks : []));
185
514
  return () => registration.dispose();
@@ -226,9 +555,9 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ host: serverHos
226
555
  if (!isCurrent()) return { value: void 0 };
227
556
  store.configureSession(require_paths.resolveSessionKey(activityContext.sessionId, activityContext.environment));
228
557
  manager.setCwd(activityContext.cwd);
229
- const cleanup = await require_paths.removeLegacyStoreDirectoryAsync(store.storePath, activityContext.cwd);
558
+ const cleanup = await require_paths.removeLegacyStoreDirectory(store.storePath, activityContext.cwd);
230
559
  if (!isCurrent()) return { value: void 0 };
231
- const sweep = require_paths.hasStorePathOverride(activityContext.environment) ? { errors: [] } : await require_paths.sweepStoreFilesAsync(store.storePath, require_config.getStoreTtlMs(activityContext.environment));
560
+ const sweep = require_paths.hasStorePathOverride(activityContext.environment) ? { errors: [] } : await require_paths.sweepStoreFiles(store.storePath, require_config.getStoreTtlMs(activityContext.environment));
232
561
  for (const error of [...cleanup.errors, ...sweep.errors]) {
233
562
  diagnostics.push(error);
234
563
  report.warn(require_telemetry.TASK_EVENT.storeSweepFailed, new Error(error));
@@ -282,12 +611,14 @@ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)(({ host: serverHos
282
611
  generation += 1;
283
612
  startupAbort.abort();
284
613
  await Promise.allSettled([startup]);
285
- unwatch?.();
286
- background?.dispose();
287
- manager.dispose();
288
- store.dispose();
289
- await ownedReadiness.dispose();
290
- await reporter.shutdown();
614
+ await (0, _agimon_ai_po_core_extensionFile.runCleanups)([
615
+ () => unwatch?.(),
616
+ () => background?.dispose(),
617
+ () => manager.dispose(),
618
+ () => store.dispose(),
619
+ () => ownedReadiness.dispose(),
620
+ () => reporter.shutdown()
621
+ ], "Task cleanup failed.");
291
622
  }
292
623
  };
293
624
  });
@@ -315,6 +646,7 @@ function present(document) {
315
646
  if (task.updatedAt) view.updatedAt = task.updatedAt;
316
647
  if (task.delegation) view.delegation = {
317
648
  ...task.delegation.agent === void 0 ? {} : { agent: task.delegation.agent },
649
+ ...task.delegation.identity === void 0 ? {} : { identity: task.delegation.identity },
318
650
  ...task.delegation.state === void 0 ? {} : { state: task.delegation.state }
319
651
  };
320
652
  return [view];
@@ -328,8 +660,9 @@ function createTasksChannel(options = {}) {
328
660
  frameType: TASKS_CHANNEL_TYPE,
329
661
  start(host) {
330
662
  const stores = /* @__PURE__ */ new Map();
331
- const open = (scope) => {
332
- if (stores.has(scope.sessionId)) return;
663
+ let closed = false;
664
+ const open = async (scope) => {
665
+ if (closed || stores.has(scope.sessionId)) return;
333
666
  let store = options.storeFor?.(scope);
334
667
  if (store === void 0) {
335
668
  if (scope.environment === void 0) throw new Error(`Task channel requires an admitted environment for session '${scope.sessionId}'.`);
@@ -339,12 +672,21 @@ function createTasksChannel(options = {}) {
339
672
  storePath: require_paths.resolveStorePath(scope.cwd, scope.environment, require_paths.resolveSessionKey(scope.sessionId, scope.environment))
340
673
  });
341
674
  }
342
- store.read();
343
675
  const source = {
344
676
  store,
345
- unsubscribe: () => void 0
677
+ unsubscribe: () => void 0,
678
+ ready: false,
679
+ latest: void 0
346
680
  };
347
681
  stores.set(scope.sessionId, source);
682
+ try {
683
+ await store.readAsync();
684
+ } catch (error) {
685
+ if (stores.get(scope.sessionId) === source) close(scope.sessionId);
686
+ throw error;
687
+ }
688
+ if (closed || stores.get(scope.sessionId) !== source) return;
689
+ source.ready = true;
348
690
  source.unsubscribe = host.directEvents.subscribe(TASKS_CHANNEL_TYPE, scope.sessionId, (payload) => {
349
691
  if (!isTaskDocument(payload)) return;
350
692
  const current = stores.get(scope.sessionId);
@@ -352,6 +694,12 @@ function createTasksChannel(options = {}) {
352
694
  current.latest = payload;
353
695
  host.publish(scope.sessionId, present(payload));
354
696
  }, { replayLatest: true });
697
+ if (!source.latest && store.snapshot.tasks.length > 0) host.publish(scope.sessionId, present(store.snapshot));
698
+ };
699
+ const requestOpen = (scope) => {
700
+ open(scope).catch((error) => {
701
+ host.onNotice(`Could not open task store for session '${scope.sessionId}': ${String(error)}`);
702
+ });
355
703
  };
356
704
  const close = (sessionId) => {
357
705
  const source = stores.get(sessionId);
@@ -360,12 +708,11 @@ function createTasksChannel(options = {}) {
360
708
  source.store.dispose();
361
709
  stores.delete(sessionId);
362
710
  };
363
- for (const scope of host.sessions()) open(scope);
711
+ for (const scope of host.sessions()) requestOpen(scope);
364
712
  return {
365
713
  homeFor(scope) {
366
- open(scope);
367
714
  const source = stores.get(scope.sessionId);
368
- const document = source?.latest ?? source?.store.snapshot;
715
+ const document = source?.ready ? source.latest ?? source.store.snapshot : void 0;
369
716
  if (!document) return {
370
717
  coverage: "unavailable",
371
718
  entities: []
@@ -416,14 +763,15 @@ function createTasksChannel(options = {}) {
416
763
  };
417
764
  },
418
765
  payloadFor(scope) {
419
- open(scope);
766
+ requestOpen(scope);
420
767
  const source = stores.get(scope.sessionId);
421
- const document = source?.latest ?? source?.store.snapshot;
768
+ const document = source?.ready ? source.latest ?? source.store.snapshot : void 0;
422
769
  return document === void 0 ? void 0 : present(document);
423
770
  },
424
- sessionAdded: open,
771
+ sessionAdded: requestOpen,
425
772
  sessionRemoved: close,
426
773
  close() {
774
+ closed = true;
427
775
  for (const sessionId of stores.keys()) close(sessionId);
428
776
  }
429
777
  };
@@ -434,105 +782,6 @@ function createTasksChannel(options = {}) {
434
782
  //#region src/extensions/(backend)/channel/task-graph.server.ts
435
783
  var task_graph_server_default = (0, _agimon_ai_po_core_extensionFile.defineChannel)(createTasksChannel);
436
784
  //#endregion
437
- //#region src/services/taskTool/index.ts
438
- function output(value) {
439
- if (typeof value === "object" && value !== null && "content" in value) return value;
440
- return {
441
- content: [{
442
- type: "text",
443
- text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
444
- }],
445
- details: value
446
- };
447
- }
448
- function failure(error) {
449
- return {
450
- content: [{
451
- type: "text",
452
- text: error instanceof Error ? error.message : String(error)
453
- }],
454
- isError: true
455
- };
456
- }
457
- async function reducerAction(store, action, params, maxTasks) {
458
- const { document, value } = await store.mutate((current) => {
459
- const result = require_reducer.applyTaskMutation(current, action, params, void 0, maxTasks);
460
- return {
461
- ...require_reducer.isCommittingOp(result.op) ? { document: result.document } : {},
462
- value: result
463
- };
464
- });
465
- if (value.op.kind === "error") throw new Error(value.op.message);
466
- return require_taskResult.buildToolResult(action, params, document, value.op);
467
- }
468
- async function assignmentBatch(manager, assignments, signal) {
469
- const result = [];
470
- for (const [index, assignment] of assignments.entries()) try {
471
- const outcome = await manager.assign(assignment.id, {
472
- agent: assignment.agent,
473
- inlineAgent: assignment.inlineAgent,
474
- instructions: assignment.instructions,
475
- relevantFiles: assignment.relevantFiles,
476
- priorFindings: assignment.priorFindings,
477
- model: assignment.model,
478
- ...assignment.context === "fork" || assignment.context === "fresh" ? { context: assignment.context } : {},
479
- signal
480
- });
481
- result.push({
482
- index,
483
- id: assignment.id,
484
- agent: assignment.agent,
485
- ...outcome
486
- });
487
- } catch (error) {
488
- result.push({
489
- index,
490
- id: assignment.id,
491
- agent: assignment.agent,
492
- ok: false,
493
- message: String(error)
494
- });
495
- }
496
- return result;
497
- }
498
- function createHeadlessTaskTool(store, manager, maxTasks) {
499
- return {
500
- name: "task",
501
- label: "Task",
502
- description: "Maintain a persistent task graph and delegate ready tasks to background agents.",
503
- parameters: require_task.TaskParamsSchema,
504
- promptSnippet: "Track complex work persistently and delegate ready tasks",
505
- executionMode: "serial",
506
- async execute(_toolCallId, rawParams, signal, onUpdate) {
507
- if (!(0, typebox_value.Check)(require_task.TaskParamsSchema, rawParams)) return failure("Invalid task parameters.");
508
- const params = rawParams;
509
- try {
510
- if ((params.action === "assign" || params.action === "cancel") && !manager) throw new Error("Delegation is not available on this connection.");
511
- if (params.action === "assign") {
512
- if (!params.assignments?.length) throw new Error("assign requires a non-empty assignments[] array");
513
- onUpdate?.(output(`Delegating ${params.assignments.length} task${params.assignments.length === 1 ? "" : "s"}...`));
514
- const items = await assignmentBatch(manager, params.assignments, signal);
515
- const assigned = items.filter((item) => item.ok).map((item) => item.id);
516
- const text = require_taskResult.formatAssignmentResults(items);
517
- if (assigned.length === 0) throw new Error(text);
518
- return require_taskResult.buildAssignmentResult(params, store.snapshot, text, {
519
- assigned,
520
- failed: items.length - assigned.length
521
- });
522
- }
523
- if (params.action === "cancel") {
524
- const outcome = await manager.cancel(params.id ?? NaN);
525
- if (!outcome.ok) throw new Error(outcome.message);
526
- return require_taskResult.buildTextResult("cancel", params, store.snapshot, outcome.message);
527
- }
528
- return reducerAction(store, params.action, params, maxTasks);
529
- } catch (error) {
530
- return failure(error);
531
- }
532
- }
533
- };
534
- }
535
- //#endregion
536
785
  //#region src/extensions/workspaces/sessions/(backend)/command/_lib/tasks.server.ts
537
786
  var tasks_server_default$1 = (context) => ({
538
787
  name: require_task.COMMAND_NAME,
@@ -550,12 +799,22 @@ var tasks_server_default$1 = (context) => ({
550
799
  //#region src/extensions/workspaces/sessions/(backend)/command/tasks.server.ts
551
800
  var tasks_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerCommand)(tasks_server_default$1);
552
801
  //#endregion
802
+ //#region src/extensions/workspaces/sessions/(backend)/resource/codemode-how-to-task.server.ts
803
+ var codemode_how_to_task_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
804
+ name: "codemode-how-to-task",
805
+ description: "Track work as a task list with the tasks namespace, so the plan and its progress survive compaction, and hand tasks to background subagents. Use at the start of any request with three or more steps, when the person gives a list of things to do, or before delegating work.",
806
+ kind: "skill",
807
+ pinned: true,
808
+ path: (0, _agimon_ai_po_core_serverPlugin.packageResourcePath)(require("url").pathToFileURL(__filename).href, "src/prompts/codemode-how-to-task/SKILL.md"),
809
+ read: () => (0, _agimon_ai_po_core_serverPlugin.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/codemode-how-to-task/SKILL.md")
810
+ });
811
+ //#endregion
553
812
  //#region src/extensions/workspaces/sessions/(backend)/resource/_lib/task-board.server.ts
554
813
  var task_board_server_default$1 = (context) => ({
555
814
  name: "po/task-board",
556
815
  kind: "context",
557
816
  /**
558
- * The same bounded projection the Pi facet renders: open work only, one line each.
817
+ * The same bounded projection the Pi extension renders: open work only, one line each.
559
818
  * Dumping the whole TaskDocument put every completed task plus the store's own
560
819
  * version/rev/nextId bookkeeping in the prompt, and an idle board still cost a
561
820
  * paragraph. '' is dropped by the prompt composer.
@@ -577,21 +836,24 @@ var task_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)
577
836
  //#endregion
578
837
  //#region generated/server.ts
579
838
  const at = (value, context) => typeof value === "function" ? value(context) : value;
839
+ /* v8 ignore next -- generated normalization branch */
840
+ const defined = (values) => values.filter((value) => value !== void 0);
580
841
  const via = (identity, value) => value === void 0 ? void 0 : {
581
842
  ...identity,
582
843
  ...value
583
844
  };
584
- const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
845
+ const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
585
846
  name: "@agimon-ai/po-task",
586
- providerOverrides: (0, _agimon_ai_po_core_serverFacet.composeServerProviderOverrides)(root_server_default),
587
- global: () => ({ get channels() {
588
- return [() => via({ frameType: "task_graph" }, task_graph_server_default())];
847
+ providerOverrides: (0, _agimon_ai_po_core_serverPlugin.composeServerProviderOverrides)(root_server_default),
848
+ injects: (0, _agimon_ai_po_core_extensionFile.composeRootInjects)({ session: [root_server_default] }),
849
+ global: (context) => ({ get channels() {
850
+ return [() => via({ frameType: "task_graph" }, at(task_graph_server_default, context))];
589
851
  } }),
590
- workspace: () => ({ get channels() {
591
- return [() => via({ frameType: "task_graph" }, task_graph_server_default())];
852
+ workspace: (context) => ({ get channels() {
853
+ return defined([context.hosted("global") ? void 0 : () => via({ frameType: "task_graph" }, at(task_graph_server_default, context))]);
592
854
  } }),
593
855
  session: async (context) => {
594
- const scopeSession = await root_server_default(context);
856
+ const scopeSession = await context.scopeRoot("session", root_server_default, context);
595
857
  const contextSession = {
596
858
  ...context,
597
859
  root: scopeSession.value
@@ -599,13 +861,13 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
599
861
  return {
600
862
  ...(0, _agimon_ai_po_core_extensionFile.composeRootHooks)(scopeSession),
601
863
  get channels() {
602
- return [() => via({ frameType: "task_graph" }, task_graph_server_default())];
864
+ return defined([context.hosted("global") ? void 0 : () => via({ frameType: "task_graph" }, at(task_graph_server_default, context))]);
603
865
  },
604
866
  get commands() {
605
867
  return [via({ name: "tasks" }, at(tasks_server_default, contextSession))];
606
868
  },
607
869
  get resources() {
608
- return [at(task_board_server_default, contextSession)];
870
+ return [at(codemode_how_to_task_server_default, contextSession), at(task_board_server_default, contextSession)];
609
871
  },
610
872
  get tools() {
611
873
  return [via({ name: "task" }, at(task_server_default, contextSession))];
@@ -618,7 +880,7 @@ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
618
880
  }
619
881
  });
620
882
  //#endregion
621
- exports.default = facet;
622
- exports.facet = facet;
883
+ exports.default = serverPlugin;
884
+ exports.serverPlugin = serverPlugin;
623
885
 
624
886
  //# sourceMappingURL=server.cjs.map