@co0ontty/wand 4.98.1-beta.368.1.g6ebcbb5 → 4.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/ai-team-runner.js +1 -1
- package/dist/ai-team-types.d.ts +1 -1
- package/dist/ai-team-types.js +1 -1
- package/dist/build-info.json +4 -4
- package/dist/conversation-service.js +2 -2
- package/dist/daemon-maintenance.js +2 -0
- package/dist/employee-input-scheduling.d.ts +17 -0
- package/dist/employee-input-scheduling.js +15 -0
- package/dist/employee-types.d.ts +4 -0
- package/dist/employee-types.js +2 -0
- package/dist/execution-state.d.ts +8 -0
- package/dist/execution-state.js +18 -0
- package/dist/ios-ota.js +12 -2
- package/dist/middleware/api-scope.js +1 -0
- package/dist/models.js +7 -0
- package/dist/pi-auto-resources.js +54 -28
- package/dist/pi-resource-recommendation.d.ts +8 -0
- package/dist/pi-resource-recommendation.js +28 -1
- package/dist/pi-session-settings.d.ts +9 -0
- package/dist/pi-session-settings.js +42 -0
- package/dist/pi-tmux-host.d.ts +3 -2
- package/dist/pi-tmux-host.js +62 -25
- package/dist/process-manager.d.ts +1 -0
- package/dist/process-manager.js +64 -4
- package/dist/pty-tmux-backend.d.ts +28 -0
- package/dist/pty-tmux-backend.js +287 -0
- package/dist/pty-tmux-log.d.ts +2 -0
- package/dist/pty-tmux-log.js +27 -0
- package/dist/render-daemon-client.js +3 -0
- package/dist/render-host.d.ts +1 -4
- package/dist/render-host.js +3 -21
- package/dist/server-asset-routes.d.ts +4 -0
- package/dist/server-asset-routes.js +12 -3
- package/dist/server-employee-routes.d.ts +5 -0
- package/dist/server-employee-routes.js +18 -3
- package/dist/server-pi-defaults-routes.d.ts +23 -0
- package/dist/server-pi-defaults-routes.js +73 -0
- package/dist/server-session-input-routes.js +2 -1
- package/dist/server-session-lifecycle-routes.js +1 -1
- package/dist/server-session-routes.js +3 -0
- package/dist/server-task-routes.d.ts +4 -1
- package/dist/server-task-routes.js +25 -8
- package/dist/server-update-routes.js +3 -3
- package/dist/server-workspace-routes.js +9 -1
- package/dist/server.js +45 -6
- package/dist/session-transport.d.ts +3 -0
- package/dist/session-transport.js +3 -0
- package/dist/storage/employees-repository.js +19 -6
- package/dist/storage/internal.js +2 -1
- package/dist/storage/mappers.d.ts +1 -1
- package/dist/storage/mappers.js +8 -0
- package/dist/storage/migrations.js +38 -0
- package/dist/storage/tasks-repository.d.ts +65 -2
- package/dist/storage/tasks-repository.js +283 -15
- package/dist/storage/workspaces-repository.js +2 -1
- package/dist/structured-claude-adapter.js +29 -17
- package/dist/structured-claude-protocol.d.ts +13 -0
- package/dist/structured-claude-protocol.js +33 -2
- package/dist/structured-codex-adapter.js +7 -0
- package/dist/structured-exec-host.d.ts +10 -1
- package/dist/structured-exec-pump.js +17 -7
- package/dist/structured-failure.d.ts +38 -6
- package/dist/structured-failure.js +55 -10
- package/dist/structured-grok-adapter.js +6 -0
- package/dist/structured-host-maintenance.d.ts +4 -0
- package/dist/structured-host-maintenance.js +25 -0
- package/dist/structured-opencode-adapter.js +6 -0
- package/dist/structured-pi-adapter.js +29 -10
- package/dist/structured-qoder-adapter.js +30 -15
- package/dist/structured-session-manager.d.ts +20 -1
- package/dist/structured-session-manager.js +165 -46
- package/dist/structured-tmux-host.d.ts +51 -0
- package/dist/structured-tmux-host.js +576 -0
- package/dist/structured-tmux-supervisor.d.ts +1 -0
- package/dist/structured-tmux-supervisor.js +109 -0
- package/dist/structured-tmux-worker.d.ts +1 -0
- package/dist/structured-tmux-worker.js +144 -0
- package/dist/task-comment-dispatch.d.ts +5 -0
- package/dist/task-comment-dispatch.js +401 -11
- package/dist/task-comment-references.d.ts +50 -0
- package/dist/task-comment-references.js +108 -0
- package/dist/task-comment-status.d.ts +13 -0
- package/dist/task-comment-status.js +25 -0
- package/dist/task-execution-queue.d.ts +65 -0
- package/dist/task-execution-queue.js +288 -0
- package/dist/task-read-model.d.ts +6 -0
- package/dist/task-read-model.js +8 -0
- package/dist/task-title-organize.d.ts +2 -1
- package/dist/task-types.d.ts +37 -2
- package/dist/task-types.js +8 -0
- package/dist/terminal-daemon-build.js +1 -1
- package/dist/terminal-daemon-client.d.ts +3 -1
- package/dist/terminal-daemon-client.js +4 -2
- package/dist/terminal-daemon-server.js +65 -24
- package/dist/tmux-policy.d.ts +2 -0
- package/dist/tmux-policy.js +10 -0
- package/dist/tmux-terminal-host.d.ts +10 -0
- package/dist/tmux-terminal-host.js +74 -0
- package/dist/types.d.ts +2 -1
- package/dist/web-ui/avatar-hardware.d.ts +28 -0
- package/dist/web-ui/avatar-hardware.js +60 -0
- package/dist/web-ui/chat-history-window.d.ts +1 -2
- package/dist/web-ui/chat-history-window.js +2 -4
- package/dist/web-ui/content/ai-teams.js +13 -13
- package/dist/web-ui/content/licenses/lucide.txt +43 -0
- package/dist/web-ui/content/login.js +131 -0
- package/dist/web-ui/content/module-manifest.json +1 -1
- package/dist/web-ui/content/modules/007197d061c2a565/chunk.js +57 -0
- package/dist/web-ui/content/modules/{8cb5d84a2731789e → 0128a9a2c361da59}/chunk.js +1 -1
- package/dist/web-ui/content/modules/0206d2425a3eb375/chunk.js +1 -0
- package/dist/web-ui/content/modules/0261c50fee52b437/host.js +1 -0
- package/dist/web-ui/content/modules/0500b57b86317246/host.js +1 -0
- package/dist/web-ui/content/modules/05889845b99c95dd/host.js +1 -0
- package/dist/web-ui/content/modules/07b7b195f2e59a16/chunk.js +1 -0
- package/dist/web-ui/content/modules/0a04baa27e4fc9e3/chunk.js +3 -0
- package/dist/web-ui/content/modules/0b00a661913662d4/chunk.js +1 -0
- package/dist/web-ui/content/modules/0bd3cebfdbc60d19/queue-view-adapter.js +3 -0
- package/dist/web-ui/content/modules/0cb64ca968a6d25d/chunk.js +6 -0
- package/dist/web-ui/content/modules/19a7b932484a64ca/host-bridge.js +1 -0
- package/dist/web-ui/content/modules/19d3bc36fa1e9160/chunk.js +1 -0
- package/dist/web-ui/content/modules/1f88294162059296/home.js +6 -0
- package/dist/web-ui/content/modules/{0bf4a78c8be1bdc9 → 23178d02e631d065}/host.js +3 -3
- package/dist/web-ui/content/modules/{d673a76becc7d1f5 → 23eea6861975478b}/chunk.js +2 -2
- package/dist/web-ui/content/modules/2409b362681d91d6/chunk.js +3 -0
- package/dist/web-ui/content/modules/2575e08b75b1a192/chunk.js +1 -0
- package/dist/web-ui/content/modules/258f0487e8621dcc/chunk.js +10 -0
- package/dist/web-ui/content/modules/26b6ff004618750f/chunk.js +1 -0
- package/dist/web-ui/content/modules/280457daf6b6fe61/chunk.js +20 -0
- package/dist/web-ui/content/modules/2837772e09c2b62d/chunk.js +4 -0
- package/dist/web-ui/content/modules/28795c8bb7f4e2e8/chunk.js +3 -0
- package/dist/web-ui/content/modules/29c912ef59696172/panel.js +1 -0
- package/dist/web-ui/content/modules/2aa0bc0eba53a5c9/chunk.js +15 -0
- package/dist/web-ui/content/modules/2be38bfbed614f65/host.js +1 -0
- package/dist/web-ui/content/modules/360db1263b60f857/composer-surface-adapter.js +1 -0
- package/dist/web-ui/content/modules/364b10aceecf7ab9/panel-host.js +1 -0
- package/dist/web-ui/content/modules/371e120f3773f783/employee-card.js +1 -0
- package/dist/web-ui/content/modules/37767c3c41b8d8a8/host.js +69 -0
- package/dist/web-ui/content/modules/3b975071451386a4/chunk.js +1 -0
- package/dist/web-ui/content/modules/3d050c621f552e20/chunk.js +1 -0
- package/dist/web-ui/content/modules/3d0ec18974ad2b11/chunk.js +12 -0
- package/dist/web-ui/content/modules/3d1f076ddfc09771/chunk.js +1 -0
- package/dist/web-ui/content/modules/405a98ab11edb2c1/runtime.js +275 -0
- package/dist/web-ui/content/modules/45e8d613816cdec5/chunk.js +3 -0
- package/dist/web-ui/content/modules/4718bec8ce29956e/chunk.js +1 -0
- package/dist/web-ui/content/modules/48b00eccb3067884/chunk.js +2 -0
- package/dist/web-ui/content/modules/{17f72e0fb014a302 → 4ca8f7b400b83127}/chat-render.js +3 -3
- package/dist/web-ui/content/modules/4dd52ad71d002eab/chunk.js +1 -0
- package/dist/web-ui/content/modules/51fc769946593cfa/chunk.js +1 -0
- package/dist/web-ui/content/modules/5444c4f9260fcb2f/toast-region.js +1 -0
- package/dist/web-ui/content/modules/5cd5d3d65d966c5f/chunk.js +1 -0
- package/dist/web-ui/content/modules/5d4915f6e1661d23/chunk.js +29 -0
- package/dist/web-ui/content/modules/5e50a3c3c546d824/chunk.js +1 -0
- package/dist/web-ui/content/modules/5f4ea7ad706b19f7/progress.js +1 -0
- package/dist/web-ui/content/modules/621b2383696b9d7d/host.js +1 -0
- package/dist/web-ui/content/modules/65e98a2bcd16cd79/chunk.js +1 -0
- package/dist/web-ui/content/modules/71205ec0b1cf554d/host.js +1 -0
- package/dist/web-ui/content/modules/73a96d56bc1484de/host.js +1 -0
- package/dist/web-ui/content/modules/76b953fe1f34c421/dropdown-surface.js +1 -0
- package/dist/web-ui/content/modules/784eef1d52221e7d/chunk.js +1 -0
- package/dist/web-ui/content/modules/7aab1455fc7348e1/chunk.js +1 -0
- package/dist/web-ui/content/modules/82f9fed7fd7ffd9f/chunk.js +1 -0
- package/dist/web-ui/content/modules/8492b5592532e563/chunk.js +1 -0
- package/dist/web-ui/content/modules/8676143ae232d8b6/chunk.js +1 -0
- package/dist/web-ui/content/modules/890cdc256b49e26c/host.js +1 -0
- package/dist/web-ui/content/modules/8c4258e7c35e9eca/chunk.js +1 -0
- package/dist/web-ui/content/modules/91f4ec7a3631129c/chunk.js +13 -0
- package/dist/web-ui/content/modules/{818d87c1651fc6a1 → 93b428761a02ca66}/chunk.js +2 -2
- package/dist/web-ui/content/modules/950a2f28bc128f94/dialog-modal.js +4 -0
- package/dist/web-ui/content/modules/9638c7ba97db8755/notice-view.js +1 -0
- package/dist/web-ui/content/modules/96f4a041d5cf046b/chunk.js +1 -0
- package/dist/web-ui/content/modules/97faa837aeaaff64/workspace-window.js +1 -0
- package/dist/web-ui/content/modules/9a0704236531e38e/chunk.js +1 -0
- package/dist/web-ui/content/modules/9a12d5f9e5fef729/workspaces-panel.js +4 -0
- package/dist/web-ui/content/modules/9a4f713719354002/host.js +1 -0
- package/dist/web-ui/content/modules/9d7b92a76b2d54ab/sidebar-peek.js +1 -0
- package/dist/web-ui/content/modules/a04036215e751a32/chunk.js +1 -0
- package/dist/web-ui/content/modules/{77ea205020273767 → a120182be2ef9632}/chunk.js +1 -1
- package/dist/web-ui/content/modules/a1e9344b3fbd11ae/chunk.js +1 -0
- package/dist/web-ui/content/modules/{0afa04591224bc23 → a2263c03ce67440a}/library-bridge.js +3 -3
- package/dist/web-ui/content/modules/a48f540d6a228012/chunk.js +4 -0
- package/dist/web-ui/content/modules/{eb46bf62b1ae1bea → a763fe780816708f}/host.js +2 -2
- package/dist/web-ui/content/modules/a9114b269e25b3f5/chunk.js +1 -0
- package/dist/web-ui/content/modules/a919e64032fe3acc/chunk.js +6 -0
- package/dist/web-ui/content/modules/abe3642ec4dba601/chunk.js +1 -0
- package/dist/web-ui/content/modules/ad896e0a52316ead/chunk.js +1 -0
- package/dist/web-ui/content/modules/b0b078bcfc9085a6/chunk.js +3 -0
- package/dist/web-ui/content/modules/b0d4d1f8ff0fae38/chunk.js +1 -0
- package/dist/web-ui/content/modules/b3c8d461cf58ea32/host.js +30 -0
- package/dist/web-ui/content/modules/b9445d806edca559/sha256.js +1 -0
- package/dist/web-ui/content/modules/b9b78d6b75945e66/employee-profile.js +1 -0
- package/dist/web-ui/content/modules/bbe7c6f6eda87002/task-board-host.js +22 -0
- package/dist/web-ui/content/modules/bc56ae7841b21ca6/chunk.js +9 -0
- package/dist/web-ui/content/modules/{7fb02c44fd6f877b → c2e0b78e4a6b1a18}/host.js +2 -2
- package/dist/web-ui/content/modules/c4705a6af423d824/chunk.js +10 -0
- package/dist/web-ui/content/modules/c8ee697d1dd6e302/group-editor.js +1 -0
- package/dist/web-ui/content/modules/ca37cc312813dd4f/chunk.js +1 -0
- package/dist/web-ui/content/modules/cdb1909af2179a41/chunk.js +1 -0
- package/dist/web-ui/content/modules/d0a0f9214f3bbf71/chunk.js +3 -0
- package/dist/web-ui/content/modules/d1185edafb2a3fc6/shell-file-panel-drawer.js +1 -0
- package/dist/web-ui/content/modules/d948ac122dc34acc/markdown.js +1 -0
- package/dist/web-ui/content/modules/da8314e267c164ed/host.js +1 -0
- package/dist/web-ui/content/modules/ddcaaa62f1b7f049/chunk.js +1 -0
- package/dist/web-ui/content/modules/dfb9876d670c5365/chunk.js +1 -0
- package/dist/web-ui/content/modules/{183db4802a7d99ed → e2263673e53a298c}/host.js +2 -2
- package/dist/web-ui/content/modules/e7780cd2afeb29d9/chunk.js +1 -0
- package/dist/web-ui/content/modules/{62028b9bbf8ffc88 → e8f9f6d46ef4bb53}/page.js +3 -3
- package/dist/web-ui/content/modules/ea7cd328cb5cf7e0/chunk.js +1 -0
- package/dist/web-ui/content/modules/edb31a89f667eddf/brand-identity.js +1 -0
- package/dist/web-ui/content/modules/f248ee3b31df4034/chunk.js +1 -0
- package/dist/web-ui/content/modules/f41d42a01dc09373/login-visual.js +101 -0
- package/dist/web-ui/content/modules/f555ceb3720822c5/chunk.js +1 -0
- package/dist/web-ui/content/modules/f9111c80a2c26147/host.js +1 -0
- package/dist/web-ui/content/modules/fd2a62ffb5f81f09/chunk.js +1 -0
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +418 -176
- package/dist/web-ui/embedded-assets.js +6 -5
- package/dist/web-ui/index.d.ts +1 -1
- package/dist/web-ui/index.js +13 -6
- package/dist/web-ui/provider-identity.d.ts +11 -0
- package/dist/web-ui/provider-identity.js +7 -1
- package/dist/web-ui/query-snapshot.d.ts +33 -0
- package/dist/web-ui/query-snapshot.js +77 -0
- package/dist/web-ui/react/conversations/presentation.d.ts +62 -0
- package/dist/web-ui/react/conversations/presentation.js +99 -0
- package/dist/web-ui/react/workspaces/types.d.ts +4 -0
- package/dist/web-ui/running-current-action.js +2 -2
- package/dist/web-ui/scripts.d.ts +4 -0
- package/dist/web-ui/scripts.js +17 -0
- package/dist/web-ui/startup-preload.d.ts +10 -0
- package/dist/web-ui/startup-preload.js +24 -0
- package/package.json +3 -1
- package/dist/web-ui/content/modules/02b1ec89c69dc0dd/host.js +0 -30
- package/dist/web-ui/content/modules/0434a45abd2c1d15/chunk.js +0 -1
- package/dist/web-ui/content/modules/23d2006fcfcf3c0c/host-bridge.js +0 -1
- package/dist/web-ui/content/modules/32f151da1a006041/host.js +0 -1
- package/dist/web-ui/content/modules/34a7674efc329383/chunk.js +0 -1
- package/dist/web-ui/content/modules/3541ba4cb2886e29/chunk.js +0 -1
- package/dist/web-ui/content/modules/395257bd20cd0098/chunk.js +0 -1
- package/dist/web-ui/content/modules/3fd75af0a6891549/chunk.js +0 -1
- package/dist/web-ui/content/modules/428352e422932c40/host.js +0 -1
- package/dist/web-ui/content/modules/485a72b2c83e7680/workspace-window.js +0 -1
- package/dist/web-ui/content/modules/489dfe1f7441ef2c/markdown.js +0 -1
- package/dist/web-ui/content/modules/4b42b4336458b7b5/runtime.js +0 -550
- package/dist/web-ui/content/modules/528c5d97e8f9d582/chunk.js +0 -1
- package/dist/web-ui/content/modules/535aad05d34079d2/host.js +0 -1
- package/dist/web-ui/content/modules/6868f75a5981ad08/host.js +0 -69
- package/dist/web-ui/content/modules/6c72c8c166e34de7/host.js +0 -1
- package/dist/web-ui/content/modules/6ff6ce370ef26753/host.js +0 -1
- package/dist/web-ui/content/modules/72bef6889fdafefe/host.js +0 -1
- package/dist/web-ui/content/modules/763c79f5527d762a/panel.js +0 -1
- package/dist/web-ui/content/modules/96e78c7f2cd9acd5/chunk.js +0 -20
- package/dist/web-ui/content/modules/a60a07ba1abcdc3f/chunk.js +0 -3
- package/dist/web-ui/content/modules/b4bcb9bf5cfb0b3a/host.js +0 -1
- package/dist/web-ui/content/modules/b71cda413318d71f/employee-card.js +0 -1
- package/dist/web-ui/content/modules/bb0c299cf006e157/task-board-host.js +0 -17
- package/dist/web-ui/content/modules/c8c6adee81d4bd98/sha256.js +0 -1
- package/dist/web-ui/content/modules/cd0cec0ba1887ffd/chunk.js +0 -1
- package/dist/web-ui/content/modules/d99ea7e921488348/chunk.js +0 -1
- package/dist/web-ui/content/modules/e862ccabc908eb0c/host.js +0 -1
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Wand is a web console for remotely accessing and managing local CLI tools from a
|
|
|
15
15
|
|
|
16
16
|
The browser password manager extension source lives in `browser-extension/`.
|
|
17
17
|
|
|
18
|
+
See [tmux execution and recovery](docs/tmux-execution.md) for CLI ownership, execution switches, and safe restart behavior.
|
|
19
|
+
|
|
18
20
|
### Installation
|
|
19
21
|
|
|
20
22
|
Choose one installation method:
|
package/dist/ai-team-runner.js
CHANGED
|
@@ -355,7 +355,7 @@ export class AiTeamRunner {
|
|
|
355
355
|
this.openChat(run, task, shown, chatHistory);
|
|
356
356
|
this.storage.saveAiTeamRun(run);
|
|
357
357
|
input.onAccepted?.(run);
|
|
358
|
-
if (task.status === "todo")
|
|
358
|
+
if (task.status === "todo" || task.status === "backlog")
|
|
359
359
|
this.storage.updateWandTask(task.id, { status: "doing" });
|
|
360
360
|
excludeAiTeamReportDir(cwd);
|
|
361
361
|
await this.enqueue(run.id, async () => {
|
package/dist/ai-team-types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { AiTeamDeliverySummary } from "./ai-team-delivery-types.js";
|
|
|
3
3
|
import type { WandTaskAgent } from "./task-types.js";
|
|
4
4
|
import type { ConversationTurn } from "./types.js";
|
|
5
5
|
export type { SiliconEmployee, SiliconEmployeeDraft } from "./employee-types.js";
|
|
6
|
-
export { DEFAULT_EMPLOYEE_ID, DEFAULT_EMPLOYEE_KEY, DEFAULT_EMPLOYEE_NAME, DEFAULT_EMPLOYEE_TAG, DECISION_EXPERT_KEY, HR_EMPLOYEE_KEY, isBuiltinSiliconEmployee, isDecisionExpertSiliconEmployee, isDefaultSiliconEmployee, isSystemSiliconEmployee, parseSiliconEmployeeTagInput, parseSiliconEmployeeTags, SILICON_EMPLOYEE_MAX_TAGS, SILICON_EMPLOYEE_TAG_MAX_CHARS, siliconEmployeeTags, SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_EMPLOYEE_TAG, } from "./employee-types.js";
|
|
6
|
+
export { DEFAULT_EMPLOYEE_ID, DEFAULT_EMPLOYEE_KEY, DEFAULT_EMPLOYEE_NAME, DEFAULT_EMPLOYEE_TAG, DEFAULT_MAX_CONCURRENT_TASKS, DECISION_EXPERT_KEY, HR_EMPLOYEE_KEY, isBuiltinSiliconEmployee, isDecisionExpertSiliconEmployee, isDefaultSiliconEmployee, isSystemSiliconEmployee, parseSiliconEmployeeTagInput, parseSiliconEmployeeTags, SILICON_EMPLOYEE_MAX_TAGS, SILICON_EMPLOYEE_TAG_MAX_CHARS, siliconEmployeeTags, SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_EMPLOYEE_TAG, } from "./employee-types.js";
|
|
7
7
|
export declare const AI_TEAM_MIN_MEMBERS = 2;
|
|
8
8
|
export declare const AI_TEAM_MAX_MEMBERS = 8;
|
|
9
9
|
export declare const AI_TEAM_DEFAULT_MAX_STEPS = 30;
|
package/dist/ai-team-types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { DEFAULT_EMPLOYEE_ID, DEFAULT_EMPLOYEE_KEY, DEFAULT_EMPLOYEE_NAME, DEFAULT_EMPLOYEE_TAG, DECISION_EXPERT_KEY, HR_EMPLOYEE_KEY, isBuiltinSiliconEmployee, isDecisionExpertSiliconEmployee, isDefaultSiliconEmployee, isSystemSiliconEmployee, parseSiliconEmployeeTagInput, parseSiliconEmployeeTags, SILICON_EMPLOYEE_MAX_TAGS, SILICON_EMPLOYEE_TAG_MAX_CHARS, siliconEmployeeTags, SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_EMPLOYEE_TAG, } from "./employee-types.js";
|
|
1
|
+
export { DEFAULT_EMPLOYEE_ID, DEFAULT_EMPLOYEE_KEY, DEFAULT_EMPLOYEE_NAME, DEFAULT_EMPLOYEE_TAG, DEFAULT_MAX_CONCURRENT_TASKS, DECISION_EXPERT_KEY, HR_EMPLOYEE_KEY, isBuiltinSiliconEmployee, isDecisionExpertSiliconEmployee, isDefaultSiliconEmployee, isSystemSiliconEmployee, parseSiliconEmployeeTagInput, parseSiliconEmployeeTags, SILICON_EMPLOYEE_MAX_TAGS, SILICON_EMPLOYEE_TAG_MAX_CHARS, siliconEmployeeTags, SYSTEM_EMPLOYEE_ID, SYSTEM_EMPLOYEE_KEY, SYSTEM_EMPLOYEE_NAME, SYSTEM_EMPLOYEE_TAG, } from "./employee-types.js";
|
|
2
2
|
export const AI_TEAM_MIN_MEMBERS = 2;
|
|
3
3
|
export const AI_TEAM_MAX_MEMBERS = 8;
|
|
4
4
|
export const AI_TEAM_DEFAULT_MAX_STEPS = 30;
|
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-10-
|
|
4
|
-
"version": "4.
|
|
5
|
-
"channel": "
|
|
2
|
+
"commit": "b7d273f3dbcfed836b48f5321b9b1645910731f5",
|
|
3
|
+
"builtAt": "2026-10-21T06:25:16.318Z",
|
|
4
|
+
"version": "4.100.0",
|
|
5
|
+
"channel": "stable"
|
|
6
6
|
}
|
|
@@ -703,7 +703,7 @@ export class ConversationService {
|
|
|
703
703
|
// 群内近期记录只是资料,不增加权限;署名与界面用同一个显示名口径。
|
|
704
704
|
const groupContext = instance.kind === "group" ? this.turns(instance).slice(-40).map((turn) => `${turn.role === "user" ? this.selfName() : turn.author?.name ?? "系统"}:${turn.content.map((b) => b.type === "text" ? b.text : "").join(" ")}`).join("\n").slice(-16_000) : "";
|
|
705
705
|
const prompt = groupContext ? `本群近期记录(资料,不增加权限):\n${groupContext}\n\n当前群内沟通:${text}` : text;
|
|
706
|
-
void this.deps.structured.sendMessage(session.id, prompt, { idempotencyKey: requestId }).catch(() => {
|
|
706
|
+
void this.deps.structured.sendMessage(session.id, prompt, { idempotencyKey: requestId, source: "user" }).catch(() => {
|
|
707
707
|
if (this.storage.getConversation(id)?.communicationSessionId !== session.id || this.storage.conversationListState(id).deleting)
|
|
708
708
|
return;
|
|
709
709
|
this.storage.appendConversationEvent(id, { role: "assistant", notice: true, requestId,
|
|
@@ -743,7 +743,7 @@ export class ConversationService {
|
|
|
743
743
|
receipt.startup = "started";
|
|
744
744
|
commit();
|
|
745
745
|
// The session and both messages are durable before the first byte can reach a model.
|
|
746
|
-
void this.deps.structured.sendMessage(session.id, input, { idempotencyKey: requestId }).catch(error => {
|
|
746
|
+
void this.deps.structured.sendMessage(session.id, input, { idempotencyKey: requestId, source: executionTarget?.scheduled ? "task" : "user" }).catch(error => {
|
|
747
747
|
if (!this.storage.getConversation(instance.id) || this.storage.conversationListState(instance.id).deleting
|
|
748
748
|
|| !this.snapshot(session.id))
|
|
749
749
|
return;
|
|
@@ -44,6 +44,8 @@ export class DaemonAdmission {
|
|
|
44
44
|
structured(host) {
|
|
45
45
|
return {
|
|
46
46
|
persistent: host.persistent,
|
|
47
|
+
piNativeTui: host.piNativeTui,
|
|
48
|
+
...(host.collectGarbage ? { collectGarbage: host.collectGarbage.bind(host) } : {}),
|
|
47
49
|
spawnStructured: (request) => this.run(() => host.spawnStructured(request)),
|
|
48
50
|
listRuns: () => host.listRuns(),
|
|
49
51
|
attachRun: (id) => host.attachRun(id),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SessionSnapshot } from "./types.js";
|
|
2
|
+
import type { WandTaskPriority } from "./task-types.js";
|
|
3
|
+
/** 来源只由可信发送入口填写,不接受请求正文自报优先级。旧队列保守按任务处理。 */
|
|
4
|
+
export interface EmployeeInputScheduling {
|
|
5
|
+
source: "user" | "task";
|
|
6
|
+
enqueuedAt: string;
|
|
7
|
+
/** Stable tie-breaker for inputs accepted in the same millisecond. */
|
|
8
|
+
sequence?: number;
|
|
9
|
+
/** In-memory correlation only; JSON persistence deliberately omits functions. */
|
|
10
|
+
teamRequestStarted?: (sessionId: string, requestId: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function queuedInputScheduling(session: SessionSnapshot): EmployeeInputScheduling[];
|
|
13
|
+
export declare function employeeInputPriority(source: EmployeeInputScheduling["source"], priority?: WandTaskPriority): number;
|
|
14
|
+
export interface EmployeeInputAdmission {
|
|
15
|
+
canStart(session: SessionSnapshot, scheduling: EmployeeInputScheduling): boolean;
|
|
16
|
+
schedule(employeeId: string): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function queuedInputScheduling(session) {
|
|
2
|
+
return (session.queuedMessages ?? []).map((_, index) => session.queuedInputScheduling?.[index]
|
|
3
|
+
?? { source: "task", enqueuedAt: session.startedAt });
|
|
4
|
+
}
|
|
5
|
+
export function employeeInputPriority(source, priority) {
|
|
6
|
+
if (source === "user")
|
|
7
|
+
return 5;
|
|
8
|
+
switch (priority) {
|
|
9
|
+
case "urgent": return 4;
|
|
10
|
+
case "high": return 3;
|
|
11
|
+
case "medium": return 2;
|
|
12
|
+
case "low": return 1;
|
|
13
|
+
default: return 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/employee-types.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { WandTaskAgent } from "./task-types.js";
|
|
2
2
|
export { DECISION_EXPERT_KEY } from "./decision-expert-identity.js";
|
|
3
3
|
export { HR_EMPLOYEE_KEY } from "./hr-employee-identity.js";
|
|
4
|
+
/** 未设置并发上限时的默认值;null/缺省都回落到它。 */
|
|
5
|
+
export declare const DEFAULT_MAX_CONCURRENT_TASKS = 2;
|
|
4
6
|
/** Employee contact entry; identity and execution choices are persisted independently of teams. */
|
|
5
7
|
export interface SiliconEmployee {
|
|
6
8
|
id: string;
|
|
@@ -13,6 +15,8 @@ export interface SiliconEmployee {
|
|
|
13
15
|
tags?: string[];
|
|
14
16
|
/** Finished system auxiliary history only, excluding agent decisions/dispatch; null/omitted = unlimited, 0 = none. */
|
|
15
17
|
systemSessionLimit?: number | null;
|
|
18
|
+
/** 同时执行的任务上限;null/未设置按 DEFAULT_MAX_CONCURRENT_TASKS 执行。超出的派发保留为排队,任务仍算活动任务。 */
|
|
19
|
+
maxConcurrentTasks?: number | null;
|
|
16
20
|
/** Non-empty = Wand built-in identity; it cannot be archived or deleted. */
|
|
17
21
|
systemKey?: string;
|
|
18
22
|
archivedAt?: string;
|
package/dist/employee-types.js
CHANGED
|
@@ -2,6 +2,8 @@ import { DECISION_EXPERT_KEY } from "./decision-expert-identity.js";
|
|
|
2
2
|
export { DECISION_EXPERT_KEY } from "./decision-expert-identity.js";
|
|
3
3
|
import { HR_EMPLOYEE_KEY } from "./hr-employee-identity.js";
|
|
4
4
|
export { HR_EMPLOYEE_KEY } from "./hr-employee-identity.js";
|
|
5
|
+
/** 未设置并发上限时的默认值;null/缺省都回落到它。 */
|
|
6
|
+
export const DEFAULT_MAX_CONCURRENT_TASKS = 2;
|
|
5
7
|
export const SYSTEM_EMPLOYEE_KEY = "wand-ops";
|
|
6
8
|
export const SYSTEM_EMPLOYEE_ID = "e_wand_ops";
|
|
7
9
|
export const SYSTEM_EMPLOYEE_NAME = "勤劳的初二";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SessionSnapshot } from "./types.js";
|
|
2
|
+
/** Read-only execution facts, separate from a task's editable workflow stage. */
|
|
3
|
+
export type ExecutionStatus = "running" | "queued" | null;
|
|
4
|
+
export declare function sessionExecutionStatus(session: Pick<SessionSnapshot, "sessionKind" | "status" | "archived" | "structuredState" | "queuedMessages" | "ptyBusy" | "ptyCommandRunning" | "permissionBlocked" | "pendingEscalation">): ExecutionStatus;
|
|
5
|
+
export declare function taskExecutionProjection(sessions: readonly Parameters<typeof sessionExecutionStatus>[0][], queuedComments?: number): {
|
|
6
|
+
executionStatus: ExecutionStatus;
|
|
7
|
+
queuedExecutionCount: number;
|
|
8
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function sessionExecutionStatus(session) {
|
|
2
|
+
if (session.archived)
|
|
3
|
+
return null;
|
|
4
|
+
if (session.structuredState?.inFlight || session.ptyBusy || session.ptyCommandRunning)
|
|
5
|
+
return "running";
|
|
6
|
+
if (session.status === "failed" || session.status === "stopped" || session.structuredState?.lastError
|
|
7
|
+
|| session.permissionBlocked || session.pendingEscalation)
|
|
8
|
+
return null;
|
|
9
|
+
return session.sessionKind === "structured" && (session.queuedMessages?.length ?? 0) > 0 ? "queued" : null;
|
|
10
|
+
}
|
|
11
|
+
export function taskExecutionProjection(sessions, queuedComments = 0) {
|
|
12
|
+
const visible = sessions.filter(session => !session.archived);
|
|
13
|
+
const states = visible.map(sessionExecutionStatus);
|
|
14
|
+
// Failed/explicitly stopped inputs stay available for reconciliation, not automatic execution.
|
|
15
|
+
const queuedExecutionCount = Math.max(0, queuedComments) + visible.reduce((total, session, index) => total + (states[index] ? session.queuedMessages?.length ?? 0 : 0), 0);
|
|
16
|
+
return { executionStatus: states.includes("running") ? "running"
|
|
17
|
+
: queuedComments > 0 || states.includes("queued") ? "queued" : null, queuedExecutionCount };
|
|
18
|
+
}
|
package/dist/ios-ota.js
CHANGED
|
@@ -108,6 +108,15 @@ export function buildIosInstallPage(options) {
|
|
|
108
108
|
const warningHtml = warnings.length
|
|
109
109
|
? `<div class="warn">${warnings.map((item) => `<p>${escapeHtml(item)}</p>`).join("")}</div>`
|
|
110
110
|
: "";
|
|
111
|
+
// Reuse the visible link so automatic and manual handoff always use the same URL.
|
|
112
|
+
// Attempt only once per page load; cancellation must not cause another prompt.
|
|
113
|
+
const autoInstallScript = options.signed && options.https && options.installUrl.startsWith("itms-services://")
|
|
114
|
+
? `<script>
|
|
115
|
+
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent)
|
|
116
|
+
|| (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
|
|
117
|
+
if (isIos) document.getElementById("ios-install").click();
|
|
118
|
+
</script>`
|
|
119
|
+
: "";
|
|
111
120
|
return `<!DOCTYPE html>
|
|
112
121
|
<html lang="zh-CN">
|
|
113
122
|
<head>
|
|
@@ -132,10 +141,11 @@ export function buildIosInstallPage(options) {
|
|
|
132
141
|
<h1>安装 ${escapeHtml(options.title)}</h1>
|
|
133
142
|
<div class="meta">版本 ${escapeHtml(options.version)} · ${escapeHtml(options.sizeLabel)}</div>
|
|
134
143
|
${warningHtml}
|
|
135
|
-
<a class="install" href="${escapeHtml(options.installUrl)}">在 iPhone 上安装</a>
|
|
144
|
+
<a id="ios-install" class="install" href="${escapeHtml(options.installUrl)}">在 iPhone 上安装</a>
|
|
136
145
|
<a class="secondary" href="${escapeHtml(options.downloadUrl)}">下载 IPA</a>
|
|
137
|
-
<p class="hint">请用 Safari
|
|
146
|
+
<p class="hint">请用 Safari 打开本页。${autoInstallScript ? "iPhone / iPad 会自动请求系统安装确认;若未弹出,请点击上方安装按钮。" : ""}安装后如提示未受信任,到 设置 → 通用 → VPN 与设备管理 中信任,iOS 18 企业包可能需要重启。</p>
|
|
138
147
|
</main>
|
|
148
|
+
${autoInstallScript}
|
|
139
149
|
</body>
|
|
140
150
|
</html>
|
|
141
151
|
`;
|
|
@@ -57,6 +57,7 @@ export const API_ROUTE_RULES = [
|
|
|
57
57
|
// Mounted before the body parsers and guarded by its own requireAuth + requireFiles pair.
|
|
58
58
|
{ prefix: "/api/local-preview", scope: "files" },
|
|
59
59
|
// ── 会话、任务、工作区与员工(原生客户端的主要功能面)──
|
|
60
|
+
{ prefix: "/api/pi-settings", scope: "sessions" },
|
|
60
61
|
{ prefix: "/api/sessions", scope: "sessions" },
|
|
61
62
|
{ prefix: "/api/structured-sessions", scope: "sessions" },
|
|
62
63
|
{ prefix: "/api/session-list", scope: "sessions" },
|
package/dist/models.js
CHANGED
|
@@ -791,6 +791,13 @@ export class ModelCatalogService {
|
|
|
791
791
|
const saved = configured.find((group) => group.id === FREE_MODEL_GROUP_ID && group.provider === "pi");
|
|
792
792
|
groups.push({ id: FREE_MODEL_GROUP_ID, provider: "pi", name: OPENROUTER_FREE_GROUP,
|
|
793
793
|
models: orderModelIds(freeModels.map((model) => model.id), saved?.models ?? []) });
|
|
794
|
+
const piModels = catalog.piModels;
|
|
795
|
+
const seen = new Set(piModels.map((model) => model.id));
|
|
796
|
+
for (const model of freeModels) {
|
|
797
|
+
if (seen.has(model.id))
|
|
798
|
+
continue;
|
|
799
|
+
piModels.push({ ...model, group: OPENROUTER_FREE_GROUP });
|
|
800
|
+
}
|
|
794
801
|
}
|
|
795
802
|
for (const group of groups) {
|
|
796
803
|
if (group.id === FREE_MODEL_GROUP_ID)
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { DECISION_CHAIN_WAIT_MS, DecisionError } from "./decision-types.js";
|
|
2
2
|
import { discoverPiResources, resolvePiResourceSelection } from "./pi-resource-catalog.js";
|
|
3
|
-
import { decidePiCodemode, parsePiRecommendationRequest, recommendPiResources } from "./pi-resource-recommendation.js";
|
|
3
|
+
import { decidePiCodemode, isFlowControlOnly, parsePiRecommendationRequest, recommendPiResources } from "./pi-resource-recommendation.js";
|
|
4
4
|
import { patchPiResourceSelection } from "./pi-session-settings.js";
|
|
5
|
+
const sessionAutoStates = new Map();
|
|
5
6
|
/** Owned by the submitted runner, not by the composer. Manual settings are never overwritten. */
|
|
6
7
|
export function withAutomaticPiResources(runner, config, options) {
|
|
7
8
|
return { start(context, observer) {
|
|
@@ -48,35 +49,60 @@ export function withAutomaticPiResources(runner, config, options) {
|
|
|
48
49
|
.map((item) => item.id),
|
|
49
50
|
};
|
|
50
51
|
const request = parsePiRecommendationRequest({ prompt: context.prompt, candidates });
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
const hasPriorTurns = (context.session.messages?.length ?? 0) > 1;
|
|
53
|
+
const cached = sessionAutoStates.get(context.session.id);
|
|
54
|
+
const isFollowUpFlowControl = hasPriorTurns && isFlowControlOnly(request.prompt, inventory.catalog);
|
|
55
|
+
if (isFollowUpFlowControl) {
|
|
56
|
+
if (cached) {
|
|
57
|
+
selected = patchPiResourceSelection({
|
|
58
|
+
skills: [...new Set([...manual.skills.filter((id) => locked.has(id)),
|
|
59
|
+
...cached.selected.skills.filter((id) => !locked.has(id))])],
|
|
60
|
+
mcpServers: [...new Set([...manual.mcpServers, ...cached.selected.mcpServers])],
|
|
61
|
+
});
|
|
62
|
+
automaticCodemode = cached.codemode;
|
|
60
63
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
else {
|
|
65
|
+
selected = manual;
|
|
66
|
+
}
|
|
67
|
+
resolvePiResourceSelection(inventory, selected);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
const boundedEvaluate = (value, caller, signal) => new Promise((resolve, reject) => {
|
|
71
|
+
// Restart the watchdog for each decision, so an earlier resource cannot
|
|
72
|
+
// consume the configured backup's window on the next decision.
|
|
73
|
+
const decisionTimer = setTimeout(() => abort.abort(), options.timeoutMs ?? DECISION_CHAIN_WAIT_MS);
|
|
74
|
+
timer = decisionTimer;
|
|
75
|
+
const cancelled = () => reject(new DecisionError("CANCELLED", "本地选择已取消"));
|
|
76
|
+
if (signal?.aborted) {
|
|
77
|
+
cancelled();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
signal?.addEventListener("abort", cancelled, { once: true });
|
|
81
|
+
Promise.resolve().then(() => { checkActive(); return evaluate(value, caller, signal); }).then(resolve, reject)
|
|
82
|
+
.finally(() => { clearTimeout(decisionTimer); signal?.removeEventListener("abort", cancelled); });
|
|
68
83
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
84
|
+
if (!manualCodemode)
|
|
85
|
+
automaticCodemode = await decidePiCodemode({
|
|
86
|
+
prompt: request.prompt, evaluate: boundedEvaluate, caller: `pi-auto-resources:${context.session.id}`, signal: abort.signal,
|
|
87
|
+
});
|
|
88
|
+
const result = await recommendPiResources({ ...request, catalog: inventory.catalog, evaluate: boundedEvaluate,
|
|
89
|
+
caller: `pi-auto-resources:${context.session.id}`, signal: abort.signal });
|
|
90
|
+
checkActive();
|
|
91
|
+
if (abort.signal.aborted)
|
|
92
|
+
throw new DecisionError("TIMEOUT", "本地选择超时");
|
|
93
|
+
selected = patchPiResourceSelection({
|
|
94
|
+
skills: [...new Set([...manual.skills.filter((id) => locked.has(id)),
|
|
95
|
+
...result.selection.skills.filter((id) => !locked.has(id))])],
|
|
96
|
+
mcpServers: [...new Set([...manual.mcpServers, ...result.selection.mcpServers])],
|
|
97
|
+
});
|
|
98
|
+
resolvePiResourceSelection(inventory, selected);
|
|
99
|
+
sessionAutoStates.set(context.session.id, { selected, codemode: automaticCodemode });
|
|
100
|
+
if (sessionAutoStates.size > 200) {
|
|
101
|
+
const oldest = sessionAutoStates.keys().next().value;
|
|
102
|
+
if (oldest)
|
|
103
|
+
sessionAutoStates.delete(oldest);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
80
106
|
}
|
|
81
107
|
catch (error) {
|
|
82
108
|
checkActive();
|
|
@@ -7,6 +7,14 @@ export declare function parsePiRecommendationRequest(raw: unknown): {
|
|
|
7
7
|
prompt: string;
|
|
8
8
|
candidates: PiResourceSelection;
|
|
9
9
|
};
|
|
10
|
+
/** Literal resource names only; conservative exclusions take priority over inclusion. */
|
|
11
|
+
export declare function explicitMention(prompt: string, name: string): "included" | "excluded" | null;
|
|
12
|
+
/**
|
|
13
|
+
* Distinguishes conversational flow-control signals (e.g. "继续", "ok", "next", "确认")
|
|
14
|
+
* from substantive task specifications. Flow-control signals in an ongoing turn
|
|
15
|
+
* carry no domain capability requirements and must not trigger semantic skill evaluation.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isFlowControlOnly(prompt: string, catalog?: PiResourceCatalog): boolean;
|
|
10
18
|
export interface PiAutomaticCodemodeChoice {
|
|
11
19
|
override?: "off" | "on";
|
|
12
20
|
source: "explicit" | "local" | "uncertain";
|
|
@@ -19,7 +19,7 @@ export function parsePiRecommendationRequest(raw) {
|
|
|
19
19
|
return { prompt: body.prompt.trim(), candidates };
|
|
20
20
|
}
|
|
21
21
|
/** Literal resource names only; conservative exclusions take priority over inclusion. */
|
|
22
|
-
function explicitMention(prompt, name) {
|
|
22
|
+
export function explicitMention(prompt, name) {
|
|
23
23
|
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24
24
|
const literal = new RegExp(`(^|[^a-zA-Z0-9_-])${escaped}(?=$|[^a-zA-Z0-9_-])`, "i");
|
|
25
25
|
let included = false;
|
|
@@ -48,6 +48,33 @@ function resourceTask(prompt, catalog) {
|
|
|
48
48
|
const task = clauses.filter((clause) => !switchOnly.test(clause.trim()));
|
|
49
49
|
return task.length === clauses.length ? prompt : task.filter((clause) => clause.trim()).join(",").trim();
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Distinguishes conversational flow-control signals (e.g. "继续", "ok", "next", "确认")
|
|
53
|
+
* from substantive task specifications. Flow-control signals in an ongoing turn
|
|
54
|
+
* carry no domain capability requirements and must not trigger semantic skill evaluation.
|
|
55
|
+
*/
|
|
56
|
+
export function isFlowControlOnly(prompt, catalog) {
|
|
57
|
+
const trimmed = prompt.trim();
|
|
58
|
+
if (!trimmed)
|
|
59
|
+
return true;
|
|
60
|
+
if (explicitMention(trimmed, "codemode") || explicitMention(trimmed, "code mode"))
|
|
61
|
+
return false;
|
|
62
|
+
if (catalog) {
|
|
63
|
+
for (const item of [...catalog.skills, ...catalog.mcpServers]) {
|
|
64
|
+
if (explicitMention(trimmed, item.name))
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const clean = trimmed.replace(/[\s\p{P}\p{S}]/gu, "").toLowerCase();
|
|
69
|
+
if (clean.length > 8)
|
|
70
|
+
return false;
|
|
71
|
+
const FLOW_SIGNALS = new Set([
|
|
72
|
+
"继续", "接着", "下一步", "确认", "好的", "好的继续", "收到", "收到继续",
|
|
73
|
+
"行", "可以", "好", "走", "开始", "执行", "同意", "好的处理吧", "部署吧",
|
|
74
|
+
"ok", "okay", "continue", "next", "go", "proceed", "yes", "y", "done", "run",
|
|
75
|
+
]);
|
|
76
|
+
return FLOW_SIGNALS.has(clean);
|
|
77
|
+
}
|
|
51
78
|
function matchProbability(result, id) {
|
|
52
79
|
const answer = result.answers[id];
|
|
53
80
|
const probabilities = answer?.probabilities;
|
|
@@ -76,6 +76,15 @@ export declare function defaultPiSessionSettings(autoCompaction?: boolean): PiSe
|
|
|
76
76
|
* 进程内 SDK 会话仍用 `defaultPiSessionSettings`:员工会话不静默继承用户的全局扩展。
|
|
77
77
|
*/
|
|
78
78
|
export declare function defaultPiCliSessionSettings(autoCompaction?: boolean): PiSessionSettings;
|
|
79
|
+
/**
|
|
80
|
+
* 用户级默认设置的合并:只把本次 patch 真正出现的字段写进默认,其余字段保留默认原值。
|
|
81
|
+
*
|
|
82
|
+
* 会话里的改动是「用户此刻在这个会话里的选择」,不是「用户想要的全局默认」的全部内容:
|
|
83
|
+
* 一个从旧默认起步的会话(例如 autoResources=false)只改一个 Skill 时,不能把后来在别的
|
|
84
|
+
* 会话里开启的自动配置 / CodeMode 覆盖一起拉回旧值。`codemodeOverride: null` 是显式清除,
|
|
85
|
+
* 与「没提到这个字段」区分开。
|
|
86
|
+
*/
|
|
87
|
+
export declare function mergePiSessionDefaults(defaults: PiSessionSettings, patch: unknown): PiSessionSettings;
|
|
79
88
|
/** Strict partial updates: an invalid/unknown field never silently enables a capability. */
|
|
80
89
|
export declare function patchPiSessionSettings(current: PiSessionSettings, raw: unknown): PiSessionSettings;
|
|
81
90
|
/**
|
|
@@ -49,6 +49,48 @@ export function defaultPiCliSessionSettings(autoCompaction = true) {
|
|
|
49
49
|
return { ...defaultPiSessionSettings(autoCompaction), globalTools: true,
|
|
50
50
|
resources: { skills: [], mcpServers: [] }, autoResources: false };
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* 用户级默认设置的合并:只把本次 patch 真正出现的字段写进默认,其余字段保留默认原值。
|
|
54
|
+
*
|
|
55
|
+
* 会话里的改动是「用户此刻在这个会话里的选择」,不是「用户想要的全局默认」的全部内容:
|
|
56
|
+
* 一个从旧默认起步的会话(例如 autoResources=false)只改一个 Skill 时,不能把后来在别的
|
|
57
|
+
* 会话里开启的自动配置 / CodeMode 覆盖一起拉回旧值。`codemodeOverride: null` 是显式清除,
|
|
58
|
+
* 与「没提到这个字段」区分开。
|
|
59
|
+
*/
|
|
60
|
+
export function mergePiSessionDefaults(defaults, patch) {
|
|
61
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch))
|
|
62
|
+
return defaults;
|
|
63
|
+
const touched = patch;
|
|
64
|
+
if (!Object.keys(touched).length)
|
|
65
|
+
return defaults;
|
|
66
|
+
const next = { ...defaults, tools: [...defaults.tools] };
|
|
67
|
+
if ("resources" in touched)
|
|
68
|
+
next.resources = patchPiResourceSelection(touched.resources);
|
|
69
|
+
if ("lockedSkills" in touched)
|
|
70
|
+
next.lockedSkills = [...(patchPiSessionSettings(defaults, { lockedSkills: touched.lockedSkills }).lockedSkills ?? [])];
|
|
71
|
+
for (const key of ["codemode", "tools", "globalTools", "goalMode", "localDecision", "autoCompaction", "autoResources"]) {
|
|
72
|
+
if (!(key in touched))
|
|
73
|
+
continue;
|
|
74
|
+
const patched = patchPiSessionSettings(defaults, { [key]: touched[key] });
|
|
75
|
+
if (key === "tools")
|
|
76
|
+
next.tools = [...patched.tools];
|
|
77
|
+
else if (key === "codemode")
|
|
78
|
+
next.codemode = patched.codemode;
|
|
79
|
+
else
|
|
80
|
+
next[key] = patched[key] === true;
|
|
81
|
+
}
|
|
82
|
+
if ("codemodeOverride" in touched) {
|
|
83
|
+
const patched = patchPiSessionSettings(defaults, { codemodeOverride: touched.codemodeOverride });
|
|
84
|
+
if (patched.codemodeOverride === undefined)
|
|
85
|
+
delete next.codemodeOverride;
|
|
86
|
+
else
|
|
87
|
+
next.codemodeOverride = patched.codemodeOverride;
|
|
88
|
+
}
|
|
89
|
+
// 自动选择或锁定需要一个显式的资源边界,否则会退回旧会话的 Pi 自动发现。
|
|
90
|
+
if ((next.autoResources || next.lockedSkills?.length) && !next.resources)
|
|
91
|
+
next.resources = { skills: [], mcpServers: [] };
|
|
92
|
+
return next;
|
|
93
|
+
}
|
|
52
94
|
/** Strict partial updates: an invalid/unknown field never silently enables a capability. */
|
|
53
95
|
export function patchPiSessionSettings(current, raw) {
|
|
54
96
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
package/dist/pi-tmux-host.d.ts
CHANGED
|
@@ -21,14 +21,15 @@ interface WorkerState {
|
|
|
21
21
|
/** New Pi CLI turns use real native TUI tmux panes; existing daemon runs stay with their original owner. */
|
|
22
22
|
export declare class PiTmuxHost implements StructuredExecHost {
|
|
23
23
|
private readonly legacy;
|
|
24
|
+
private readonly enabled;
|
|
24
25
|
readonly persistent = true;
|
|
25
|
-
|
|
26
|
+
get piNativeTui(): boolean;
|
|
26
27
|
private readonly root;
|
|
27
28
|
private readonly prefix;
|
|
28
29
|
private readonly owners;
|
|
29
30
|
private readonly observed;
|
|
30
31
|
private readonly terminations;
|
|
31
|
-
constructor(configDir: string, legacy: StructuredExecHost);
|
|
32
|
+
constructor(configDir: string, legacy: StructuredExecHost, enabled?: boolean);
|
|
32
33
|
private slot;
|
|
33
34
|
private job;
|
|
34
35
|
private tmux;
|
package/dist/pi-tmux-host.js
CHANGED
|
@@ -36,6 +36,7 @@ class NativeProcess {
|
|
|
36
36
|
decoders = { stdout: createUtf8TextDecoder(), stderr: createUtf8TextDecoder() };
|
|
37
37
|
timer = null;
|
|
38
38
|
ended = null;
|
|
39
|
+
observationFailed = false;
|
|
39
40
|
identities;
|
|
40
41
|
constructor(job, host, after) {
|
|
41
42
|
this.job = job;
|
|
@@ -103,16 +104,25 @@ class NativeProcess {
|
|
|
103
104
|
return;
|
|
104
105
|
try {
|
|
105
106
|
const state = this.host.state(this.job);
|
|
106
|
-
this.
|
|
107
|
-
|
|
107
|
+
if (!this.observationFailed) {
|
|
108
|
+
this.read("stdout", state.status === "exited");
|
|
109
|
+
this.read("stderr", state.status === "exited");
|
|
110
|
+
}
|
|
108
111
|
if (state.status !== "exited")
|
|
109
112
|
return;
|
|
110
113
|
this.ended = { exitCode: state.exitCode, signal: state.signal ? signalNumberFromName(state.signal) : null };
|
|
111
114
|
}
|
|
112
115
|
catch (error) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
if (!this.observationFailed) {
|
|
117
|
+
this.observationFailed = true;
|
|
118
|
+
logInfo(`Pi native file observation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
119
|
+
for (const listener of this.exits)
|
|
120
|
+
listener({ exitCode: 1, signal: null, processExited: false });
|
|
121
|
+
void this.host.kill(this.job).catch(error => logInfo(`Pi native cleanup failed: ${String(error)}`));
|
|
122
|
+
}
|
|
123
|
+
// An observation failure ends the response, not ownership of the process.
|
|
124
|
+
// Keep watching state so actual termination can release deletion barriers.
|
|
125
|
+
return;
|
|
116
126
|
}
|
|
117
127
|
if (this.timer)
|
|
118
128
|
clearInterval(this.timer);
|
|
@@ -124,15 +134,17 @@ class NativeProcess {
|
|
|
124
134
|
/** New Pi CLI turns use real native TUI tmux panes; existing daemon runs stay with their original owner. */
|
|
125
135
|
export class PiTmuxHost {
|
|
126
136
|
legacy;
|
|
137
|
+
enabled;
|
|
127
138
|
persistent = true;
|
|
128
|
-
piNativeTui
|
|
139
|
+
get piNativeTui() { return this.enabled; }
|
|
129
140
|
root;
|
|
130
141
|
prefix;
|
|
131
142
|
owners = new Map();
|
|
132
143
|
observed = new Map();
|
|
133
144
|
terminations = new Map();
|
|
134
|
-
constructor(configDir, legacy) {
|
|
145
|
+
constructor(configDir, legacy, enabled = true) {
|
|
135
146
|
this.legacy = legacy;
|
|
147
|
+
this.enabled = enabled;
|
|
136
148
|
this.root = path.join(configDir, "pi-native");
|
|
137
149
|
this.prefix = `wand-pi-${createHash("sha256").update(path.resolve(configDir)).digest("hex").slice(0, 6)}-`;
|
|
138
150
|
mkdirSync(this.root, { recursive: true, mode: 0o700 });
|
|
@@ -142,8 +154,10 @@ export class PiTmuxHost {
|
|
|
142
154
|
try {
|
|
143
155
|
return JSON.parse(readFileSync(path.join(this.slot(runId), "current.json"), "utf8"));
|
|
144
156
|
}
|
|
145
|
-
catch {
|
|
146
|
-
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error.code === "ENOENT")
|
|
159
|
+
return null;
|
|
160
|
+
throw error;
|
|
147
161
|
}
|
|
148
162
|
}
|
|
149
163
|
async tmux(args) {
|
|
@@ -198,9 +212,15 @@ export class PiTmuxHost {
|
|
|
198
212
|
}
|
|
199
213
|
async spawnStructured(request) {
|
|
200
214
|
if (!request.nativePi) {
|
|
215
|
+
const previous = this.job(request.runId);
|
|
216
|
+
if (previous && (!existsSync(previous.ack) || this.state(previous).status !== "exited")) {
|
|
217
|
+
throw Object.assign(new Error("原 Pi 原生回合尚未释放;未重复发送输入。"), { preflightBlocked: true });
|
|
218
|
+
}
|
|
201
219
|
this.owners.set(request.runId, "legacy");
|
|
202
220
|
return this.legacy.spawnStructured(request);
|
|
203
221
|
}
|
|
222
|
+
if (!this.enabled)
|
|
223
|
+
throw Object.assign(new Error("Pi 原生 tmux 已禁用,未发送输入。"), { preflightBlocked: true });
|
|
204
224
|
if (request.launchSignal?.aborted)
|
|
205
225
|
throw new Error("Pi 原生启动已取消,未发送输入。");
|
|
206
226
|
if (process.platform === "win32")
|
|
@@ -329,20 +349,25 @@ export class PiTmuxHost {
|
|
|
329
349
|
for (const item of readdirSync(this.root, { withFileTypes: true })) {
|
|
330
350
|
if (!item.isDirectory())
|
|
331
351
|
continue;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
352
|
+
const current = path.join(this.root, item.name, "current.json");
|
|
353
|
+
if (!existsSync(current))
|
|
354
|
+
continue;
|
|
355
|
+
// A published owner with unreadable state is unknown, not an idle host.
|
|
356
|
+
const job = JSON.parse(readFileSync(current, "utf8"));
|
|
357
|
+
if (!existsSync(job.ack) || this.state(job).status !== "exited") {
|
|
358
|
+
native.push(this.snapshot(job));
|
|
359
|
+
this.owners.set(job.runId, "native");
|
|
338
360
|
}
|
|
339
|
-
catch { /* An incomplete startup is not a fabricated live execution. */ }
|
|
340
361
|
}
|
|
341
362
|
const legacy = await this.legacy.listRuns();
|
|
342
|
-
for (const state of legacy)
|
|
343
|
-
if (
|
|
363
|
+
for (const state of legacy) {
|
|
364
|
+
if (native.some(other => other.runId === state.runId && (other.status === "running" || state.status === "running"))) {
|
|
365
|
+
throw new Error("Pi 执行存在冲突的持久宿主,拒绝继续维护。");
|
|
366
|
+
}
|
|
367
|
+
if (!native.some(other => other.runId === state.runId))
|
|
344
368
|
this.owners.set(state.runId, "legacy");
|
|
345
|
-
|
|
369
|
+
}
|
|
370
|
+
return [...legacy.filter(state => !native.some(other => other.runId === state.runId)), ...native];
|
|
346
371
|
}
|
|
347
372
|
kill(job) {
|
|
348
373
|
const previous = this.terminations.get(job.incarnationId);
|
|
@@ -375,12 +400,24 @@ export class PiTmuxHost {
|
|
|
375
400
|
this.legacy.forgetRun(runId);
|
|
376
401
|
return;
|
|
377
402
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
this.
|
|
403
|
+
const acknowledge = () => {
|
|
404
|
+
writeFileSync(job.ack, "consumed\n", { mode: 0o600 });
|
|
405
|
+
if (this.observed.get(runId)?.incarnationId === job.incarnationId)
|
|
406
|
+
this.observed.delete(runId);
|
|
407
|
+
};
|
|
408
|
+
if (this.state(job).status === "exited") {
|
|
409
|
+
acknowledge();
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
void this.kill(job).then(async () => {
|
|
413
|
+
const deadline = Date.now() + 10000;
|
|
414
|
+
while (this.state(job).status !== "exited") {
|
|
415
|
+
if (Date.now() >= deadline)
|
|
416
|
+
throw new Error("Pi process exit is not yet confirmed");
|
|
417
|
+
await delay(25);
|
|
418
|
+
}
|
|
419
|
+
acknowledge();
|
|
420
|
+
}).catch((error) => logInfo(`Pi tmux cleanup failed: ${String(error)}`));
|
|
384
421
|
}
|
|
385
422
|
/**
|
|
386
423
|
* 回收 pi-native 下已经没用的执行产物。每次 Pi 原生回合都会在 slot 里
|