@co0ontty/wand 4.106.0 → 4.106.1
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 +2 -2
- package/dist/ai-text-runner.js +24 -14
- package/dist/build-info.d.ts +2 -0
- package/dist/build-info.js +18 -0
- package/dist/build-info.json +3 -3
- package/dist/cli.js +8 -2
- package/dist/daemon-maintenance-state.js +1 -1
- package/dist/daemon-maintenance-targets.d.ts +1 -0
- package/dist/daemon-maintenance-targets.js +25 -9
- package/dist/daemon-maintenance.d.ts +3 -0
- package/dist/daemon-maintenance.js +60 -13
- package/dist/employee-im-types.d.ts +1 -1
- package/dist/employee-input-scheduling.d.ts +4 -0
- package/dist/employee-knowledge-cli.js +5 -5
- package/dist/employee-knowledge.d.ts +3 -1
- package/dist/employee-knowledge.js +24 -8
- package/dist/git-quick-commit.d.ts +2 -0
- package/dist/git-quick-commit.js +15 -2
- package/dist/git-worktree-batch.d.ts +26 -0
- package/dist/git-worktree-batch.js +139 -0
- package/dist/global-knowledge.d.ts +12 -0
- package/dist/global-knowledge.js +124 -0
- package/dist/iteration-log.d.ts +13 -5
- package/dist/iteration-log.js +120 -59
- package/dist/knowledge-types.d.ts +12 -1
- package/dist/knowledge-types.js +4 -0
- package/dist/middleware/api-scope.js +1 -0
- package/dist/model-groups.js +6 -3
- package/dist/models/parsers/opencode.js +31 -1
- package/dist/models.js +15 -14
- package/dist/npm-update-utils.d.ts +5 -2
- package/dist/npm-update-utils.js +34 -4
- package/dist/opencode-cli.d.ts +6 -0
- package/dist/opencode-cli.js +51 -0
- package/dist/opencode-system-fallback.d.ts +1 -0
- package/dist/opencode-system-fallback.js +16 -4
- package/dist/pi-native-event-bridge.js +55 -3
- package/dist/pi-native-input.d.ts +22 -0
- package/dist/pi-native-input.js +77 -0
- package/dist/pi-tmux-host.d.ts +14 -5
- package/dist/pi-tmux-host.js +68 -17
- package/dist/process-manager.js +17 -3
- package/dist/pty-tmux-backend.d.ts +27 -2
- package/dist/pty-tmux-backend.js +471 -70
- package/dist/pty-tmux-log.d.ts +1 -1
- package/dist/pty-tmux-log.js +23 -2
- package/dist/retention-protection.d.ts +1 -1
- package/dist/retention-protection.js +3 -2
- package/dist/retention.d.ts +5 -0
- package/dist/retention.js +11 -0
- package/dist/server-knowledge-routes.js +2 -2
- package/dist/server-session-input-routes.js +38 -19
- package/dist/server-session-lifecycle-routes.js +14 -1
- package/dist/server-session-worktree-routes.js +105 -12
- package/dist/server-task-routes.js +41 -12
- package/dist/server-workspace-routes.js +77 -9
- package/dist/server.js +67 -35
- package/dist/session-registry.d.ts +17 -3
- package/dist/session-registry.js +66 -13
- package/dist/session-service.js +1 -1
- package/dist/storage/internal.d.ts +4 -3
- package/dist/storage/internal.js +3 -3
- package/dist/storage/knowledge-repository.d.ts +5 -0
- package/dist/storage/knowledge-repository.js +75 -16
- package/dist/storage/mappers.d.ts +1 -0
- package/dist/storage/mappers.js +6 -1
- package/dist/storage/migrations.js +60 -0
- package/dist/storage/session-input-repository.d.ts +19 -0
- package/dist/storage/session-input-repository.js +35 -0
- package/dist/storage/task-workflow-repository.d.ts +29 -0
- package/dist/storage/task-workflow-repository.js +110 -0
- package/dist/storage/tasks-repository.d.ts +6 -1
- package/dist/storage/tasks-repository.js +94 -34
- package/dist/storage/workspaces-repository.d.ts +7 -0
- package/dist/storage/workspaces-repository.js +28 -2
- package/dist/storage-cleanup.d.ts +7 -2
- package/dist/storage-cleanup.js +16 -0
- package/dist/storage-schema.js +2 -0
- package/dist/storage.d.ts +5 -1
- package/dist/storage.js +12 -0
- package/dist/structured-exec-host.d.ts +4 -0
- package/dist/structured-exec-pump.d.ts +1 -0
- package/dist/structured-exec-pump.js +18 -11
- package/dist/structured-opencode-adapter.d.ts +2 -1
- package/dist/structured-opencode-adapter.js +32 -8
- package/dist/structured-pi-adapter.js +13 -2
- package/dist/structured-runner.d.ts +6 -0
- package/dist/structured-session-manager-replay.d.ts +2 -0
- package/dist/structured-session-manager-replay.js +27 -0
- package/dist/structured-session-manager.d.ts +32 -21
- package/dist/structured-session-manager.js +395 -118
- package/dist/structured-tmux-host.d.ts +23 -2
- package/dist/structured-tmux-host.js +143 -20
- package/dist/task-actions.js +5 -3
- package/dist/task-archive-policy.js +2 -1
- package/dist/task-comment-dispatch.d.ts +2 -1
- package/dist/task-comment-dispatch.js +19 -6
- package/dist/task-execution-queue.d.ts +2 -0
- package/dist/task-execution-queue.js +10 -10
- package/dist/task-hierarchy.js +1 -1
- package/dist/task-read-model.d.ts +1 -1
- package/dist/task-read-model.js +2 -1
- package/dist/task-types.d.ts +34 -3
- package/dist/task-types.js +21 -5
- package/dist/task-workflow-cli.d.ts +2 -0
- package/dist/task-workflow-cli.js +29 -0
- package/dist/task-workflow-runner.d.ts +4 -0
- package/dist/task-workflow-runner.js +36 -0
- package/dist/task-workflow.d.ts +13 -0
- package/dist/task-workflow.js +48 -0
- package/dist/terminal-daemon-server.js +12 -4
- package/dist/tmux-policy.d.ts +9 -0
- package/dist/tmux-policy.js +46 -0
- package/dist/tmux-terminal-host.js +5 -2
- package/dist/tui/commands.js +2 -1
- package/dist/types.d.ts +5 -0
- package/dist/wand-task-sync.js +5 -0
- package/dist/web-ui/content/ai-teams.js +9 -9
- package/dist/web-ui/content/module-manifest.json +1 -1
- package/dist/web-ui/content/modules/{52574891ef08e29b → 014fa5c6f973badf}/host.js +3 -3
- package/dist/web-ui/content/modules/0818b1d31a11d006/employee-profile.js +1 -0
- package/dist/web-ui/content/modules/{31157ceb6d23b809 → 0a58d9ec273078e4}/chunk.js +3 -3
- package/dist/web-ui/content/modules/{bf3ee58e0da44822 → 0a979dcd165cd0cc}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{5f298a8f43dd0589 → 0c143928e8f96abc}/chunk.js +1 -1
- package/dist/web-ui/content/modules/0e9e42a319f6b8fc/workspace-window.js +1 -0
- package/dist/web-ui/content/modules/{b713cad51ca4c512 → 0f0d1769b732c0bd}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{4970319a83432ec7 → 1447886e6a1e74a4}/chunk.js +1 -1
- package/dist/web-ui/content/modules/151c734cbca31da5/host.js +1 -0
- package/dist/web-ui/content/modules/{e5174201f9d918fb → 16e4ab9c5263fcfd}/chunk.js +1 -1
- package/dist/web-ui/content/modules/17e752fb53952753/host.js +1 -0
- package/dist/web-ui/content/modules/{913187c92a98a1ac → 20ed1454fc09fa6f}/chunk.js +1 -1
- package/dist/web-ui/content/modules/255a3baf59d2b734/home.js +6 -0
- package/dist/web-ui/content/modules/{2f801e53dda62770 → 296dd81886c42b45}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{8891ca8165435ca1 → 2a01f4e525c0725e}/chunk.js +1 -1
- package/dist/web-ui/content/modules/2ab4409c82b44fba/markdown.js +1 -0
- package/dist/web-ui/content/modules/2c955eced11610c2/chunk.js +1 -0
- package/dist/web-ui/content/modules/2d7ee4f9e2c0aca4/panel.js +1 -0
- package/dist/web-ui/content/modules/{3f8830f8ad28decc → 33ae550e4a295c85}/chunk.js +1 -1
- package/dist/web-ui/content/modules/35f4aa4443696bd0/chunk.js +1 -0
- package/dist/web-ui/content/modules/388b37ffcce9d4ff/host.js +1 -0
- package/dist/web-ui/content/modules/39279604dcdac7c7/runtime.js +338 -0
- package/dist/web-ui/content/modules/{57c357d321db5df9 → 3a3cdff2a662b7d3}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{d49f106c4d106057 → 3ab646be55514243}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{16dab1297efd71a7 → 3ae88a5c5e1949d2}/chunk.js +1 -1
- package/dist/web-ui/content/modules/3e3b0e71d6ce80d8/chunk.js +1 -0
- package/dist/web-ui/content/modules/{ec33e17c00c1eb24 → 434aaaaf9604dc34}/chunk.js +1 -1
- package/dist/web-ui/content/modules/4385cd48771e1d4f/host.js +1 -0
- package/dist/web-ui/content/modules/{face3dbf117d63e3 → 4638129d60f549a0}/chunk.js +1 -1
- package/dist/web-ui/content/modules/47407209931b7011/host.js +13 -0
- package/dist/web-ui/content/modules/4829dd712d8b366b/chunk.js +1 -0
- package/dist/web-ui/content/modules/488d5b747bf374c8/chunk.js +1 -0
- package/dist/web-ui/content/modules/{ed7405f064944215 → 4ab085c195f7d76a}/sha256.js +1 -1
- package/dist/web-ui/content/modules/{f27a5d3c6c02a71c → 4c485bd44740fec7}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{771439a41e737ee2 → 4ca0494308ab2bb3}/chunk.js +1 -1
- package/dist/web-ui/content/modules/4ec571218779ba3e/composer-surface-adapter.js +1 -0
- package/dist/web-ui/content/modules/{5933ce8965aa4004 → 5023bf0294c2e7cb}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{e63582a3bce48f7d → 5456e3417600bf15}/chunk.js +1 -1
- package/dist/web-ui/content/modules/55c588b0f5b41a52/host-bridge.js +1 -0
- package/dist/web-ui/content/modules/{9d941d6ff39861b8 → 5c3c8237ba7d8460}/chunk.js +1 -1
- package/dist/web-ui/content/modules/624b858da9834757/host.js +1 -0
- package/dist/web-ui/content/modules/6290be936320d4b1/host.js +1 -0
- package/dist/web-ui/content/modules/66be408793048cc3/progress.js +1 -0
- package/dist/web-ui/content/modules/67a11176a563317b/chunk.js +1 -0
- package/dist/web-ui/content/modules/{e060508ecd50fa7e → 68ef6ec7d26d78cd}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{41445c6589dba325 → 6ec3e41df31927d9}/host.js +2 -2
- package/dist/web-ui/content/modules/{97d7f267959fd385 → 6f10f369445bbcbe}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{d47d75a78ae598e3 → 7295d9ff92d5e1e7}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{f383d892fef73483 → 72cd613de1a5f69b}/chunk.js +1 -1
- package/dist/web-ui/content/modules/73aae1daafeea7e7/workspaces-panel.js +4 -0
- package/dist/web-ui/content/modules/{c2f09c8a472f5d83 → 73d2689f13b9a3e9}/dialog-modal.js +1 -1
- package/dist/web-ui/content/modules/{2f97ddba3842adaa → 75cf0c048e9b92ab}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{4ba1e8c74bed7ef2 → 75dabda3b141296e}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{f3cff7792ba39df8 → 76c10b58d5f92d02}/login-visual.js +1 -1
- package/dist/web-ui/content/modules/{b63e075f222a1266 → 783583a12f5010f8}/library-bridge.js +1 -1
- package/dist/web-ui/content/modules/7e13a8a4a981f2f1/group-editor.js +1 -0
- package/dist/web-ui/content/modules/{0d76e582a7a71b2f → 7e3034fea34c6dae}/chunk.js +1 -1
- package/dist/web-ui/content/modules/80bf3291f2577a68/host.js +1 -0
- package/dist/web-ui/content/modules/{cba6f13c0b2aec1c → 82c3e08f34a6b828}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{dedd4a19bb70e327 → 83d1f4cf82c65f19}/page.js +3 -3
- package/dist/web-ui/content/modules/844f97958f25240c/shell-file-panel-drawer.js +1 -0
- package/dist/web-ui/content/modules/{62e0023451f428cf → 899cdc467044d418}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{5083a5dbb5b155b7 → 8c7ca1fe72741c07}/chunk.js +1 -1
- package/dist/web-ui/content/modules/8dae4ca2261525e4/task-board-host.js +27 -0
- package/dist/web-ui/content/modules/92195c14c74929da/list-filter-panel.js +1 -0
- package/dist/web-ui/content/modules/{a61393bfa976d8d5 → 93793696af76bcbf}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{db521a246e14e5e4 → 97cd6af3da5622b8}/chunk.js +4 -4
- package/dist/web-ui/content/modules/{8de8368570ab089d → 9d3179258249ec77}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{579d486763d47c0d → a234c484078c0568}/chunk.js +1 -1
- package/dist/web-ui/content/modules/a4d215448a089a7d/host.js +1 -0
- package/dist/web-ui/content/modules/{c0a446100d969f3e → ae003f89901c5687}/chunk.js +1 -1
- package/dist/web-ui/content/modules/ae712bdd45b9917e/employee-card.js +1 -0
- package/dist/web-ui/content/modules/{a2caed0139df4b21 → b2a15293f7965d09}/chunk.js +1 -1
- package/dist/web-ui/content/modules/b4ee65e9998f0088/host.js +61 -0
- package/dist/web-ui/content/modules/{bd3daf04a8bf4422 → b666137d17f83be9}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{831b6c7b43e800be → b66beb6c0185256b}/host.js +1 -1
- package/dist/web-ui/content/modules/{816eb9b3a000fb2c → bb03b17e877657de}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{1eab7410d5586038 → bc343afc991db1a1}/chunk.js +1 -1
- package/dist/web-ui/content/modules/bca45976ff8fe2ac/host.js +69 -0
- package/dist/web-ui/content/modules/{d434edbb2f4672e5 → c2715dbfc9eaf510}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{d6fffe2c2a3a738d → c30c220281f35d74}/toast-region.js +1 -1
- package/dist/web-ui/content/modules/c4cc46fa9b4adddc/dropdown-surface.js +1 -0
- package/dist/web-ui/content/modules/c6dd19ee3d3ffd59/brand-identity.js +1 -0
- package/dist/web-ui/content/modules/c7ea6a114e6ff8ae/host.js +1 -0
- package/dist/web-ui/content/modules/{a59734be368daa7e → c916d82c8acef9c8}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{182929e188c1ab3a → cceaedda619a737a}/host.js +1 -1
- package/dist/web-ui/content/modules/cf67f52b076b9d2d/panel-host.js +1 -0
- package/dist/web-ui/content/modules/{9e163d54ff8fd1aa → d26c86558d422313}/chunk.js +1 -1
- package/dist/web-ui/content/modules/d2b8c6c6f3706032/queue-view-adapter.js +1 -0
- package/dist/web-ui/content/modules/d52ebe2ef12a9fa8/chunk.js +3 -0
- package/dist/web-ui/content/modules/{3fe11a75284ad8ae → d552b3bff2151eb6}/host.js +2 -2
- package/dist/web-ui/content/modules/d5d6b4511ac76a6e/chunk.js +3 -0
- package/dist/web-ui/content/modules/{bd7dc4bb46731ee7 → df42e151d625463b}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{2a791cd2e14aa1e0 → e0a04f5ae56c68aa}/notice-view.js +1 -1
- package/dist/web-ui/content/modules/{438807b8bf112cd0 → e28e607c95d6f63a}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{50da446c1377c220 → e3880df97ea62d0c}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{87c7f50d9455d55e → e66196f1ece3e3ad}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{9b12c2301f3a18f3 → eb76307444ac9d71}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{c33935155289c22d → ebff7ca22cee1468}/chunk.js +1 -1
- package/dist/web-ui/content/modules/{4861eca9a8a87ad0 → ed1c712c569960d6}/chunk.js +1 -1
- package/dist/web-ui/content/modules/ee8b9c2d4bec63d4/chunk.js +1 -0
- package/dist/web-ui/content/modules/f458a194ce4208e2/chunk.js +1 -0
- package/dist/web-ui/content/modules/{11af5d14b30e57b6 → f938e826420cfe1b}/chunk.js +1 -1
- package/dist/web-ui/content/modules/fa7b9bf6cc84bfc1/chat-render.js +81 -0
- package/dist/web-ui/content/modules/{ea8fe4b9999fd2aa → fd1fb1834f5f06df}/chunk.js +1 -1
- package/dist/web-ui/content/modules/fd3084e562a3dbd6/host.js +1 -0
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +416 -413
- package/dist/web-ui/embedded-assets.js +5 -5
- package/dist/web-ui/page-route.js +2 -2
- package/dist/web-ui/react/workspaces/types.d.ts +3 -0
- package/dist/web-ui/thinking-efforts.d.ts +2 -0
- package/dist/web-ui/thinking-efforts.js +8 -0
- package/package.json +1 -2
- package/scripts/stage-render-binaries.js +0 -1
- package/skills/wand-knowledge/SKILL.md +5 -3
- package/dist/structured-bounded-keys.d.ts +0 -19
- package/dist/structured-bounded-keys.js +0 -47
- package/dist/web-ui/content/modules/00b168a19664439e/dropdown-surface.js +0 -1
- package/dist/web-ui/content/modules/059c5fb7f128d340/task-board-host.js +0 -27
- package/dist/web-ui/content/modules/07494f5a623e4471/chat-render.js +0 -76
- package/dist/web-ui/content/modules/0a743ad3b4db6874/chunk.js +0 -3
- package/dist/web-ui/content/modules/1858670c0f84fec5/employee-profile.js +0 -1
- package/dist/web-ui/content/modules/20c47dc0442f5a04/host.js +0 -1
- package/dist/web-ui/content/modules/226241b999d12008/host.js +0 -1
- package/dist/web-ui/content/modules/23c4b8d223ec64c5/host.js +0 -61
- package/dist/web-ui/content/modules/2882c97388ff4f7b/employee-card.js +0 -1
- package/dist/web-ui/content/modules/2c90c3be260e6cce/progress.js +0 -1
- package/dist/web-ui/content/modules/2d7be9935394f397/workspace-window.js +0 -1
- package/dist/web-ui/content/modules/389a5112332ec23a/host.js +0 -1
- package/dist/web-ui/content/modules/3ea13e8b3c2deaa4/panel-host.js +0 -1
- package/dist/web-ui/content/modules/42e5c34002fcffb7/chunk.js +0 -1
- package/dist/web-ui/content/modules/4a5d669c90f545cb/host.js +0 -1
- package/dist/web-ui/content/modules/5705d25468274534/host.js +0 -1
- package/dist/web-ui/content/modules/5961ab2947c86ca1/shell-file-panel-drawer.js +0 -1
- package/dist/web-ui/content/modules/5b6e1369df7dea69/chunk.js +0 -1
- package/dist/web-ui/content/modules/6787bdcf56f743a5/host.js +0 -1
- package/dist/web-ui/content/modules/67c39b0398186a9f/host.js +0 -1
- package/dist/web-ui/content/modules/6b16f35c0627bafb/chunk.js +0 -1
- package/dist/web-ui/content/modules/6dd4f3e2f619f7a0/chunk.js +0 -1
- package/dist/web-ui/content/modules/70a2e13e0ccc8549/panel.js +0 -1
- package/dist/web-ui/content/modules/710db590e9707f73/runtime.js +0 -338
- package/dist/web-ui/content/modules/7249950f8771dbeb/workspaces-panel.js +0 -4
- package/dist/web-ui/content/modules/87dcd516ffd9f688/composer-surface-adapter.js +0 -1
- package/dist/web-ui/content/modules/8b7cd7bffdfd69e7/brand-identity.js +0 -1
- package/dist/web-ui/content/modules/8bf9917f6c3429f6/host.js +0 -1
- package/dist/web-ui/content/modules/8e612d4881fa4118/home.js +0 -6
- package/dist/web-ui/content/modules/8e6178262ea63dec/markdown.js +0 -1
- package/dist/web-ui/content/modules/96f2ae970f8c576b/host.js +0 -1
- package/dist/web-ui/content/modules/ba89cd97627e6682/queue-view-adapter.js +0 -1
- package/dist/web-ui/content/modules/c351eb11e0bdec2c/sidebar-peek.js +0 -1
- package/dist/web-ui/content/modules/ca7ca5902a35d26e/chunk.js +0 -1
- package/dist/web-ui/content/modules/d5d28ec375826ef2/chunk.js +0 -3
- package/dist/web-ui/content/modules/d6b16dedb9011c33/chunk.js +0 -1
- package/dist/web-ui/content/modules/d8a7011760f61719/group-editor.js +0 -1
- package/dist/web-ui/content/modules/d9e2b65e9679ad39/host.js +0 -75
- package/dist/web-ui/content/modules/eac72f69716dba05/chunk.js +0 -1
- package/dist/web-ui/content/modules/ebc53dedc3945514/host.js +0 -1
- package/dist/web-ui/content/modules/f43da7050badf54c/host.js +0 -1
- package/dist/web-ui/content/modules/fb2356eced24c4cc/host-bridge.js +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
import { normalizeProjectCwd } from "../workspace-binding.js";
|
|
2
3
|
import { assertTaskHierarchy } from "../task-hierarchy.js";
|
|
3
4
|
import { TASK_RETENTION_ARCHIVE_VERSION } from "../task-retention.js";
|
|
4
5
|
import { firstLayoutTabId } from "../layout-tree.js";
|
|
@@ -6,7 +7,7 @@ import { nowIso } from "../password-manager.js";
|
|
|
6
7
|
import { isSessionProvider } from "../session-provider.js";
|
|
7
8
|
import { isSystemAiCall } from "../system-ai-call.js";
|
|
8
9
|
import { isThinkingEffort } from "../structured-provider-common.js";
|
|
9
|
-
import { DEFAULT_ITERATION_NAME, DEFAULT_WAND_TASK_PRIORITY, isTaskExecutionSubject, normalizeWandTaskAgentMode } from "../task-types.js";
|
|
10
|
+
import { DEFAULT_ITERATION_NAME, DEFAULT_WAND_TASK_PRIORITY, isTaskExecutionSubject, isWandTaskStatus, normalizeWandTaskAgentMode, taskAiVerified, taskHumanAccepted } from "../task-types.js";
|
|
10
11
|
import { GLOBAL_WORKSPACE_ID } from "../types.js";
|
|
11
12
|
import { safeJsonParse, mapWandMilestoneRow, mapIterationPromptRow } from "./mappers.js";
|
|
12
13
|
import { parseWandTaskAgent } from "./mappers.js";
|
|
@@ -88,6 +89,8 @@ export class TaskRepository {
|
|
|
88
89
|
mapWandTaskRow(row) {
|
|
89
90
|
return {
|
|
90
91
|
acceptance: safeJsonParse(String(row.acceptance_json ?? "null")),
|
|
92
|
+
verification: safeJsonParse(String(row.verification_json ?? "null")),
|
|
93
|
+
deliveryRevision: Number(row.delivery_revision) || 0,
|
|
91
94
|
id: String(row.id),
|
|
92
95
|
identifier: typeof row.identifier === "string" && row.identifier ? row.identifier : `TASK-${String(row.id).slice(0, 6)}`,
|
|
93
96
|
workspaceId: typeof row.workspace_id === "string" ? row.workspace_id : null,
|
|
@@ -97,7 +100,7 @@ export class TaskRepository {
|
|
|
97
100
|
titleSource: row.title_source === "auto" ? "auto" : "user",
|
|
98
101
|
autoTitleSignature: typeof row.auto_title_signature === "string" && row.auto_title_signature ? row.auto_title_signature : null,
|
|
99
102
|
description: String(row.description ?? ""),
|
|
100
|
-
status: row.status
|
|
103
|
+
status: isWandTaskStatus(row.status) ? row.status : "todo",
|
|
101
104
|
priority: row.priority === "low" || row.priority === "medium" || row.priority === "high" || row.priority === "urgent" ? row.priority : "none",
|
|
102
105
|
labels: (() => { const parsed = safeJsonParse(String(row.labels_json ?? "[]")); return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : []; })(),
|
|
103
106
|
dueDate: typeof row.due_date === "string" ? row.due_date : null,
|
|
@@ -143,10 +146,13 @@ export class TaskRepository {
|
|
|
143
146
|
.all();
|
|
144
147
|
return new Map(rows.map(row => [row.task_id, Number(row.count) || 0]));
|
|
145
148
|
}
|
|
149
|
+
isTaskReviewComment(id) {
|
|
150
|
+
return Boolean(this.db.prepare("SELECT 1 FROM wand_task_comment_dispatches WHERE comment_id = ? AND purpose = 'review' LIMIT 1").get(id));
|
|
151
|
+
}
|
|
146
152
|
getWandTaskComment(id) {
|
|
147
153
|
const row = this.db.prepare(`SELECT c.*, d.request_id, d.source_comment_id, d.employee_id, d.employee_name,
|
|
148
154
|
d.instruction, d.task_version, d.state, d.session_id, d.error, d.execution_status, d.referenced_task_ids,
|
|
149
|
-
d.result_start_index, d.result_end_index, d.result_request_id, d.result_outcome, d.result_fingerprint, d.result_start_fingerprint FROM wand_task_comments c
|
|
155
|
+
d.result_start_index, d.result_end_index, d.result_request_id, d.result_outcome, d.result_fingerprint, d.result_start_fingerprint, d.purpose, d.review_revision FROM wand_task_comments c
|
|
150
156
|
LEFT JOIN wand_task_comment_dispatches d ON d.comment_id = c.id WHERE c.id = ?`).get(id);
|
|
151
157
|
return row ? this.mapWandTaskCommentRow(row) : null;
|
|
152
158
|
}
|
|
@@ -158,7 +164,7 @@ export class TaskRepository {
|
|
|
158
164
|
const placeholders = boundedIds.map(() => "?").join(", ");
|
|
159
165
|
const rows = this.db.prepare(`SELECT c.*, d.request_id, d.source_comment_id, d.employee_id, d.employee_name,
|
|
160
166
|
d.instruction, d.task_version, d.state, d.session_id, d.error, d.execution_status, d.referenced_task_ids,
|
|
161
|
-
d.result_start_index, d.result_end_index, d.result_request_id, d.result_outcome, d.result_fingerprint, d.result_start_fingerprint
|
|
167
|
+
d.result_start_index, d.result_end_index, d.result_request_id, d.result_outcome, d.result_fingerprint, d.result_start_fingerprint, d.purpose, d.review_revision
|
|
162
168
|
FROM wand_task_comments c LEFT JOIN wand_task_comment_dispatches d ON d.comment_id = c.id
|
|
163
169
|
WHERE c.task_id = ? AND c.id IN (${placeholders})`).all(taskId, ...boundedIds);
|
|
164
170
|
const byId = new Map(rows.map(row => [row.id, this.mapWandTaskCommentRow(row)]));
|
|
@@ -167,6 +173,7 @@ export class TaskRepository {
|
|
|
167
173
|
mapWandTaskCommentRow(row) {
|
|
168
174
|
const referencedTaskIds = parseReferencedTaskIds(row.referenced_task_ids);
|
|
169
175
|
return { id: row.id, taskId: row.task_id, authorName: row.author_name, body: row.body, createdAt: row.created_at,
|
|
176
|
+
purpose: row.purpose === "review" ? "review" : "execution", reviewRevision: row.review_revision == null ? null : Number(row.review_revision),
|
|
170
177
|
...(row.request_id ? { requestId: row.request_id, sourceCommentId: row.source_comment_id, instruction: row.instruction, taskVersion: row.task_version,
|
|
171
178
|
...(referencedTaskIds.length ? { referencedTaskIds } : {}),
|
|
172
179
|
dispatch: row.employee_id ? { employeeId: row.employee_id, employeeName: row.employee_name,
|
|
@@ -190,8 +197,8 @@ export class TaskRepository {
|
|
|
190
197
|
this.db.prepare(`INSERT INTO wand_task_comments(id, task_id, author_name, body, created_at) VALUES (?, ?, ?, ?, ?)`)
|
|
191
198
|
.run(id, input.taskId, "用户", input.body, nowIso());
|
|
192
199
|
this.db.prepare(`INSERT INTO wand_task_comment_dispatches(comment_id, task_id, request_id, signature, source_comment_id,
|
|
193
|
-
employee_id, employee_name, instruction, task_version, state, referenced_task_ids, agent_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
194
|
-
.run(id, input.taskId, input.requestId, input.signature, input.sourceCommentId, input.employeeId, input.employeeName, input.instruction, input.taskVersion, input.employeeId ? input.queued ? "queued" : "pending" : "accepted", JSON.stringify(input.referencedTaskIds ?? []), input.agent ? JSON.stringify(input.agent) : null);
|
|
200
|
+
employee_id, employee_name, instruction, task_version, state, referenced_task_ids, agent_json, purpose, review_revision) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
201
|
+
.run(id, input.taskId, input.requestId, input.signature, input.sourceCommentId, input.employeeId, input.employeeName, input.instruction, input.taskVersion, input.employeeId ? input.queued ? "queued" : "pending" : "accepted", JSON.stringify(input.referencedTaskIds ?? []), input.agent ? JSON.stringify(input.agent) : null, input.purpose ?? "execution", input.reviewRevision ?? null);
|
|
195
202
|
return this.getWandTaskComment(id);
|
|
196
203
|
});
|
|
197
204
|
}
|
|
@@ -456,8 +463,8 @@ export class TaskRepository {
|
|
|
456
463
|
FROM wand_tasks WHERE identifier GLOB 'TASK-[0-9]*'`).get();
|
|
457
464
|
try {
|
|
458
465
|
this.db.prepare(`INSERT INTO wand_tasks (${WAND_TASK_FIELDS})
|
|
459
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
460
|
-
.run(id, `TASK-${number.value + 1}`, input.workspaceId ?? null, input.workspaceTaskId ?? null, input.parentTaskId ?? null, input.title, input.titleSource ?? "user", null, input.description ?? "", status, input.priority ?? DEFAULT_WAND_TASK_PRIORITY, JSON.stringify(input.labels ?? []), input.dueDate ?? null, input.milestoneId ?? null, max.value + 1, input.agent ? JSON.stringify(input.agent) : null, input.executionSubject ? JSON.stringify(input.executionSubject) : null, archivedAt, createdAtValue, createdAtValue, input.acceptance ? JSON.stringify(input.acceptance) : null);
|
|
466
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
467
|
+
.run(id, `TASK-${number.value + 1}`, input.workspaceId ?? null, input.workspaceTaskId ?? null, input.parentTaskId ?? null, input.title, input.titleSource ?? "user", null, input.description ?? "", status, input.priority ?? DEFAULT_WAND_TASK_PRIORITY, JSON.stringify(input.labels ?? []), input.dueDate ?? null, input.milestoneId ?? null, max.value + 1, input.agent ? JSON.stringify(input.agent) : null, input.executionSubject ? JSON.stringify(input.executionSubject) : null, archivedAt, createdAtValue, createdAtValue, input.acceptance ? JSON.stringify(input.acceptance) : null, null, 0);
|
|
461
468
|
}
|
|
462
469
|
catch (error) {
|
|
463
470
|
if (input.workspaceTaskId && this.getWandTaskByWorkspaceTaskId(input.workspaceTaskId)) {
|
|
@@ -471,8 +478,12 @@ export class TaskRepository {
|
|
|
471
478
|
}
|
|
472
479
|
if (input.parentTaskId) {
|
|
473
480
|
const parent = this.getWandTask(input.parentTaskId);
|
|
474
|
-
if (parent
|
|
475
|
-
this.writeWandTask(parent, {
|
|
481
|
+
if (parent && (parent.verification || parent.acceptance?.acceptedAt))
|
|
482
|
+
this.writeWandTask(parent, {
|
|
483
|
+
deliveryRevision: (parent.deliveryRevision ?? 0) + 1, verification: null,
|
|
484
|
+
...(parent.acceptance ? { acceptance: { ...parent.acceptance, acceptedAt: null, confirmedRevision: undefined } } : {}),
|
|
485
|
+
...(parent.status === "ready" || parent.status === "review" ? { status: "doing" } : {}),
|
|
486
|
+
}, true);
|
|
476
487
|
}
|
|
477
488
|
this.s.notifyTaskTitleChange();
|
|
478
489
|
return this.getWandTask(id);
|
|
@@ -480,12 +491,20 @@ export class TaskRepository {
|
|
|
480
491
|
createWandTask(input) {
|
|
481
492
|
return this.s.transaction(() => {
|
|
482
493
|
const linked = input.workspaceTaskId ? this.s.getWorkspaceTask(input.workspaceTaskId) : null;
|
|
483
|
-
|
|
494
|
+
let workspaceId = input.workspaceId === undefined && linked
|
|
484
495
|
? linked.workspaceId === GLOBAL_WORKSPACE_ID ? null : linked.workspaceId
|
|
485
496
|
: input.workspaceId ?? null;
|
|
486
|
-
|
|
497
|
+
let workspace = workspaceId ? this.s.getWorkspace(workspaceId) : this.s.ensureGlobalWorkspace();
|
|
487
498
|
if (!workspace)
|
|
488
499
|
throw new Error("任务所属工作区不存在。");
|
|
500
|
+
if (input.cwd && (!workspaceId || workspace.id === GLOBAL_WORKSPACE_ID)) {
|
|
501
|
+
const normalized = normalizeProjectCwd(input.cwd);
|
|
502
|
+
const match = this.s.listWorkspaces().find(w => w.id !== GLOBAL_WORKSPACE_ID && normalizeProjectCwd(w.cwd) === normalized);
|
|
503
|
+
if (match) {
|
|
504
|
+
workspace = match;
|
|
505
|
+
workspaceId = match.id;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
489
508
|
const milestoneId = this.s.taskMilestoneForWrite(input.milestoneId, workspaceId);
|
|
490
509
|
if (input.workspaceTaskId) {
|
|
491
510
|
const container = this.s.getWorkspaceTask(input.workspaceTaskId);
|
|
@@ -498,23 +517,41 @@ export class TaskRepository {
|
|
|
498
517
|
}
|
|
499
518
|
const workspaceTaskId = input.workspaceTaskId ?? this.s.insertWorkspaceTask({
|
|
500
519
|
workspaceId: workspace.id, name: input.title,
|
|
501
|
-
status: input.status === "
|
|
520
|
+
status: input.status === "archived" ? "done" : "active",
|
|
502
521
|
milestoneId,
|
|
522
|
+
cwd: input.cwd ?? null,
|
|
503
523
|
});
|
|
504
524
|
return this.insertWandTask({ ...input, workspaceId, workspaceTaskId, milestoneId });
|
|
505
525
|
});
|
|
506
526
|
}
|
|
507
527
|
/** Private canonical writer; callers own the transaction, never a reverse writer. */
|
|
508
|
-
writeWandTask(current, patch) {
|
|
509
|
-
const next = { ...current, ...patch, updatedAt:
|
|
528
|
+
writeWandTask(current, patch, workflow = false) {
|
|
529
|
+
const next = { ...current, ...patch, updatedAt: new Date(Math.max(Date.now(), (Date.parse(current.updatedAt) || 0) + 1)).toISOString() };
|
|
530
|
+
const deliveryChanged = patch.description !== undefined && patch.description !== current.description
|
|
531
|
+
|| patch.parentTaskId !== undefined && patch.parentTaskId !== current.parentTaskId
|
|
532
|
+
|| patch.workspaceId !== undefined && patch.workspaceId !== current.workspaceId
|
|
533
|
+
|| patch.acceptance !== undefined && (patch.acceptance?.evidence !== current.acceptance?.evidence || patch.acceptance?.blocker !== current.acceptance?.blocker)
|
|
534
|
+
|| patch.status !== undefined && ["backlog", "todo", "doing"].includes(patch.status) && patch.status !== current.status && ["ready", "review", "done", "archived"].includes(current.status);
|
|
535
|
+
if (!workflow && deliveryChanged) {
|
|
536
|
+
next.deliveryRevision = (current.deliveryRevision ?? 0) + 1;
|
|
537
|
+
next.verification = null;
|
|
538
|
+
if (next.acceptance)
|
|
539
|
+
next.acceptance = { ...next.acceptance, acceptedAt: null, confirmedRevision: undefined };
|
|
540
|
+
if (next.status === "ready" || next.status === "review")
|
|
541
|
+
next.status = "doing";
|
|
542
|
+
}
|
|
543
|
+
if (next.status === "ready" && !taskAiVerified(next))
|
|
544
|
+
throw new Error("待归档需要当前交付的 AI 验收记录,请走验收工作流。");
|
|
545
|
+
if (!workflow && next.status !== current.status && next.status === "archived" && !taskHumanAccepted(current))
|
|
546
|
+
throw new Error("请先经 AI 验收,再由人工确认并归档。");
|
|
547
|
+
if (!workflow && patch.acceptance?.acceptedAt && patch.acceptance.acceptedAt !== current.acceptance?.acceptedAt)
|
|
548
|
+
throw new Error("人工确认只能通过验收工作流写入。");
|
|
510
549
|
assertTaskHierarchy(this.listWandTasks(), current.id, next.parentTaskId, next.workspaceId, current);
|
|
511
|
-
if (next
|
|
512
|
-
if (
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
throw new Error("
|
|
516
|
-
else if (this.listWandTasks().some(child => child.parentTaskId === current.id && !child.acceptance?.acceptedAt))
|
|
517
|
-
throw new Error("仍有子任务未验收通过,不能通过主目标整体验收。");
|
|
550
|
+
if (taskHumanAccepted(next)) {
|
|
551
|
+
if (!next.acceptance.evidence.trim() || next.acceptance.blocker.trim())
|
|
552
|
+
throw new Error("人工确认需要交付证据,并先解除阻塞。");
|
|
553
|
+
if (this.listWandTaskChildren(current.id).some(child => !taskHumanAccepted(child)))
|
|
554
|
+
throw new Error("仍有子任务未由人工确认。");
|
|
518
555
|
}
|
|
519
556
|
// 归档时间只在进入归档时写一次;取消归档/重新打开时清空,恢复“未动多久”重新计时。
|
|
520
557
|
if (next.status === "archived") {
|
|
@@ -544,15 +581,15 @@ export class TaskRepository {
|
|
|
544
581
|
throw new Error("任务所属工作区不存在。");
|
|
545
582
|
next.workspaceTaskId = this.s.insertWorkspaceTask({
|
|
546
583
|
workspaceId: workspace.id, name: next.title, milestoneId: next.milestoneId,
|
|
547
|
-
status:
|
|
584
|
+
status: "active", createdAt: next.createdAt,
|
|
548
585
|
});
|
|
549
586
|
}
|
|
550
587
|
this.db.prepare(`UPDATE wand_tasks SET workspace_id = ?, workspace_task_id = ?, parent_task_id = ?,
|
|
551
588
|
title = ?, title_source = ?, auto_title_signature = ?, description = ?, status = ?, priority = ?,
|
|
552
589
|
labels_json = ?, due_date = ?, milestone_id = ?, sort_order = ?, agent_json = ?, execution_subject_json = ?,
|
|
553
|
-
archived_at = ?, updated_at = ?, acceptance_json = ?
|
|
590
|
+
archived_at = ?, updated_at = ?, acceptance_json = ?, verification_json = ?, delivery_revision = ?
|
|
554
591
|
WHERE id = ?`)
|
|
555
|
-
.run(next.workspaceId, next.workspaceTaskId, next.parentTaskId, next.title, next.titleSource, next.autoTitleSignature ?? null, next.description, next.status, next.priority, JSON.stringify(next.labels), next.dueDate, next.milestoneId ?? null, next.sortOrder, next.agent ? JSON.stringify(next.agent) : null, next.executionSubject ? JSON.stringify(next.executionSubject) : null, next.archivedAt, next.updatedAt, next.acceptance ? JSON.stringify(next.acceptance) : null, next.id);
|
|
592
|
+
.run(next.workspaceId, next.workspaceTaskId, next.parentTaskId, next.title, next.titleSource, next.autoTitleSignature ?? null, next.description, next.status, next.priority, JSON.stringify(next.labels), next.dueDate, next.milestoneId ?? null, next.sortOrder, next.agent ? JSON.stringify(next.agent) : null, next.executionSubject ? JSON.stringify(next.executionSubject) : null, next.archivedAt, next.updatedAt, next.acceptance ? JSON.stringify(next.acceptance) : null, next.verification ? JSON.stringify(next.verification) : null, next.deliveryRevision ?? 0, next.id);
|
|
556
593
|
// Only a real transition may opt into the new policy. Editing/backfilling an old archive must not do so.
|
|
557
594
|
if (next.status !== current.status) {
|
|
558
595
|
this.db.prepare("UPDATE wand_tasks SET retention_archive_version = ? WHERE id = ?")
|
|
@@ -566,11 +603,18 @@ export class TaskRepository {
|
|
|
566
603
|
this.db.prepare("UPDATE command_sessions SET workspace_id = ? WHERE workspace_task_id = ?")
|
|
567
604
|
.run(workspaceId, next.workspaceTaskId);
|
|
568
605
|
}
|
|
569
|
-
if (
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
606
|
+
if (deliveryChanged || patch.parentTaskId !== undefined && patch.parentTaskId !== current.parentTaskId || patch.deliveryRevision !== undefined && patch.deliveryRevision !== current.deliveryRevision
|
|
607
|
+
|| patch.verification !== undefined && !taskAiVerified(next)
|
|
608
|
+
|| patch.acceptance !== undefined && taskHumanAccepted(current) && !taskHumanAccepted(next))
|
|
609
|
+
for (const parentId of new Set([current.parentTaskId, next.parentTaskId].filter((id) => Boolean(id)))) {
|
|
610
|
+
const parent = this.getWandTask(parentId);
|
|
611
|
+
if (parent && (parent.verification || parent.acceptance?.acceptedAt))
|
|
612
|
+
this.writeWandTask(parent, {
|
|
613
|
+
deliveryRevision: (parent.deliveryRevision ?? 0) + 1, verification: null,
|
|
614
|
+
...(parent.acceptance ? { acceptance: { ...parent.acceptance, acceptedAt: null, confirmedRevision: undefined } } : {}),
|
|
615
|
+
...(parent.status === "ready" || parent.status === "review" ? { status: "doing" } : {}),
|
|
616
|
+
}, true);
|
|
617
|
+
}
|
|
574
618
|
this.s.notifyTaskTitleChange();
|
|
575
619
|
return next;
|
|
576
620
|
}
|
|
@@ -582,6 +626,18 @@ export class TaskRepository {
|
|
|
582
626
|
return this.writeWandTask(current, patch);
|
|
583
627
|
});
|
|
584
628
|
}
|
|
629
|
+
/** Explicit destructive project removal collects history, never claims delivery acceptance. */
|
|
630
|
+
archiveTaskForWorkspaceRemoval(id) {
|
|
631
|
+
return this.s.transaction(() => {
|
|
632
|
+
const current = this.getWandTask(id);
|
|
633
|
+
if (!current)
|
|
634
|
+
return null;
|
|
635
|
+
const task = this.writeWandTask(current, { status: "archived", workspaceTaskId: null }, true);
|
|
636
|
+
this.db.prepare("INSERT INTO wand_task_comments(id, task_id, author_name, body, created_at) VALUES (?, ?, ?, ?, ?)")
|
|
637
|
+
.run(crypto.randomUUID(), id, "项目移除", "项目被明确删除,仅收纳原任务与历史;这不是 AI 验收或人工接受交付。", task.updatedAt);
|
|
638
|
+
return task;
|
|
639
|
+
});
|
|
640
|
+
}
|
|
585
641
|
/** Commit completion archives only the selected completed cards, atomically. */
|
|
586
642
|
archiveCompletedWandTasks(ids) {
|
|
587
643
|
return this.archiveWandTasks(ids, { completedOnly: true });
|
|
@@ -597,7 +653,9 @@ export class TaskRepository {
|
|
|
597
653
|
const task = this.getWandTask(id);
|
|
598
654
|
if (!task || task.status === "archived")
|
|
599
655
|
continue;
|
|
600
|
-
if (options.completedOnly && task
|
|
656
|
+
if (options.completedOnly && !taskHumanAccepted(task))
|
|
657
|
+
continue;
|
|
658
|
+
if (!taskHumanAccepted(task))
|
|
601
659
|
continue;
|
|
602
660
|
this.writeWandTask(task, { status: "archived" });
|
|
603
661
|
archived.push(id);
|
|
@@ -851,6 +909,8 @@ export class TaskRepository {
|
|
|
851
909
|
const target = taskId ? this.s.getWorkspaceTask(taskId) : null;
|
|
852
910
|
if (taskId && !target)
|
|
853
911
|
throw new Error("未找到目标任务。");
|
|
912
|
+
if (target?.archived)
|
|
913
|
+
throw new Error("目标已归档,请先恢复后再移入会话。");
|
|
854
914
|
if (target && !this.s.getWorkspace(target.workspaceId))
|
|
855
915
|
throw new Error("目标工作区不存在。");
|
|
856
916
|
const source = session.workspaceTaskId ? this.s.getWorkspaceTask(session.workspaceTaskId) : null;
|
|
@@ -862,16 +922,16 @@ export class TaskRepository {
|
|
|
862
922
|
this.s.saveWorkspaceTaskLayout(source.id, { ...source.layout, windows });
|
|
863
923
|
}
|
|
864
924
|
const targetCard = target ? this.getWandTaskByWorkspaceTaskId(target.id) : null;
|
|
865
|
-
if (target && !targetCard)
|
|
925
|
+
if (target && target.kind !== "section" && !targetCard)
|
|
866
926
|
throw new Error("未找到目标任务。");
|
|
867
927
|
this.db.prepare("DELETE FROM wand_task_sessions WHERE session_id = ? AND (? IS NULL OR task_id != ?)")
|
|
868
928
|
.run(sessionId, targetCard?.id ?? null, targetCard?.id ?? null);
|
|
869
929
|
this.db.prepare("UPDATE command_sessions SET workspace_task_id = ?, workspace_id = ? WHERE id = ?")
|
|
870
930
|
.run(target?.id ?? null, target?.workspaceId ?? session.workspaceId ?? null, sessionId);
|
|
871
|
-
if (
|
|
931
|
+
if (targetCard) {
|
|
872
932
|
this.db.prepare("INSERT OR IGNORE INTO wand_task_sessions (task_id, session_id, bound_at) VALUES (?, ?, ?)")
|
|
873
933
|
.run(targetCard.id, sessionId, nowIso());
|
|
874
|
-
if (source?.id !== target
|
|
934
|
+
if (source?.id !== target?.id)
|
|
875
935
|
this.recordTaskSession(this.s.getSessionSlim(sessionId));
|
|
876
936
|
}
|
|
877
937
|
});
|
|
@@ -62,6 +62,13 @@ export declare class WorkspaceRepository {
|
|
|
62
62
|
createdAt?: string;
|
|
63
63
|
}): string;
|
|
64
64
|
taskMilestoneForWrite(id: string | null | undefined, workspaceId: string | null): string;
|
|
65
|
+
/** A user-named session container; deliberately has no task-board card. */
|
|
66
|
+
createWorkspaceSection(input: {
|
|
67
|
+
workspaceId: string;
|
|
68
|
+
name: string;
|
|
69
|
+
cwd?: string;
|
|
70
|
+
sessionId?: string;
|
|
71
|
+
}): WorkspaceTask;
|
|
65
72
|
createWorkspaceTask(input: {
|
|
66
73
|
workspaceId: string;
|
|
67
74
|
name: string;
|
|
@@ -242,6 +242,21 @@ export class WorkspaceRepository {
|
|
|
242
242
|
return workspaceId && milestone.workspaceId && milestone.workspaceId !== workspaceId
|
|
243
243
|
? this.s.ensureDefaultWandMilestone().id : id;
|
|
244
244
|
}
|
|
245
|
+
/** A user-named session container; deliberately has no task-board card. */
|
|
246
|
+
createWorkspaceSection(input) {
|
|
247
|
+
return this.s.transaction(() => {
|
|
248
|
+
if (!this.getWorkspace(input.workspaceId))
|
|
249
|
+
throw new Error("分区所属工作区不存在。");
|
|
250
|
+
const name = input.name.trim();
|
|
251
|
+
if (!name || name.length > 80)
|
|
252
|
+
throw new Error("请输入 1–80 字的分区名称。");
|
|
253
|
+
const id = this.insertWorkspaceTask({ ...input, name });
|
|
254
|
+
this.db.prepare("UPDATE workspace_tasks SET container_kind = 'section' WHERE id = ?").run(id);
|
|
255
|
+
if (input.sessionId)
|
|
256
|
+
this.s.moveSessionToWorkspaceTask(input.sessionId, id);
|
|
257
|
+
return this.getWorkspaceTask(id);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
245
260
|
createWorkspaceTask(input) {
|
|
246
261
|
return this.s.transaction(() => {
|
|
247
262
|
const workspace = this.getWorkspace(input.workspaceId);
|
|
@@ -263,8 +278,16 @@ export class WorkspaceRepository {
|
|
|
263
278
|
updateWorkspaceTask(id, patch) {
|
|
264
279
|
this.s.transaction(() => {
|
|
265
280
|
const card = this.s.getWandTaskByWorkspaceTaskId(id);
|
|
266
|
-
if (!card)
|
|
267
|
-
|
|
281
|
+
if (!card) {
|
|
282
|
+
const container = this.getWorkspaceTask(id);
|
|
283
|
+
if (container?.kind !== "section")
|
|
284
|
+
throw new Error("未找到该任务。");
|
|
285
|
+
if (patch.name !== undefined)
|
|
286
|
+
this.db.prepare("UPDATE workspace_tasks SET name = ? WHERE id = ?").run(patch.name, id);
|
|
287
|
+
if (patch.status !== undefined)
|
|
288
|
+
this.db.prepare("UPDATE workspace_tasks SET status = ? WHERE id = ?").run(patch.status, id);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
268
291
|
if (patch.worktree !== undefined) {
|
|
269
292
|
this.db.prepare("UPDATE workspace_tasks SET worktree_json = ? WHERE id = ?")
|
|
270
293
|
.run(patch.worktree ? JSON.stringify(patch.worktree) : null, id);
|
|
@@ -286,6 +309,9 @@ export class WorkspaceRepository {
|
|
|
286
309
|
}
|
|
287
310
|
archiveWorkspaceTask(id) {
|
|
288
311
|
const card = this.s.getWandTaskByWorkspaceTaskId(id);
|
|
312
|
+
if (!card && this.getWorkspaceTask(id)?.kind === "section") {
|
|
313
|
+
throw new Error("分区不需要归档,请将会话移回工作区后删除空分区。");
|
|
314
|
+
}
|
|
289
315
|
return card ? this.s.updateWandTask(card.id, { status: "archived" }) : null;
|
|
290
316
|
}
|
|
291
317
|
saveWorkspaceTaskLayout(id, layout, expectedRevision) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type TempKind } from "./managed-temp.js";
|
|
2
2
|
import type { UploadRepository } from "./storage/uploads-repository.js";
|
|
3
|
+
import type { PtyTmuxGcReport } from "./pty-tmux-backend.js";
|
|
3
4
|
export declare const STORAGE_CLEANUP_RETENTION_DAYS = 7;
|
|
4
5
|
export interface CleanupReport {
|
|
5
6
|
applied: boolean;
|
|
@@ -11,7 +12,7 @@ export interface CleanupReport {
|
|
|
11
12
|
allocatedBytes: number;
|
|
12
13
|
skipped: number;
|
|
13
14
|
issues: string[];
|
|
14
|
-
byKind: Partial<Record<TempKind | "upload" | "diagnostic-log" | "distribution-package" | "native-run" | "migration-snapshot", number>>;
|
|
15
|
+
byKind: Partial<Record<TempKind | "upload" | "diagnostic-log" | "distribution-package" | "native-run" | "migration-snapshot" | "pty-tmux", number>>;
|
|
15
16
|
}
|
|
16
17
|
/** pi-native 回收结果(与 PiTmuxHost.collectGarbage 的返回一致)。 */
|
|
17
18
|
export interface PiNativeGcReport {
|
|
@@ -52,6 +53,10 @@ interface CleanupOptions {
|
|
|
52
53
|
deleted: string[];
|
|
53
54
|
freedBytes: number;
|
|
54
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* 回收 pty-tmux 下废弃的会话记录与 /tmp 遗留的失效 socket。
|
|
58
|
+
*/
|
|
59
|
+
collectPtyTmuxArtifacts?: () => PtyTmuxGcReport | null;
|
|
55
60
|
}
|
|
56
61
|
/** Runtime-only, explicit ownership. User history, downloads and rollback inputs are never candidates. */
|
|
57
62
|
export declare class StorageCleanup {
|
|
@@ -81,5 +86,5 @@ export declare class StorageCleanup {
|
|
|
81
86
|
private sweepDistributionArtifacts;
|
|
82
87
|
private sweepTemporary;
|
|
83
88
|
}
|
|
84
|
-
export declare function createStorageCleanup(configDir: string, options?: Pick<CleanupOptions, "uploads" | "uploadsActive" | "onUploadRemoved" | "pruneDistributionArtifacts" | "collectNativeArtifacts" | "pruneMigrationSnapshots">): StorageCleanup;
|
|
89
|
+
export declare function createStorageCleanup(configDir: string, options?: Pick<CleanupOptions, "uploads" | "uploadsActive" | "onUploadRemoved" | "pruneDistributionArtifacts" | "collectNativeArtifacts" | "pruneMigrationSnapshots" | "collectPtyTmuxArtifacts">): StorageCleanup;
|
|
85
90
|
export {};
|
package/dist/storage-cleanup.js
CHANGED
|
@@ -268,6 +268,22 @@ export class StorageCleanup {
|
|
|
268
268
|
report.issues.push("Migration snapshot cleanup failed; snapshots preserved.");
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
|
+
if (this.options.collectPtyTmuxArtifacts) {
|
|
272
|
+
try {
|
|
273
|
+
const ptyReport = this.options.collectPtyTmuxArtifacts();
|
|
274
|
+
const removed = (ptyReport?.removedRecords ?? 0) + (ptyReport?.removedSockets ?? 0);
|
|
275
|
+
if (ptyReport && removed > 0) {
|
|
276
|
+
report.removed += removed;
|
|
277
|
+
report.logicalBytes += ptyReport.freedBytes;
|
|
278
|
+
report.byKind["pty-tmux"] = removed;
|
|
279
|
+
detail.push(`PTY tmux 产物 ${removed} 项(${(ptyReport.freedBytes / 1024 / 1024).toFixed(1)} MB)`
|
|
280
|
+
+ `:记录 ${ptyReport.removedRecords} 条 / socket ${ptyReport.removedSockets} 个`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
report.issues.push("PTY tmux artifact cleanup failed; artifacts preserved.");
|
|
285
|
+
}
|
|
286
|
+
}
|
|
271
287
|
// 后台删除必须留痕迹:这些路径不是用户主动触发,没有日志就无法事后追溯删了什么。
|
|
272
288
|
if (detail.length > 0)
|
|
273
289
|
process.stdout.write(`[storage-cleanup] 已回收 ${detail.join(";")}\n`);
|
package/dist/storage-schema.js
CHANGED
|
@@ -259,6 +259,8 @@ const INIT_SQL = `
|
|
|
259
259
|
agent_json TEXT,
|
|
260
260
|
execution_subject_json TEXT,
|
|
261
261
|
acceptance_json TEXT,
|
|
262
|
+
verification_json TEXT,
|
|
263
|
+
delivery_revision INTEGER NOT NULL DEFAULT 0,
|
|
262
264
|
workspace_task_id TEXT,
|
|
263
265
|
parent_task_id TEXT,
|
|
264
266
|
title_source TEXT,
|
package/dist/storage.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { ConversationOrganizationRepository } from "./storage/conversation-organ
|
|
|
10
10
|
import { PreferencesRepository } from "./storage/preferences-repository.js";
|
|
11
11
|
import { WorkspaceRepository } from "./storage/workspaces-repository.js";
|
|
12
12
|
import { TaskRepository } from "./storage/tasks-repository.js";
|
|
13
|
+
import { TaskWorkflowRepository } from "./storage/task-workflow-repository.js";
|
|
13
14
|
import { SecretsRepository } from "./storage/secrets-repository.js";
|
|
14
15
|
import { KnowledgeRepository } from "./storage/knowledge-repository.js";
|
|
15
16
|
import { EmployeeRepository } from "./storage/employees-repository.js";
|
|
@@ -17,6 +18,7 @@ import { UserMemoryRepository } from "./storage/user-memory-repository.js";
|
|
|
17
18
|
import { AiTeamRepository } from "./storage/ai-teams-repository.js";
|
|
18
19
|
import { MissionRepository } from "./storage/missions-repository.js";
|
|
19
20
|
import { SessionRepository } from "./storage/sessions-repository.js";
|
|
21
|
+
import { SessionInputRepository } from "./storage/session-input-repository.js";
|
|
20
22
|
import { UploadRepository } from "./storage/uploads-repository.js";
|
|
21
23
|
import { FeedbackRepository } from "./storage/feedback-repository.js";
|
|
22
24
|
export { parseWandTaskAgent };
|
|
@@ -26,7 +28,7 @@ export { ensureDatabaseFile } from "./storage-schema.js";
|
|
|
26
28
|
type RepositoryMethods<T> = Pick<T, {
|
|
27
29
|
[K in keyof T]: T[K] extends (...args: never[]) => unknown ? K : never;
|
|
28
30
|
}[keyof T]>;
|
|
29
|
-
export interface WandStorage extends RepositoryMethods<DingTalkRepository>, RepositoryMethods<ConversationRepository>, RepositoryMethods<ConversationOrganizationRepository>, RepositoryMethods<PreferencesRepository>, RepositoryMethods<WorkspaceRepository>, RepositoryMethods<TaskRepository>, RepositoryMethods<SecretsRepository>, RepositoryMethods<EmployeeRepository>, RepositoryMethods<KnowledgeRepository>, RepositoryMethods<UserMemoryRepository>, RepositoryMethods<AiTeamRepository>, RepositoryMethods<MissionRepository>, RepositoryMethods<SessionRepository>, RepositoryMethods<UploadRepository>, RepositoryMethods<FeedbackRepository> {
|
|
31
|
+
export interface WandStorage extends RepositoryMethods<DingTalkRepository>, RepositoryMethods<ConversationRepository>, RepositoryMethods<ConversationOrganizationRepository>, RepositoryMethods<PreferencesRepository>, RepositoryMethods<WorkspaceRepository>, RepositoryMethods<TaskRepository>, RepositoryMethods<TaskWorkflowRepository>, RepositoryMethods<SecretsRepository>, RepositoryMethods<EmployeeRepository>, RepositoryMethods<KnowledgeRepository>, RepositoryMethods<UserMemoryRepository>, RepositoryMethods<AiTeamRepository>, RepositoryMethods<MissionRepository>, RepositoryMethods<SessionRepository>, RepositoryMethods<SessionInputRepository>, RepositoryMethods<UploadRepository>, RepositoryMethods<FeedbackRepository> {
|
|
30
32
|
}
|
|
31
33
|
export declare class WandStorage {
|
|
32
34
|
readonly dingtalk: DingTalkRepository;
|
|
@@ -37,6 +39,7 @@ export declare class WandStorage {
|
|
|
37
39
|
readonly preferences: PreferencesRepository;
|
|
38
40
|
readonly workspaces: WorkspaceRepository;
|
|
39
41
|
readonly tasks: TaskRepository;
|
|
42
|
+
readonly taskWorkflow: TaskWorkflowRepository;
|
|
40
43
|
readonly secrets: SecretsRepository;
|
|
41
44
|
readonly employees: EmployeeRepository;
|
|
42
45
|
readonly knowledge: KnowledgeRepository;
|
|
@@ -44,6 +47,7 @@ export declare class WandStorage {
|
|
|
44
47
|
readonly aiTeams: AiTeamRepository;
|
|
45
48
|
readonly missions: MissionRepository;
|
|
46
49
|
readonly sessions: SessionRepository;
|
|
50
|
+
readonly sessionInputs: SessionInputRepository;
|
|
47
51
|
readonly uploads: UploadRepository;
|
|
48
52
|
readonly feedback: FeedbackRepository;
|
|
49
53
|
private readonly closeListeners;
|
package/dist/storage.js
CHANGED
|
@@ -13,6 +13,7 @@ import { ConversationOrganizationRepository } from "./storage/conversation-organ
|
|
|
13
13
|
import { PreferencesRepository } from "./storage/preferences-repository.js";
|
|
14
14
|
import { WorkspaceRepository } from "./storage/workspaces-repository.js";
|
|
15
15
|
import { TaskRepository } from "./storage/tasks-repository.js";
|
|
16
|
+
import { TaskWorkflowRepository } from "./storage/task-workflow-repository.js";
|
|
16
17
|
import { SecretsRepository } from "./storage/secrets-repository.js";
|
|
17
18
|
import { KnowledgeRepository } from "./storage/knowledge-repository.js";
|
|
18
19
|
import { EmployeeRepository } from "./storage/employees-repository.js";
|
|
@@ -20,6 +21,7 @@ import { UserMemoryRepository } from "./storage/user-memory-repository.js";
|
|
|
20
21
|
import { AiTeamRepository } from "./storage/ai-teams-repository.js";
|
|
21
22
|
import { MissionRepository } from "./storage/missions-repository.js";
|
|
22
23
|
import { SessionRepository } from "./storage/sessions-repository.js";
|
|
24
|
+
import { SessionInputRepository } from "./storage/session-input-repository.js";
|
|
23
25
|
import { UploadRepository } from "./storage/uploads-repository.js";
|
|
24
26
|
import { FeedbackRepository } from "./storage/feedback-repository.js";
|
|
25
27
|
export { parseWandTaskAgent };
|
|
@@ -33,6 +35,7 @@ export class WandStorage {
|
|
|
33
35
|
preferences;
|
|
34
36
|
workspaces;
|
|
35
37
|
tasks;
|
|
38
|
+
taskWorkflow;
|
|
36
39
|
secrets;
|
|
37
40
|
employees;
|
|
38
41
|
knowledge;
|
|
@@ -40,6 +43,7 @@ export class WandStorage {
|
|
|
40
43
|
aiTeams;
|
|
41
44
|
missions;
|
|
42
45
|
sessions;
|
|
46
|
+
sessionInputs;
|
|
43
47
|
uploads;
|
|
44
48
|
feedback;
|
|
45
49
|
closeListeners = new Set();
|
|
@@ -54,6 +58,10 @@ export class WandStorage {
|
|
|
54
58
|
return `${this.projectionEpoch}:${own.revision}:${external.data_version}`;
|
|
55
59
|
}
|
|
56
60
|
onClose(listener) {
|
|
61
|
+
if (this.closed) {
|
|
62
|
+
listener();
|
|
63
|
+
return () => { };
|
|
64
|
+
}
|
|
57
65
|
this.closeListeners.add(listener);
|
|
58
66
|
return () => { this.closeListeners.delete(listener); };
|
|
59
67
|
}
|
|
@@ -100,6 +108,7 @@ export class WandStorage {
|
|
|
100
108
|
this.preferences = new PreferencesRepository(this.db, this);
|
|
101
109
|
this.workspaces = new WorkspaceRepository(this.db, this);
|
|
102
110
|
this.tasks = new TaskRepository(this.db, this);
|
|
111
|
+
this.taskWorkflow = new TaskWorkflowRepository(this.db, this);
|
|
103
112
|
this.secrets = new SecretsRepository(this.db, this);
|
|
104
113
|
this.employees = new EmployeeRepository(this.db, this);
|
|
105
114
|
this.knowledge = new KnowledgeRepository(this.db, this);
|
|
@@ -107,6 +116,7 @@ export class WandStorage {
|
|
|
107
116
|
this.aiTeams = new AiTeamRepository(this.db, this);
|
|
108
117
|
this.missions = new MissionRepository(this.db, this);
|
|
109
118
|
this.sessions = new SessionRepository(this.db, this);
|
|
119
|
+
this.sessionInputs = new SessionInputRepository(this.db, this);
|
|
110
120
|
this.uploads = new UploadRepository(this.db, this);
|
|
111
121
|
this.feedback = new FeedbackRepository(this.db, this);
|
|
112
122
|
this.schedules = new ScheduledTaskRepository(this.db, action => this.transaction(action));
|
|
@@ -256,6 +266,7 @@ const REPOSITORY_FORWARDS = [
|
|
|
256
266
|
["preferences", PreferencesRepository],
|
|
257
267
|
["workspaces", WorkspaceRepository],
|
|
258
268
|
["tasks", TaskRepository],
|
|
269
|
+
["taskWorkflow", TaskWorkflowRepository],
|
|
259
270
|
["secrets", SecretsRepository],
|
|
260
271
|
["employees", EmployeeRepository],
|
|
261
272
|
["knowledge", KnowledgeRepository],
|
|
@@ -263,6 +274,7 @@ const REPOSITORY_FORWARDS = [
|
|
|
263
274
|
["aiTeams", AiTeamRepository],
|
|
264
275
|
["missions", MissionRepository],
|
|
265
276
|
["sessions", SessionRepository],
|
|
277
|
+
["sessionInputs", SessionInputRepository],
|
|
266
278
|
["uploads", UploadRepository],
|
|
267
279
|
["feedback", FeedbackRepository],
|
|
268
280
|
];
|
|
@@ -16,6 +16,7 @@ export interface StructuredSpawnRequest {
|
|
|
16
16
|
stdinData?: string;
|
|
17
17
|
/** Internal opt-in: a real Pi native TUI in an owned tmux pane. Never supplied by HTTP command text. */
|
|
18
18
|
nativePi?: boolean;
|
|
19
|
+
nativeInputMessageId?: string;
|
|
19
20
|
requestId?: string;
|
|
20
21
|
/** Native launch cancellation before input has been accepted; not sent to daemon RPCs. */
|
|
21
22
|
launchSignal?: AbortSignal;
|
|
@@ -70,8 +71,11 @@ export interface StructuredExecProcess {
|
|
|
70
71
|
export interface StructuredExecHost {
|
|
71
72
|
readonly persistent: boolean;
|
|
72
73
|
readonly piNativeTui?: boolean;
|
|
74
|
+
offerPiInput?(runId: string, boundaryId: string, take: (identity: import("./pi-native-input.js").PiInputHandoff) => string | null): boolean;
|
|
75
|
+
resolvePiInput?(runId: string, handoff: import("./pi-native-input.js").PiInputHandoff): import("./pi-native-input.js").PiInputResolution;
|
|
73
76
|
collectGarbage?(options: {
|
|
74
77
|
liveSessionIds: ReadonlySet<string>;
|
|
78
|
+
activeSessionIds?: ReadonlySet<string>;
|
|
75
79
|
retentionMs: number;
|
|
76
80
|
now?: number;
|
|
77
81
|
}): {
|
|
@@ -31,6 +31,7 @@ export interface StructuredCliPumpOptions<S extends StructuredRunnerTurnState> {
|
|
|
31
31
|
/** Pi opts in: stdout is captured to a private file; only file reads feed processLine. */
|
|
32
32
|
stdoutFile?: PiOutputFileOptions;
|
|
33
33
|
nativePi?: boolean;
|
|
34
|
+
nativeInputMessageId?: string;
|
|
34
35
|
requestId?: string;
|
|
35
36
|
/** Provider-owned streaming projection; defaults to the strict shared line framer. */
|
|
36
37
|
createProtocolReader?(onLine: (line: string) => void): {
|