openfox 1.6.102 → 2.0.0-beta.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 (39) hide show
  1. package/dist/agent-defaults/builder.agent.md +1 -2
  2. package/dist/agent-defaults/code-reviewer.agent.md +16 -9
  3. package/dist/agent-defaults/planner.agent.md +1 -1
  4. package/dist/agent-defaults/verifier.agent.md +2 -3
  5. package/dist/{auto-compaction-7LMAY5JV.js → auto-compaction-UIWTO3H5.js} +6 -6
  6. package/dist/{chat-handler-ZJVIM7U4.js → chat-handler-IVIWOR3D.js} +9 -10
  7. package/dist/{chunk-RYEZ7LDX.js → chunk-ALH4KM2Y.js} +108 -231
  8. package/dist/{chunk-RCQOHFAN.js → chunk-CEZNMLOO.js} +10 -2
  9. package/dist/{chunk-ZPCJLFAG.js → chunk-CTQ2FS4K.js} +501 -263
  10. package/dist/{chunk-MEYDERUX.js → chunk-FQLK5GL5.js} +1 -1
  11. package/dist/{chunk-AI3CY7T6.js → chunk-JZQ644DE.js} +7 -5
  12. package/dist/{chunk-6WZI6F6G.js → chunk-NONI4CRP.js} +19 -1
  13. package/dist/{chunk-IZC2EZ4D.js → chunk-QFSSKIQ3.js} +4 -4
  14. package/dist/{chunk-PDPXHSNZ.js → chunk-UFY4I643.js} +4 -4
  15. package/dist/{chunk-J335KZ6U.js → chunk-XKR3HCAL.js} +14 -3
  16. package/dist/cli/dev.js +25 -1
  17. package/dist/cli/index.js +25 -1
  18. package/dist/cli/update.sh +8 -3
  19. package/dist/{events-OKTZRT3Y.js → events-OHJWCI3S.js} +5 -3
  20. package/dist/{folding-Z3OMWNOE.js → folding-U6UHQAS5.js} +4 -2
  21. package/dist/{orchestrator-5EYWRAZ2.js → orchestrator-7ZXM4J22.js} +7 -7
  22. package/dist/package.json +1 -1
  23. package/dist/{processor-XJYCHNV6.js → processor-TKBJLQ2N.js} +7 -7
  24. package/dist/{protocol-CdVNdXi8.d.ts → protocol-BQ12Aw5J.d.ts} +14 -3
  25. package/dist/{protocol-TNC6MCJV.js → protocol-K62EPEGS.js} +5 -3
  26. package/dist/{serve-SGFEQ5N7.js → serve-FGPHMDOC.js} +8 -8
  27. package/dist/server/index.d.ts +7 -1
  28. package/dist/server/index.js +7 -7
  29. package/dist/{service-EUOBAATS.js → service-GB7AIOG5.js} +10 -4
  30. package/dist/shared/index.d.ts +2 -2
  31. package/dist/shared/index.js +1 -1
  32. package/dist/{tools-WFIYKFBE.js → tools-Z7X4HXZN.js} +6 -6
  33. package/dist/web/assets/index-BDezz42a.js +299 -0
  34. package/dist/web/assets/{index-aAebFDVk.css → index-BY8EbT5Z.css} +1 -1
  35. package/dist/web/index.html +2 -2
  36. package/dist/web/sw.js +1 -1
  37. package/dist/workflow-defaults/default.workflow.json +49 -10
  38. package/package.json +1 -1
  39. package/dist/web/assets/index-DcGVOFte.js +0 -299
@@ -11,8 +11,7 @@ allowedTools:
11
11
  - edit_file
12
12
  - run_command
13
13
  - ask_user
14
- - criterion:complete,get
15
- - todo:list,add,write,update,remove
14
+ - session_metadata:get,add,update,remove
16
15
  - call_sub_agent
17
16
  - load_skill
18
17
  - dev_server
@@ -3,19 +3,26 @@ id: code_reviewer
3
3
  name: Code Reviewer
4
4
  description: Review code changes for quality, bugs, and best practices
5
5
  subagent: true
6
- color: '#3b82f6'
6
+ color: '#ef4444'
7
7
  allowedTools:
8
8
  - read_file
9
9
  - web_fetch
10
+ - session_metadata:get,add,update,remove
10
11
  ---
11
12
 
12
- You are a senior code reviewer.
13
- Review the provided code changes for:
13
+ You are a code reviewer. Review all current changes.
14
+ You're mostly interested in:
14
15
 
