trellis 3.1.35 → 3.2.2

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 (287) hide show
  1. package/CHANGELOG.md +23 -5
  2. package/README.md +63 -156
  3. package/bin/trellis.mjs +2 -75
  4. package/dist/{better-sqlite-backend-ahx5p0br.js → better-sqlite-backend-2P4F6AOJ.js} +91 -29
  5. package/dist/boot-middleware-MHLHFCUC.js +9 -0
  6. package/dist/browser/index.d.ts +18 -0
  7. package/dist/browser/index.d.ts.map +1 -0
  8. package/dist/browser/index.js +95 -0
  9. package/dist/{index-53f3b8p8.js → chunk-2W3MHTMG.js} +552 -213
  10. package/dist/chunk-44FFQKQX.js +142 -0
  11. package/dist/chunk-4HYPLFJD.js +150 -0
  12. package/dist/chunk-4XIVMVHC.js +361 -0
  13. package/dist/{index-yp88he8n.js → chunk-6CTA6MCE.js} +88 -64
  14. package/dist/chunk-6GEZ6DN5.js +394 -0
  15. package/dist/chunk-7ZFRVCUE.js +211 -0
  16. package/dist/chunk-CAG4FULI.js +121 -0
  17. package/dist/chunk-FF36CQHZ.js +61 -0
  18. package/dist/{index-h32txmxe.js → chunk-FKQO5A3H.js} +6 -13
  19. package/dist/{index-nq520y6k.js → chunk-FWRS4CSC.js} +46 -32
  20. package/dist/chunk-GFZCJ4EH.js +108 -0
  21. package/dist/chunk-GLM4HGN4.js +55 -0
  22. package/dist/{index-4cdr7x2x.js → chunk-GU374KWZ.js} +182 -111
  23. package/dist/chunk-H6JB3PZ3.js +45 -0
  24. package/dist/chunk-IZX2PLIB.js +1240 -0
  25. package/dist/chunk-J2TXUFCZ.js +289 -0
  26. package/dist/chunk-J3WYZO3Q.js +211 -0
  27. package/dist/{index-xzym9w0m.js → chunk-JA7AIHRK.js} +12 -7
  28. package/dist/chunk-JHHEXEDM.js +162 -0
  29. package/dist/chunk-JUEMDWLU.js +233 -0
  30. package/dist/chunk-KFQGP6VL.js +33 -0
  31. package/dist/chunk-KIJITUZB.js +419 -0
  32. package/dist/{index-4wxa8xz4.js → chunk-KQ4A2D2P.js} +162 -23
  33. package/dist/chunk-KSU2GW22.js +958 -0
  34. package/dist/{index-rv1p47gp.js → chunk-L5N5PR2S.js} +3015 -2480
  35. package/dist/{index-h9e2efx4.js → chunk-LNUIGRDZ.js} +71 -55
  36. package/dist/{index-skhn0agf.js → chunk-MLC5BUYO.js} +19 -20
  37. package/dist/chunk-MPXUVGT3.js +104 -0
  38. package/dist/chunk-N6MYZT4O.js +68 -0
  39. package/dist/chunk-O2AV5WMN.js +48 -0
  40. package/dist/chunk-PZ4XYZ4J.js +143 -0
  41. package/dist/chunk-QB5ISE47.js +419 -0
  42. package/dist/chunk-RSWUFTO2.js +857 -0
  43. package/dist/chunk-S3XLFZ27.js +1095 -0
  44. package/dist/{index-w5wccer3.js → chunk-S6GBJ2ZB.js} +28 -12
  45. package/dist/{index-7pjz3tsy.js → chunk-SGMDTWJJ.js} +57 -15
  46. package/dist/chunk-SPSPV5BC.js +390 -0
  47. package/dist/chunk-TCKXSOBP.js +123 -0
  48. package/dist/chunk-UBGUDMUV.js +59 -0
  49. package/dist/{index-wt8rz4gn.js → chunk-UQISRW6T.js} +97 -26
  50. package/dist/chunk-USEINYUL.js +12 -0
  51. package/dist/{index-bmyt7k8n.js → chunk-UZRUP7QW.js} +12 -4
  52. package/dist/{index-xhcp6xrn.js → chunk-VBYUTRXX.js} +695 -514
  53. package/dist/{index-vkpkfwhq.js → chunk-VDAKEOML.js} +234 -194
  54. package/dist/chunk-WXSWA3MV.js +0 -0
  55. package/dist/{index-n9f2qyh5.js → chunk-X5FLTRUB.js} +55 -33
  56. package/dist/{index-h7zxhhhh.js → chunk-XMQ7G77X.js} +46 -38
  57. package/dist/{index-w7ng765c.js → chunk-YCM7ZYEZ.js} +102 -49
  58. package/dist/cli/deploy-cli.d.ts +18 -0
  59. package/dist/cli/deploy-cli.d.ts.map +1 -0
  60. package/dist/cli/errors.d.ts +6 -0
  61. package/dist/cli/errors.d.ts.map +1 -0
  62. package/dist/cli/examples.d.ts +23 -0
  63. package/dist/cli/examples.d.ts.map +1 -0
  64. package/dist/cli/index.d.ts +1 -1
  65. package/dist/cli/index.d.ts.map +1 -1
  66. package/dist/cli/index.js +2426 -6225
  67. package/dist/client/index.browser.d.ts +29 -0
  68. package/dist/client/index.browser.d.ts.map +1 -0
  69. package/dist/client/index.browser.js +64 -0
  70. package/dist/client/index.d.ts +6 -1
  71. package/dist/client/index.d.ts.map +1 -1
  72. package/dist/client/index.js +41 -21
  73. package/dist/client/live.d.ts +67 -0
  74. package/dist/client/live.d.ts.map +1 -0
  75. package/dist/client/reactive.d.ts +31 -0
  76. package/dist/client/reactive.d.ts.map +1 -0
  77. package/dist/client/sdk.browser.d.ts +104 -0
  78. package/dist/client/sdk.browser.d.ts.map +1 -0
  79. package/dist/client/sdk.browser.js +9 -0
  80. package/dist/client/sdk.d.ts +26 -2
  81. package/dist/client/sdk.d.ts.map +1 -1
  82. package/dist/client/sdk.js +9 -0
  83. package/dist/client/vcs-client.d.ts +129 -0
  84. package/dist/client/vcs-client.d.ts.map +1 -0
  85. package/dist/cms/index.js +171 -163
  86. package/dist/{config-8hczw0rs.js → config-PFTP67TR.js} +8 -9
  87. package/dist/core/computation/index.d.ts +5 -0
  88. package/dist/core/computation/index.d.ts.map +1 -0
  89. package/dist/core/computation/rollup.d.ts +18 -0
  90. package/dist/core/computation/rollup.d.ts.map +1 -0
  91. package/dist/core/index.d.ts +5 -0
  92. package/dist/core/index.d.ts.map +1 -1
  93. package/dist/core/index.js +171 -104
  94. package/dist/core/kernel/boot-middleware.d.ts +10 -0
  95. package/dist/core/kernel/boot-middleware.d.ts.map +1 -0
  96. package/dist/core/kernel/logic-middleware.d.ts +7 -1
  97. package/dist/core/kernel/logic-middleware.d.ts.map +1 -1
  98. package/dist/core/kernel/trellis-kernel.d.ts.map +1 -1
  99. package/dist/core/ontology/types.d.ts +5 -0
  100. package/dist/core/ontology/types.d.ts.map +1 -1
  101. package/dist/core/persist/better-sqlite-backend.d.ts +9 -2
  102. package/dist/core/persist/better-sqlite-backend.d.ts.map +1 -1
  103. package/dist/core/persist/factory.d.ts +6 -7
  104. package/dist/core/persist/factory.d.ts.map +1 -1
  105. package/dist/core/persist/factory.js +2 -3
  106. package/dist/core/persist/sqljs-backend.js +2 -3
  107. package/dist/db/index.d.ts +4 -1
  108. package/dist/db/index.d.ts.map +1 -1
  109. package/dist/db/index.js +67 -54
  110. package/dist/db/inspector.js +11 -19
  111. package/dist/db/trellis.css +1 -1
  112. package/dist/decisions/index.js +9 -10
  113. package/dist/deploy-LQ7GUGJ5.js +9 -0
  114. package/dist/deploy-YNVG5E4E.js +9 -0
  115. package/dist/deploy-cli-24BCHAXY.js +67 -0
  116. package/dist/deploy-cli-C35HTITO.js +67 -0
  117. package/dist/embeddings/auto-embed.d.ts +2 -2
  118. package/dist/embeddings/auto-embed.d.ts.map +1 -1
  119. package/dist/embeddings/index.js +20 -22
  120. package/dist/embeddings/search.d.ts +2 -1
  121. package/dist/embeddings/search.d.ts.map +1 -1
  122. package/dist/embeddings/store.d.ts +25 -4
  123. package/dist/embeddings/store.d.ts.map +1 -1
  124. package/dist/engine.d.ts +59 -19
  125. package/dist/engine.d.ts.map +1 -1
  126. package/dist/import-UZEKXU3B.js +10 -0
  127. package/dist/index.js +102 -93
  128. package/dist/launch-explorer-HZ4ZJA4X.js +95 -0
  129. package/dist/links/index.js +24 -26
  130. package/dist/mcp/server.d.ts.map +1 -1
  131. package/dist/plugins/agent-memory/index.js +316 -0
  132. package/dist/plugins/idea-garden/index.js +165 -0
  133. package/dist/plugins/plan-approval/index.js +579 -0
  134. package/dist/plugins/proactive-watcher/index.js +194 -0
  135. package/dist/{index-2r4jxwnb.js → query-XYLTJYSA.js} +14 -15
  136. package/dist/react/index.js +39 -70
  137. package/dist/react/realtime.js +11 -0
  138. package/dist/react/schema-hooks.js +87 -0
  139. package/dist/realtime/broadcast-channel-transport.d.ts +43 -0
  140. package/dist/realtime/broadcast-channel-transport.d.ts.map +1 -0
  141. package/dist/realtime/durable-object-relay-transport.d.ts +96 -0
  142. package/dist/realtime/durable-object-relay-transport.d.ts.map +1 -0
  143. package/dist/realtime/index.d.ts +44 -0
  144. package/dist/realtime/index.d.ts.map +1 -0
  145. package/dist/realtime/index.js +40 -0
  146. package/dist/realtime/memory-hub.d.ts +32 -0
  147. package/dist/realtime/memory-hub.d.ts.map +1 -0
  148. package/dist/realtime/persistent-channel.d.ts +105 -0
  149. package/dist/realtime/persistent-channel.d.ts.map +1 -0
  150. package/dist/realtime/presence.d.ts +73 -0
  151. package/dist/realtime/presence.d.ts.map +1 -0
  152. package/dist/realtime/relay-persistence.d.ts +37 -0
  153. package/dist/realtime/relay-persistence.d.ts.map +1 -0
  154. package/dist/realtime/relay-persistence.js +107 -0
  155. package/dist/realtime/relay-server.d.ts +103 -0
  156. package/dist/realtime/relay-server.d.ts.map +1 -0
  157. package/dist/realtime/room.d.ts +98 -0
  158. package/dist/realtime/room.d.ts.map +1 -0
  159. package/dist/realtime/text.d.ts +73 -0
  160. package/dist/realtime/text.d.ts.map +1 -0
  161. package/dist/realtime/types.d.ts +89 -0
  162. package/dist/realtime/types.d.ts.map +1 -0
  163. package/dist/realtime/websocket-relay-transport.d.ts +28 -0
  164. package/dist/realtime/websocket-relay-transport.d.ts.map +1 -0
  165. package/dist/realtime.bundle.js +1100 -0
  166. package/dist/{remote-manager-xvbg4230.js → remote-manager-ODE3T2KR.js} +25 -15
  167. package/dist/scaffold/seed.d.ts.map +1 -1
  168. package/dist/scaffold/write.d.ts +1 -1
  169. package/dist/scaffold/write.d.ts.map +1 -1
  170. package/dist/schema/define.d.ts +137 -0
  171. package/dist/schema/define.d.ts.map +1 -0
  172. package/dist/schema/entity-projection.d.ts +34 -0
  173. package/dist/schema/entity-projection.d.ts.map +1 -0
  174. package/dist/schema/eql.d.ts +46 -0
  175. package/dist/schema/eql.d.ts.map +1 -0
  176. package/dist/schema/index.d.ts +21 -0
  177. package/dist/schema/index.d.ts.map +1 -0
  178. package/dist/schema/index.js +46 -0
  179. package/dist/schema/kernel-resolve.d.ts +21 -0
  180. package/dist/schema/kernel-resolve.d.ts.map +1 -0
  181. package/dist/schema/mutations.d.ts +20 -0
  182. package/dist/schema/mutations.d.ts.map +1 -0
  183. package/dist/schema/resolve.d.ts +21 -0
  184. package/dist/schema/resolve.d.ts.map +1 -0
  185. package/dist/server/deploy-meta.d.ts +25 -0
  186. package/dist/server/deploy-meta.d.ts.map +1 -0
  187. package/dist/server/deploy.d.ts +7 -2
  188. package/dist/server/deploy.d.ts.map +1 -1
  189. package/dist/server/index.d.ts +7 -2
  190. package/dist/server/index.d.ts.map +1 -1
  191. package/dist/server/index.js +100 -58
  192. package/dist/server/node-adapter.js +5 -104
  193. package/dist/server/realtime.d.ts +14 -3
  194. package/dist/server/realtime.d.ts.map +1 -1
  195. package/dist/server/server.d.ts +8 -16
  196. package/dist/server/server.d.ts.map +1 -1
  197. package/dist/server/sprites.d.ts +18 -1
  198. package/dist/server/sprites.d.ts.map +1 -1
  199. package/dist/server/tenancy.d.ts +4 -0
  200. package/dist/server/tenancy.d.ts.map +1 -1
  201. package/dist/server/usage-meter.d.ts +53 -0
  202. package/dist/server/usage-meter.d.ts.map +1 -0
  203. package/dist/server-MB3OPSPI.js +18 -0
  204. package/dist/server-ZVWGLLRF.js +18 -0
  205. package/dist/sprites-KQGTGM6W.js +27 -0
  206. package/dist/{sprites-vc4qbrp1.js → sprites-RU3E4XQN.js} +6 -7
  207. package/dist/svelte/index.d.ts +17 -0
  208. package/dist/svelte/index.d.ts.map +1 -0
  209. package/dist/svelte/index.js +51 -0
  210. package/dist/svelte/schema-hooks.d.ts +45 -0
  211. package/dist/svelte/schema-hooks.d.ts.map +1 -0
  212. package/dist/svelte/schema-hooks.js +71 -0
  213. package/dist/svelte/stores.d.ts +78 -0
  214. package/dist/svelte/stores.d.ts.map +1 -0
  215. package/dist/sync/http-transport.d.ts +3 -3
  216. package/dist/sync/http-transport.d.ts.map +1 -1
  217. package/dist/sync/index.d.ts +15 -1
  218. package/dist/sync/index.d.ts.map +1 -1
  219. package/dist/sync/index.js +617 -0
  220. package/dist/sync/memory-room.d.ts +37 -0
  221. package/dist/sync/memory-room.d.ts.map +1 -0
  222. package/dist/sync/memory-transport.d.ts +3 -3
  223. package/dist/sync/memory-transport.d.ts.map +1 -1
  224. package/dist/sync/partykit-room.d.ts +40 -0
  225. package/dist/sync/partykit-room.d.ts.map +1 -0
  226. package/dist/sync/partykit-transport.d.ts +84 -0
  227. package/dist/sync/partykit-transport.d.ts.map +1 -0
  228. package/dist/sync/room-core.d.ts +53 -0
  229. package/dist/sync/room-core.d.ts.map +1 -0
  230. package/dist/sync/sync-engine.d.ts +40 -2
  231. package/dist/sync/sync-engine.d.ts.map +1 -1
  232. package/dist/sync/sync-room-server.d.ts +39 -0
  233. package/dist/sync/sync-room-server.d.ts.map +1 -0
  234. package/dist/sync/types.d.ts +70 -3
  235. package/dist/sync/types.d.ts.map +1 -1
  236. package/dist/sync/vcs-sync-peer.d.ts +63 -0
  237. package/dist/sync/vcs-sync-peer.d.ts.map +1 -0
  238. package/dist/sync/ws-transport.d.ts +2 -2
  239. package/dist/sync/ws-transport.d.ts.map +1 -1
  240. package/dist/tenancy-NBLLGCNJ.js +14 -0
  241. package/dist/tenancy-POMWQP6M.js +16 -0
  242. package/dist/ui/client.html +355 -67
  243. package/dist/ui/launch-explorer.d.ts +22 -0
  244. package/dist/ui/launch-explorer.d.ts.map +1 -0
  245. package/dist/ui/server.d.ts +1 -1
  246. package/dist/ui/server.d.ts.map +1 -1
  247. package/dist/vcs/blob-store.d.ts.map +1 -1
  248. package/dist/vcs/idb-op-log.d.ts +67 -0
  249. package/dist/vcs/idb-op-log.d.ts.map +1 -0
  250. package/dist/vcs/index.d.ts +1 -0
  251. package/dist/vcs/index.d.ts.map +1 -1
  252. package/dist/vcs/index.js +81 -72
  253. package/dist/vcs/issue.d.ts +22 -5
  254. package/dist/vcs/issue.d.ts.map +1 -1
  255. package/dist/vcs/lane-materialize.d.ts +5 -0
  256. package/dist/vcs/lane-materialize.d.ts.map +1 -1
  257. package/dist/vcs/op-log.d.ts +28 -2
  258. package/dist/vcs/op-log.d.ts.map +1 -1
  259. package/dist/vcs/ops.d.ts +10 -0
  260. package/dist/vcs/ops.d.ts.map +1 -1
  261. package/dist/vcs/types.d.ts +2 -0
  262. package/dist/vcs/types.d.ts.map +1 -1
  263. package/dist/{vm-config-6xhsj6b3.js → vm-config-JI4OXKDQ.js} +9 -10
  264. package/dist/vue/hooks.d.ts +64 -0
  265. package/dist/vue/hooks.d.ts.map +1 -0
  266. package/dist/vue/index.d.ts +19 -0
  267. package/dist/vue/index.d.ts.map +1 -0
  268. package/dist/vue/index.js +59 -0
  269. package/dist/vue/schema-hooks.d.ts +41 -0
  270. package/dist/vue/schema-hooks.d.ts.map +1 -0
  271. package/dist/vue/schema-hooks.js +64 -0
  272. package/package.json +130 -17
  273. package/dist/deploy-999q207z.js +0 -10
  274. package/dist/engine-y0724kjq.js +0 -8
  275. package/dist/import-s2b8e0ft.js +0 -11
  276. package/dist/index-a76rekgs.js +0 -67
  277. package/dist/index-c9h37r6h.js +0 -1
  278. package/dist/index-hr9qvv77.js +0 -860
  279. package/dist/index-k5b0xskw.js +0 -1
  280. package/dist/index-nzb3am4f.js +0 -80
  281. package/dist/index-wncptktd.js +0 -292
  282. package/dist/index-y6a4kj0p.js +0 -43
  283. package/dist/index-yhwjgfvj.js +0 -342
  284. package/dist/sdk-bepky0xs.js +0 -16
  285. package/dist/server-szdjx0nt.js +0 -13
  286. package/dist/sqlite-backend-0vsmc6qj.js +0 -8
  287. package/dist/tenancy-pjm32b4v.js +0 -14
