@agimon-ai/doompi-task 0.0.1-alpha.12 → 0.0.1-alpha.121
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -15
- package/dist/apiContracts.cjs +54 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +53 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +49 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/commands.cjs +4 -1
- package/dist/commands.d.mts +20 -2
- package/dist/commands.d.mts.map +1 -0
- package/dist/commands.mjs +2 -1
- package/dist/config-BPNE_wEU.cjs +173 -0
- package/dist/config-BPNE_wEU.cjs.map +1 -0
- package/dist/config-DmsCPDuF.mjs +72 -0
- package/dist/config-DmsCPDuF.mjs.map +1 -0
- package/dist/config.cjs +19 -1
- package/dist/config.d.mts +2 -2
- package/dist/config.mjs +2 -1
- package/dist/delegation-3hMdTFXF.cjs +661 -0
- package/dist/delegation-3hMdTFXF.cjs.map +1 -0
- package/dist/delegation-BiOy3_7g.mjs +7 -0
- package/dist/delegation-BiOy3_7g.mjs.map +1 -0
- package/dist/delegation-CkGbRaOl.mjs +626 -0
- package/dist/delegation-CkGbRaOl.mjs.map +1 -0
- package/dist/delegation-LDpHP2CC.cjs +12 -0
- package/dist/delegation-LDpHP2CC.cjs.map +1 -0
- package/dist/delegation-Ot2xltLi.d.mts +6 -0
- package/dist/delegation-Ot2xltLi.d.mts.map +1 -0
- package/dist/delegationManager.cjs +10 -0
- package/dist/delegationManager.d.mts +3 -0
- package/dist/delegationManager.mjs +3 -0
- package/dist/delegationPlatform-Cfn-Lqew.cjs +95 -0
- package/dist/delegationPlatform-Cfn-Lqew.cjs.map +1 -0
- package/dist/delegationPlatform-DZ4SZ8a5.mjs +64 -0
- package/dist/delegationPlatform-DZ4SZ8a5.mjs.map +1 -0
- package/dist/extensions/mcp-ui.mjs +23 -0
- package/dist/extensions/mcp-ui.mjs.map +1 -0
- package/dist/extensions/mcp.cjs +1876 -0
- package/dist/extensions/mcp.cjs.map +1 -0
- package/dist/extensions/mcp.d.mts +5 -0
- package/dist/extensions/mcp.d.mts.map +1 -0
- package/dist/extensions/mcp.mjs +1846 -0
- package/dist/extensions/mcp.mjs.map +1 -0
- package/dist/extensions/pi.cjs +437 -1
- package/dist/extensions/pi.cjs.map +1 -1
- package/dist/extensions/pi.d.mts +5 -2
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +432 -1
- package/dist/extensions/pi.mjs.map +1 -1
- package/dist/extensions/server.cjs +380 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +375 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +1013 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/format.cli-ChQsP1MQ.cjs +393 -0
- package/dist/format.cli-ChQsP1MQ.cjs.map +1 -0
- package/dist/format.cli-Cnc591eb.mjs +322 -0
- package/dist/format.cli-Cnc591eb.mjs.map +1 -0
- package/dist/{services/delegation/manager.d.mts → index-3-3ZJlaH.d.mts} +35 -31
- package/dist/index-3-3ZJlaH.d.mts.map +1 -0
- package/dist/{adapters/store/taskStore.d.cts → index-B7oVjSey.d.mts} +11 -28
- package/dist/index-B7oVjSey.d.mts.map +1 -0
- package/dist/{services/store/reconcile.d.cts → index-BNMm9g0K.d.mts} +4 -4
- package/dist/index-BNMm9g0K.d.mts.map +1 -0
- package/dist/{commands/task/responseEnvelope.d.cts → index-C3DgOhEm.d.mts} +17 -5
- package/dist/index-C3DgOhEm.d.mts.map +1 -0
- package/dist/{types/config.d.cts → index-D4goIk4Z.d.mts} +8 -3
- package/dist/index-D4goIk4Z.d.mts.map +1 -0
- package/dist/{services/store/reducer.d.cts → index-DIpc6_uJ.d.mts} +5 -5
- package/dist/index-DIpc6_uJ.d.mts.map +1 -0
- package/dist/{adapters/store/paths.d.cts → index-XY9VPmfm.d.mts} +6 -6
- package/dist/index-XY9VPmfm.d.mts.map +1 -0
- package/dist/index.cjs +106 -1
- package/dist/index.d.mts +16 -16
- package/dist/index.mjs +16 -1
- package/dist/invariants-DhjEjBPU.cjs +79 -0
- package/dist/invariants-DhjEjBPU.cjs.map +1 -0
- package/dist/invariants-q_UamF7D.mjs +62 -0
- package/dist/invariants-q_UamF7D.mjs.map +1 -0
- package/dist/logSinkTelemetry-C5QjZipw.mjs +41 -0
- package/dist/logSinkTelemetry-C5QjZipw.mjs.map +1 -0
- package/dist/logSinkTelemetry-CqiTuh3a.cjs +52 -0
- package/dist/logSinkTelemetry-CqiTuh3a.cjs.map +1 -0
- package/dist/logSinkTelemetry.cjs +6 -1
- package/dist/logSinkTelemetry.d.mts +23 -2
- package/dist/logSinkTelemetry.d.mts.map +1 -0
- package/dist/logSinkTelemetry.mjs +3 -1
- package/dist/paths-Bg8EEbk1.mjs +218 -0
- package/dist/paths-Bg8EEbk1.mjs.map +1 -0
- package/dist/paths-BsFVRulr.cjs +320 -0
- package/dist/paths-BsFVRulr.cjs.map +1 -0
- package/dist/processLiveness-Ccd9wenT.mjs +20 -0
- package/dist/processLiveness-Ccd9wenT.mjs.map +1 -0
- package/dist/processLiveness-umpNgsPR.cjs +25 -0
- package/dist/processLiveness-umpNgsPR.cjs.map +1 -0
- package/dist/promptGuidelines-DaxWrqud.d.mts +14 -0
- package/dist/promptGuidelines-DaxWrqud.d.mts.map +1 -0
- package/dist/promptGuidelines-g4QT8GNM.mjs +26 -0
- package/dist/promptGuidelines-g4QT8GNM.mjs.map +1 -0
- package/dist/promptGuidelines-j_SZTzlH.cjs +31 -0
- package/dist/promptGuidelines-j_SZTzlH.cjs.map +1 -0
- package/dist/reconcile-BcD-hTbd.mjs +63 -0
- package/dist/reconcile-BcD-hTbd.mjs.map +1 -0
- package/dist/reconcile-cRL0NjDr.cjs +80 -0
- package/dist/reconcile-cRL0NjDr.cjs.map +1 -0
- package/dist/reducer-BEfJFM5L.mjs +345 -0
- package/dist/reducer-BEfJFM5L.mjs.map +1 -0
- package/dist/reducer-BV0YIZ2o.cjs +380 -0
- package/dist/reducer-BV0YIZ2o.cjs.map +1 -0
- package/dist/root.cli-swHZqusx.d.mts +56 -0
- package/dist/root.cli-swHZqusx.d.mts.map +1 -0
- package/dist/selectors-BaS6dObz.mjs +142 -0
- package/dist/selectors-BaS6dObz.mjs.map +1 -0
- package/dist/{tui/selectors.d.cts → selectors-DPDPPjH3.d.mts} +11 -4
- package/dist/selectors-DPDPPjH3.d.mts.map +1 -0
- package/dist/selectors-b-69vb4W.cjs +189 -0
- package/dist/selectors-b-69vb4W.cjs.map +1 -0
- package/dist/storeInvariants.cjs +5 -0
- package/dist/storeInvariants.d.mts +23 -0
- package/dist/storeInvariants.d.mts.map +1 -0
- package/dist/storeInvariants.mjs +2 -0
- package/dist/storePaths.cjs +14 -0
- package/dist/storePaths.d.mts +2 -0
- package/dist/storePaths.mjs +2 -0
- package/dist/storeProcessLiveness.cjs +3 -0
- package/dist/{services/store/processLiveness.d.cts → storeProcessLiveness.d.mts} +3 -4
- package/dist/storeProcessLiveness.d.mts.map +1 -0
- package/dist/storeProcessLiveness.mjs +2 -0
- package/dist/storeReconcile.cjs +5 -0
- package/dist/storeReconcile.d.mts +2 -0
- package/dist/storeReconcile.mjs +2 -0
- package/dist/storeReducer.cjs +8 -0
- package/dist/storeReducer.d.mts +2 -0
- package/dist/storeReducer.mjs +2 -0
- package/dist/storeTaskGraph.cjs +7 -0
- package/dist/storeTaskGraph.d.mts +2 -0
- package/dist/storeTaskGraph.mjs +2 -0
- package/dist/storeTaskStore.cjs +3 -0
- package/dist/storeTaskStore.d.mts +2 -0
- package/dist/storeTaskStore.mjs +2 -0
- package/dist/storeTypes.cjs +6 -0
- package/dist/storeTypes.d.mts +2 -0
- package/dist/storeTypes.mjs +2 -0
- package/dist/task-B4aF5J9s.mjs +6 -0
- package/dist/task-B4aF5J9s.mjs.map +1 -0
- package/dist/task-CXF9VULl.cjs +49 -0
- package/dist/task-CXF9VULl.cjs.map +1 -0
- package/dist/task-CkFjC3Fo.d.mts +5 -0
- package/dist/task-CkFjC3Fo.d.mts.map +1 -0
- package/dist/{schemas/task.d.mts → task-DHSvdK6E.d.mts} +33 -17
- package/dist/task-DHSvdK6E.d.mts.map +1 -0
- package/dist/task-DKHKuems.mjs +116 -0
- package/dist/task-DKHKuems.mjs.map +1 -0
- package/dist/task-DaagqdPK.cjs +11 -0
- package/dist/task-DaagqdPK.cjs.map +1 -0
- package/dist/task-Dqy88_rr.cjs +193 -0
- package/dist/task-Dqy88_rr.cjs.map +1 -0
- package/dist/task-giCbpKzV.mjs +26 -0
- package/dist/task-giCbpKzV.mjs.map +1 -0
- package/dist/{services/store/types.d.mts → task-hLh4BOO7.d.mts} +37 -15
- package/dist/task-hLh4BOO7.d.mts.map +1 -0
- package/dist/task-space.cli-BH4Iy_7m.cjs +372 -0
- package/dist/task-space.cli-BH4Iy_7m.cjs.map +1 -0
- package/dist/task-space.cli-CMYNjgOW.mjs +355 -0
- package/dist/task-space.cli-CMYNjgOW.mjs.map +1 -0
- package/dist/task.cli-BM34E7GG.mjs +157 -0
- package/dist/task.cli-BM34E7GG.mjs.map +1 -0
- package/dist/task.cli-CiTkjUaX.cjs +174 -0
- package/dist/task.cli-CiTkjUaX.cjs.map +1 -0
- package/dist/taskGraph-BOQvT0-M.mjs +63 -0
- package/dist/taskGraph-BOQvT0-M.mjs.map +1 -0
- package/dist/taskGraph-BskRslrr.cjs +92 -0
- package/dist/taskGraph-BskRslrr.cjs.map +1 -0
- package/dist/{services/store/taskGraph.d.cts → taskGraph-YQXCfXTn.d.mts} +4 -4
- package/dist/taskGraph-YQXCfXTn.d.mts.map +1 -0
- package/dist/taskOverlay-B5wJHiml.cjs +175 -0
- package/dist/taskOverlay-B5wJHiml.cjs.map +1 -0
- package/dist/taskOverlay-CljDoTj_.mjs +164 -0
- package/dist/taskOverlay-CljDoTj_.mjs.map +1 -0
- package/dist/taskResult-D2G7b4w-.cjs +224 -0
- package/dist/taskResult-D2G7b4w-.cjs.map +1 -0
- package/dist/taskResult-edBAAKSH.mjs +165 -0
- package/dist/taskResult-edBAAKSH.mjs.map +1 -0
- package/dist/taskStore-CFx12KJk.mjs +213 -0
- package/dist/taskStore-CFx12KJk.mjs.map +1 -0
- package/dist/taskStore-T1pPy-UJ.cjs +220 -0
- package/dist/taskStore-T1pPy-UJ.cjs.map +1 -0
- package/dist/tasks.cli-8VvuN9YQ.cjs +40 -0
- package/dist/tasks.cli-8VvuN9YQ.cjs.map +1 -0
- package/dist/tasks.cli-BZj83YD_.mjs +29 -0
- package/dist/tasks.cli-BZj83YD_.mjs.map +1 -0
- package/dist/telemetry-DOyZLj8E.d.mts +36 -0
- package/dist/telemetry-DOyZLj8E.d.mts.map +1 -0
- package/dist/telemetry-I4md7Xzz.cjs +31 -0
- package/dist/telemetry-I4md7Xzz.cjs.map +1 -0
- package/dist/telemetry-PmX_1Y8a.mjs +26 -0
- package/dist/telemetry-PmX_1Y8a.mjs.map +1 -0
- package/dist/toolPromptGuidelines.cjs +3 -0
- package/dist/toolPromptGuidelines.d.mts +2 -0
- package/dist/toolPromptGuidelines.mjs +2 -0
- package/dist/toolResponseEnvelope.cjs +12 -0
- package/dist/toolResponseEnvelope.d.mts +2 -0
- package/dist/toolResponseEnvelope.mjs +2 -0
- package/dist/toolSchema.cjs +17 -0
- package/dist/toolSchema.d.mts +3 -0
- package/dist/toolSchema.mjs +3 -0
- package/dist/toolTaskTool.cjs +6 -0
- package/dist/toolTaskTool.d.mts +3 -0
- package/dist/toolTaskTool.mjs +3 -0
- package/dist/tuiFormat.cjs +14 -0
- package/dist/tuiFormat.d.mts +61 -0
- package/dist/tuiFormat.d.mts.map +1 -0
- package/dist/tuiFormat.mjs +2 -0
- package/dist/tuiSelectors.cjs +10 -0
- package/dist/tuiSelectors.d.mts +2 -0
- package/dist/tuiSelectors.mjs +2 -0
- package/dist/tuiTaskOverlay.cjs +4 -0
- package/dist/{tui/taskOverlay.d.cts → tuiTaskOverlay.d.mts} +9 -8
- package/dist/tuiTaskOverlay.d.mts.map +1 -0
- package/dist/tuiTaskOverlay.mjs +2 -0
- package/dist/tuiTaskSpace.cjs +5 -0
- package/dist/{tui/taskSpace.d.cts → tuiTaskSpace.d.mts} +11 -13
- package/dist/tuiTaskSpace.d.mts.map +1 -0
- package/dist/tuiTaskSpace.mjs +2 -0
- package/package.json +175 -109
- package/src/types/webTasks.ts +24 -0
- package/dist/_virtual/_rolldown/runtime.cjs +0 -1
- package/dist/adapters/pi/extension.cjs +0 -3
- package/dist/adapters/pi/extension.cjs.map +0 -1
- package/dist/adapters/pi/extension.d.cts +0 -12
- package/dist/adapters/pi/extension.d.cts.map +0 -1
- package/dist/adapters/pi/extension.d.mts +0 -12
- package/dist/adapters/pi/extension.d.mts.map +0 -1
- package/dist/adapters/pi/extension.mjs +0 -3
- package/dist/adapters/pi/extension.mjs.map +0 -1
- package/dist/adapters/store/paths.cjs +0 -2
- package/dist/adapters/store/paths.cjs.map +0 -1
- package/dist/adapters/store/paths.d.cts.map +0 -1
- package/dist/adapters/store/paths.d.mts +0 -26
- package/dist/adapters/store/paths.d.mts.map +0 -1
- package/dist/adapters/store/paths.mjs +0 -2
- package/dist/adapters/store/paths.mjs.map +0 -1
- package/dist/adapters/store/taskStore.cjs +0 -2
- package/dist/adapters/store/taskStore.cjs.map +0 -1
- package/dist/adapters/store/taskStore.d.cts.map +0 -1
- package/dist/adapters/store/taskStore.d.mts +0 -87
- package/dist/adapters/store/taskStore.d.mts.map +0 -1
- package/dist/adapters/store/taskStore.mjs +0 -2
- package/dist/adapters/store/taskStore.mjs.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.cjs +0 -2
- package/dist/adapters/telemetry/logSinkTelemetry.cjs.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts +0 -52
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts +0 -52
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.mjs +0 -2
- package/dist/adapters/telemetry/logSinkTelemetry.mjs.map +0 -1
- package/dist/commands/index.cjs +0 -2
- package/dist/commands/index.cjs.map +0 -1
- package/dist/commands/index.d.cts +0 -15
- package/dist/commands/index.d.cts.map +0 -1
- package/dist/commands/index.d.mts +0 -15
- package/dist/commands/index.d.mts.map +0 -1
- package/dist/commands/index.mjs +0 -2
- package/dist/commands/index.mjs.map +0 -1
- package/dist/commands/task/promptGuidelines.cjs +0 -2
- package/dist/commands/task/promptGuidelines.cjs.map +0 -1
- package/dist/commands/task/promptGuidelines.d.cts +0 -5
- package/dist/commands/task/promptGuidelines.d.cts.map +0 -1
- package/dist/commands/task/promptGuidelines.d.mts +0 -5
- package/dist/commands/task/promptGuidelines.d.mts.map +0 -1
- package/dist/commands/task/promptGuidelines.mjs +0 -2
- package/dist/commands/task/promptGuidelines.mjs.map +0 -1
- package/dist/commands/task/responseEnvelope.cjs +0 -6
- package/dist/commands/task/responseEnvelope.cjs.map +0 -1
- package/dist/commands/task/responseEnvelope.d.cts.map +0 -1
- package/dist/commands/task/responseEnvelope.d.mts +0 -39
- package/dist/commands/task/responseEnvelope.d.mts.map +0 -1
- package/dist/commands/task/responseEnvelope.mjs +0 -6
- package/dist/commands/task/responseEnvelope.mjs.map +0 -1
- package/dist/commands/task/taskTool.cjs +0 -3
- package/dist/commands/task/taskTool.cjs.map +0 -1
- package/dist/commands/task/taskTool.d.cts +0 -18
- package/dist/commands/task/taskTool.d.cts.map +0 -1
- package/dist/commands/task/taskTool.d.mts +0 -18
- package/dist/commands/task/taskTool.d.mts.map +0 -1
- package/dist/commands/task/taskTool.mjs +0 -3
- package/dist/commands/task/taskTool.mjs.map +0 -1
- package/dist/commands.d.cts +0 -2
- package/dist/config.d.cts +0 -2
- package/dist/delegation/manager.cjs +0 -1
- package/dist/delegation/manager.d.cts +0 -2
- package/dist/delegation/manager.d.mts +0 -2
- package/dist/delegation/manager.mjs +0 -1
- package/dist/extension.cjs +0 -1
- package/dist/extension.d.cts +0 -2
- package/dist/extension.d.mts +0 -2
- package/dist/extension.mjs +0 -1
- package/dist/extensions/doom.cjs +0 -2
- package/dist/extensions/doom.cjs.map +0 -1
- package/dist/extensions/doom.d.cts +0 -6
- package/dist/extensions/doom.d.cts.map +0 -1
- package/dist/extensions/doom.d.mts +0 -7
- package/dist/extensions/doom.d.mts.map +0 -1
- package/dist/extensions/doom.mjs +0 -2
- package/dist/extensions/doom.mjs.map +0 -1
- package/dist/extensions/pi.d.cts +0 -2
- package/dist/index.d.cts +0 -16
- package/dist/logSinkTelemetry.d.cts +0 -2
- package/dist/schemas/task.cjs +0 -2
- package/dist/schemas/task.cjs.map +0 -1
- package/dist/schemas/task.d.cts +0 -86
- package/dist/schemas/task.d.cts.map +0 -1
- package/dist/schemas/task.d.mts.map +0 -1
- package/dist/schemas/task.mjs +0 -2
- package/dist/schemas/task.mjs.map +0 -1
- package/dist/services/delegation/manager.cjs +0 -6
- package/dist/services/delegation/manager.cjs.map +0 -1
- package/dist/services/delegation/manager.d.cts +0 -188
- package/dist/services/delegation/manager.d.cts.map +0 -1
- package/dist/services/delegation/manager.d.mts.map +0 -1
- package/dist/services/delegation/manager.mjs +0 -6
- package/dist/services/delegation/manager.mjs.map +0 -1
- package/dist/services/narration/taskNarration.cjs +0 -2
- package/dist/services/narration/taskNarration.cjs.map +0 -1
- package/dist/services/narration/taskNarration.mjs +0 -2
- package/dist/services/narration/taskNarration.mjs.map +0 -1
- package/dist/services/store/invariants.cjs +0 -2
- package/dist/services/store/invariants.cjs.map +0 -1
- package/dist/services/store/invariants.d.cts +0 -14
- package/dist/services/store/invariants.d.cts.map +0 -1
- package/dist/services/store/invariants.d.mts +0 -14
- package/dist/services/store/invariants.d.mts.map +0 -1
- package/dist/services/store/invariants.mjs +0 -2
- package/dist/services/store/invariants.mjs.map +0 -1
- package/dist/services/store/paths.cjs +0 -1
- package/dist/services/store/paths.mjs +0 -1
- package/dist/services/store/processLiveness.cjs +0 -2
- package/dist/services/store/processLiveness.cjs.map +0 -1
- package/dist/services/store/processLiveness.d.cts.map +0 -1
- package/dist/services/store/processLiveness.d.mts +0 -12
- package/dist/services/store/processLiveness.d.mts.map +0 -1
- package/dist/services/store/processLiveness.mjs +0 -2
- package/dist/services/store/processLiveness.mjs.map +0 -1
- package/dist/services/store/reconcile.cjs +0 -2
- package/dist/services/store/reconcile.cjs.map +0 -1
- package/dist/services/store/reconcile.d.cts.map +0 -1
- package/dist/services/store/reconcile.d.mts +0 -34
- package/dist/services/store/reconcile.d.mts.map +0 -1
- package/dist/services/store/reconcile.mjs +0 -2
- package/dist/services/store/reconcile.mjs.map +0 -1
- package/dist/services/store/reducer.cjs +0 -3
- package/dist/services/store/reducer.cjs.map +0 -1
- package/dist/services/store/reducer.d.cts.map +0 -1
- package/dist/services/store/reducer.d.mts +0 -72
- package/dist/services/store/reducer.d.mts.map +0 -1
- package/dist/services/store/reducer.mjs +0 -3
- package/dist/services/store/reducer.mjs.map +0 -1
- package/dist/services/store/taskGraph.cjs +0 -2
- package/dist/services/store/taskGraph.cjs.map +0 -1
- package/dist/services/store/taskGraph.d.cts.map +0 -1
- package/dist/services/store/taskGraph.d.mts +0 -25
- package/dist/services/store/taskGraph.d.mts.map +0 -1
- package/dist/services/store/taskGraph.mjs +0 -2
- package/dist/services/store/taskGraph.mjs.map +0 -1
- package/dist/services/store/taskStore.cjs +0 -1
- package/dist/services/store/taskStore.d.cts +0 -2
- package/dist/services/store/taskStore.d.mts +0 -2
- package/dist/services/store/taskStore.mjs +0 -1
- package/dist/services/store/types.cjs +0 -2
- package/dist/services/store/types.cjs.map +0 -1
- package/dist/services/store/types.d.cts +0 -165
- package/dist/services/store/types.d.cts.map +0 -1
- package/dist/services/store/types.d.mts.map +0 -1
- package/dist/services/store/types.mjs +0 -2
- package/dist/services/store/types.mjs.map +0 -1
- package/dist/store/invariants.cjs +0 -1
- package/dist/store/invariants.d.cts +0 -2
- package/dist/store/invariants.d.mts +0 -2
- package/dist/store/invariants.mjs +0 -1
- package/dist/store/paths.cjs +0 -1
- package/dist/store/paths.d.cts +0 -2
- package/dist/store/paths.d.mts +0 -2
- package/dist/store/paths.mjs +0 -1
- package/dist/store/processLiveness.cjs +0 -1
- package/dist/store/processLiveness.d.cts +0 -2
- package/dist/store/processLiveness.d.mts +0 -2
- package/dist/store/processLiveness.mjs +0 -1
- package/dist/store/reconcile.cjs +0 -1
- package/dist/store/reconcile.d.cts +0 -2
- package/dist/store/reconcile.d.mts +0 -2
- package/dist/store/reconcile.mjs +0 -1
- package/dist/store/reducer.cjs +0 -1
- package/dist/store/reducer.d.cts +0 -2
- package/dist/store/reducer.d.mts +0 -2
- package/dist/store/reducer.mjs +0 -1
- package/dist/store/taskGraph.cjs +0 -1
- package/dist/store/taskGraph.d.cts +0 -2
- package/dist/store/taskGraph.d.mts +0 -2
- package/dist/store/taskGraph.mjs +0 -1
- package/dist/store/taskStore.cjs +0 -1
- package/dist/store/taskStore.d.cts +0 -3
- package/dist/store/taskStore.d.mts +0 -3
- package/dist/store/taskStore.mjs +0 -1
- package/dist/store/types.cjs +0 -1
- package/dist/store/types.d.cts +0 -2
- package/dist/store/types.d.mts +0 -2
- package/dist/store/types.mjs +0 -1
- package/dist/tool/promptGuidelines.cjs +0 -1
- package/dist/tool/promptGuidelines.d.cts +0 -2
- package/dist/tool/promptGuidelines.d.mts +0 -2
- package/dist/tool/promptGuidelines.mjs +0 -1
- package/dist/tool/responseEnvelope.cjs +0 -1
- package/dist/tool/responseEnvelope.d.cts +0 -2
- package/dist/tool/responseEnvelope.d.mts +0 -2
- package/dist/tool/responseEnvelope.mjs +0 -1
- package/dist/tool/schema.cjs +0 -1
- package/dist/tool/schema.d.cts +0 -2
- package/dist/tool/schema.d.mts +0 -2
- package/dist/tool/schema.mjs +0 -1
- package/dist/tool/taskTool.cjs +0 -1
- package/dist/tool/taskTool.d.cts +0 -3
- package/dist/tool/taskTool.d.mts +0 -3
- package/dist/tool/taskTool.mjs +0 -1
- package/dist/tui/format.cjs +0 -4
- package/dist/tui/format.cjs.map +0 -1
- package/dist/tui/format.d.cts +0 -62
- package/dist/tui/format.d.cts.map +0 -1
- package/dist/tui/format.d.mts +0 -62
- package/dist/tui/format.d.mts.map +0 -1
- package/dist/tui/format.mjs +0 -4
- package/dist/tui/format.mjs.map +0 -1
- package/dist/tui/selectors.cjs +0 -2
- package/dist/tui/selectors.cjs.map +0 -1
- package/dist/tui/selectors.d.cts.map +0 -1
- package/dist/tui/selectors.d.mts +0 -53
- package/dist/tui/selectors.d.mts.map +0 -1
- package/dist/tui/selectors.mjs +0 -2
- package/dist/tui/selectors.mjs.map +0 -1
- package/dist/tui/taskOverlay.cjs +0 -2
- package/dist/tui/taskOverlay.cjs.map +0 -1
- package/dist/tui/taskOverlay.d.cts.map +0 -1
- package/dist/tui/taskOverlay.d.mts +0 -38
- package/dist/tui/taskOverlay.d.mts.map +0 -1
- package/dist/tui/taskOverlay.mjs +0 -2
- package/dist/tui/taskOverlay.mjs.map +0 -1
- package/dist/tui/taskSpace.cjs +0 -5
- package/dist/tui/taskSpace.cjs.map +0 -1
- package/dist/tui/taskSpace.d.cts.map +0 -1
- package/dist/tui/taskSpace.d.mts +0 -62
- package/dist/tui/taskSpace.d.mts.map +0 -1
- package/dist/tui/taskSpace.mjs +0 -5
- package/dist/tui/taskSpace.mjs.map +0 -1
- package/dist/types/config.cjs +0 -2
- package/dist/types/config.cjs.map +0 -1
- package/dist/types/config.d.cts.map +0 -1
- package/dist/types/config.d.mts +0 -38
- package/dist/types/config.d.mts.map +0 -1
- package/dist/types/config.mjs +0 -2
- package/dist/types/config.mjs.map +0 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { n as MSG_NO_TASKS, s as TASK_STATUSES } from "./task-DKHKuems.mjs";
|
|
2
|
+
import { r as isBlocked } from "./taskGraph-BOQvT0-M.mjs";
|
|
3
|
+
import { a as isCommittingOp, o as singleItemOutcome, r as applyTaskMutation } from "./reducer-BEfJFM5L.mjs";
|
|
4
|
+
import { c as visibleTasks, t as countTasks } from "./selectors-BaS6dObz.mjs";
|
|
5
|
+
import { a as STATUS_LABEL, u as overlayStatusGlyph } from "./format.cli-Cnc591eb.mjs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
8
|
+
import { DOOM_FULLSCREEN_UI_OPTIONS, DOOM_OVERLAY_ACCENT, DoomOverlay } from "@agimon-ai/doompi-ui/doomOverlay";
|
|
9
|
+
import { fitStyledLine } from "@agimon-ai/doompi-ui/rendering";
|
|
10
|
+
//#region src/extensions/workspaces/sessions/(frontend)/overlay/_lib/task-space.cli.ts
|
|
11
|
+
/**
|
|
12
|
+
* Task Space: the `SPC t l` overlay.
|
|
13
|
+
*
|
|
14
|
+
* The task list and detail pane render from plain values so the whole surface
|
|
15
|
+
* can be asserted as text without a live terminal.
|
|
16
|
+
*
|
|
17
|
+
* The overlay reads the store on every render rather than caching rows, so an
|
|
18
|
+
* external write by a delegated child shows up without closing the overlay.
|
|
19
|
+
*
|
|
20
|
+
* Every commit it makes is a single-entry `upsert` that carries the selected
|
|
21
|
+
* task's id. That id is what keeps creating a task a tool-only path: an entry
|
|
22
|
+
* without one would create rather than be rejected.
|
|
23
|
+
*/
|
|
24
|
+
const TASK_SPACE_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;
|
|
25
|
+
const KEY_BACKSPACE = "";
|
|
26
|
+
const KEY_ENTER = "\r";
|
|
27
|
+
const KEY_NEWLINE = "\n";
|
|
28
|
+
const FIRST_PRINTABLE_CODE_POINT = 32;
|
|
29
|
+
const DELETE_CODE_POINT = 127;
|
|
30
|
+
/**
|
|
31
|
+
* Keystrokes that carry no text: escape sequences, control keys, delete.
|
|
32
|
+
* Indexed rather than iterated so surrogate pairs stay intact; both halves sit
|
|
33
|
+
* far above the control range, so no emoji is ever mistaken for one.
|
|
34
|
+
*/
|
|
35
|
+
function isControlInput(data) {
|
|
36
|
+
for (let index = 0; index < data.length; index++) {
|
|
37
|
+
const code = data.charCodeAt(index);
|
|
38
|
+
if (code < FIRST_PRINTABLE_CODE_POINT || code === DELETE_CODE_POINT) return true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Store path for the list heading: home collapses to `~`, and an over-long path
|
|
44
|
+
* loses leading segments rather than its tail, because the file name identifies
|
|
45
|
+
* the store while `/var/folders/...` does not.
|
|
46
|
+
*/
|
|
47
|
+
function storeLabel(storePath, width) {
|
|
48
|
+
const home = homedir();
|
|
49
|
+
const abbreviated = home && storePath.startsWith(home) ? `~${storePath.slice(home.length)}` : storePath;
|
|
50
|
+
if (visibleWidth(abbreviated) <= width) return abbreviated;
|
|
51
|
+
const segments = abbreviated.split("/");
|
|
52
|
+
let tail = segments.pop() ?? abbreviated;
|
|
53
|
+
while (segments.length > 0) {
|
|
54
|
+
const candidate = `${segments[segments.length - 1]}/${tail}`;
|
|
55
|
+
if (visibleWidth(`…/${candidate}`) > width) break;
|
|
56
|
+
tail = candidate;
|
|
57
|
+
segments.pop();
|
|
58
|
+
}
|
|
59
|
+
return truncateToWidth(`…/${tail}`, width, "");
|
|
60
|
+
}
|
|
61
|
+
/** Each task occupies a heading row and a metadata row beneath it. */
|
|
62
|
+
const ROWS_PER_TASK = 2;
|
|
63
|
+
/** Hanging indent for the metadata row: clears marker, glyph and id. */
|
|
64
|
+
const META_INDENT = 6;
|
|
65
|
+
const MIN_WIDTH = 48;
|
|
66
|
+
/** A third for the list, two thirds for the task being read or edited. */
|
|
67
|
+
const LIST_PANE_RATIO = 1 / 3;
|
|
68
|
+
/** One blank column each side of the pane divider so neither column touches it. */
|
|
69
|
+
const PANE_GUTTER = 1;
|
|
70
|
+
const MIN_PANE_WIDTH = 18;
|
|
71
|
+
const SELECTION_MARKER = "›";
|
|
72
|
+
const CURRENT_MARKER = "▸";
|
|
73
|
+
const CURSOR_BLOCK = "█";
|
|
74
|
+
const ELLIPSIS = "…";
|
|
75
|
+
const NO_VALUE = "none";
|
|
76
|
+
const TITLE = "TASK SPACE";
|
|
77
|
+
const BREADCRUMB = "SPC › t › t / tasks";
|
|
78
|
+
/** Key/label pairs rendered as capped keys, matching the mockup's footer. */
|
|
79
|
+
const LIST_HINTS = [
|
|
80
|
+
["↑↓", "select"],
|
|
81
|
+
["enter", "edit subject"],
|
|
82
|
+
["s", "status"],
|
|
83
|
+
["esc", "close"]
|
|
84
|
+
];
|
|
85
|
+
const LIST_HEADER_RIGHT = "esc close";
|
|
86
|
+
const STATUS_HINT = "STATUS s cycles · enter commits";
|
|
87
|
+
const SUBJECT_HINT = "SUBJECT enter commits · esc cancels";
|
|
88
|
+
function fitRow(text, width) {
|
|
89
|
+
return fitStyledLine(text, width, ELLIPSIS);
|
|
90
|
+
}
|
|
91
|
+
function rightAligned(left, right, width) {
|
|
92
|
+
const rightWidth = visibleWidth(right);
|
|
93
|
+
const leftWidth = Math.max(0, width - rightWidth - 1);
|
|
94
|
+
return fitRow(left, leftWidth) + " ".repeat(Math.max(1, width - leftWidth - rightWidth)) + fitRow(right, rightWidth);
|
|
95
|
+
}
|
|
96
|
+
function wrap(text, width) {
|
|
97
|
+
if (width <= 0) return [];
|
|
98
|
+
const lines = [];
|
|
99
|
+
let current = "";
|
|
100
|
+
for (const word of text.split(/\s+/).filter(Boolean)) if (current.length === 0) current = word;
|
|
101
|
+
else if (current.length + 1 + word.length <= width) current += ` ${word}`;
|
|
102
|
+
else {
|
|
103
|
+
lines.push(current);
|
|
104
|
+
current = word;
|
|
105
|
+
}
|
|
106
|
+
if (current.length > 0) lines.push(current);
|
|
107
|
+
return lines;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Task Space overlay component.
|
|
111
|
+
*
|
|
112
|
+
* Rendering is pure: `render(width)` reads the live store and returns lines with
|
|
113
|
+
* no side effects, so the fidelity job can capture it and unit tests can assert on it.
|
|
114
|
+
*/
|
|
115
|
+
var TaskSpaceComponent = class extends DoomOverlay {
|
|
116
|
+
options;
|
|
117
|
+
done;
|
|
118
|
+
unwatch;
|
|
119
|
+
mode = "browse";
|
|
120
|
+
selected = 0;
|
|
121
|
+
statusIndex = 0;
|
|
122
|
+
draft = "";
|
|
123
|
+
notice;
|
|
124
|
+
bodyHeight = 1;
|
|
125
|
+
constructor(tui, theme, options, done) {
|
|
126
|
+
super(tui, theme);
|
|
127
|
+
this.options = options;
|
|
128
|
+
this.done = done;
|
|
129
|
+
this.unwatch = options.store.onExternalChange(() => this.tui.requestRender());
|
|
130
|
+
}
|
|
131
|
+
tasks() {
|
|
132
|
+
return visibleTasks(this.options.store.snapshot.tasks);
|
|
133
|
+
}
|
|
134
|
+
selectedTask() {
|
|
135
|
+
const tasks = this.tasks();
|
|
136
|
+
if (tasks.length === 0) return void 0;
|
|
137
|
+
return tasks[Math.min(this.selected, tasks.length - 1)];
|
|
138
|
+
}
|
|
139
|
+
move(delta) {
|
|
140
|
+
const tasks = this.tasks();
|
|
141
|
+
if (tasks.length === 0) return;
|
|
142
|
+
this.selected = Math.max(0, Math.min(tasks.length - 1, this.selected + delta));
|
|
143
|
+
this.tui.requestRender();
|
|
144
|
+
}
|
|
145
|
+
/** Commits through the same reducer the task tool uses, so both paths share every invariant. */
|
|
146
|
+
commit(item) {
|
|
147
|
+
this.options.store.mutate((document) => {
|
|
148
|
+
const result = applyTaskMutation(document, "upsert", { tasks: [item] });
|
|
149
|
+
if (!isCommittingOp(result.op)) return { value: result.op };
|
|
150
|
+
return {
|
|
151
|
+
document: result.document,
|
|
152
|
+
value: result.op
|
|
153
|
+
};
|
|
154
|
+
}).then((outcome) => {
|
|
155
|
+
const single = singleItemOutcome(outcome.value);
|
|
156
|
+
this.notice = single?.kind === "failed" ? single.message : void 0;
|
|
157
|
+
this.tui.requestRender();
|
|
158
|
+
}).catch((error) => {
|
|
159
|
+
this.notice = error instanceof Error ? error.message : String(error);
|
|
160
|
+
this.tui.requestRender();
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
handleStatusInput(data) {
|
|
164
|
+
const task = this.selectedTask();
|
|
165
|
+
if (matchesKey(data, "up")) this.statusIndex = Math.max(0, this.statusIndex - 1);
|
|
166
|
+
else if (matchesKey(data, "down")) this.statusIndex = Math.min(TASK_STATUSES.length - 1, this.statusIndex + 1);
|
|
167
|
+
else if (data === "s") this.statusIndex = (this.statusIndex + 1) % TASK_STATUSES.length;
|
|
168
|
+
else if (data === KEY_ENTER || data === KEY_NEWLINE) {
|
|
169
|
+
this.mode = "browse";
|
|
170
|
+
if (task) this.commit({
|
|
171
|
+
id: task.id,
|
|
172
|
+
status: TASK_STATUSES[this.statusIndex]
|
|
173
|
+
});
|
|
174
|
+
} else if (matchesKey(data, "escape")) this.mode = "browse";
|
|
175
|
+
this.tui.requestRender();
|
|
176
|
+
}
|
|
177
|
+
handleSubjectInput(data) {
|
|
178
|
+
const task = this.selectedTask();
|
|
179
|
+
if (data === KEY_ENTER || data === KEY_NEWLINE) {
|
|
180
|
+
this.mode = "browse";
|
|
181
|
+
if (task) this.commit({
|
|
182
|
+
id: task.id,
|
|
183
|
+
subject: this.draft
|
|
184
|
+
});
|
|
185
|
+
} else if (matchesKey(data, "escape")) this.mode = "browse";
|
|
186
|
+
else if (data === KEY_BACKSPACE) this.draft = this.draft.slice(0, -1);
|
|
187
|
+
else if (!isControlInput(data)) this.draft += data;
|
|
188
|
+
this.tui.requestRender();
|
|
189
|
+
}
|
|
190
|
+
handleInput(data) {
|
|
191
|
+
if (this.mode === "status") {
|
|
192
|
+
this.handleStatusInput(data);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (this.mode === "subject") {
|
|
196
|
+
this.handleSubjectInput(data);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
|
|
200
|
+
this.done(void 0);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (matchesKey(data, "up")) {
|
|
204
|
+
this.move(-1);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (matchesKey(data, "down")) {
|
|
208
|
+
this.move(1);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const task = this.selectedTask();
|
|
212
|
+
if (!task) return;
|
|
213
|
+
if (data === "s") {
|
|
214
|
+
this.mode = "status";
|
|
215
|
+
this.statusIndex = Math.max(0, TASK_STATUSES.indexOf(task.status));
|
|
216
|
+
this.tui.requestRender();
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (data === KEY_ENTER || data === KEY_NEWLINE) {
|
|
220
|
+
this.mode = "subject";
|
|
221
|
+
this.draft = task.subject;
|
|
222
|
+
this.tui.requestRender();
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A padded, background-filled chip. Foreground is applied inside the fill so
|
|
227
|
+
* the colour closes with it, rather than a reset stripping the background
|
|
228
|
+
* partway through the label.
|
|
229
|
+
*/
|
|
230
|
+
badge(text, background, colour = "text") {
|
|
231
|
+
return this.theme.bg(background, this.theme.fg(colour, ` ${text} `));
|
|
232
|
+
}
|
|
233
|
+
/** Footer hints as capped keys: `[ enter ] edit subject`, per the mockup. */
|
|
234
|
+
hintLine(hints) {
|
|
235
|
+
return hints.map(([key, label]) => `${this.badge(key, "selectedBg")}${this.theme.fg("dim", ` ${label}`)}`).join(this.theme.fg("dim", " "));
|
|
236
|
+
}
|
|
237
|
+
listLines(width) {
|
|
238
|
+
const tasks = this.tasks();
|
|
239
|
+
const label = this.theme.bold("TASKS");
|
|
240
|
+
const pathWidth = Math.max(0, width - visibleWidth("TASKS") - 2);
|
|
241
|
+
const lines = [`${label} ${this.theme.fg("dim", storeLabel(this.options.store.storePath, pathWidth))}`, ""];
|
|
242
|
+
if (tasks.length === 0) {
|
|
243
|
+
lines.push(this.theme.fg("dim", MSG_NO_TASKS));
|
|
244
|
+
return lines;
|
|
245
|
+
}
|
|
246
|
+
const budget = Math.max(1, Math.floor((this.bodyHeight - lines.length) / ROWS_PER_TASK));
|
|
247
|
+
const start = Math.max(0, Math.min(this.selected - budget + 1, Math.max(0, tasks.length - budget)));
|
|
248
|
+
for (const [offset, task] of tasks.slice(start, start + budget).entries()) {
|
|
249
|
+
const active = start + offset === Math.min(this.selected, tasks.length - 1);
|
|
250
|
+
const marker = active ? this.theme.fg("accent", SELECTION_MARKER) : " ";
|
|
251
|
+
const subject = active ? this.theme.bold(task.subject) : task.subject;
|
|
252
|
+
const glyph = overlayStatusGlyph(task.status, this.theme);
|
|
253
|
+
const owner = task.owner ?? task.delegation?.agent ?? NO_VALUE;
|
|
254
|
+
const state = task.status === "pending" && isBlocked(this.options.store.snapshot.tasks, task) ? this.theme.fg("warning", `blocked by ${(task.blockedBy ?? []).map((id) => `#${id}`).join(", ")}`) : this.theme.fg("dim", STATUS_LABEL[task.status]);
|
|
255
|
+
const heading = `${marker} ${glyph} ${this.theme.fg("dim", `#${task.id}`)} ${subject}`;
|
|
256
|
+
const meta = `${" ".repeat(META_INDENT)}${this.badge(owner, "userMessageBg", "muted")} ${state}`;
|
|
257
|
+
const background = active ? "selectedBg" : "userMessageBg";
|
|
258
|
+
for (const row of [heading, meta]) lines.push(this.theme.bg(background, fitRow(row, width)));
|
|
259
|
+
}
|
|
260
|
+
return lines;
|
|
261
|
+
}
|
|
262
|
+
statusLines(task, width) {
|
|
263
|
+
if (this.mode !== "status") {
|
|
264
|
+
const glyph = overlayStatusGlyph(task.status, this.theme);
|
|
265
|
+
return [this.theme.fg("dim", "STATUS"), `${glyph} ${STATUS_LABEL[task.status]}`];
|
|
266
|
+
}
|
|
267
|
+
const lines = [this.theme.fg("dim", STATUS_HINT)];
|
|
268
|
+
for (const [index, status] of TASK_STATUSES.entries()) {
|
|
269
|
+
const selected = index === this.statusIndex;
|
|
270
|
+
const marker = selected ? this.theme.fg("accent", CURRENT_MARKER) : " ";
|
|
271
|
+
const label = selected ? this.theme.bold(this.theme.fg("accent", status)) : this.theme.fg("muted", status);
|
|
272
|
+
const current = status === task.status ? this.theme.fg("dim", "current") : "";
|
|
273
|
+
const row = rightAligned(` ${marker} ${label}`, current, width);
|
|
274
|
+
lines.push(this.theme.bg(selected ? "selectedBg" : "userMessageBg", row));
|
|
275
|
+
}
|
|
276
|
+
return lines;
|
|
277
|
+
}
|
|
278
|
+
/** The subject as an input: a filled field with a caret, as in the mockup. */
|
|
279
|
+
subjectField(task, width) {
|
|
280
|
+
const editing = this.mode === "subject";
|
|
281
|
+
const value = editing ? `${this.draft}${CURSOR_BLOCK}` : task.subject;
|
|
282
|
+
return [this.theme.fg("dim", editing ? SUBJECT_HINT : "SUBJECT"), this.theme.bg(editing ? "selectedBg" : "userMessageBg", fitRow(` ${value}`, width))];
|
|
283
|
+
}
|
|
284
|
+
detailLines(width) {
|
|
285
|
+
const task = this.selectedTask();
|
|
286
|
+
if (!task) return [this.theme.fg("dim", "No task selected")];
|
|
287
|
+
const badge = this.mode === "subject" || this.mode === "status" ? this.badge("EDIT", "toolSuccessBg", "warning") : "";
|
|
288
|
+
const lines = [rightAligned(this.theme.bold(this.theme.fg("accent", `TASK #${task.id}`)), badge, width), ""];
|
|
289
|
+
lines.push(...this.subjectField(task, width));
|
|
290
|
+
lines.push("", ...this.statusLines(task, width), "");
|
|
291
|
+
if (task.activeForm) lines.push(this.theme.fg("dim", "ACTIVE FORM"), task.activeForm, "");
|
|
292
|
+
const owner = task.owner ?? task.delegation?.agent ?? NO_VALUE;
|
|
293
|
+
const delegated = task.delegation?.runId ? this.theme.fg("success", `delegated run ${task.delegation.runId}`) : "";
|
|
294
|
+
lines.push(this.theme.fg("dim", "OWNER"), delegated ? `${owner} ${this.theme.fg("dim", "·")} ${delegated}` : owner, "");
|
|
295
|
+
lines.push(this.theme.fg("dim", "BLOCKED BY"), task.blockedBy?.length ? task.blockedBy.map((id) => `#${id}`).join(" · ") : NO_VALUE);
|
|
296
|
+
if (task.description) lines.push("", this.theme.fg("dim", "DESCRIPTION"), ...wrap(task.description, width));
|
|
297
|
+
if (this.notice) lines.push("", this.theme.fg("error", this.notice));
|
|
298
|
+
return lines;
|
|
299
|
+
}
|
|
300
|
+
headerSummary() {
|
|
301
|
+
const counts = countTasks(this.options.store.snapshot.tasks);
|
|
302
|
+
const summary = [`${counts.completed}/${counts.total} completed`];
|
|
303
|
+
if (counts.inProgress > 0) summary.push(`${counts.inProgress} in progress`);
|
|
304
|
+
if (counts.blocked > 0) summary.push(`${counts.blocked} blocked`);
|
|
305
|
+
if (counts.failed > 0) summary.push(`${counts.failed} failed`);
|
|
306
|
+
return summary.join(" · ");
|
|
307
|
+
}
|
|
308
|
+
getChrome() {
|
|
309
|
+
return {
|
|
310
|
+
title: TITLE,
|
|
311
|
+
accent: DOOM_OVERLAY_ACCENT,
|
|
312
|
+
breadcrumb: BREADCRUMB,
|
|
313
|
+
headerRight: `${this.headerSummary()} · ${LIST_HEADER_RIGHT}`,
|
|
314
|
+
footer: this.hintLine(LIST_HINTS)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
renderBody(width, height) {
|
|
318
|
+
this.bodyHeight = height;
|
|
319
|
+
if (width < MIN_WIDTH) return this.renderStacked(width, height);
|
|
320
|
+
const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * LIST_PANE_RATIO));
|
|
321
|
+
const rightWidth = Math.max(1, width - leftWidth - 1);
|
|
322
|
+
const leftContent = Math.max(1, leftWidth - PANE_GUTTER);
|
|
323
|
+
const rightContent = Math.max(1, rightWidth - PANE_GUTTER);
|
|
324
|
+
const left = this.listLines(leftContent);
|
|
325
|
+
const right = this.detailLines(rightContent);
|
|
326
|
+
const divider = this.theme.fg("borderMuted", "│");
|
|
327
|
+
return Array.from({ length: height }, (_, index) => {
|
|
328
|
+
const row = `${fitRow(left[index] ?? "", leftContent)} ${divider} ${fitRow(right[index] ?? "", rightContent)}`;
|
|
329
|
+
return truncateToWidth(row, width, ELLIPSIS);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
renderStacked(width, height) {
|
|
333
|
+
const topHeight = Math.max(1, Math.floor((height - 1) / 2));
|
|
334
|
+
const bottomHeight = Math.max(0, height - topHeight - 1);
|
|
335
|
+
this.bodyHeight = topHeight;
|
|
336
|
+
const top = this.listLines(width);
|
|
337
|
+
const bottom = this.detailLines(width);
|
|
338
|
+
return [
|
|
339
|
+
...top.slice(0, topHeight),
|
|
340
|
+
...Array.from({ length: Math.max(0, topHeight - top.length) }, () => ""),
|
|
341
|
+
this.theme.fg("borderMuted", "─".repeat(width)),
|
|
342
|
+
...bottom.slice(0, bottomHeight)
|
|
343
|
+
];
|
|
344
|
+
}
|
|
345
|
+
dispose() {
|
|
346
|
+
this.unwatch();
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
async function openTaskSpace(ctx, options) {
|
|
350
|
+
await ctx.ui.custom((tui, theme, _keybindings, done) => new TaskSpaceComponent(tui, theme, options, done), DOOM_FULLSCREEN_UI_OPTIONS);
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
353
|
+
export { TaskSpaceComponent as n, openTaskSpace as r, TASK_SPACE_OVERLAY_OPTIONS as t };
|
|
354
|
+
|
|
355
|
+
//# sourceMappingURL=task-space.cli-CMYNjgOW.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-space.cli-CMYNjgOW.mjs","names":[],"sources":["../src/extensions/workspaces/sessions/(frontend)/overlay/_lib/task-space.cli.ts"],"sourcesContent":["/**\n * Task Space: the `SPC t l` overlay.\n *\n * The task list and detail pane render from plain values so the whole surface\n * can be asserted as text without a live terminal.\n *\n * The overlay reads the store on every render rather than caching rows, so an\n * external write by a delegated child shows up without closing the overlay.\n *\n * Every commit it makes is a single-entry `upsert` that carries the selected\n * task's id. That id is what keeps creating a task a tool-only path: an entry\n * without one would create rather than be rejected.\n */\n\nimport { homedir } from 'node:os';\n\nimport {\n DOOM_FULLSCREEN_UI_OPTIONS,\n DOOM_OVERLAY_ACCENT,\n DoomOverlay,\n type DoomOverlayChrome,\n type DoomOverlayTui,\n} from '@agimon-ai/doompi-ui/doomOverlay';\nimport { fitStyledLine } from '@agimon-ai/doompi-ui/rendering';\nimport type { ExtensionContext, Theme } from '@earendil-works/pi-coding-agent';\nimport { matchesKey, truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport type { Task, TaskItemMutation } from '../../../../../../models/task';\nimport { isBlocked } from '../../../../../../models/taskGraph';\nimport { MSG_NO_TASKS, TASK_STATUSES } from '../../../../../../schemas/task';\nimport { applyTaskMutation, isCommittingOp, type Op, singleItemOutcome } from '../../../../../../services/reducer';\nimport type { TaskStore } from '../../../../../../services/taskStore';\nimport { overlayStatusGlyph, STATUS_LABEL } from '../../_shared/format.cli';\nimport { countTasks, visibleTasks } from '.././_lib/selectors';\n\nexport const TASK_SPACE_OVERLAY_OPTIONS = DOOM_FULLSCREEN_UI_OPTIONS.overlayOptions;\n\nexport interface TaskSpaceOptions {\n store: TaskStore;\n}\n\ntype EditMode = 'browse' | 'status' | 'subject';\n\nconst KEY_BACKSPACE = '\\x7f';\nconst KEY_ENTER = '\\r';\nconst KEY_NEWLINE = '\\n';\nconst FIRST_PRINTABLE_CODE_POINT = 0x20;\nconst DELETE_CODE_POINT = 0x7f;\n\n/**\n * Keystrokes that carry no text: escape sequences, control keys, delete.\n * Indexed rather than iterated so surrogate pairs stay intact; both halves sit\n * far above the control range, so no emoji is ever mistaken for one.\n */\nfunction isControlInput(data: string): boolean {\n for (let index = 0; index < data.length; index++) {\n const code = data.charCodeAt(index);\n if (code < FIRST_PRINTABLE_CODE_POINT || code === DELETE_CODE_POINT) return true;\n }\n return false;\n}\n\n/**\n * Store path for the list heading: home collapses to `~`, and an over-long path\n * loses leading segments rather than its tail, because the file name identifies\n * the store while `/var/folders/...` does not.\n */\nfunction storeLabel(storePath: string, width: number): string {\n const home = homedir();\n const abbreviated = home && storePath.startsWith(home) ? `~${storePath.slice(home.length)}` : storePath;\n if (visibleWidth(abbreviated) <= width) return abbreviated;\n\n const segments = abbreviated.split('/');\n let tail = segments.pop() ?? abbreviated;\n while (segments.length > 0) {\n const candidate = `${segments[segments.length - 1]}/${tail}`;\n if (visibleWidth(`…/${candidate}`) > width) break;\n tail = candidate;\n segments.pop();\n }\n return truncateToWidth(`…/${tail}`, width, '');\n}\n\n/** Neither palette name is exported, so take both from the theme's methods. */\ntype ThemeBg = Parameters<Theme['bg']>[0];\ntype ThemeColor = Parameters<Theme['fg']>[0];\n\n/** Each task occupies a heading row and a metadata row beneath it. */\nconst ROWS_PER_TASK = 2;\n/** Hanging indent for the metadata row: clears marker, glyph and id. */\nconst META_INDENT = 6;\n\nconst MIN_WIDTH = 48;\n/** A third for the list, two thirds for the task being read or edited. */\nconst LIST_PANE_RATIO = 1 / 3;\n/** One blank column each side of the pane divider so neither column touches it. */\nconst PANE_GUTTER = 1;\nconst MIN_PANE_WIDTH = 18;\nconst SELECTION_MARKER = '›';\nconst CURRENT_MARKER = '▸';\nconst CURSOR_BLOCK = '█';\nconst ELLIPSIS = '…';\nconst NO_VALUE = 'none';\n\nconst TITLE = 'TASK SPACE';\nconst BREADCRUMB = 'SPC › t › t / tasks';\n/** Key/label pairs rendered as capped keys, matching the mockup's footer. */\nconst LIST_HINTS: readonly (readonly [string, string])[] = [\n ['↑↓', 'select'],\n ['enter', 'edit subject'],\n ['s', 'status'],\n ['esc', 'close'],\n];\nconst LIST_HEADER_RIGHT = 'esc close';\nconst STATUS_HINT = 'STATUS s cycles · enter commits';\nconst SUBJECT_HINT = 'SUBJECT enter commits · esc cancels';\nfunction fitRow(text: string, width: number): string {\n return fitStyledLine(text, width, ELLIPSIS);\n}\n\nfunction rightAligned(left: string, right: string, width: number): string {\n const rightWidth = visibleWidth(right);\n const leftWidth = Math.max(0, width - rightWidth - 1);\n return fitRow(left, leftWidth) + ' '.repeat(Math.max(1, width - leftWidth - rightWidth)) + fitRow(right, rightWidth);\n}\n\nfunction wrap(text: string, width: number): string[] {\n if (width <= 0) return [];\n const lines: string[] = [];\n let current = '';\n for (const word of text.split(/\\s+/).filter(Boolean)) {\n if (current.length === 0) current = word;\n else if (current.length + 1 + word.length <= width) current += ` ${word}`;\n else {\n lines.push(current);\n current = word;\n }\n }\n if (current.length > 0) lines.push(current);\n return lines;\n}\n\n/**\n * Task Space overlay component.\n *\n * Rendering is pure: `render(width)` reads the live store and returns lines with\n * no side effects, so the fidelity job can capture it and unit tests can assert on it.\n */\nexport class TaskSpaceComponent extends DoomOverlay {\n private readonly options: TaskSpaceOptions;\n private readonly done: (result: undefined) => void;\n private readonly unwatch: () => void;\n\n private mode: EditMode = 'browse';\n private selected = 0;\n private statusIndex = 0;\n private draft = '';\n private notice: string | undefined;\n private bodyHeight = 1;\n\n constructor(tui: DoomOverlayTui, theme: Theme, options: TaskSpaceOptions, done: (result: undefined) => void) {\n super(tui, theme);\n this.options = options;\n this.done = done;\n this.unwatch = options.store.onExternalChange(() => this.tui.requestRender());\n }\n\n private tasks(): Task[] {\n return visibleTasks(this.options.store.snapshot.tasks);\n }\n\n private selectedTask(): Task | undefined {\n const tasks = this.tasks();\n if (tasks.length === 0) return undefined;\n return tasks[Math.min(this.selected, tasks.length - 1)];\n }\n\n private move(delta: number): void {\n const tasks = this.tasks();\n if (tasks.length === 0) return;\n this.selected = Math.max(0, Math.min(tasks.length - 1, this.selected + delta));\n this.tui.requestRender();\n }\n\n /** Commits through the same reducer the task tool uses, so both paths share every invariant. */\n private commit(item: TaskItemMutation): void {\n this.options.store\n .mutate<Op>((document) => {\n const result = applyTaskMutation(document, 'upsert', { tasks: [item] });\n // A rejected mutation must not reach the writer: committing it would\n // bump `rev` for an edit that never happened.\n if (!isCommittingOp(result.op)) return { value: result.op };\n return { document: result.document, value: result.op };\n })\n .then((outcome) => {\n // The reducer's message is unprefixed, so the notice reads\n // \"subject must not be blank\" rather than \"item[0] failed: ...\".\n const single = singleItemOutcome(outcome.value);\n this.notice = single?.kind === 'failed' ? single.message : undefined;\n this.tui.requestRender();\n })\n .catch((error: unknown) => {\n // Shown in the overlay rather than swallowed: a rejected write means the\n // edit the operator just made never landed.\n this.notice = error instanceof Error ? error.message : String(error);\n this.tui.requestRender();\n });\n }\n\n private handleStatusInput(data: string): void {\n const task = this.selectedTask();\n if (matchesKey(data, 'up')) this.statusIndex = Math.max(0, this.statusIndex - 1);\n else if (matchesKey(data, 'down')) this.statusIndex = Math.min(TASK_STATUSES.length - 1, this.statusIndex + 1);\n else if (data === 's') this.statusIndex = (this.statusIndex + 1) % TASK_STATUSES.length;\n else if (data === KEY_ENTER || data === KEY_NEWLINE) {\n this.mode = 'browse';\n if (task) this.commit({ id: task.id, status: TASK_STATUSES[this.statusIndex] });\n } else if (matchesKey(data, 'escape')) this.mode = 'browse';\n this.tui.requestRender();\n }\n\n private handleSubjectInput(data: string): void {\n const task = this.selectedTask();\n if (data === KEY_ENTER || data === KEY_NEWLINE) {\n this.mode = 'browse';\n if (task) this.commit({ id: task.id, subject: this.draft });\n } else if (matchesKey(data, 'escape')) this.mode = 'browse';\n else if (data === KEY_BACKSPACE) this.draft = this.draft.slice(0, -1);\n else if (!isControlInput(data)) this.draft += data;\n this.tui.requestRender();\n }\n\n handleInput(data: string): void {\n if (this.mode === 'status') {\n this.handleStatusInput(data);\n return;\n }\n if (this.mode === 'subject') {\n this.handleSubjectInput(data);\n return;\n }\n\n if (matchesKey(data, 'escape') || matchesKey(data, 'ctrl+c')) {\n this.done(undefined);\n return;\n }\n if (matchesKey(data, 'up')) {\n this.move(-1);\n return;\n }\n if (matchesKey(data, 'down')) {\n this.move(1);\n return;\n }\n\n const task = this.selectedTask();\n if (!task) return;\n if (data === 's') {\n this.mode = 'status';\n this.statusIndex = Math.max(0, TASK_STATUSES.indexOf(task.status));\n this.tui.requestRender();\n return;\n }\n if (data === KEY_ENTER || data === KEY_NEWLINE) {\n this.mode = 'subject';\n this.draft = task.subject;\n this.tui.requestRender();\n }\n }\n\n /**\n * A padded, background-filled chip. Foreground is applied inside the fill so\n * the colour closes with it, rather than a reset stripping the background\n * partway through the label.\n */\n private badge(text: string, background: ThemeBg, colour: ThemeColor = 'text'): string {\n return this.theme.bg(background, this.theme.fg(colour, ` ${text} `));\n }\n\n /** Footer hints as capped keys: `[ enter ] edit subject`, per the mockup. */\n private hintLine(hints: readonly (readonly [string, string])[]): string {\n return hints\n .map(([key, label]) => `${this.badge(key, 'selectedBg')}${this.theme.fg('dim', ` ${label}`)}`)\n .join(this.theme.fg('dim', ' '));\n }\n\n private listLines(width: number): string[] {\n const tasks = this.tasks();\n const label = this.theme.bold('TASKS');\n const pathWidth = Math.max(0, width - visibleWidth('TASKS') - 2);\n const lines = [`${label} ${this.theme.fg('dim', storeLabel(this.options.store.storePath, pathWidth))}`, ''];\n if (tasks.length === 0) {\n lines.push(this.theme.fg('dim', MSG_NO_TASKS));\n return lines;\n }\n\n // Two rows per task: at a third of the width a single row left the subject\n // with a handful of columns once owner and state took their share.\n const budget = Math.max(1, Math.floor((this.bodyHeight - lines.length) / ROWS_PER_TASK));\n const start = Math.max(0, Math.min(this.selected - budget + 1, Math.max(0, tasks.length - budget)));\n for (const [offset, task] of tasks.slice(start, start + budget).entries()) {\n const index = start + offset;\n const active = index === Math.min(this.selected, tasks.length - 1);\n const marker = active ? this.theme.fg('accent', SELECTION_MARKER) : ' ';\n const subject = active ? this.theme.bold(task.subject) : task.subject;\n const glyph = overlayStatusGlyph(task.status, this.theme);\n const owner = task.owner ?? task.delegation?.agent ?? NO_VALUE;\n const blocked = task.status === 'pending' && isBlocked(this.options.store.snapshot.tasks, task);\n const state = blocked\n ? this.theme.fg('warning', `blocked by ${(task.blockedBy ?? []).map((id) => `#${id}`).join(', ')}`)\n : this.theme.fg('dim', STATUS_LABEL[task.status]);\n // Subject owns the first row outright; the metadata hangs under it.\n const heading = `${marker} ${glyph} ${this.theme.fg('dim', `#${task.id}`)} ${subject}`;\n const meta = `${' '.repeat(META_INDENT)}${this.badge(owner, 'userMessageBg', 'muted')} ${state}`;\n // Every task sits on a band, the selected one a shade lighter, as in the\n // mockup; the marker stays so selection survives themes with no background.\n const background: ThemeBg = active ? 'selectedBg' : 'userMessageBg';\n for (const row of [heading, meta]) {\n lines.push(this.theme.bg(background, fitRow(row, width)));\n }\n }\n return lines;\n }\n\n private statusLines(task: Task, width: number): string[] {\n if (this.mode !== 'status') {\n const glyph = overlayStatusGlyph(task.status, this.theme);\n return [this.theme.fg('dim', 'STATUS'), `${glyph} ${STATUS_LABEL[task.status]}`];\n }\n // Editing draws the picker as a filled panel, so the whole option list reads\n // as one surface rather than five loose rows.\n const lines = [this.theme.fg('dim', STATUS_HINT)];\n for (const [index, status] of TASK_STATUSES.entries()) {\n const selected = index === this.statusIndex;\n const marker = selected ? this.theme.fg('accent', CURRENT_MARKER) : ' ';\n const label = selected ? this.theme.bold(this.theme.fg('accent', status)) : this.theme.fg('muted', status);\n const current = status === task.status ? this.theme.fg('dim', 'current') : '';\n const row = rightAligned(` ${marker} ${label}`, current, width);\n lines.push(this.theme.bg(selected ? 'selectedBg' : 'userMessageBg', row));\n }\n return lines;\n }\n\n /** The subject as an input: a filled field with a caret, as in the mockup. */\n private subjectField(task: Task, width: number): string[] {\n const editing = this.mode === 'subject';\n const value = editing ? `${this.draft}${CURSOR_BLOCK}` : task.subject;\n return [\n this.theme.fg('dim', editing ? SUBJECT_HINT : 'SUBJECT'),\n this.theme.bg(editing ? 'selectedBg' : 'userMessageBg', fitRow(` ${value}`, width)),\n ];\n }\n\n private detailLines(width: number): string[] {\n const task = this.selectedTask();\n if (!task) return [this.theme.fg('dim', 'No task selected')];\n\n const editing = this.mode === 'subject' || this.mode === 'status';\n const badge = editing ? this.badge('EDIT', 'toolSuccessBg', 'warning') : '';\n const lines = [rightAligned(this.theme.bold(this.theme.fg('accent', `TASK #${task.id}`)), badge, width), ''];\n lines.push(...this.subjectField(task, width));\n lines.push('', ...this.statusLines(task, width), '');\n\n if (task.activeForm) lines.push(this.theme.fg('dim', 'ACTIVE FORM'), task.activeForm, '');\n const owner = task.owner ?? task.delegation?.agent ?? NO_VALUE;\n const delegated = task.delegation?.runId ? this.theme.fg('success', `delegated run ${task.delegation.runId}`) : '';\n lines.push(\n this.theme.fg('dim', 'OWNER'),\n delegated ? `${owner} ${this.theme.fg('dim', '·')} ${delegated}` : owner,\n '',\n );\n lines.push(\n this.theme.fg('dim', 'BLOCKED BY'),\n task.blockedBy?.length ? task.blockedBy.map((id) => `#${id}`).join(' · ') : NO_VALUE,\n );\n if (task.description) lines.push('', this.theme.fg('dim', 'DESCRIPTION'), ...wrap(task.description, width));\n if (this.notice) lines.push('', this.theme.fg('error', this.notice));\n return lines;\n }\n\n private headerSummary(): string {\n const counts = countTasks(this.options.store.snapshot.tasks);\n const summary = [`${counts.completed}/${counts.total} completed`];\n if (counts.inProgress > 0) summary.push(`${counts.inProgress} in progress`);\n if (counts.blocked > 0) summary.push(`${counts.blocked} blocked`);\n if (counts.failed > 0) summary.push(`${counts.failed} failed`);\n return summary.join(' · ');\n }\n\n protected getChrome(): DoomOverlayChrome {\n return {\n title: TITLE,\n accent: DOOM_OVERLAY_ACCENT,\n breadcrumb: BREADCRUMB,\n headerRight: `${this.headerSummary()} · ${LIST_HEADER_RIGHT}`,\n footer: this.hintLine(LIST_HINTS),\n };\n }\n\n protected renderBody(width: number, height: number): string[] {\n this.bodyHeight = height;\n if (width < MIN_WIDTH) return this.renderStacked(width, height);\n\n const leftWidth = Math.max(MIN_PANE_WIDTH, Math.floor((width - 1) * LIST_PANE_RATIO));\n const rightWidth = Math.max(1, width - leftWidth - 1);\n // Each column gives up one column to the gutter, so content never abuts the\n // divider: a long store path used to run straight into the detail heading.\n const leftContent = Math.max(1, leftWidth - PANE_GUTTER);\n const rightContent = Math.max(1, rightWidth - PANE_GUTTER);\n const left = this.listLines(leftContent);\n const right = this.detailLines(rightContent);\n\n const divider = this.theme.fg('borderMuted', '│');\n return Array.from({ length: height }, (_, index) => {\n const row = `${fitRow(left[index] ?? '', leftContent)} ${divider} ${fitRow(right[index] ?? '', rightContent)}`;\n return truncateToWidth(row, width, ELLIPSIS);\n });\n }\n\n private renderStacked(width: number, height: number): string[] {\n const topHeight = Math.max(1, Math.floor((height - 1) / 2));\n const bottomHeight = Math.max(0, height - topHeight - 1);\n this.bodyHeight = topHeight;\n const top = this.listLines(width);\n const bottom = this.detailLines(width);\n return [\n ...top.slice(0, topHeight),\n ...Array.from({ length: Math.max(0, topHeight - top.length) }, () => ''),\n this.theme.fg('borderMuted', '─'.repeat(width)),\n ...bottom.slice(0, bottomHeight),\n ];\n }\n\n dispose(): void {\n this.unwatch();\n }\n}\n\nexport async function openTaskSpace(ctx: ExtensionContext, options: TaskSpaceOptions): Promise<void> {\n await ctx.ui.custom<undefined>(\n (tui, theme, _keybindings, done) => new TaskSpaceComponent(tui, theme, options, done),\n DOOM_FULLSCREEN_UI_OPTIONS,\n );\n}\n\nexport default openTaskSpace;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { c as TOOL_LABEL, f as TaskParamsSchema, l as TOOL_NAME, p as taskActionAcceptsField, r as MSG_UPSERT_FIELD_MISPLACED } from "./task-DKHKuems.mjs";
|
|
2
|
+
import "./config-DmsCPDuF.mjs";
|
|
3
|
+
import { t as TASK_EVENT } from "./telemetry-PmX_1Y8a.mjs";
|
|
4
|
+
import { a as buildAssignmentResult, c as formatAssignmentResults, o as buildTextResult, s as buildToolResult, u as formatUpsertFailureText } from "./taskResult-edBAAKSH.mjs";
|
|
5
|
+
import { t as DEFAULT_PROMPT_GUIDELINES } from "./promptGuidelines-g4QT8GNM.mjs";
|
|
6
|
+
import { a as isCommittingOp, r as applyTaskMutation } from "./reducer-BEfJFM5L.mjs";
|
|
7
|
+
import { defineCliTool } from "@agimon-ai/doompi-core/extensionFile";
|
|
8
|
+
import { definePiTool } from "@agimon-ai/doompi-core/piExtension";
|
|
9
|
+
//#region src/extensions/workspaces/sessions/(backend)/tool/_lib/task.cli.ts
|
|
10
|
+
/** @deprecated Task usage policy now lives only in the tool description. */
|
|
11
|
+
const DEFAULT_PROMPT_SNIPPET = "Track only complex, multi-step jobs that benefit from persistent progress or delegation; skip simple work";
|
|
12
|
+
var task_cli_default = defineCliTool((context) => definePiTool(createTaskTool(context.root.toolDependencies)));
|
|
13
|
+
const ACTION_ATTRIBUTE = "tool.action";
|
|
14
|
+
const TASK_ID_ATTRIBUTE = "task.id";
|
|
15
|
+
const REDUCER_ACTIONS = /* @__PURE__ */ new Set([
|
|
16
|
+
"upsert",
|
|
17
|
+
"list",
|
|
18
|
+
"get",
|
|
19
|
+
"delete",
|
|
20
|
+
"clear"
|
|
21
|
+
]);
|
|
22
|
+
var TaskToolExecutionError = class extends Error {};
|
|
23
|
+
function actionableTaskError(action, message) {
|
|
24
|
+
return new TaskToolExecutionError([
|
|
25
|
+
`Task ${action} failed: ${message}`,
|
|
26
|
+
"",
|
|
27
|
+
"Options:",
|
|
28
|
+
"- List the task board and inspect the current ids, states, and blockers.",
|
|
29
|
+
"- Correct the arguments or state conflict, then retry once.",
|
|
30
|
+
"- Ask the user before cancelling work or changing dependencies to recover."
|
|
31
|
+
].join("\n"));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Reject a field that belongs to a different action.
|
|
35
|
+
*
|
|
36
|
+
* The params schema is flat and shared across every action, so this is the only
|
|
37
|
+
* place `{"action":"upsert","id":3}` can be caught — and it must be, because
|
|
38
|
+
* the entry it carries has no id and would silently create a duplicate task.
|
|
39
|
+
*/
|
|
40
|
+
function rejectStrayFields(action, params) {
|
|
41
|
+
const stray = Object.keys(params).filter((key) => params[key] !== void 0 && !taskActionAcceptsField(action, key));
|
|
42
|
+
if (stray.length === 0) return;
|
|
43
|
+
const hint = action === "upsert" ? ` ${MSG_UPSERT_FIELD_MISPLACED}` : "";
|
|
44
|
+
throw actionableTaskError(action, `${action} does not accept ${stray.join(", ")}.${hint}`);
|
|
45
|
+
}
|
|
46
|
+
/** assignments[] is the only assign contract, even when it contains one task. */
|
|
47
|
+
function resolveAssignments(params) {
|
|
48
|
+
const assignments = params.assignments;
|
|
49
|
+
if (!assignments || assignments.length === 0) throw actionableTaskError("assign", "assign requires a non-empty assignments[] array");
|
|
50
|
+
return assignments;
|
|
51
|
+
}
|
|
52
|
+
function assignOptions(request, signal) {
|
|
53
|
+
return {
|
|
54
|
+
agent: request.agent,
|
|
55
|
+
inlineAgent: request.inlineAgent,
|
|
56
|
+
instructions: request.instructions,
|
|
57
|
+
relevantFiles: request.relevantFiles,
|
|
58
|
+
priorFindings: request.priorFindings,
|
|
59
|
+
model: request.model,
|
|
60
|
+
context: request.context,
|
|
61
|
+
signal
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async function executeAssignmentBatch(delegation, assignments, signal, report) {
|
|
65
|
+
const results = [];
|
|
66
|
+
for (const [index, assignment] of assignments.entries()) {
|
|
67
|
+
let outcome;
|
|
68
|
+
try {
|
|
69
|
+
outcome = await delegation.assign(assignment.id, assignOptions(assignment, signal));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
report?.error(TASK_EVENT.toolFailed, error, {
|
|
72
|
+
[ACTION_ATTRIBUTE]: "assign",
|
|
73
|
+
[TASK_ID_ATTRIBUTE]: assignment.id
|
|
74
|
+
});
|
|
75
|
+
outcome = {
|
|
76
|
+
ok: false,
|
|
77
|
+
message: error instanceof Error ? error.message : String(error)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
results.push({
|
|
81
|
+
index,
|
|
82
|
+
id: assignment.id,
|
|
83
|
+
agent: assignment.agent,
|
|
84
|
+
...outcome
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return results;
|
|
88
|
+
}
|
|
89
|
+
/** Run an action through the reducer, persisting only when it produced a change. */
|
|
90
|
+
async function executeReducerAction(store, action, params, maxTasks) {
|
|
91
|
+
const { document, value } = await store.mutate((current) => {
|
|
92
|
+
const result = applyTaskMutation(current, action, params, void 0, maxTasks);
|
|
93
|
+
return {
|
|
94
|
+
...isCommittingOp(result.op) ? { document: result.document } : {},
|
|
95
|
+
value: result
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
if (value.op.kind === "error") throw actionableTaskError(action, value.op.message);
|
|
99
|
+
if (value.op.kind === "upsert" && value.op.applied === 0) throw actionableTaskError(action, formatUpsertFailureText(value.op));
|
|
100
|
+
return buildToolResult(action, params, document, value.op);
|
|
101
|
+
}
|
|
102
|
+
function createTaskTool(dependencies, renderers = {}) {
|
|
103
|
+
const { store, delegation, maxTasks = 15 } = dependencies;
|
|
104
|
+
return {
|
|
105
|
+
name: TOOL_NAME,
|
|
106
|
+
label: TOOL_LABEL,
|
|
107
|
+
description: "Shared task list for complex jobs, plus delegation of tracked tasks to background subagents. Use it only when persistent coordination pays off: dependencies, parallel workstreams, or a long-running plan. Do not use it for simple requests, routine edits, straightforward command sequences, or merely because the user listed multiple steps. Actions: upsert (create and change tasks), list, get, delete (tombstone), clear (close the list), assign (delegate through assignments[]), cancel (stop a delegated run). The list is shared across the current session tree, including delegated subagents, while unrelated sessions start empty and stores persist until retention cleanup.",
|
|
108
|
+
promptGuidelines: DEFAULT_PROMPT_GUIDELINES,
|
|
109
|
+
parameters: TaskParamsSchema,
|
|
110
|
+
renderShell: "self",
|
|
111
|
+
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
112
|
+
const action = params.action;
|
|
113
|
+
const mutationParams = params;
|
|
114
|
+
try {
|
|
115
|
+
await dependencies.waitUntilReady?.(ctx, signal);
|
|
116
|
+
rejectStrayFields(action, mutationParams);
|
|
117
|
+
if (REDUCER_ACTIONS.has(action)) {
|
|
118
|
+
const result = await executeReducerAction(store, action, mutationParams, maxTasks);
|
|
119
|
+
dependencies.onChange?.();
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
if (action === "assign") {
|
|
123
|
+
const assignments = resolveAssignments(mutationParams);
|
|
124
|
+
const first = assignments[0];
|
|
125
|
+
const progress = assignments.length === 1 && first ? `Delegating task #${first.id}...` : `Delegating ${assignments.length} tasks...`;
|
|
126
|
+
onUpdate?.(buildTextResult(action, mutationParams, store.snapshot, progress));
|
|
127
|
+
const results = await executeAssignmentBatch(delegation, assignments, signal, dependencies.report);
|
|
128
|
+
dependencies.onChange?.();
|
|
129
|
+
const text = formatAssignmentResults(results);
|
|
130
|
+
const assigned = results.flatMap((item) => item.ok ? [item.id] : []);
|
|
131
|
+
if (assigned.length === 0) throw actionableTaskError(action, text);
|
|
132
|
+
return buildAssignmentResult(mutationParams, store.snapshot, text, {
|
|
133
|
+
assigned,
|
|
134
|
+
failed: results.length - assigned.length
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
onUpdate?.(buildTextResult(action, mutationParams, store.snapshot, `Requesting cancellation for task #${mutationParams.id ?? "unknown"}...`));
|
|
138
|
+
const outcome = await delegation.cancel(mutationParams.id ?? NaN);
|
|
139
|
+
dependencies.onChange?.();
|
|
140
|
+
if (!outcome.ok) throw actionableTaskError(action, outcome.message);
|
|
141
|
+
return buildTextResult(action, mutationParams, store.snapshot, outcome.message, void 0);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
dependencies.report?.error(TASK_EVENT.toolFailed, error, {
|
|
144
|
+
[ACTION_ATTRIBUTE]: action,
|
|
145
|
+
...mutationParams.id === void 0 ? {} : { [TASK_ID_ATTRIBUTE]: mutationParams.id }
|
|
146
|
+
});
|
|
147
|
+
if (error instanceof TaskToolExecutionError) throw error;
|
|
148
|
+
throw actionableTaskError(action, error instanceof Error ? error.message : String(error));
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
...renderers
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
export { createTaskTool as n, task_cli_default as r, DEFAULT_PROMPT_SNIPPET as t };
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=task.cli-BM34E7GG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.cli-BM34E7GG.mjs","names":[],"sources":["../src/extensions/workspaces/sessions/(backend)/tool/_lib/task.cli.ts"],"sourcesContent":["import { defineCliTool, type WithRoot } from '@agimon-ai/doompi-core/extensionFile';\nimport { definePiTool, type PiPluginContext } from '@agimon-ai/doompi-core/piExtension';\nimport type { ToolDefinition, ExtensionContext } from '@earendil-works/pi-coding-agent';\n\nimport { DEFAULT_PROMPT_GUIDELINES } from '../../../../../../constants/promptGuidelines';\nimport type { TaskAction, TaskAssignment, TaskMutationParams } from '../../../../../../models/task';\nimport {\n MSG_UPSERT_FIELD_MISPLACED,\n TaskParamsSchema,\n TOOL_LABEL,\n TOOL_NAME,\n taskActionAcceptsField,\n} from '../../../../../../schemas/task';\nimport { DEFAULT_MAX_TASKS } from '../../../../../../services/config';\nimport type { AssignOptions, DelegationManager, DelegationOutcome } from '../../../../../../services/delegation';\nimport { applyTaskMutation, isCommittingOp, type ReducerAction } from '../../../../../../services/reducer';\nimport {\n type AssignmentItemResult,\n buildAssignmentResult,\n buildTextResult,\n buildToolResult,\n formatAssignmentResults,\n formatUpsertFailureText,\n type ToolResult,\n} from '../../../../../../services/taskResult';\nimport type { TaskStore } from '../../../../../../services/taskStore';\nimport { TASK_EVENT, type TaskFailureReporter } from '../../../../../../types/telemetry';\nimport type { TaskPiScope } from '../../_lib/root.cli';\n\nexport { DEFAULT_PROMPT_GUIDELINES } from '../../../../../../constants/promptGuidelines';\n\n/** @deprecated Task usage policy now lives only in the tool description. */\nexport const DEFAULT_PROMPT_SNIPPET =\n 'Track only complex, multi-step jobs that benefit from persistent progress or delegation; skip simple work';\n\nexport interface TaskToolDependencies {\n store: TaskStore;\n delegation: DelegationManager;\n maxTasks?: number;\n onChange?: () => void;\n report?: TaskFailureReporter;\n waitUntilReady?: (context: ExtensionContext, signal?: AbortSignal) => Promise<void>;\n}\n\nexport default defineCliTool((context: WithRoot<PiPluginContext, TaskPiScope>) =>\n definePiTool(createTaskTool(context.root.toolDependencies)),\n);\n\nconst ACTION_ATTRIBUTE = 'tool.action';\nconst TASK_ID_ATTRIBUTE = 'task.id';\nconst REDUCER_ACTIONS = new Set<TaskAction>(['upsert', 'list', 'get', 'delete', 'clear']);\n\nclass TaskToolExecutionError extends Error {}\n\nfunction actionableTaskError(action: TaskAction, message: string): TaskToolExecutionError {\n return new TaskToolExecutionError(\n [\n `Task ${action} failed: ${message}`,\n '',\n 'Options:',\n '- List the task board and inspect the current ids, states, and blockers.',\n '- Correct the arguments or state conflict, then retry once.',\n '- Ask the user before cancelling work or changing dependencies to recover.',\n ].join('\\n'),\n );\n}\n\n/**\n * Reject a field that belongs to a different action.\n *\n * The params schema is flat and shared across every action, so this is the only\n * place `{\"action\":\"upsert\",\"id\":3}` can be caught — and it must be, because\n * the entry it carries has no id and would silently create a duplicate task.\n */\nfunction rejectStrayFields(action: TaskAction, params: TaskMutationParams): void {\n const stray = Object.keys(params).filter((key) => params[key] !== undefined && !taskActionAcceptsField(action, key));\n if (stray.length === 0) return;\n const hint = action === 'upsert' ? ` ${MSG_UPSERT_FIELD_MISPLACED}` : '';\n throw actionableTaskError(action, `${action} does not accept ${stray.join(', ')}.${hint}`);\n}\n\n/** assignments[] is the only assign contract, even when it contains one task. */\nfunction resolveAssignments(params: TaskMutationParams): TaskAssignment[] {\n const assignments = params.assignments;\n if (!assignments || assignments.length === 0) {\n throw actionableTaskError('assign', 'assign requires a non-empty assignments[] array');\n }\n return assignments;\n}\n\nfunction assignOptions(request: TaskAssignment, signal: AbortSignal | undefined): AssignOptions {\n return {\n agent: request.agent,\n inlineAgent: request.inlineAgent,\n instructions: request.instructions,\n relevantFiles: request.relevantFiles,\n priorFindings: request.priorFindings,\n model: request.model,\n context: request.context,\n signal,\n };\n}\n\nasync function executeAssignmentBatch(\n delegation: DelegationManager,\n assignments: readonly TaskAssignment[],\n signal: AbortSignal | undefined,\n report: TaskFailureReporter | undefined,\n): Promise<AssignmentItemResult[]> {\n const results: AssignmentItemResult[] = [];\n for (const [index, assignment] of assignments.entries()) {\n let outcome: DelegationOutcome;\n try {\n outcome = await delegation.assign(assignment.id, assignOptions(assignment, signal));\n } catch (error) {\n report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: 'assign',\n [TASK_ID_ATTRIBUTE]: assignment.id,\n });\n outcome = { ok: false, message: error instanceof Error ? error.message : String(error) };\n }\n results.push({ index, id: assignment.id, agent: assignment.agent, ...outcome });\n }\n return results;\n}\n\n/** Run an action through the reducer, persisting only when it produced a change. */\nasync function executeReducerAction(\n store: TaskStore,\n action: ReducerAction,\n params: TaskMutationParams,\n maxTasks: number,\n): Promise<ToolResult> {\n const { document, value } = await store.mutate((current) => {\n const result = applyTaskMutation(current, action, params, undefined, maxTasks);\n return {\n ...(isCommittingOp(result.op) ? { document: result.document } : {}),\n value: result,\n };\n });\n if (value.op.kind === 'error') throw actionableTaskError(action, value.op.message);\n // An upsert that applied nothing is a failed call: it wrote nothing and left\n // `rev` alone, so it must not read to the model as a success. A batch where\n // some entries landed returns normally — that is what partial apply means.\n if (value.op.kind === 'upsert' && value.op.applied === 0) {\n throw actionableTaskError(action, formatUpsertFailureText(value.op));\n }\n // `document` is the committed document, so `details.rev` matches what landed\n // on disk; `value.document` is the pre-write copy and lags by one.\n return buildToolResult(action, params, document, value.op);\n}\n\nexport function createTaskTool(\n dependencies: TaskToolDependencies,\n renderers: Pick<ToolDefinition<typeof TaskParamsSchema, ToolResult['details']>, 'renderCall' | 'renderResult'> = {},\n): ToolDefinition<typeof TaskParamsSchema, ToolResult['details']> {\n const { store, delegation, maxTasks = DEFAULT_MAX_TASKS } = dependencies;\n\n return {\n name: TOOL_NAME,\n label: TOOL_LABEL,\n description:\n 'Shared task list for complex jobs, plus delegation of tracked tasks to background subagents. Use it only when persistent coordination pays off: dependencies, parallel workstreams, or a long-running plan. Do not use it for simple requests, routine edits, straightforward command sequences, or merely because the user listed multiple steps. Actions: upsert (create and change tasks), list, get, delete (tombstone), clear (close the list), assign (delegate through assignments[]), cancel (stop a delegated run). The list is shared across the current session tree, including delegated subagents, while unrelated sessions start empty and stores persist until retention cleanup.',\n promptGuidelines: DEFAULT_PROMPT_GUIDELINES,\n parameters: TaskParamsSchema,\n // Task rows carry their own status colors. Owning the shell prevents Pi's\n // pending/success/error background fill from obscuring those row states.\n renderShell: 'self',\n\n async execute(_toolCallId, params, signal, onUpdate, ctx) {\n const action = params.action as TaskAction;\n const mutationParams = params as TaskMutationParams;\n\n try {\n await dependencies.waitUntilReady?.(ctx, signal);\n rejectStrayFields(action, mutationParams);\n if (REDUCER_ACTIONS.has(action)) {\n const result = await executeReducerAction(store, action as ReducerAction, mutationParams, maxTasks);\n dependencies.onChange?.();\n return result;\n }\n\n if (action === 'assign') {\n const assignments = resolveAssignments(mutationParams);\n const first = assignments[0];\n const progress =\n assignments.length === 1 && first\n ? `Delegating task #${first.id}...`\n : `Delegating ${assignments.length} tasks...`;\n onUpdate?.(buildTextResult(action, mutationParams, store.snapshot, progress));\n const results = await executeAssignmentBatch(delegation, assignments, signal, dependencies.report);\n dependencies.onChange?.();\n const text = formatAssignmentResults(results);\n const assigned = results.flatMap((item) => (item.ok ? [item.id] : []));\n if (assigned.length === 0) throw actionableTaskError(action, text);\n return buildAssignmentResult(mutationParams, store.snapshot, text, {\n assigned,\n failed: results.length - assigned.length,\n });\n }\n\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Requesting cancellation for task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n const outcome = await delegation.cancel(mutationParams.id ?? Number.NaN);\n dependencies.onChange?.();\n if (!outcome.ok) throw actionableTaskError(action, outcome.message);\n return buildTextResult(action, mutationParams, store.snapshot, outcome.message, undefined);\n } catch (error) {\n // Rethrown so pi still renders the failure to the model; recorded\n // because this is where a store fault becomes visible to the user.\n dependencies.report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: action,\n ...(mutationParams.id === undefined ? {} : { [TASK_ID_ATTRIBUTE]: mutationParams.id }),\n });\n if (error instanceof TaskToolExecutionError) throw error;\n throw actionableTaskError(action, error instanceof Error ? error.message : String(error));\n }\n },\n\n ...renderers,\n };\n}\n"],"mappings":"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"}
|