15
- - Bugs and logic errors
16
- - Security vulnerabilities
17
- - Performance issues
18
- - Code style and best practices
19
- - Missing edge cases
16
+ 1. **For the user (UX interaction)** — does this feel good to use? Any rough edges, confusing behavior, or unnecessary friction?
17
+ 2. **For the project (code quality + guidelines)** — does this follow project conventions? Is it maintainable? Does it bloat the software?
20
18
 
21
- Provide clear, actionable feedback.
19
+ You're not looking for 100% perfection. Just something that feels good to use and doesn't bloat the software.
20
+
21
+ ## Managing Findings
22
+
23
+ Use `session_metadata` to track your findings:
24
+
25
+ - **First review**: Create findings with `session_metadata` action `add` on key `review_findings`. Set status to `open` and include a description of the issue.
26
+ - **Re-review** (findings already exist): Check existing `review_findings` with `session_metadata` action `get`. If a finding has been addressed, update its status to `resolved`. If it's no longer relevant, update to `dismissed`. Create new findings for any new issues.
27
+
28
+ Each finding should have a clear, actionable description so the builder knows exactly what to fix.
@@ -8,7 +8,7 @@ allowedTools:
8
8
  - read_file
9
9
  - web_fetch
10
10
  - run_command
11
- - criterion:add,get,update,remove
11
+ - session_metadata:get,add,update,remove
12
12
  - call_sub_agent
13
13
  - load_skill
14
14
  - background_process
@@ -7,7 +7,7 @@ color: '#22c55e'
7
7
  allowedTools:
8
8
  - read_file
9
9
  - run_command
10
- - criterion:pass,fail
10
+ - session_metadata:get,add,update,remove
11
11
  - web_fetch
12
12
  ---
13
13
 
@@ -30,8 +30,7 @@ For each criterion marked [NEEDS VERIFICATION]:
30
30
 
31
31
  Then call:
32
32
 
33
- - `criterion` with action "pass" if the criterion is satisfied
34
- - `criterion` with action "fail" if it is NOT satisfied (explain why clearly)
33
+ Then call `session_metadata` with action "update" to set status to "passed" if the criterion is satisfied, or "failed" if it is NOT satisfied (explain why clearly in the reason).
35
34
 
36
35
  ## IMPORTANT
37
36
 
@@ -2,19 +2,19 @@ import {
2
2
  maybeAutoCompactContext,
3
3
  performManualContextCompaction,
4
4
  resolveCompactionStatsIdentity
5
- } from "./chunk-RYEZ7LDX.js";
5
+ } from "./chunk-ALH4KM2Y.js";
6
6
  import "./chunk-PSJIT5LZ.js";
7
7
  import "./chunk-XAMAYRDA.js";
8
8
  import "./chunk-DL6ZILAF.js";
9
9
  import "./chunk-PBGOZMVY.js";
10
10
  import "./chunk-VRGRAQDG.js";
11
11
  import "./chunk-HGAMIPFO.js";
12
- import "./chunk-J335KZ6U.js";
12
+ import "./chunk-XKR3HCAL.js";
13
13
  import "./chunk-FBGWG4N6.js";
14
- import "./chunk-6WZI6F6G.js";
15
- import "./chunk-RCQOHFAN.js";
14
+ import "./chunk-NONI4CRP.js";
15
+ import "./chunk-CEZNMLOO.js";
16
16
  import "./chunk-BJYPTN5S.js";
17
- import "./chunk-MEYDERUX.js";
17
+ import "./chunk-FQLK5GL5.js";
18
18
  import "./chunk-CQGTEGKL.js";
19
19
  import "./chunk-CGZHLM3K.js";
20
20
  import "./chunk-SZKEGZIB.js";
@@ -24,4 +24,4 @@ export {
24
24
  performManualContextCompaction,
25
25
  resolveCompactionStatsIdentity
26
26
  };
27
- //# sourceMappingURL=auto-compaction-7LMAY5JV.js.map
27
+ //# sourceMappingURL=auto-compaction-UIWTO3H5.js.map
@@ -5,11 +5,11 @@ import {
5
5
  generateSessionName,
6
6
  getSessionMessageCount,
7
7
  needsNameGenerationCheck
8
- } from "./chunk-IZC2EZ4D.js";
8
+ } from "./chunk-QFSSKIQ3.js";
9
9
  import {
10
10
  runChatTurn
11
- } from "./chunk-PDPXHSNZ.js";
12
- import "./chunk-RYEZ7LDX.js";
11
+ } from "./chunk-UFY4I643.js";
12
+ import "./chunk-ALH4KM2Y.js";
13
13
  import "./chunk-PSJIT5LZ.js";