@@ -0,0 +1,579 @@
1
+ import "../../chunk-KFQGP6VL.js";
2
+
3
+ // src/plugins/plan-approval/ontology.ts
4
+ var planApprovalOntology = {
5
+ id: "trellis:plan-approval",
6
+ name: "Plan Approval",
7
+ version: "1.0.0",
8
+ description: "Multi-turn planning with buffered mutations and user approval",
9
+ entities: [
10
+ {
11
+ name: "PendingPlan",
12
+ description: "A buffered set of graph mutations awaiting user approval",
13
+ attributes: [
14
+ { name: "title", type: "string", required: true },
15
+ { name: "description", type: "string" },
16
+ {
17
+ name: "status",
18
+ type: "string",
19
+ required: true,
20
+ enum: ["drafting", "submitted", "approved", "rejected"],
21
+ default: "drafting"
22
+ },
23
+ { name: "submittedAt", type: "string", description: "ISO 8601 timestamp" },
24
+ { name: "resolvedAt", type: "string", description: "ISO 8601 timestamp" },
25
+ { name: "resolvedBy", type: "string", description: "Agent or user who approved/rejected" },
26
+ { name: "rejectionReason", type: "string" },
27
+ { name: "operationCount", type: "number", description: "Number of planned operations" }
28
+ ]
29
+ },
30
+ {
31
+ name: "PlannedOperation",
32
+ description: "A single buffered graph mutation within a plan",
33
+ attributes: [
34
+ {
35
+ name: "kind",
36
+ type: "string",
37
+ required: true,
38
+ enum: ["createEntity", "updateEntity", "deleteEntity", "addLink", "removeLink"]
39
+ },
40
+ { name: "entityId", type: "string", description: "Target entity ID" },
41
+ { name: "entityType", type: "string", description: "Entity type (for createEntity)" },
42
+ { name: "attributes", type: "any", description: "JSON-serialized attributes" },
43
+ { name: "sourceId", type: "string", description: "Source entity (for link operations)" },
44
+ { name: "targetId", type: "string", description: "Target entity (for link operations)" },
45
+ { name: "linkAttribute", type: "string", description: "Link attribute name" },
46
+ { name: "description", type: "string", description: "Human-readable description of this operation" },
47
+ { name: "sequence", type: "number", description: "Execution order within the plan" }
48
+ ]
49
+ }
50
+ ],
51
+ relations: [
52
+ {
53
+ name: "hasOperation",
54
+ sourceTypes: ["PendingPlan"],
55
+ targetTypes: ["PlannedOperation"],
56
+ cardinality: "many"
57
+ },
58
+ {
59
+ name: "planForRun",
60
+ sourceTypes: ["PendingPlan"],
61
+ targetTypes: ["AgentRun"],
62
+ cardinality: "one",
63
+ description: "Links a plan to the agent run that produced it"
64
+ }
65
+ ]
66
+ };
67
+
68
+ // src/plugins/plan-approval/plugin.ts
69
+ function createPlanApprovalPlugin() {
70
+ return {
71
+ id: "trellis:plan-approval",
72
+ name: "Plan Approval",
73
+ version: "1.0.0",
74
+ description: "Multi-turn planning with buffered mutations and user approval",
75
+ ontologies: [planApprovalOntology],
76
+ eventHandlers: [
77
+ {
78
+ event: "entity:updated",
79
+ handler: (data) => {
80
+ if (!data || typeof data !== "object") return;
81
+ const d = data;
82
+ if (d.type !== "PendingPlan") return;
83
+ }
84
+ }
85
+ ],
86
+ onLoad: async (ctx) => {
87
+ ctx.log("Plan approval system loaded");
88
+ },
89
+ onUnload: async (ctx) => {
90
+ ctx.log("Plan approval system unloaded");
91
+ }
92
+ };
93
+ }
94
+ function createEnterPlanModeTool(ctx) {
95
+ return {
96
+ def: {
97
+ name: "enterPlanMode",
98
+ description: "Enter plan mode. Subsequent planCreateEntity/planUpdateEntity/planAddLink calls will be buffered for user review instead of executing immediately. Use this before performing bulk operations or significant architectural changes.",
99
+ schema: JSON.stringify({
100
+ type: "object",
101
+ properties: {
102
+ title: { type: "string", description: "Short title describing the planned changes" },
103
+ description: { type: "string", description: "Detailed description of what will be changed and why" }
104
+ },
105
+ required: ["title"]
106
+ })
107
+ },
108
+ handler: async (input) => {
109
+ const { title, description } = input;
110
+ const planId = await ctx.planManager.enterPlanMode(title, description);
111
+ return {
112
+ success: true,
113
+ output: { planId, message: `Plan mode active. Use planCreateEntity/planUpdateEntity/planAddLink to buffer operations, then submitPlan to send for review.` }
114
+ };
115
+ }
116
+ };
117
+ }
118
+ function createPlanCreateEntityTool(ctx) {
119
+ return {
120
+ def: {
121
+ name: "planCreateEntity",
122
+ description: "Buffer a new entity creation in the active plan. Must be in plan mode.",
123
+ schema: JSON.stringify({
124
+ type: "object",
125
+ properties: {
126
+ entityId: { type: "string", description: "Unique entity ID" },
127
+ entityType: { type: "string", description: "Entity type name" },
128
+ attributes: { type: "object", description: "Entity attributes as key-value pairs" },
129
+ description: { type: "string", description: "Human-readable description of this operation" }
130
+ },
131
+ required: ["entityId", "entityType"]
132
+ })
133
+ },
134
+ handler: async (input) => {
135
+ const { entityId, entityType, attributes, description } = input;
136
+ const opId = await ctx.planManager.planCreateEntity(entityId, entityType, attributes, description);
137
+ return { success: true, output: { operationId: opId } };
138
+ }
139
+ };
140
+ }
141
+ function createPlanUpdateEntityTool(ctx) {
142
+ return {
143
+ def: {
144
+ name: "planUpdateEntity",
145
+ description: "Buffer an entity update in the active plan. Must be in plan mode.",
146
+ schema: JSON.stringify({
147
+ type: "object",
148
+ properties: {
149
+ entityId: { type: "string", description: "Target entity ID" },
150
+ attributes: { type: "object", description: "Attributes to update" },
151
+ description: { type: "string", description: "Human-readable description" }
152
+ },
153
+ required: ["entityId", "attributes"]
154
+ })
155
+ },
156
+ handler: async (input) => {
157
+ const { entityId, attributes, description } = input;
158
+ const opId = await ctx.planManager.planUpdateEntity(entityId, attributes, description);
159
+ return { success: true, output: { operationId: opId } };
160
+ }
161
+ };
162
+ }
163
+ function createPlanAddLinkTool(ctx) {
164
+ return {
165
+ def: {
166
+ name: "planAddLink",
167
+ description: "Buffer a link creation in the active plan. Must be in plan mode.",
168
+ schema: JSON.stringify({
169
+ type: "object",
170
+ properties: {
171
+ sourceId: { type: "string", description: "Source entity ID" },
172
+ linkAttribute: { type: "string", description: "Relationship attribute name" },
173
+ targetId: { type: "string", description: "Target entity ID" },
174
+ description: { type: "string", description: "Human-readable description" }
175
+ },
176
+ required: ["sourceId", "linkAttribute", "targetId"]
177
+ })
178
+ },
179
+ handler: async (input) => {
180
+ const { sourceId, linkAttribute, targetId, description } = input;
181
+ const opId = await ctx.planManager.planAddLink(sourceId, linkAttribute, targetId, description);
182
+ return { success: true, output: { operationId: opId } };
183
+ }
184
+ };
185
+ }
186
+ function createSubmitPlanTool(ctx) {
187
+ return {
188
+ def: {
189
+ name: "submitPlan",
190
+ description: "Submit the active plan for user review. The plan will be presented to the user for approval before any operations are executed. The agent loop will pause until the user approves or rejects.",
191
+ schema: JSON.stringify({
192
+ type: "object",
193
+ properties: {}
194
+ })
195
+ },
196
+ handler: async () => {
197
+ const plan = await ctx.planManager.submitPlan();
198
+ return {
199
+ success: true,
200
+ output: {
201
+ _planPending: true,
202
+ planId: plan.id,
203
+ title: plan.title,
204
+ description: plan.description,
205
+ operationCount: plan.operations.length,
206
+ operations: plan.operations.map((op) => ({
207
+ kind: op.kind,
208
+ description: op.description,
209
+ entityId: op.entityId,
210
+ entityType: op.entityType
211
+ }))
212
+ }
213
+ };
214
+ }
215
+ };
216
+ }
217
+ function createCancelPlanTool(ctx) {
218
+ return {
219
+ def: {
220
+ name: "cancelPlan",
221
+ description: "Cancel the active plan without submitting. Discards all buffered operations.",
222
+ schema: JSON.stringify({
223
+ type: "object",
224
+ properties: {}
225
+ })
226
+ },
227
+ handler: async () => {
228
+ await ctx.planManager.cancelPlan();
229
+ return { success: true, output: { message: "Plan cancelled." } };
230
+ }
231
+ };
232
+ }
233
+ function registerPlanTools(harness, ctx) {
234
+ const tools = [
235
+ createEnterPlanModeTool(ctx),
236
+ createPlanCreateEntityTool(ctx),
237
+ createPlanUpdateEntityTool(ctx),
238
+ createPlanAddLinkTool(ctx),
239
+ createSubmitPlanTool(ctx),
240
+ createCancelPlanTool(ctx)
241
+ ];
242
+ return Promise.all(
243
+ tools.map((t) => harness.registerTool(t.def, t.handler))
244
+ );
245
+ }
246
+
247
+ // src/plugins/plan-approval/plan-manager.ts
248
+ var planIdCounter = 0;
249
+ var PlanManager = class {
250
+ kernel;
251
+ activePlan = null;
252
+ constructor(kernel) {
253
+ this.kernel = kernel;
254
+ }
255
+ // -------------------------------------------------------------------------
256
+ // Plan mode lifecycle
257
+ // -------------------------------------------------------------------------
258
+ /**
259
+ * Enter plan mode. Creates a PendingPlan entity in the graph and sets it
260
+ * as the active plan. All subsequent `addOperation()` calls buffer into it.
261
+ */
262
+ async enterPlanMode(title, description) {
263
+ if (this.activePlan && this.activePlan.status === "drafting") {
264
+ throw new Error("PlanManager: Already in plan mode. Submit or cancel the current plan first.");
265
+ }
266
+ const id = `plan:${Date.now()}:${++planIdCounter}`;
267
+ const now = (/* @__PURE__ */ new Date()).toISOString();
268
+ const plan = {
269
+ id,
270
+ status: "drafting",
271
+ title,
272
+ description,
273
+ operations: [],
274
+ createdAt: now
275
+ };
276
+ const attrs = {
277
+ title,
278
+ status: "drafting"
279
+ };
280
+ if (description) attrs.description = description;
281
+ attrs.operationCount = 0;
282
+ await this.kernel.createEntity(id, "PendingPlan", attrs);
283
+ this.activePlan = plan;
284
+ return id;
285
+ }
286
+ /**
287
+ * Whether a plan is currently being drafted.
288
+ */
289
+ isInPlanMode() {
290
+ return this.activePlan !== null && this.activePlan.status === "drafting";
291
+ }
292
+ /**
293
+ * Get the active plan (if any).
294
+ */
295
+ getActivePlan() {
296
+ return this.activePlan;
297
+ }
298
+ // -------------------------------------------------------------------------
299
+ // Buffer operations
300
+ // -------------------------------------------------------------------------
301
+ /**
302
+ * Buffer a planned graph operation. Only valid in plan mode.
303
+ * Returns the operation ID.
304
+ */
305
+ async addOperation(op) {
306
+ if (!this.activePlan || this.activePlan.status !== "drafting") {
307
+ throw new Error("PlanManager: Not in plan mode. Call enterPlanMode() first.");
308
+ }
309
+ const sequence = this.activePlan.operations.length;
310
+ const opId = `${this.activePlan.id}:op:${sequence}`;
311
+ const planned = {
312
+ ...op,
313
+ id: opId,
314
+ sequence
315
+ };
316
+ this.activePlan.operations.push(planned);
317
+ const attrs = {
318
+ kind: op.kind,
319
+ sequence
320
+ };
321
+ if (op.entityId) attrs.entityId = op.entityId;
322
+ if (op.entityType) attrs.entityType = op.entityType;
323
+ if (op.attributes) attrs.attributes = JSON.stringify(op.attributes);
324
+ if (op.sourceId) attrs.sourceId = op.sourceId;
325
+ if (op.targetId) attrs.targetId = op.targetId;
326
+ if (op.linkAttribute) attrs.linkAttribute = op.linkAttribute;
327
+ if (op.description) attrs.description = op.description;
328
+ await this.kernel.createEntity(opId, "PlannedOperation", attrs);
329
+ await this.kernel.addLink(this.activePlan.id, "hasOperation", opId);
330
+ await this.kernel.updateEntity(this.activePlan.id, {
331
+ operationCount: this.activePlan.operations.length
332
+ });
333
+ return opId;
334
+ }
335
+ // -------------------------------------------------------------------------
336
+ // Convenience buffers (mirror the kernel entity API)
337
+ // -------------------------------------------------------------------------
338
+ async planCreateEntity(entityId, entityType, attributes, description) {
339
+ return this.addOperation({
340
+ kind: "createEntity",
341
+ entityId,
342
+ entityType,
343
+ attributes,
344
+ description: description ?? `Create ${entityType} "${entityId}"`
345
+ });
346
+ }
347
+ async planUpdateEntity(entityId, attributes, description) {
348
+ return this.addOperation({
349
+ kind: "updateEntity",
350
+ entityId,
351
+ attributes,
352
+ description: description ?? `Update "${entityId}"`
353
+ });
354
+ }
355
+ async planDeleteEntity(entityId, description) {
356
+ return this.addOperation({
357
+ kind: "deleteEntity",
358
+ entityId,
359
+ description: description ?? `Delete "${entityId}"`
360
+ });
361
+ }
362
+ async planAddLink(sourceId, linkAttribute, targetId, description) {
363
+ return this.addOperation({
364
+ kind: "addLink",
365
+ sourceId,
366
+ targetId,
367
+ linkAttribute,
368
+ description: description ?? `Link ${sourceId} -[${linkAttribute}]-> ${targetId}`
369
+ });
370
+ }
371
+ async planRemoveLink(sourceId, linkAttribute, targetId, description) {
372
+ return this.addOperation({
373
+ kind: "removeLink",
374
+ sourceId,
375
+ targetId,
376
+ linkAttribute,
377
+ description: description ?? `Unlink ${sourceId} -[${linkAttribute}]-> ${targetId}`
378
+ });
379
+ }
380
+ // -------------------------------------------------------------------------
381
+ // Plan resolution
382
+ // -------------------------------------------------------------------------
383
+ /**
384
+ * Submit the active plan for review. Marks it as submitted and returns
385
+ * the plan for the caller to present to the user.
386
+ */
387
+ async submitPlan() {
388
+ if (!this.activePlan || this.activePlan.status !== "drafting") {
389
+ throw new Error("PlanManager: No active plan to submit.");
390
+ }
391
+ if (this.activePlan.operations.length === 0) {
392
+ throw new Error("PlanManager: Cannot submit an empty plan.");
393
+ }
394
+ const now = (/* @__PURE__ */ new Date()).toISOString();
395
+ this.activePlan.status = "submitted";
396
+ this.activePlan.submittedAt = now;
397
+ await this.kernel.updateEntity(this.activePlan.id, {
398
+ status: "submitted",
399
+ submittedAt: now
400
+ });
401
+ return { ...this.activePlan };
402
+ }
403
+ /**
404
+ * Approve a submitted plan. Replays all buffered operations against the
405
+ * real kernel in sequence order. Returns the results of each operation.
406
+ */
407
+ async approvePlan(resolvedBy) {
408
+ if (!this.activePlan || this.activePlan.status !== "submitted") {
409
+ throw new Error("PlanManager: No submitted plan to approve.");
410
+ }
411
+ const plan = this.activePlan;
412
+ const now = (/* @__PURE__ */ new Date()).toISOString();
413
+ const results = [];
414
+ const ops = [...plan.operations].sort((a, b) => a.sequence - b.sequence);
415
+ for (const op of ops) {
416
+ const result = await this._executeOperation(op);
417
+ if (result) results.push(result);
418
+ }
419
+ plan.status = "approved";
420
+ plan.resolvedAt = now;
421
+ plan.resolvedBy = resolvedBy;
422
+ await this.kernel.updateEntity(plan.id, {
423
+ status: "approved",
424
+ resolvedAt: now,
425
+ ...resolvedBy ? { resolvedBy } : {}
426
+ });
427
+ this.activePlan = null;
428
+ return {
429
+ planId: plan.id,
430
+ operationsExecuted: results.length,
431
+ results
432
+ };
433
+ }
434
+ /**
435
+ * Reject a submitted plan. The plan and its operations remain in the graph
436
+ * as entities, preserving them as substrate for the Idea Garden (Phase 6).
437
+ */
438
+ async rejectPlan(reason, resolvedBy) {
439
+ if (!this.activePlan || this.activePlan.status !== "submitted") {
440
+ throw new Error("PlanManager: No submitted plan to reject.");
441
+ }
442
+ const now = (/* @__PURE__ */ new Date()).toISOString();
443
+ this.activePlan.status = "rejected";
444
+ this.activePlan.resolvedAt = now;
445
+ this.activePlan.resolvedBy = resolvedBy;
446
+ this.activePlan.rejectionReason = reason;
447
+ const updates = {
448
+ status: "rejected",
449
+ resolvedAt: now
450
+ };
451
+ if (reason) updates.rejectionReason = reason;
452
+ if (resolvedBy) updates.resolvedBy = resolvedBy;
453
+ await this.kernel.updateEntity(this.activePlan.id, updates);
454
+ this.activePlan = null;
455
+ }
456
+ /**
457
+ * Cancel a drafting plan without submitting. Like rejection but for
458
+ * plans that were never submitted.
459
+ */
460
+ async cancelPlan() {
461
+ if (!this.activePlan || this.activePlan.status !== "drafting") {
462
+ throw new Error("PlanManager: No active plan to cancel.");
463
+ }
464
+ await this.kernel.updateEntity(this.activePlan.id, {
465
+ status: "rejected",
466
+ resolvedAt: (/* @__PURE__ */ new Date()).toISOString(),
467
+ rejectionReason: "Cancelled before submission"
468
+ });
469
+ this.activePlan = null;
470
+ }
471
+ // -------------------------------------------------------------------------
472
+ // Query helpers
473
+ // -------------------------------------------------------------------------
474
+ /**
475
+ * Load a plan from the graph by ID, including its operations.
476
+ */
477
+ loadPlan(planId) {
478
+ const entity = this.kernel.getEntity(planId);
479
+ if (!entity || entity.type !== "PendingPlan") return null;
480
+ const get = (a) => entity.facts.find((f) => f.a === a)?.v;
481
+ const store = this.kernel.getStore();
482
+ const opLinks = store.getLinksByEntityAndAttribute(planId, "hasOperation");
483
+ const operations = [];
484
+ for (const link of opLinks) {
485
+ const opEntity = this.kernel.getEntity(link.e2);
486
+ if (!opEntity || opEntity.type !== "PlannedOperation") continue;
487
+ const opGet = (a) => opEntity.facts.find((f) => f.a === a)?.v;
488
+ let attributes;
489
+ const attrsRaw = opGet("attributes");
490
+ if (attrsRaw) {
491
+ try {
492
+ attributes = JSON.parse(attrsRaw);
493
+ } catch {
494
+ }
495
+ }
496
+ operations.push({
497
+ id: opEntity.id,
498
+ kind: opGet("kind"),
499
+ entityId: opGet("entityId"),
500
+ entityType: opGet("entityType"),
501
+ attributes,
502
+ sourceId: opGet("sourceId"),
503
+ targetId: opGet("targetId"),
504
+ linkAttribute: opGet("linkAttribute"),
505
+ description: opGet("description"),
506
+ sequence: opGet("sequence") ?? 0
507
+ });
508
+ }
509
+ operations.sort((a, b) => a.sequence - b.sequence);
510
+ return {
511
+ id: planId,
512
+ status: get("status") ?? "drafting",
513
+ title: String(get("title") ?? ""),
514
+ description: get("description"),
515
+ operations,
516
+ createdAt: String(get("createdAt") ?? ""),
517
+ submittedAt: get("submittedAt"),
518
+ resolvedAt: get("resolvedAt"),
519
+ resolvedBy: get("resolvedBy"),
520
+ rejectionReason: get("rejectionReason")
521
+ };
522
+ }
523
+ /**
524
+ * List all plans, optionally filtered by status.
525
+ */
526
+ listPlans(status) {
527
+ const entities = this.kernel.listEntities("PendingPlan", status ? { status } : void 0);
528
+ return entities.map((e) => this.loadPlan(e.id)).filter((p) => p !== null);
529
+ }
530
+ // -------------------------------------------------------------------------
531
+ // Internal
532
+ // -------------------------------------------------------------------------
533
+ /**
534
+ * Execute a single planned operation against the real kernel.
535
+ */
536
+ async _executeOperation(op) {
537
+ switch (op.kind) {
538
+ case "createEntity":
539
+ if (!op.entityId || !op.entityType) {
540
+ throw new Error(`PlannedOperation ${op.id}: createEntity requires entityId and entityType`);
541
+ }
542
+ return this.kernel.createEntity(op.entityId, op.entityType, op.attributes ?? {});
543
+ case "updateEntity":
544
+ if (!op.entityId || !op.attributes) {
545
+ throw new Error(`PlannedOperation ${op.id}: updateEntity requires entityId and attributes`);
546
+ }
547
+ return this.kernel.updateEntity(op.entityId, op.attributes);
548
+ case "deleteEntity":
549
+ if (!op.entityId) {
550
+ throw new Error(`PlannedOperation ${op.id}: deleteEntity requires entityId`);
551
+ }
552
+ return this.kernel.deleteEntity(op.entityId);
553
+ case "addLink":
554
+ if (!op.sourceId || !op.linkAttribute || !op.targetId) {
555
+ throw new Error(`PlannedOperation ${op.id}: addLink requires sourceId, linkAttribute, and targetId`);
556
+ }
557
+ return this.kernel.addLink(op.sourceId, op.linkAttribute, op.targetId);
558
+ case "removeLink":
559
+ if (!op.sourceId || !op.linkAttribute || !op.targetId) {
560
+ throw new Error(`PlannedOperation ${op.id}: removeLink requires sourceId, linkAttribute, and targetId`);
561
+ }
562
+ return this.kernel.removeLink(op.sourceId, op.linkAttribute, op.targetId);
563
+ default:
564
+ throw new Error(`PlannedOperation ${op.id}: Unknown operation kind "${op.kind}"`);
565
+ }
566
+ }
567
+ };
568
+ export {
569
+ PlanManager,
570
+ createCancelPlanTool,
571
+ createEnterPlanModeTool,
572
+ createPlanAddLinkTool,
573
+ createPlanApprovalPlugin,
574
+ createPlanCreateEntityTool,
575
+ createPlanUpdateEntityTool,
576
+ createSubmitPlanTool,
577
+ planApprovalOntology,
578
+ registerPlanTools
579
+ };