@prjct.app/pi-team 0.6.0 → 0.7.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/CHANGELOG.md +71 -0
- package/CONTRIBUTING.md +2 -1
- package/README.md +23 -177
- package/docs/architecture.md +36 -168
- package/package.json +10 -4
- package/src/commands/team-command.ts +37 -0
- package/src/domain/lease.ts +54 -0
- package/src/domain/member.ts +58 -0
- package/src/domain/message.ts +91 -0
- package/src/domain/request.ts +67 -0
- package/src/domain/team.ts +71 -0
- package/src/dynamic/domain.ts +110 -0
- package/src/dynamic/memory.ts +38 -0
- package/src/dynamic/panel.ts +155 -0
- package/src/dynamic/peer-log.ts +39 -0
- package/src/dynamic/runner.ts +196 -0
- package/src/dynamic/service.ts +292 -0
- package/src/dynamic/store.ts +57 -0
- package/src/dynamic/view.ts +21 -0
- package/src/dynamic/worker.ts +210 -0
- package/src/dynamic/workspace.ts +43 -0
- package/src/index.ts +204 -679
- package/src/process-identity.ts +68 -0
- package/src/runtime/delivery.ts +326 -0
- package/src/runtime/membership.ts +212 -0
- package/src/runtime/presence.ts +98 -0
- package/src/runtime/purge.ts +39 -0
- package/src/runtime/reconciler.ts +112 -0
- package/src/runtime/requests.ts +353 -0
- package/src/runtime/resources.ts +117 -0
- package/src/runtime/team-runtime.ts +47 -0
- package/src/runtime/team-tool.ts +191 -0
- package/src/storage/atomic.ts +347 -0
- package/src/storage/inbox-store.ts +290 -0
- package/src/storage/lease-store.ts +158 -0
- package/src/storage/paths.ts +76 -0
- package/src/storage/receipt-store.ts +117 -0
- package/src/storage/team-store.ts +190 -0
- package/src/supervisor/control-protocol.ts +125 -0
- package/src/supervisor/runtime-store.ts +231 -0
- package/src/supervisor/shutdown.ts +141 -0
- package/src/supervisor/supervisor.ts +657 -0
- package/src/supervisor/tmux-adapter.ts +192 -0
- package/src/supervisor/worker-bootstrap.ts +43 -0
- package/src/supervisor/worker-client.ts +233 -0
- package/src/ui/team-dashboard.ts +179 -0
- package/src/mailbox.ts +0 -536
- package/src/schema.ts +0 -25
- package/src/store.ts +0 -230
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,74 @@
|
|
|
1
|
+
## [0.7.0](https://github.com/prjct-app/pi-team/compare/v0.6.1...v0.7.0) (2026-09-22)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* /team completions with descriptions and the prjct mark ([afa687d](https://github.com/prjct-app/pi-team/commit/afa687d2edeba4776f6e200850b6114738914b88))
|
|
6
|
+
* /team is a docked panel of Runs and Experts with traceable assignments ([6f5b025](https://github.com/prjct-app/pi-team/commit/6f5b025a3ad49c8188322e3a98b1d8fca3f0c4df))
|
|
7
|
+
* add durable managed team state ([3380be1](https://github.com/prjct-app/pi-team/commit/3380be1cc4b106041a32c24ff1cfc119b7bc5d3d))
|
|
8
|
+
* add live team plan panel ([58635e2](https://github.com/prjct-app/pi-team/commit/58635e2db7f12fcee407932561c4a29e8d43b79d))
|
|
9
|
+
* add persistent dynamic team orchestration ([0a11bfc](https://github.com/prjct-app/pi-team/commit/0a11bfc25b2a3ca910dcfa01cfedf12dc9819ab5)), closes [#49](https://github.com/prjct-app/pi-team/issues/49)
|
|
10
|
+
* add persistent dynamic team orchestration ([57c8d03](https://github.com/prjct-app/pi-team/commit/57c8d0350b53bad0e963debbf79e5b39c28c1c4e))
|
|
11
|
+
* add Team v2 messaging runtime ([d0df88f](https://github.com/prjct-app/pi-team/commit/d0df88fbbfa57ffe4a7ad7373bd18d6591db7c54))
|
|
12
|
+
* add Team v2 storage core ([b75d230](https://github.com/prjct-app/pi-team/commit/b75d2306efc5670fd51668658bb536d3a19b4e41))
|
|
13
|
+
* add Team v2 supervised peer lifecycle ([3415872](https://github.com/prjct-app/pi-team/commit/3415872ab6a6bb6076736f1d2981f174a90551eb))
|
|
14
|
+
* Experts message each other directly (team_peers, team_message) ([298188f](https://github.com/prjct-app/pi-team/commit/298188f1037ff492955040088d262af165468638))
|
|
15
|
+
* integrate Team v2 extension ([81c64da](https://github.com/prjct-app/pi-team/commit/81c64da3c3b28ddb4c7e34bd811dda6d502a4922))
|
|
16
|
+
* isolate managed agents in worktrees ([35a68a3](https://github.com/prjct-app/pi-team/commit/35a68a3751e962ad260c07b54d70a21b45289b1b))
|
|
17
|
+
* keep an unattended teammate reachable after the auto-turn cap ([e354af4](https://github.com/prjct-app/pi-team/commit/e354af44dafc49171129ccf76f6213b10d35536e))
|
|
18
|
+
* launch autonomous teams from prompts ([6b72638](https://github.com/prjct-app/pi-team/commit/6b7263815dc6a0c4cca5b785211b1b5eb23a5b07))
|
|
19
|
+
* link team requests to optional subagents ([c51722f](https://github.com/prjct-app/pi-team/commit/c51722feac67405705ca3ddd69564bf6825a2bbc))
|
|
20
|
+
* run managed peers in persistent terminals ([4376b08](https://github.com/prjct-app/pi-team/commit/4376b08c331707263deb49af119c909ae85a75de))
|
|
21
|
+
* run persistent managed peer sessions ([6b2e249](https://github.com/prjct-app/pi-team/commit/6b2e249f82499d1a988e11c07a9d3fc54c1ee393))
|
|
22
|
+
* schedule managed work from dependencies ([18c5817](https://github.com/prjct-app/pi-team/commit/18c5817c890a08c212856fcf36ef4d87769b6cdb))
|
|
23
|
+
* send each Expert the project memory for its stance ([36caefc](https://github.com/prjct-app/pi-team/commit/36caefc442b7dcbfe5a00c26bbe97fb69f13b561))
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* a real parallel team — one Expert per role, own worktree each, orchestrator only coordinates ([140091d](https://github.com/prjct-app/pi-team/commit/140091d331ec75195a225f874847df601aa64dac))
|
|
28
|
+
* accept objectives through team command ([8f05337](https://github.com/prjct-app/pi-team/commit/8f05337c26a7f6cef7c4cafe7de2581c3c89d2ad))
|
|
29
|
+
* Experts launch again: short control socket, tmux 3.6 targets, lease token shape ([22c185b](https://github.com/prjct-app/pi-team/commit/22c185b49c91e0bedeb347795fca94df22477e1e))
|
|
30
|
+
* expose the authorized integration target ([f1bf132](https://github.com/prjct-app/pi-team/commit/f1bf13268985f92ff9866b9003a253908620deb0))
|
|
31
|
+
* harden managed runtime shutdown ([316cf72](https://github.com/prjct-app/pi-team/commit/316cf7218c7e6f27f11be4ef825a8447921cd97b))
|
|
32
|
+
* harden managed team records ([652e8d3](https://github.com/prjct-app/pi-team/commit/652e8d3cc4aef61280c8bbbadb6c1a16b3b65ae7))
|
|
33
|
+
* isolate managed peer extensions ([b69e02c](https://github.com/prjct-app/pi-team/commit/b69e02cf64b3c7ff41d039f95d36dc448a8a4a2a))
|
|
34
|
+
* keep worktree locks for the duration of git and refuse secret commits ([0d8c427](https://github.com/prjct-app/pi-team/commit/0d8c42783cc231b7464c79ec11c2373e8db74c05))
|
|
35
|
+
* only create and check the short socket fallback directory ([990f2a6](https://github.com/prjct-app/pi-team/commit/990f2a67650b5bc12542fd90ac0650675cbb8750))
|
|
36
|
+
* preserve lead checkout during managed work ([54e3159](https://github.com/prjct-app/pi-team/commit/54e3159368e36880305481c6fedf18edf9218c76))
|
|
37
|
+
* reject conflicting managed objectives ([5102c8b](https://github.com/prjct-app/pi-team/commit/5102c8b40bdc33f40eba4b18fad6d690b29b87b0))
|
|
38
|
+
* reject presence symlinks, redact more credentials, and bound the read cache ([c55bd27](https://github.com/prjct-app/pi-team/commit/c55bd27565441a86f711a4b8046cd7bbadeefa86))
|
|
39
|
+
* sanitize git and verification subprocess environments ([b4819bf](https://github.com/prjct-app/pi-team/commit/b4819bf37b5615e249cb2ca8b60557dd21dd913c))
|
|
40
|
+
|
|
41
|
+
## Unreleased
|
|
42
|
+
|
|
43
|
+
- Add `npm run build:pi`: a compiled local build in `~/.pi/agent/builds/<package>` that Pi loads instead of the TypeScript sources; supervised workers launch the built entry.
|
|
44
|
+
|
|
45
|
+
### Breaking changes
|
|
46
|
+
|
|
47
|
+
- replace manual create/join membership with explicit `/team <objective>` orchestration
|
|
48
|
+
- remove legacy inspection, migration, and v1 mailbox code from the package
|
|
49
|
+
- store persistent project Teams under `${PRJCT_HOME:-~/.prjct}/pi-team/orchestration-v2/`
|
|
50
|
+
|
|
51
|
+
### Features
|
|
52
|
+
|
|
53
|
+
- persist bounded Run history and reusable Expert identities, sessions, memory, and assignment history
|
|
54
|
+
- dynamically create missing Experts and reuse existing roles across later Runs
|
|
55
|
+
- queue busy Experts and later objectives while allowing bounded parallel work across distinct Experts
|
|
56
|
+
- add the active-Run-only `team_orchestrate` tool and bounded status, history, doctor, and cancellation commands
|
|
57
|
+
- execute Experts through authenticated supervised workers with durable correlated replies and resource leases
|
|
58
|
+
|
|
59
|
+
### Security
|
|
60
|
+
|
|
61
|
+
- keep normal prompts inert until an explicit Team objective
|
|
62
|
+
- fence owners and late results by process identity, epoch, generation, request, and receipt
|
|
63
|
+
- inherit the launching Pi environment explicitly when tmux already has a server
|
|
64
|
+
- validate worker request bodies and durable assignment/sender identity before model execution
|
|
65
|
+
- stop only proven-owned workers; interruption preserves history without automatic replay
|
|
66
|
+
## [0.6.1](https://github.com/prjct-app/pi-team/compare/v0.6.0...v0.6.1) (2026-09-11)
|
|
67
|
+
|
|
68
|
+
### Bug Fixes
|
|
69
|
+
|
|
70
|
+
* preserve mailbox locks across rolling upgrades ([3509903](https://github.com/prjct-app/pi-team/commit/3509903026205a0a3d00fcd52eecb3b970ba4d7b))
|
|
71
|
+
|
|
1
72
|
## [0.6.0](https://github.com/prjct-app/pi-team/compare/v0.5.7...v0.6.0) (2026-09-10)
|
|
2
73
|
|
|
3
74
|
### Features
|
package/CONTRIBUTING.md
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
- Deliver changes through a pull request using `.github/pull_request_template.md`.
|
|
7
7
|
- Use English for code, documentation, tests, issues, and pull requests.
|
|
8
8
|
- Use strict TypeScript and only APIs documented by Pi 0.85.1.
|
|
9
|
-
- Use immutable values: `npm run check` fails on any `let` under `src/`.
|
|
9
|
+
- Use immutable values: `npm run check` fails on any `let` under `src/`.
|
|
10
10
|
- Do not import host internals, monkey-patch prototypes, or access real credentials, sessions, or user configuration in tests.
|
|
11
11
|
- Keep runtime dependencies in `dependencies`; list Pi-provided packages in `peerDependencies` with a `*` range.
|
|
12
12
|
- Run `npm run check`, `npm test`, and `npm pack --dry-run` before review.
|
|
13
|
+
- Build the compiled local copy Pi loads with `npm run build:pi`. It writes `~/.pi/agent/builds/<package>` outside the repository, because compiled code inside it would load the repository's development copy of Pi instead of the host's.
|
|
13
14
|
- Never push, open or merge a pull request, publish, or deploy without explicit authorization.
|
|
14
15
|
|
|
15
16
|
## Package documentation
|
package/README.md
CHANGED
|
@@ -1,191 +1,49 @@
|
|
|
1
1
|
# pi-team
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Coordinate independent PI Agent sessions with local team messaging, queued tasks,
|
|
6
|
-
and shared results.
|
|
7
|
-
|
|
8
|
-
You open the terminals; `pi-team` lets those sessions send each other work, wake a
|
|
9
|
-
free teammate, and return a result the requester can verify. Everything stays on
|
|
10
|
-
this machine, in local files.
|
|
11
|
-
|
|
12
|
-
[](https://github.com/prjct-app/pi-team/raw/refs/heads/main/media/pi-team-demo/pi-team-demo.mp4)
|
|
3
|
+
Explicit project Teams with durable Runs, reusable Experts, and supervised local execution. Normal prompts are not intercepted.
|
|
13
4
|
|
|
14
5
|
## Install
|
|
15
6
|
|
|
16
|
-
Requires Pi
|
|
17
|
-
Pi **0.85.1**; newer versions are not yet verified. Independent community package.
|
|
7
|
+
Requires Pi **0.85.1**, Node.js **22.19+**, authenticated model access, and `tmux` for Expert execution.
|
|
18
8
|
|
|
19
9
|
```sh
|
|
20
10
|
pi install npm:@prjct.app/pi-team
|
|
21
11
|
```
|
|
22
12
|
|
|
23
|
-
|
|
24
|
-
the usual `pi list` / `pi update` / `pi remove` and `pi config`. Do not install the
|
|
25
|
-
same extension from both GitHub and npm: Pi treats those as different packages.
|
|
26
|
-
|
|
27
|
-
## Quickstart
|
|
28
|
-
|
|
29
|
-
Open two interactive Pi terminals. In the first:
|
|
13
|
+
Restart Pi, then explicitly start an objective:
|
|
30
14
|
|
|
31
15
|
```text
|
|
32
|
-
/team
|
|
33
|
-
/team join demo coordinator
|
|
16
|
+
/team Ship login validation
|
|
34
17
|
```
|
|
35
18
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
```text
|
|
39
|
-
/team join demo reviewer
|
|
40
|
-
```
|
|
19
|
+
This lazily creates a project Team and queues a Run. Main Pi orchestrates through the active-only `team_orchestrate` tool. Dispatch reports whether an Expert was created or reused. Busy Experts queue; distinct Experts can execute concurrently, up to three. An Expert's identity, session file, instructions, bounded memory, and assignment history survive process shutdown and later Runs.
|
|
41
20
|
|
|
42
|
-
|
|
21
|
+
## Commands
|
|
43
22
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
23
|
+
- `/team <objective>` — start or queue an objective (one active Run).
|
|
24
|
+
- `/team` or `/team status` — bounded plain Team/Run/Expert/Assignment overview.
|
|
25
|
+
- `/team history` — recent Run history.
|
|
26
|
+
- `/team doctor` — bounded diagnostics without process or ownership tokens.
|
|
27
|
+
- `/team cancel [run-id]` — cancel an owned active or queued Run.
|
|
28
|
+
- `/team help` — usage.
|
|
48
29
|
|
|
49
|
-
The
|
|
50
|
-
The request wakes the reviewer once it is idle, and its result comes back to the
|
|
51
|
-
coordinator. Installing alone never joins a team.
|
|
30
|
+
The old create/join/start/migrate/legacy lifecycle commands are unsupported. No project YAML or Markdown configuration is loaded by this extension. Startup does not detect or migrate old stores.
|
|
52
31
|
|
|
53
|
-
|
|
54
|
-
cross-machine messaging, and native Windows are not supported.
|
|
32
|
+
## Orchestration tool
|
|
55
33
|
|
|
56
|
-
|
|
34
|
+
During an active Run, `team_orchestrate` supports `dispatch`, `status`, `cancel_assignment`, `cancel_run`, and `finish`. Dispatch requires role, capabilities, task, and an explicit built-in tool allowlist; instructions are optional. It returns Expert ID, stable session reference, Assignment ID, and `created`/`reused`. Status includes bounded recent evidence. Finish is blocked while assignments remain outstanding. Expert reports are untrusted evidence, never user authorization.
|
|
57
35
|
|
|
58
|
-
|
|
59
|
-
address, not a privileged role or an automatic persona, and shared rather than
|
|
60
|
-
private — anyone using this OS account can rejoin an offline alias and see its
|
|
61
|
-
history. Each session keeps its own model, cwd, instructions, permissions, and
|
|
62
|
-
conversation. Two agents editing the same files can still overwrite each other:
|
|
63
|
-
this package does not manage file ownership.
|
|
36
|
+
Only an explicit objective starts orchestration. Completing a Run allows the next queued objective to start in the owning session. Shutdown, reload, new, resume, and fork terminally interrupt active work, fence ownership, and preserve queued objectives without automatic replay. A later explicit objective can claim an unowned Team and process its queue.
|
|
64
37
|
|
|
65
|
-
|
|
66
|
-
| --- | --- |
|
|
67
|
-
| `request` | Work for a teammate. Starts a model turn when the recipient is idle, and always produces one correlated result back to the emitter. |
|
|
68
|
-
| `note` | Display-only FYI. Appears in the transcript; never starts a model turn. |
|
|
69
|
-
| `result` | The automatic reply to a request: outcome, final text, and observed files. Delivered to the emitter for verification. |
|
|
38
|
+
## Storage and safety
|
|
70
39
|
|
|
71
|
-
|
|
72
|
-
where state is `connected`, `working`, `paused`, or `select a model`, plus a
|
|
73
|
-
pending count when work is queued for you.
|
|
40
|
+
State is isolated under `${PRJCT_HOME:-~/.prjct}/pi-team/orchestration-v2/`. Project identity uses the canonical Git root (or cwd outside Git); moving a project changes its identity. Existing old stores are not modified.
|
|
74
41
|
|
|
75
|
-
|
|
76
|
-
reloaded. `/new` and `/fork` start unaffiliated sessions on purpose.
|
|
42
|
+
Records use strict schemas, byte bounds, private permissions, symlink checks, locks, and atomic writes. Limits: 64 Runs, 128 Assignments, 16 Experts, 32 assignment references per Expert, and three concurrent/unresolved workers. Terminal history is pruned within these bounds. Full Pi sessions are durable and are not bounded metadata.
|
|
77
43
|
|
|
78
|
-
|
|
44
|
+
Production execution uses authenticated supervisor control, durable requests/replies, receipts, and leases. A dispatch or process launch is not success: completion requires a correlated reply and a proven worker stop. Unprovable shutdown blocks the Expert rather than guessing ownership. Use doctor and manually verify process identity before recovery; no automatic adoption or retry is provided.
|
|
79
45
|
|
|
80
|
-
|
|
81
|
-
| --- | --- |
|
|
82
|
-
| `/team create shop` | Create explicitly; does not join automatically |
|
|
83
|
-
| `/team delete shop` | Permanently delete an inactive team after confirmation |
|
|
84
|
-
| `/team rename-team shop store` | Rename a team after every member is offline |
|
|
85
|
-
| `/team join shop backend` | Register this session and enable automatic reception |
|
|
86
|
-
| `/team list` | List teams; refresh team-name completion |
|
|
87
|
-
| `/team members` | Show other aliases, cwd, and idle/busy/paused/offline status; excludes this session |
|
|
88
|
-
| `/team remove backend` | Remove an offline alias and interrupt its unresolved work after confirmation |
|
|
89
|
-
| `/team rename-member backend api` | Rename your own alias, or an offline teammate, while preserving its history and queued work |
|
|
90
|
-
| `/team status` | Show every unresolved requester → assignee relationship |
|
|
91
|
-
| `/team wake [message]` | Queue an actionable check-in for every other teammate |
|
|
92
|
-
| `/team send backend Implement login` | Queue a request that can start work |
|
|
93
|
-
| `/team note frontend API contract changed` | Display an FYI; never starts a model turn |
|
|
94
|
-
| `/team inbox` | Show the most recent 20 records and their states |
|
|
95
|
-
| `/team pause` | Pause new work, without cancelling current work |
|
|
96
|
-
| `/team resume` | Resume reception and reset the automatic turn budget |
|
|
97
|
-
| `/team leave` | Leave; if processing a request, report its result first |
|
|
98
|
-
|
|
99
|
-
Names and aliases are 1–48 lowercase letters, digits, or hyphens, starting with a
|
|
100
|
-
letter. Unknown teams are rejected, never implicitly created; duplicate live
|
|
101
|
-
aliases are rejected. Sending to an offline **known** alias queues until someone
|
|
102
|
-
rejoins it. Removing that alias instead settles every unresolved request involving
|
|
103
|
-
it; incoming requests produce an interrupted result so their requesters stop waiting.
|
|
104
|
-
Renaming an alias rewrites its message addresses so queued work follows the new
|
|
105
|
-
name. Team deletion and rename require every member to be offline, and destructive
|
|
106
|
-
operations require confirmation. Tab completion covers subcommands, discovered
|
|
107
|
-
teams, and teammates.
|
|
108
|
-
|
|
109
|
-
## Agent tools
|
|
110
|
-
|
|
111
|
-
- `team_members` — discover other teammates and their status; excludes this session.
|
|
112
|
-
- `team_send` — send `{ to, kind: "request" | "note", subject, body }`.
|
|
113
|
-
- `team_status` — outstanding work: what you emitted and is unresolved, what is
|
|
114
|
-
queued for you, results awaiting your review, and third-party team activity.
|
|
115
|
-
|
|
116
|
-
Tools cannot create teams, join, resume reception, change permissions, or launch
|
|
117
|
-
terminals; they require membership you established. Discovery results and recipient
|
|
118
|
-
autocomplete exclude the current session, and sending to yourself is rejected at
|
|
119
|
-
the mailbox boundary. A request returns **queued**, never "task completed".
|
|
120
|
-
|
|
121
|
-
## How delivery works
|
|
122
|
-
|
|
123
|
-
A request or result starts a turn only when the recipient is idle, has a selected
|
|
124
|
-
model, no pending user message or open prompt, and an empty editor. No running
|
|
125
|
-
tool is interrupted.
|
|
126
|
-
|
|
127
|
-
For each processed request the extension sends **one** result after the agent
|
|
128
|
-
settles: the last assistant text capped at 3,000 characters (no thinking), up to
|
|
129
|
-
50 absolute paths observed in successful `edit`/`write` calls, and an outcome of
|
|
130
|
-
completed, failed, or interrupted.
|
|
131
|
-
|
|
132
|
-
That file list is **not** a Git diff. Files changed through bash, custom tools, or
|
|
133
|
-
other processes are not enumerated, and the extension never infers test success
|
|
134
|
-
from a shell command or a model claim. **A completed run is not proof of success**:
|
|
135
|
-
review the reported outcome and the recipient worktree.
|
|
136
|
-
|
|
137
|
-
Once a task result is persisted, the session can accept the next queued request.
|
|
138
|
-
While a request you emitted stays unresolved past five minutes, a review turn
|
|
139
|
-
asks your agent to chase the teammate or tell you what is blocked. See
|
|
140
|
-
[Architecture](docs/architecture.md) for implementation details.
|
|
141
|
-
|
|
142
|
-
## Safety
|
|
143
|
-
|
|
144
|
-
- **This is not a sandbox or an authorization system.** Agents and processes under
|
|
145
|
-
the same OS user already have filesystem access. Prompt-level rules are not a
|
|
146
|
-
hard guarantee against a model that ignores them. Do not place untrusted agents
|
|
147
|
-
in a team or rely on team boundaries to protect secrets from that OS user.
|
|
148
|
-
- Peer messages are identified as untrusted data and **are not user consent**.
|
|
149
|
-
Agents are instructed not to relay denied work, change configuration, or evade
|
|
150
|
-
plan mode. Peer text is never executed as a slash command or expanded as a file
|
|
151
|
-
mention.
|
|
152
|
-
- Messages stay in local files, but when processed their text goes to the
|
|
153
|
-
recipient's configured **model provider** like any prompt, and results go to the
|
|
154
|
-
requester. Do not send credentials or unrelated secrets.
|
|
155
|
-
- User takeover during a peer task pauses reception and reports an interrupted
|
|
156
|
-
result instead of forwarding your unrelated work.
|
|
157
|
-
|
|
158
|
-
## Limits
|
|
159
|
-
|
|
160
|
-
| Limit | Value |
|
|
161
|
-
| --- | --- |
|
|
162
|
-
| Automatic peer turns before reception pauses | 5, then `/team resume` |
|
|
163
|
-
| Messages in one automatically linked conversation | 8 non-result |
|
|
164
|
-
| Unsettled deliveries per member | 50 slots, one reserved per outstanding request |
|
|
165
|
-
| Records per team | 500, including reserved result capacity |
|
|
166
|
-
| Members per team | 100 |
|
|
167
|
-
| Outgoing body / serialized message | 16 KB / 20 KB |
|
|
168
|
-
| Automatic result | 32 KB, file list shortened with a notice |
|
|
169
|
-
| Presence lease | 30 s, renewed every 2 s |
|
|
170
|
-
| Review threshold / cadence | 5 min unresolved, checked every 1 min |
|
|
171
|
-
| Duplicate suppression | identical message within 1 min is refused |
|
|
172
|
-
|
|
173
|
-
No daily token or monetary budget is enforced. History is never silently deleted:
|
|
174
|
-
create a fresh team when one is full. Review cadence and the turn budget are fixed
|
|
175
|
-
defaults, not user-configurable yet.
|
|
176
|
-
|
|
177
|
-
## Troubleshooting
|
|
178
|
-
|
|
179
|
-
| Symptom | Cause and action |
|
|
180
|
-
| --- | --- |
|
|
181
|
-
| A request stays queued | Run `/team status`. The recipient may be busy, paused, offline, missing a model, or typing. After five minutes, review turns chase it or surface the blockage. |
|
|
182
|
-
| `Team auto-turn limit reached` | Five automatic turns ran without user input. Review the transcript, then `/team resume`. |
|
|
183
|
-
| `Membership expired or replaced` | Another live session took your alias. Rejoin, choosing a new alias if the old one is in use. |
|
|
184
|
-
| `Recipient inbox full` / `Sender inbox full` | Fifty unsettled deliveries per member, one slot reserved per outstanding request. Let the teammate drain; notes need no reservation. |
|
|
185
|
-
| `Team history full (500 records)` | At capacity; history is never deleted. Create a fresh team and rejoin. |
|
|
186
|
-
| Repeated storage warnings | Conflicts retry automatically and never pause reception. If one persists, check that the teams directory is on a local disk and report it. |
|
|
187
|
-
| A teammate went offline mid-task | Its claimed work is interrupted and the emitter receives that result; it is not replayed. Review the worktree, then resend explicitly. |
|
|
188
|
-
| Work remains queued for an alias that will not return | Use `/team remove <alias>` to interrupt and settle its unresolved work, or `/team rename-member <alias> <new-alias>` to preserve the queue under a replacement alias. |
|
|
46
|
+
This is not an OS sandbox: tools, especially Bash, run with the current user's permissions. Do not send secrets. Metadata redaction is best-effort, not a secret detector. Model requests use the worker's configured authenticated provider. A live model/tmux/PTY roundtrip remains a manual verification requirement; deterministic tests cover the adapter boundary with fake supervision and real durable transport.
|
|
189
47
|
|
|
190
48
|
## Development
|
|
191
49
|
|
|
@@ -193,19 +51,7 @@ defaults, not user-configurable yet.
|
|
|
193
51
|
npm ci --ignore-scripts
|
|
194
52
|
npm run check
|
|
195
53
|
npm test
|
|
196
|
-
npm run
|
|
54
|
+
npm pack --dry-run
|
|
197
55
|
```
|
|
198
56
|
|
|
199
|
-
|
|
200
|
-
to try a checkout. Tests use isolated temporary state and never call model APIs.
|
|
201
|
-
|
|
202
|
-
`npm run check` also enforces that `src/` contains no `let`: session state is a
|
|
203
|
-
single immutable record updated functionally, and reads go through its accessor at
|
|
204
|
-
the point of use rather than being captured across an `await`.
|
|
205
|
-
|
|
206
|
-
## More
|
|
207
|
-
|
|
208
|
-
- [Architecture](docs/architecture.md) — storage, concurrency, recovery, context budget
|
|
209
|
-
- [Package structure](docs/package.md) · [Releases](docs/releases.md) · [Contributing](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
|
|
210
|
-
|
|
211
|
-
[MIT](LICENSE).
|
|
57
|
+
[Architecture](docs/architecture.md) · [Package structure](docs/package.md) · [Contributing](CONTRIBUTING.md) · [MIT](LICENSE)
|
package/docs/architecture.md
CHANGED
|
@@ -1,170 +1,38 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
Presence lives outside the shared record. Each member rewrites only its own
|
|
40
|
-
`presence/<alias>.json` every two seconds, so heartbeats add no write contention
|
|
41
|
-
and never touch `state.json`.
|
|
42
|
-
|
|
43
|
-
These files are deliberately non-durable: the atomic rename is kept, both fsyncs
|
|
44
|
-
are not. Presence expires after 30 seconds and is rewritten every 2, so a write
|
|
45
|
-
lost to a crash only makes a member look offline sooner — never alive longer.
|
|
46
|
-
A member is also considered gone as soon as its recorded process has exited. A
|
|
47
|
-
heartbeat never creates a missing parent directory, so one already in flight
|
|
48
|
-
cannot resurrect a team after rename or deletion.
|
|
49
|
-
|
|
50
|
-
## Request lifecycle
|
|
51
|
-
|
|
52
|
-
A request is queued, claimed when the recipient is idle, worked on, and settled
|
|
53
|
-
with a result delivered back to the emitter. Once settlement is durable, the
|
|
54
|
-
recipient can accept another team turn; the emitter verifies the result against
|
|
55
|
-
its original request and replies in-thread only if something is missing.
|
|
56
|
-
|
|
57
|
-
States are `pending`, `processing`, `completed`, `interrupted`, and `seen`
|
|
58
|
-
(notes already displayed).
|
|
59
|
-
|
|
60
|
-
## Sweeping orphaned claims
|
|
61
|
-
|
|
62
|
-
A session that dies holding a claim would otherwise leave its requester waiting
|
|
63
|
-
forever, so peers interrupt the claim on its behalf and the requester receives an
|
|
64
|
-
`interrupted` result.
|
|
65
|
-
|
|
66
|
-
Leaving marks a member offline but retains its address and history so the same
|
|
67
|
-
alias can rejoin. Therefore "someone is offline" is not enough to decide when to
|
|
68
|
-
sweep. A snapshot instead reports `sweepable`, true only when a member the record
|
|
69
|
-
still counts as connected is actually dead **and** still holds a claim, which is
|
|
70
|
-
the only case where sweeping changes anything. Everything else degrades correctly
|
|
71
|
-
without it: rejoining re-admits a stale alias on its own, and displayed status
|
|
72
|
-
comes from presence rather than the record.
|
|
73
|
-
|
|
74
|
-
## Team and member lifecycle
|
|
75
|
-
|
|
76
|
-
Lifecycle changes are user-only commands; agents receive no tool that can delete
|
|
77
|
-
or rename identities. Removing a member is allowed only while it is offline. The
|
|
78
|
-
operation removes the roster entry, cancels unresolved work emitted by that alias,
|
|
79
|
-
and turns requests addressed to it into interrupted results for their requesters.
|
|
80
|
-
Renaming rewrites every message endpoint so pending work and history follow the new
|
|
81
|
-
alias. A live session may rename itself; only offline peers can be renamed by
|
|
82
|
-
another member. Ownership tokens fence the old alias after either operation.
|
|
83
|
-
|
|
84
|
-
Team rename and deletion require every recorded member to be offline. They acquire
|
|
85
|
-
stable locks for both names in lexical order, preventing deadlock and fencing
|
|
86
|
-
concurrent joins or publishers. Rename moves the directory first and then writes a
|
|
87
|
-
new revision with the new team name. If the process stops between those steps,
|
|
88
|
-
repeating the same rename recognizes and completes that partial state. Deletion
|
|
89
|
-
first moves the directory to a hidden tombstone and then recursively removes it,
|
|
90
|
-
so readers never observe a partially deleted public team directory.
|
|
91
|
-
|
|
92
|
-
## Context budget
|
|
93
|
-
|
|
94
|
-
What an extension puts in the model context is paid on every later turn and
|
|
95
|
-
stays in the session branch, so injected values are bounded and any elision is
|
|
96
|
-
stated rather than silent.
|
|
97
|
-
|
|
98
|
-
| Carrier | In LLM context | Used for |
|
|
99
|
-
| --- | --- | --- |
|
|
100
|
-
| `before_agent_start` system prompt | yes, every turn | peer rules and team identity, carried exactly once |
|
|
101
|
-
| `sendMessage` content | yes, and it persists | peer messages and review turns |
|
|
102
|
-
| Tool results | yes, and they persist | `team_members`, `team_send`, `team_status` |
|
|
103
|
-
| `appendEntry` | **no**, TUI only | notes, `/team inbox`, sent-message previews |
|
|
104
|
-
|
|
105
|
-
Consequences worth knowing:
|
|
106
|
-
|
|
107
|
-
- Peer rules are **not** repeated inside each message; they arrive once per turn
|
|
108
|
-
through the system prompt.
|
|
109
|
-
- A delivered result quotes the original request excerpted to 500 characters,
|
|
110
|
-
with the id kept. Verification of a very long request works from an extract.
|
|
111
|
-
- `team_status` lists are capped and report an `omitted` count. Its
|
|
112
|
-
`otherTeamWork` list carries only third-party work; anything addressed to or
|
|
113
|
-
emitted by this session is already in the other lists.
|
|
114
|
-
- Each `team_status` call is a point-in-time snapshot. Earlier results in the
|
|
115
|
-
same conversation are stale but cannot be retracted, which is why each one is
|
|
116
|
-
kept small.
|
|
117
|
-
- Teammate discovery, status rosters, `/team members`, and recipient completion
|
|
118
|
-
omit the current alias. The mailbox independently rejects self-addressed
|
|
119
|
-
messages, so a stale UI or direct tool call cannot create a self-reply loop.
|
|
120
|
-
|
|
121
|
-
## Recovery and guarantees
|
|
122
|
-
|
|
123
|
-
Ownership tokens fence out replaced, renamed, or removed sessions. Pending
|
|
124
|
-
messages survive disconnection and alias/team rename. Claimed work is marked
|
|
125
|
-
interrupted on disconnect or rejoin and is **not automatically replayed**, since
|
|
126
|
-
edits may already have happened.
|
|
127
|
-
|
|
128
|
-
This favours avoiding duplicate side effects over guaranteed execution. **There is
|
|
129
|
-
no exactly-once guarantee** for filesystem changes or model actions: a crash after
|
|
130
|
-
claiming but before starting also leaves an interrupted task. If storage cannot
|
|
131
|
-
record a result, reception pauses and reports an error.
|
|
132
|
-
|
|
133
|
-
Membership and pause state are recorded in Pi session entries. Resuming the same
|
|
134
|
-
session rejoins; `/new` and `/fork` do not inherit membership. Before claiming
|
|
135
|
-
work the extension records that restoration must pause, without pausing the live
|
|
136
|
-
session, so an abrupt process death during a task restores paused and requires
|
|
137
|
-
`/team resume`. A crash just before a claim can conservatively require resume too.
|
|
138
|
-
Legacy pending-compaction fields from earlier releases are ignored on restore.
|
|
139
|
-
|
|
140
|
-
Directory watchers provide prompt delivery; polling every two seconds recovers
|
|
141
|
-
missed notifications. Both run only for joined interactive sessions and close on
|
|
142
|
-
shutdown. Transient storage errors are reported but never pause reception.
|
|
143
|
-
|
|
144
|
-
## Design decisions and non-goals
|
|
145
|
-
|
|
146
|
-
| Concern | Choice |
|
|
147
|
-
| --- | --- |
|
|
148
|
-
| Session creation | The user opens every terminal; nothing is spawned |
|
|
149
|
-
| Discovery | Explicit named teams and aliases, never inferred from directories |
|
|
150
|
-
| Transport | Local filesystem records; no broker, socket server, or daemon |
|
|
151
|
-
| Presence | Per-member files outside the record; heartbeats never lock |
|
|
152
|
-
| Concurrent writes | Compare-and-swap with retry; no team-wide lock |
|
|
153
|
-
| Follow-up | Periodic review turns delegated to the agent, not programmatic retries |
|
|
154
|
-
| Active recipient | Wait until fully idle; no steering between tools |
|
|
155
|
-
| Offline recipient | Persist to a known alias until it rejoins |
|
|
156
|
-
| Approval | Never supplied by peers; local policies always win |
|
|
157
|
-
| Coordination | Direct messages and bulk check-ins; no task board, automatic compaction, or worktree manager |
|
|
158
|
-
| Scope | Local disks only: no network filesystems, cross-machine transport, or native Windows |
|
|
159
|
-
|
|
160
|
-
Not provided: file ownership between agents, a sandbox, an authorization system,
|
|
161
|
-
or protection of secrets from other processes under the same OS user.
|
|
162
|
-
|
|
163
|
-
## Pi interfaces used
|
|
164
|
-
|
|
165
|
-
`registerCommand`, `registerTool`, `sendMessage`, `appendEntry`, custom entry and
|
|
166
|
-
message renderers, `setWidget`, `getEditorText`, `confirm`, `isIdle`,
|
|
167
|
-
`hasPendingMessages`, session lifecycle events, UI prompt events, `tool_result`,
|
|
168
|
-
`message_end`, and `agent_settled`. All public and documented; no host internals
|
|
169
|
-
are imported, no prototypes patched, and peer text is never shell-evaluated or
|
|
170
|
-
expanded as file mentions.
|
|
3
|
+
## Active integration
|
|
4
|
+
|
|
5
|
+
`src/index.ts` registers only `/team`. Fresh session startup creates no records, timers, tool, or prompt changes. An explicit objective lazily binds the canonical project, persists a Run, claims a fenced owner, and calls `sendUserMessage` once when that Run becomes active. Normal input is not intercepted. `team_orchestrate` is lazily registered and active only during owned Runs; its prompt suffix is absent outside Runs. Deactivation removes only that tool, preserving unrelated active tools.
|
|
6
|
+
|
|
7
|
+
`src/dynamic/domain.ts`, `store.ts`, and `service.ts` define strict bounded Team, Run, Expert, and Assignment records. A locked atomic project record enforces one active Run, one active assignment per Expert, unique roles, and a maximum of three busy/blocked Experts. Suitable Experts are reused, busy Experts queue, and capability/tool-policy escalation is rejected. Generation plus owner epoch fences results. Terminal cancellation never becomes success after a late reply.
|
|
8
|
+
|
|
9
|
+
## Storage
|
|
10
|
+
|
|
11
|
+
The new namespace is `${PRJCT_HOME:-~/.prjct}/pi-team/orchestration-v2/`:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
projects/<project-id>/state.json
|
|
15
|
+
projects/<project-id>/sessions/<stable-session-ref>.jsonl
|
|
16
|
+
transport/teams/<project-id>/...
|
|
17
|
+
transport/control/...
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Project IDs hash canonical Git root or cwd. A project move deliberately produces a different identity. Metadata bounds are 64 Runs, 128 Assignments, 16 Experts, and 32 assignment references per Expert; old terminal records may be pruned. Private directories, strict schemas, byte bounds, storage locks, and atomic publication reuse the existing storage primitives. Pi session files retain conversation history separately from bounded Expert memory.
|
|
21
|
+
|
|
22
|
+
## Production execution
|
|
23
|
+
|
|
24
|
+
`runner.ts` adapts the existing `TeamSupervisor`, `TeamRuntime`, membership leases, durable request/reply spool, and receipts. Transport records live in the isolated namespace; no old Team bytes are reused. The adapter creates a private stable Pi session header once and launches Pi with `--session` referencing the same file across assignments and Runs. It disables ambient extension/skill/template/context-file discovery and passes an explicit tool allowlist.
|
|
25
|
+
|
|
26
|
+
`worker.ts` is selected only for supervised worker environments. It authenticates using the existing private control socket bootstrap, validates durable Expert identity/session and active assignment generation/owner epoch, loads role instructions and bounded memory, and enforces the allowlist at `tool_call`. Its only extension tool is `team_reply`. Requests are durably claimed/read before `sendUserMessage`; replies are explicitly correlated. Membership and delivery leases renew during work. Neither launch nor a model turn is treated as successful execution. The adapter requires a valid reply receipt and a proven stop before reporting completion.
|
|
27
|
+
|
|
28
|
+
The existing supervisor revalidates owner identity, PID start identity, process group, and marked tmux metadata before bounded graceful/TERM/KILL escalation. Tokens are never projected into Team UI/history. Unproven stops block capacity and require manual investigation. Worker startup failures and deadlines produce failure, not fabricated results.
|
|
29
|
+
|
|
30
|
+
## Interruption
|
|
31
|
+
|
|
32
|
+
Reload, new, resume, fork, and shutdown cancel active assignments and terminally cancel the active Run with an interruption reason. They stop only owned workers, release/fence the owner, retain Team/Experts/sessions/history/queued Runs, and never automatically restore execution. A new explicit objective may claim an unowned/dead-owned Team. Dead-owner recovery interrupts abandoned active work and blocks unresolved Experts rather than adopting or replaying them.
|
|
33
|
+
|
|
34
|
+
## Views and compatibility
|
|
35
|
+
|
|
36
|
+
`view.ts` projects bounded plain status/history/doctor summaries without owner/process/control/lease tokens. Free text is control-sanitized and best-effort secret-redacted. No color is required. The previous interactive dashboard remains inactive library code. Legacy inspection/migration and v1 mailbox sources are removed; old command forms are rejected and old stores are untouched.
|
|
37
|
+
|
|
38
|
+
Only documented Pi 0.85.1 extension APIs and CLI flags are used. Deterministic tests cover scheduling, storage, lifecycle, supervisor safety, and the production adapter with fake supervision plus real durable transport. Live authenticated model/tmux/PTY behavior remains manually unchecked. There is no OS sandbox, exactly-once side-effect guarantee, automatic recovery/adoption, Git/worktree automation, deployment, cross-machine transport, or network-filesystem support.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prjct.app/pi-team",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Coordinate
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Coordinate explicit local Pi teams with durable messaging and safely supervised peers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"pi-package",
|
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
"image": "https://raw.githubusercontent.com/prjct-app/pi-clipboard/main/docs/covers/pi-team.png"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
|
+
"build": "rm -rf build && mkdir -p build && npm pack --ignore-scripts --pack-destination build >/dev/null && tar -xzf build/*.tgz -C build --strip-components=1 && rm -f build/*.tgz",
|
|
27
28
|
"check": "tsc --noEmit && npm run check:immutable",
|
|
28
29
|
"check:immutable": "! grep -rn '\\blet\\b' src/ || (echo 'Use immutable values: no let bindings in src/' && exit 1)",
|
|
29
30
|
"test": "node --import tsx --test tests/*.test.ts tests/*.test.mjs",
|
|
30
|
-
"check:package": "npm pack --dry-run --ignore-scripts"
|
|
31
|
+
"check:package": "npm pack --dry-run --ignore-scripts",
|
|
32
|
+
"build:pi": "node scripts/build-pi.mjs"
|
|
31
33
|
},
|
|
32
34
|
"engines": {
|
|
33
35
|
"node": ">=22.19.0"
|
|
@@ -43,6 +45,7 @@
|
|
|
43
45
|
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
44
46
|
"@earendil-works/pi-tui": "0.85.1",
|
|
45
47
|
"@types/node": "^22.19.0",
|
|
48
|
+
"esbuild": "^0.28.1",
|
|
46
49
|
"tsx": "^4.20.0",
|
|
47
50
|
"typebox": "1.3.7",
|
|
48
51
|
"typescript": "^5.9.3"
|
|
@@ -68,5 +71,8 @@
|
|
|
68
71
|
"CONTRIBUTING.md",
|
|
69
72
|
"LICENSE",
|
|
70
73
|
"CHANGELOG.md"
|
|
71
|
-
]
|
|
74
|
+
],
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"@prjct.app/pi-tui-kit": "file:../pi-tui-kit"
|
|
77
|
+
}
|
|
72
78
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AutocompleteItem } from '@earendil-works/pi-tui';
|
|
2
|
+
import { bounded } from '../dynamic/domain.ts';
|
|
3
|
+
import { completer } from '@prjct.app/pi-tui-kit';
|
|
4
|
+
|
|
5
|
+
export const TEAM_HELP = '/team <objective> | status | history | doctor | cancel [run-id] | help';
|
|
6
|
+
export type TeamCommand =
|
|
7
|
+
| { readonly action: 'objective'; readonly objective: string }
|
|
8
|
+
| { readonly action: 'status' | 'history' | 'doctor' | 'help' }
|
|
9
|
+
| { readonly action: 'cancel'; readonly runId?: string };
|
|
10
|
+
const removed = new Set(['create', 'join', 'migrate', 'legacy', 'start', 'stop', 'kill', 'leave', 'close', 'purge', 'receive', 'inbox']);
|
|
11
|
+
export function parseTeamCommand(input: string): TeamCommand {
|
|
12
|
+
const text = input.trim();
|
|
13
|
+
bounded(text, 8192, 'Objective');
|
|
14
|
+
if (!text) return { action: 'status' };
|
|
15
|
+
const [first, ...args] = text.split(/\s+/);
|
|
16
|
+
const action = first!.toLowerCase();
|
|
17
|
+
// Old lifecycle commands were short ("create shop lead"). A sentence that
|
|
18
|
+
// merely starts with one of those words ("Create three files…") is an objective.
|
|
19
|
+
if (removed.has(action) && args.length <= 2) throw new Error(`Unsupported Team command. ${TEAM_HELP}`);
|
|
20
|
+
if (['status', 'history', 'doctor', 'help'].includes(action)) {
|
|
21
|
+
if (args.length) throw new Error(TEAM_HELP);
|
|
22
|
+
return { action: action as 'status' | 'history' | 'doctor' | 'help' };
|
|
23
|
+
}
|
|
24
|
+
if (action === 'cancel') {
|
|
25
|
+
if (args.length > 1 || (args[0] && !/^[a-zA-Z0-9-]{1,128}$/.test(args[0]))) throw new Error(TEAM_HELP);
|
|
26
|
+
return { action, ...(args[0] ? { runId: args[0] } : {}) };
|
|
27
|
+
}
|
|
28
|
+
return { action: 'objective', objective: text };
|
|
29
|
+
}
|
|
30
|
+
/** Subcommands with the prjct mark. Anything else typed after /team is a new objective. */
|
|
31
|
+
export const commandCompletions: (prefix: string) => AutocompleteItem[] | null = completer([
|
|
32
|
+
{ value: 'status', description: 'panel of Runs and Experts' },
|
|
33
|
+
{ value: 'history', description: 'the last Runs as text' },
|
|
34
|
+
{ value: 'doctor', description: 'ownership and blocked experts' },
|
|
35
|
+
{ value: 'cancel', description: 'cancel the active Run (owner only)' },
|
|
36
|
+
{ value: 'help', description: 'what /team accepts' },
|
|
37
|
+
]);
|