14
14
  import "./chunk-XAMAYRDA.js";
15
15
  import "./chunk-DL6ZILAF.js";
@@ -18,16 +18,16 @@ import "./chunk-VRGRAQDG.js";
18
18
  import "./chunk-HGAMIPFO.js";
19
19
  import {
20
20
  getEventStore
21
- } from "./chunk-J335KZ6U.js";
21
+ } from "./chunk-XKR3HCAL.js";
22
22
  import "./chunk-FBGWG4N6.js";
23
- import "./chunk-6WZI6F6G.js";
23
+ import "./chunk-NONI4CRP.js";
24
24
  import {
25
25
  createChatMessageMessage,
26
26
  createPhaseChangedMessage,
27
27
  createSessionRunningMessage
28
- } from "./chunk-RCQOHFAN.js";
28
+ } from "./chunk-CEZNMLOO.js";
29
29
  import "./chunk-BJYPTN5S.js";
30
- import "./chunk-MEYDERUX.js";
30
+ import "./chunk-FQLK5GL5.js";
31
31
  import "./chunk-CQGTEGKL.js";
32
32
  import "./chunk-CGZHLM3K.js";
33
33
  import "./chunk-SZKEGZIB.js";
@@ -49,7 +49,6 @@ async function startChatSession(sessionId, content, deps, options) {
49
49
  }
50
50
  if (session.phase === "blocked") {
51
51
  sessionManager.setPhase(sessionId, "build");
52
- sessionManager.resetAllCriteriaAttempts(sessionId);
53
52
  broadcastForSession(sessionId, createPhaseChangedMessage("build"));
54
53
  }
55
54
  const controller = new AbortController();
@@ -61,7 +60,7 @@ async function startChatSession(sessionId, content, deps, options) {
61
60
  sessionManager.setRunning(sessionId, true);
62
61
  broadcastForSession(sessionId, createSessionRunningMessage(true));
63
62
  try {
64
- const { maybeAutoCompactContext } = await import("./auto-compaction-7LMAY5JV.js");
63
+ const { maybeAutoCompactContext } = await import("./auto-compaction-UIWTO3H5.js");
65
64
  await maybeAutoCompactContext({
66
65
  sessionManager,
67
66
  sessionId,
@@ -175,4 +174,4 @@ export {
175
174
  startChatSession,
176
175
  stopSessionExecution
177
176
  };
178
- //# sourceMappingURL=chat-handler-ZJVIM7U4.js.map
177
+ //# sourceMappingURL=chat-handler-IVIWOR3D.js.map
@@ -31,7 +31,7 @@ import {
31
31
  import {
32
32
  getCurrentContextWindowId,
33
33
  getEventStore
34
- } from "./chunk-J335KZ6U.js";
34
+ } from "./chunk-XKR3HCAL.js";
35
35
  import {
36
36
  buildContextMessagesFromEventHistory,
37
37
  foldContextState,
@@ -40,7 +40,7 @@ import {
40
40
  handleToolCall,
41
41
  handleToolResult,
42
42
  stripOrphanedToolCalls
43
- } from "./chunk-6WZI6F6G.js";
43
+ } from "./chunk-NONI4CRP.js";
44
44
  import {
45
45
  createChatDoneMessage,
46
46
  createChatMessageMessage,
@@ -48,7 +48,7 @@ import {
48
48
  createChatPathConfirmationMessage,
49
49
  createChatVisionFallbackMessage,
50
50
  createQueueStateMessage
51
- } from "./chunk-RCQOHFAN.js";
51
+ } from "./chunk-CEZNMLOO.js";
52
52
  import {
53
53
  AskUserInterrupt,
54
54
  askUserTool
@@ -2568,55 +2568,71 @@ function executeCommand(command, cwd, timeout, signal, onProgress) {
2568
2568
  });
2569
2569
  }
2570
2570
 
2571
- // src/server/tools/criterion.ts
2572
- function formatCriteriaList(criteria) {
2573
- if (criteria.length === 0) return "No criteria defined.";
2574
- return criteria.map((c, i) => `${i + 1}. [${c.id}] ${c.description}`).join("\n");
2575
- }
2576
- function completeCriterion(session, context, id, statusType, reason) {
2577
- const criterion = session.criteria.find((c) => c.id === id);
2578
- if (!criterion) {
2579
- return { success: false, output: `Criterion "${id}" not found` };
2580
- }
2581
- const status = statusType === "passed" ? { type: "passed", verifiedAt: (/* @__PURE__ */ new Date()).toISOString(), ...reason && { reason } } : { type: "failed", failedAt: (/* @__PURE__ */ new Date()).toISOString(), reason };
2582
- context.sessionManager.updateCriterionStatus(context.sessionId, id, status);
2583
- context.sessionManager.addCriterionAttempt(context.sessionId, id, {
2584
- attemptNumber: criterion.attempts.length + 1,
2585
- status: statusType,
2586
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2587
- ...reason ? { details: reason } : {}
2588
- });
2589
- return {
2590
- success: true,
2591
- output: statusType === "passed" ? `Criterion "${id}" verified as PASSED.${reason ? ` Verification: ${reason}` : ""}` : `Criterion "${id}" marked as FAILED. Reason: ${reason}`
2592
- };
2593
- }
2594
- var criterionTool = createTool(
2595
- "criterion",
2571
+ // src/server/tools/session-metadata.ts
2572
+ var SCHEMAS = {
2573
+ criteria: {
2574
+ description: "Acceptance criteria that drive workflow transitions",
2575
+ fields: {
2576
+ id: "string (auto-generated)",
2577
+ description: "string \u2014 what needs to be done and how to verify it",
2578
+ status: "pending | completed | passed | failed"
2579
+ }
2580
+ },
2581
+ todos: {
2582
+ description: "Task tracking items for the builder",
2583
+ fields: {
2584
+ id: "string (auto-generated)",
2585
+ description: "string \u2014 task description",
2586
+ status: "pending | in_progress | completed"
2587
+ }
2588
+ },
2589
+ review_findings: {
2590
+ description: "Code review findings from the code_reviewer sub-agent",
2591
+ fields: {
2592
+ id: "string (auto-generated)",
2593
+ description: "string \u2014 finding description",
2594
+ status: "open | resolved | dismissed",
2595
+ severity: "minor | major | critical (optional)"
2596
+ }
2597
+ }
2598
+ };
2599
+ function requireKeyAndId(args, helpers, entries) {
2600
+ if (!args.key) return helpers.error("Missing required field: key");
2601
+ if (!args.id) return helpers.error("Missing required field: id");
2602
+ const current = entries[args.key];
2603
+ if (!current) return helpers.error(`Key "${args.key}" not found.`);
2604
+ return current;
2605
+ }
2606
+ var sessionMetadataTool = createTool(
2607
+ "session_metadata",
2596
2608
  {
2597
2609
  type: "function",
2598
2610
  function: {
2599
- name: "criterion",
2600
- description: "Manage acceptance criteria. Actions: get (list all), add (create new), update (modify), remove (delete), complete (mark done), pass (verify), fail (reject).",
2611
+ name: "session_metadata",
2612
+ description: "Manage structured session data. Each key holds an array of items with id (auto), description, and status. Known keys: criteria, todos, review_findings. Use action=schema to see the expected shape for a specific key.",
2601
2613
  parameters: {
2602
2614
  type: "object",
2603
2615
  properties: {
2604
2616
  action: {
2605
2617
  type: "string",
2606
- enum: ["get", "add", "update", "remove", "complete", "pass", "fail"],
2618
+ enum: ["get", "list", "add", "update", "remove", "schema"],
2607
2619
  description: "The action to perform"
2608
2620
  },
2621
+ key: {
2622
+ type: "string",
2623
+ description: "Metadata key (required for: get, add, update, remove, schema). Known keys: criteria, todos, review_findings."
2624
+ },
2609
2625
  id: {
2610
2626
  type: "string",
2611
- description: "Criterion ID (required for: update, remove, complete, pass, fail; auto-generated for add)"
2627
+ description: "Item ID (required for: update, remove)"
2612
2628
  },
2613
2629
  description: {
2614
2630
  type: "string",
2615
- description: "Criterion description (required for: add, update)"
2631
+ description: "Item description (required for: add)"
2616
2632
  },
2617
- reason: {
2633
+ status: {
2618
2634
  type: "string",
2619
- description: "Reason (required for: fail; optional for: complete, pass)"
2635
+ description: 'Item status (for: add, update). Defaults to "pending" on add.'
2620
2636
  }
2621
2637
  },
2622
2638
  required: ["action"]
@@ -2626,207 +2642,76 @@ var criterionTool = createTool(
2626
2642
  async (args, context, helpers) => {
2627
2643
  const actionError = validateActionWithPermission(
2628
2644
  args.action,
2629
- ["get", "add", "update", "remove", "complete", "pass", "fail"],
2630
- "criterion",
2645
+ ["get", "list", "add", "update", "remove", "schema"],
2646
+ "session_metadata",
2631
2647
  context.permittedActions
2632
2648
  );
2633
2649
  if (actionError) return actionError;
2634
2650
  const session = requireSession(context.sessionManager, context.sessionId);
2635
- if (args.action === "get") {
2636
- return helpers.success(
2637
- session.criteria.length === 0 ? "No criteria defined yet." : JSON.stringify(
2638
- session.criteria.map((c) => ({ id: c.id, description: c.description })),
2639
- null,
2640
- 2
2641
- )
2642
- );
2643
- }
2644
- if (args.action === "add") {
2645
- if (!args.description) return helpers.error("Missing required field: description");
2646
- const criterion = {
2647
- id: args.id || "",
2648
- description: args.description,
2649
- status: { type: "pending" },
2650
- attempts: []
2651
- };
2652
- const result = context.sessionManager.addCriterion(context.sessionId, criterion);
2653
- if ("error" in result) return helpers.error(result.error);
2654
- return helpers.success(
2655
- `Added criterion "${result.actualId}". Current criteria:
2656
- ${formatCriteriaList(result.criteria)}`
2657
- );
2658
- }
2659
- if (args.action === "update") {
2660
- if (!args.id) return helpers.error("Missing required field: id");
2661
- if (!args.description) return helpers.error("Missing required field: description");
2662
- if (!session.criteria.find((c) => c.id === args.id)) return helpers.error(`Criterion "${args.id}" not found`);
2663
- const criteria = context.sessionManager.updateCriterionFull(context.sessionId, args.id, {
2664
- description: args.description
2665
- });
2666
- return helpers.success(`Updated criterion "${args.id}". Current criteria:
2667
- ${formatCriteriaList(criteria)}`);
2668
- }
2669
- if (args.action === "remove") {
2670
- if (!args.id) return helpers.error("Missing required field: id");
2671
- if (!session.criteria.find((c) => c.id === args.id)) return helpers.error(`Criterion "${args.id}" not found`);
2672
- const criteria = context.sessionManager.removeCriterion(context.sessionId, args.id);
2651
+ const entries = session.metadataEntries ?? {};
2652
+ if (args.action === "list") {
2653
+ const keys = Object.keys(entries);
2654
+ if (keys.length === 0) return helpers.success("No metadata keys defined.");
2673
2655
  return helpers.success(
2674
- criteria.length === 0 ? `Removed criterion "${args.id}". No criteria remaining.` : `Removed criterion "${args.id}". Current criteria:
2675
- ${formatCriteriaList(criteria)}`
2656
+ `Metadata keys:
2657
+ ${keys.map((k) => `- ${k} (${entries[k]?.length ?? 0} items)`).join("\n")}`
2676
2658
  );
2677
2659
  }
2678
- if (args.action === "complete") {
2679
- if (!args.id) return helpers.error("Missing required field: id");
2680
- const criterion = session.criteria.find((c) => c.id === args.id);
2681
- if (!criterion)
2682
- return helpers.error(
2683
- `Criterion "${args.id}" not found. Available: ${session.criteria.map((c) => c.id).join(", ")}`
2660
+ if (args.action === "schema") {
2661
+ if (!args.key) return helpers.error("Missing required field: key");
2662
+ const schema = SCHEMAS[args.key];
2663
+ if (!schema)
2664
+ return helpers.success(
2665
+ `No schema defined for key "${args.key}". Items have id, description, and status fields.`
2684
2666
  );
2685
- context.sessionManager.updateCriterionStatus(context.sessionId, args.id, {
2686
- type: "completed",
2687
- completedAt: (/* @__PURE__ */ new Date()).toISOString(),
2688
- ...args.reason ? { reason: args.reason } : {}
2689
- });
2690
2667
  return helpers.success(
2691
- `Criterion "${args.id}" marked as completed.${args.reason ? ` Reason: ${args.reason}` : ""}`
2668
+ `Key: ${args.key}
2669
+ Description: ${schema.description}
2670
+ Fields:
2671
+ ${Object.entries(schema.fields).map(([f, t]) => ` ${f}: ${t}`).join("\n")}`
2692
2672
  );
2693
2673
  }
2694
- if (args.action === "pass") {
2695
- if (!args.id) return helpers.error("Missing required field: id");
2696
- const result = completeCriterion(session, context, args.id, "passed", args.reason);
2697
- return result.success ? helpers.success(result.output) : helpers.error(result.output);
2698
- }
2699
- if (args.action === "fail") {
2700
- if (!args.id) return helpers.error("Missing required field: id");
2701
- if (!args.reason) return helpers.error("Missing required field: reason");
2702
- const result = completeCriterion(session, context, args.id, "failed", args.reason);
2703
- return result.success ? helpers.success(result.output) : helpers.error(result.output);
2704
- }
2705
- return helpers.error("Unexpected error");
2706
- }
2707
- );
2708
-
2709
- // src/server/tools/todo.ts
2710
- var sessionTodos = /* @__PURE__ */ new Map();
2711
- var onTodoUpdate = null;
2712
- function buildTaskListSummary(todosList) {
2713
- const pending = todosList.filter((t) => t.status === "pending").length;
2714
- const inProgress = todosList.filter((t) => t.status === "in_progress").length;
2715
- const completed = todosList.filter((t) => t.status === "completed").length;
2716
- return `${completed} completed, ${inProgress} in progress, ${pending} pending`;
2717
- }
2718
- function validateIndex(index, todosList, helpers) {
2719
- if (index === void 0) return helpers.error("Missing required field: index");
2720
- if (index < 0 || index >= todosList.length) {
2721
- return helpers.error(`Index out of range: ${index}. Valid range: 0-${todosList.length - 1}`);
2722
- }
2723
- return todosList[index];
2724
- }
2725
- var todoTool = createTool(
2726
- "todo",
2727
- {
2728
- type: "function",
2729
- function: {
2730
- name: "todo",
2731
- description: "Manage task list. Actions: list (show all), write (replace all), add (create new), update (modify), remove (delete).",
2732
- parameters: {
2733
- type: "object",
2734
- properties: {
2735
- action: {
2736
- type: "string",
2737
- enum: ["list", "write", "add", "update", "remove"],
2738
- description: "The action to perform"
2739
- },
2740
- todos: {
2741
- type: "array",
2742
- description: "Complete todo list (required for: write)",
2743
- items: {
2744
- type: "object",
2745
- properties: {
2746
- content: { type: "string" },
2747
- status: { type: "string", enum: ["pending", "in_progress", "completed"] }
2748
- },
2749
- required: ["content", "status"]
2750
- }
2751
- },
2752
- content: {
2753
- type: "string",
2754
- description: "Task content (required for: add)"
2755
- },
2756
- index: {
2757
- type: "number",
2758
- description: "Task index 0-based (required for: update, remove)"
2759
- },
2760
- status: {
2761
- type: "string",
2762
- enum: ["pending", "in_progress", "completed"],
2763
- description: "Task status (required for: update)"
2764
- }
2765
- },
2766
- required: ["action"]
2767
- }
2768
- }
2769
- },
2770
- async (args, context, helpers) => {
2771
- const actionError = validateActionWithPermission(
2772
- args.action,
2773
- ["list", "write", "add", "update", "remove"],
2774
- "todo",
2775
- context.permittedActions
2776
- );
2777
- if (actionError) return actionError;
2778
- if (args.action === "list") {
2779
- const todosList = sessionTodos.get(context.sessionId) ?? [];
2780
- return helpers.success(todosList.length === 0 ? "No tasks defined yet." : JSON.stringify(todosList, null, 2));
2781
- }
2782
- if (args.action === "write") {
2783
- if (!args.todos) return helpers.error("Missing required field: todos");
2784
- if (!Array.isArray(args.todos)) return helpers.error("todos must be an array");
2785
- for (const todo of args.todos) {
2786
- if (!todo.content || !todo.status) return helpers.error("Each todo must have content and status");
2787
- if (!["pending", "in_progress", "completed"].includes(todo.status)) {
2788
- return helpers.error(`Invalid status: ${todo.status}. Must be pending, in_progress, or completed`);
2789
- }
2790
- }
2791
- sessionTodos.set(context.sessionId, args.todos);
2792
- if (onTodoUpdate) onTodoUpdate(context.sessionId, args.todos);
2793
- return helpers.success(
2794
- `${args.todos.filter((t) => t.status === "completed").length} completed, ${args.todos.filter((t) => t.status === "in_progress").length} in progress, ${args.todos.filter((t) => t.status === "pending").length} pending`
2795
- );
2674
+ if (args.action === "get") {
2675
+ if (!args.key) return helpers.error("Missing required field: key");
2676
+ const keyEntries = entries[args.key];
2677
+ if (!keyEntries || keyEntries.length === 0) return helpers.success(`No entries for key "${args.key}".`);
2678
+ return helpers.success(JSON.stringify(keyEntries, null, 2));
2796
2679
  }
2797
2680
  if (args.action === "add") {
2798
- if (!args.content) return helpers.error("Missing required field: content");
2799
- const todosList = sessionTodos.get(context.sessionId) ?? [];
2800
- todosList.push({ content: args.content, status: "pending" });
2801
- sessionTodos.set(context.sessionId, todosList);
2802
- if (onTodoUpdate) onTodoUpdate(context.sessionId, todosList);
2803
- return helpers.success(`Added task "${args.content}". Task list: ${buildTaskListSummary(todosList)}`);
2681
+ if (!args.key) return helpers.error("Missing required field: key");
2682
+ if (!args.description) return helpers.error("Missing required field: description");
2683
+ const current = entries[args.key] ?? [];
2684
+ const newEntry = {
2685
+ id: args.id || current.length.toString(),
2686
+ description: args.description,
2687
+ status: args.status || "pending"
2688
+ };
2689
+ const updated = [...current, newEntry];
2690
+ context.sessionManager.setMetadataEntries(context.sessionId, args.key, updated);
2691
+ return helpers.success(`Added item "${newEntry.id}" to "${args.key}". Total: ${updated.length} items.`);
2804
2692
  }
2805
2693
  if (args.action === "update") {
2806
- if (!args.content && !args.status) return helpers.error("update requires content or status");
2807
- if (args.status && !["pending", "in_progress", "completed"].includes(args.status)) {
2808
- return helpers.error(`Invalid status: ${args.status}. Must be pending, in_progress, or completed`);
2809
- }
2810
- const todosList = sessionTodos.get(context.sessionId) ?? [];
2811
- const indexResult = validateIndex(args.index, todosList, helpers);
2812
- if ("success" in indexResult && !indexResult.success) return indexResult;
2813
- const todo = indexResult;
2814
- if (args.content) todo.content = args.content;
2815
- if (args.status) todo.status = args.status;
2816
- sessionTodos.set(context.sessionId, todosList);
2817
- if (onTodoUpdate) onTodoUpdate(context.sessionId, todosList);
2818
- return helpers.success(`Updated task ${args.index}. Task list: ${buildTaskListSummary(todosList)}`);
2694
+ const current = requireKeyAndId(args, helpers, entries);
2695
+ if (!Array.isArray(current)) return current;
2696
+ const idx = current.findIndex((e) => e.id === args.id);
2697
+ if (idx === -1) return helpers.error(`Item "${args.id}" not found in "${args.key}".`);
2698
+ const updated = current.map(
2699
+ (e, i) => i === idx ? {
2700
+ ...e,
2701
+ ...args.description !== void 0 ? { description: args.description } : {},
2702
+ ...args.status !== void 0 ? { status: args.status } : {}
2703
+ } : e
2704
+ );
2705
+ context.sessionManager.setMetadataEntries(context.sessionId, args.key, updated);
2706
+ return helpers.success(`Updated item "${args.id}" in "${args.key}".`);
2819
2707
  }
2820
2708
  if (args.action === "remove") {
2821
- const todosList = sessionTodos.get(context.sessionId) ?? [];
2822
- const indexResult = validateIndex(args.index, todosList, helpers);
2823
- if ("success" in indexResult && !indexResult.success) return indexResult;
2824
- const removed = todosList.splice(args.index, 1)[0];
2825
- sessionTodos.set(context.sessionId, todosList);
2826
- if (onTodoUpdate) onTodoUpdate(context.sessionId, todosList);
2827
- return helpers.success(
2828
- todosList.length === 0 ? `Removed task "${removed.content}". No tasks remaining.` : `Removed task "${removed.content}". Task list: ${buildTaskListSummary(todosList)}`
2829
- );
2709
+ const current = requireKeyAndId(args, helpers, entries);
2710
+ if (!Array.isArray(current)) return current;
2711
+ const updated = current.filter((e) => e.id !== args.id);
2712
+ if (updated.length === current.length) return helpers.error(`Item "${args.id}" not found in "${args.key}".`);
2713
+ context.sessionManager.setMetadataEntries(context.sessionId, args.key, updated);
2714
+ return helpers.success(`Removed item "${args.id}" from "${args.key}". ${updated.length} items remaining.`);
2830
2715
  }
2831
2716
  return helpers.error("Unexpected error");
2832
2717
  }
@@ -3112,10 +2997,8 @@ function getCurrentWindowMessageOptions(sessionId) {
3112
2997
  async function executeToolBatch(assistantMsgId, toolCalls, ctx) {
3113
2998
  const eventStore = getEventStore();
3114
2999
  const toolMessages = [];
3115
- let criteriaChanged = false;
3116
3000
  let returnValueContent;
3117
3001
  let returnValueResult;
3118
- const session = ctx.sessionManager.requireSession(ctx.sessionId);
3119
3002
  if (ctx.signal?.aborted) {
3120
3003
  throw new Error("Aborted");
3121
3004
  }
@@ -3224,12 +3107,7 @@ Error: ${toolResult.error}` : `Error: ${toolResult.error}`
3224
3107
  toolCallId: result.toolCall.id
3225
3108
  });
3226
3109
  }
3227
- const updatedSession = ctx.sessionManager.requireSession(ctx.sessionId);
3228
- if (JSON.stringify(updatedSession.criteria) !== JSON.stringify(session.criteria)) {
3229
- eventStore.append(ctx.sessionId, { type: "criteria.set", data: { criteria: updatedSession.criteria } });
3230
- criteriaChanged = true;
3231
- }
3232
- return { toolMessages, criteriaChanged, returnValueContent, returnValueResult };
3110
+ return { toolMessages, criteriaChanged: false, returnValueContent, returnValueResult };
3233
3111
  }
3234
3112
  var MAX_FORMAT_RETRIES = 10;
3235
3113
  var MAX_TRUNCATION_RETRIES = 3;
@@ -3989,7 +3867,7 @@ var callSubAgentTool = {
3989
3867
  };
3990
3868
  }
3991
3869
  try {
3992
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-WFIYKFBE.js");
3870
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-Z7X4HXZN.js");
3993
3871
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3994
3872
  const turnMetrics = new TurnMetrics();
3995
3873
  const result = await executeSubAgent({
@@ -4903,8 +4781,7 @@ function getAllToolsMap() {
4903
4781
  editFileTool,
4904
4782
  runCommandTool,
4905
4783
  askUserTool,
4906
- criterionTool,
4907
- todoTool,
4784
+ sessionMetadataTool,
4908
4785
  callSubAgentTool,
4909
4786
  loadSkillTool,
4910
4787
  returnValueTool,
@@ -5191,4 +5068,4 @@ export {
5191
5068
  getToolRegistryForAgent,
5192
5069
  createToolRegistry
5193
5070
  };
5194
- //# sourceMappingURL=chunk-RYEZ7LDX.js.map
5071
+ //# sourceMappingURL=chunk-ALH4KM2Y.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createServerMessage,
3
3
  isClientMessage
4
- } from "./chunk-MEYDERUX.js";
4
+ } from "./chunk-FQLK5GL5.js";
5
5
 
6
6
  // src/server/ws/protocol.ts
7
7
  function enrichMessagesWithToolResults(messages) {
@@ -132,6 +132,9 @@ function createPhaseChangedMessage(phase) {
132
132
  function createCriteriaUpdatedMessage(criteria, changedId) {
133
133
  return createServerMessage("criteria.updated", { criteria, ...changedId ? { changedId } : {} });
134
134
  }
135
+ function createMetadataUpdatedMessage(key, entries) {
136
+ return createServerMessage("metadata.updated", { key, entries });
137
+ }
135
138
  function createContextStateMessage(context, subAgentId) {
136
139
  return createServerMessage("context.state", { context, ...subAgentId && { subAgentId } });
137
140
  }
@@ -245,6 +248,10 @@ function storedEventToServerMessage(event) {
245
248
  const data = event.data;
246
249
  return createCriteriaUpdatedMessage(data.criteria);
247
250
  }
251
+ case "metadata.set": {
252
+ const data = event.data;
253
+ return createMetadataUpdatedMessage(data.key, data.entries);
254
+ }
248
255
  case "criterion.updated": {
249
256
  return null;
250
257
  }
@@ -317,6 +324,7 @@ export {
317
324
  createModeChangedMessage,
318
325
  createPhaseChangedMessage,
319
326
  createCriteriaUpdatedMessage,
327
+ createMetadataUpdatedMessage,
320
328
  createContextStateMessage,
321
329
  createSessionNameGeneratedMessage,
322
330
  isSessionLoadPayload,
@@ -326,4 +334,4 @@ export {
326
334
  createQueueStateMessage,
327
335
  storedEventToServerMessage
328
336
  };
329
- //# sourceMappingURL=chunk-RCQOHFAN.js.map
337
+ //# sourceMappingURL=chunk-CEZNMLOO.js.map