gentle-pi 3.3.0 → 3.5.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 +88 -59
- package/assets/orchestrator-delegation.md +1 -1
- package/bin/gentle-shell.mjs +198 -0
- package/docs/assets/brand/gentle-shell-banner.gif +0 -0
- package/docs/assets/diagrams/odd-workflow.svg +74 -0
- package/docs/assets/features/agents-view.png +0 -0
- package/docs/assets/features/changes-view.png +0 -0
- package/docs/assets/features/command-palette.png +0 -0
- package/docs/assets/features/profiles-routing.png +0 -0
- package/docs/gentle-agents-activity.md +95 -0
- package/docs/gentle-shell.md +26 -2
- package/docs/readme-reference.md +99 -6
- package/extensions/ask-user-choice.ts +70 -22
- package/extensions/ask-user-question.ts +338 -0
- package/extensions/gentle-agents.ts +41 -1
- package/extensions/gentle-ai.ts +59 -18
- package/extensions/gentle-shell.ts +99 -10
- package/extensions/quiet-tools.ts +28 -5
- package/extensions/startup-banner.ts +25 -10
- package/lib/agents-rpc-publisher.ts +342 -0
- package/lib/agents-runner.ts +7 -2
- package/lib/animation-policy.ts +52 -0
- package/lib/background-cache-warming.ts +38 -0
- package/lib/command-palette-catalog.ts +1 -0
- package/lib/gentle-shell-launcher.ts +482 -0
- package/lib/inprocess-reviewer.ts +38 -1
- package/lib/native-review-cli.ts +36 -10
- package/lib/questionnaire/questionnaire-view.ts +603 -0
- package/lib/questionnaire/schema.ts +82 -0
- package/lib/questionnaire/validate.ts +141 -0
- package/lib/review-candidate-view-owner.ts +20 -5
- package/lib/review-candidate-view.ts +9 -2
- package/lib/review-host-relay.ts +10 -0
- package/lib/review-integration-v2.ts +4 -1
- package/lib/rpc-host.ts +36 -0
- package/lib/shell-bar.ts +13 -0
- package/lib/shell-sidebar-layout.ts +10 -4
- package/lib/shell-usage-view.ts +5 -2
- package/lib/shell-usage.ts +120 -6
- package/package.json +5 -1
- package/runtime/gentle-shell-launcher.mjs +483 -0
- package/runtime/native-review-cli.mjs +35 -9
- package/runtime/review-integration-v2.mjs +4 -1
- package/scripts/build-runtime-modules.mjs +1 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/install-gentle-ai.mjs +14 -7
- package/scripts/install-tui-mode-setting.mjs +78 -1
- package/scripts/verify-package-files.mjs +6 -3
- package/tests/agents-rpc-publisher.test.ts +407 -0
- package/tests/agents-runner.test.ts +10 -0
- package/tests/animation-policy.test.ts +42 -0
- package/tests/ask-user-choice.test.ts +129 -0
- package/tests/ask-user-question.test.ts +661 -0
- package/tests/background-cache-warming.test.ts +60 -0
- package/tests/background-subagents.test.ts +68 -0
- package/tests/command-palette.test.ts +9 -0
- package/tests/gentle-agents.test.ts +161 -2
- package/tests/gentle-ai-binary.test.ts +1 -1
- package/tests/gentle-ai-installer.test.ts +47 -47
- package/tests/gentle-ai.test.ts +56 -4
- package/tests/gentle-shell-bin.test.ts +188 -0
- package/tests/gentle-shell-launcher.test.ts +718 -0
- package/tests/gentle-shell.test.ts +355 -2
- package/tests/inprocess-reviewer.test.ts +92 -0
- package/tests/install-tui-mode-guard.test.ts +99 -0
- package/tests/install-tui-mode-setting.test.ts +39 -1
- package/tests/native-review-capability-contract.test.ts +16 -1
- package/tests/native-review-parity.test.ts +19 -0
- package/tests/package-manifest.test.ts +6 -17
- package/tests/questionnaire-schema.test.ts +274 -0
- package/tests/questionnaire-view.test.ts +446 -0
- package/tests/rdd-status-line.test.ts +21 -4
- package/tests/review-candidate-owner-retry.test.ts +63 -0
- package/tests/review-candidate-view.test.ts +15 -0
- package/tests/review-controller-native-routing.test.ts +86 -0
- package/tests/review-host-relay.test.ts +21 -0
- package/tests/review-integration-v2.test.ts +30 -0
- package/tests/review-ledger-contract.test.ts +1 -2
- package/tests/review-relay-transport-agent.test.ts +107 -2
- package/tests/review-risk-assessment.test.ts +104 -0
- package/tests/rpc-host.test.ts +77 -0
- package/tests/shell-bar.test.ts +8 -0
- package/tests/shell-sidebar-layout.test.ts +60 -5
- package/tests/shell-usage.test.ts +129 -0
- package/tests/skill-collision-prefixes.test.ts +1 -1
- package/tests/startup-banner.test.ts +93 -2
- package/docs/assets/brand/gentle-pi-banner.png +0 -0
- package/skills/release/SKILL.md +0 -137
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<a id="top"></a>
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
|
-
<img src="docs/assets/brand/gentle-
|
|
4
|
+
<img src="docs/assets/brand/gentle-shell-banner.gif" width="1200" alt="gentle-shell — Ecosystem, Agent, One shell">
|
|
5
5
|
</div>
|
|
6
6
|
|
|
7
7
|
<h1 align="center">gentle-shell™</h1>
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
<p align="center"><sub>One workspace. A coding agent you direct. A workflow you can inspect.</sub></p>
|
|
36
36
|
|
|
37
|
-
<p align="center"><strong>BUILT FOR PI</strong> · Coding-agent workspace · Focused agents · ODD
|
|
37
|
+
<p align="center"><strong>BUILT FOR PI</strong> · Coding-agent workspace · Focused agents · ODD</p>
|
|
38
38
|
|
|
39
39
|
<p align="center">
|
|
40
40
|
<a href="https://github.com/Gentleman-Programming/gentle-pi/stargazers"><strong>★ Star gentle-shell on GitHub</strong></a>
|
|
@@ -74,122 +74,126 @@
|
|
|
74
74
|
|
|
75
75
|
### gentle-shell — Your coding agent, in the workspace you lead
|
|
76
76
|
|
|
77
|
-
<
|
|
78
|
-
<img src="docs/assets/features/gentle-shell.png" width="1200" alt="gentle-shell showing an SDD agent task, todo list, changes summary, status bar, and usage footer in Pi">
|
|
79
|
-
</p>
|
|
77
|
+
<img width="100%" src="https://github.com/user-attachments/assets/5d9eefc2-7b2a-48f8-b212-1439834ce195" alt="gentle-shell running a live agent session: a header row with branch, model, and context gauge above the transcript, with status, changes, and todo cards in the right rail">
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
See active tasks, session changes, and runtime status without leaving the work you are leading.
|
|
79
|
+
A bare terminal answers "what is the agent doing?" only with scrollback. gentle-shell turns your Pi session into a workspace: agent orchestration, live changes and runtime status, usage monitoring for supported provider accounts, and built-in diff views — so you lead the work instead of chasing it.
|
|
84
80
|
|
|
85
81
|
<p align="center"><sub>gentle-shell in action. Screenshot from <a href="https://raw.githubusercontent.com/Gentleman-Programming/gentle-ai/main/docs/assets/features/gentle-shell.png">Gentle-AI</a>.</sub></p>
|
|
86
82
|
|
|
87
|
-
**[→
|
|
83
|
+
**[Docs →](docs/gentle-shell.md)**
|
|
88
84
|
|
|
89
85
|
---
|
|
90
86
|
|
|
91
87
|
### el Gentleman — Think before you build
|
|
92
88
|
|
|
93
|
-
<
|
|
94
|
-
<img src="docs/assets/diagrams/gentleman-workflow.svg" width="1200" alt="Diagram of el Gentleman turning human intent into clarified scope, a smallest workflow choice, evidence, and a human delivery decision">
|
|
95
|
-
</p>
|
|
96
|
-
|
|
97
|
-
Say what you need once, then keep moving. el Gentleman helps turn intent into clear scope, a sensible next step, and evidence people can review—without making every task feel like a process meeting.
|
|
89
|
+
<img width="100%" src="docs/assets/diagrams/gentleman-workflow.svg" alt="Diagram of el Gentleman turning human intent into clarified scope, a smallest workflow choice, evidence, and a human delivery decision">
|
|
98
90
|
|
|
99
|
-
|
|
91
|
+
Say what you need once, then keep moving. el Gentleman helps turn intent into clear scope, a sensible next step, and evidence people can review — without making every task feel like a process meeting.
|
|
100
92
|
|
|
101
|
-
**[→
|
|
93
|
+
**[Docs →](docs/readme-reference.md#organic-driven-development)**
|
|
102
94
|
|
|
103
95
|
---
|
|
104
96
|
|
|
105
97
|
### Focused agents — Context with a return path
|
|
106
98
|
|
|
107
|
-
<
|
|
108
|
-
<img src="docs/assets/diagrams/agent-orchestration.svg" width="1200" alt="Diagram of one parent session directing bounded map, implementation, and verification work and receiving evidence back">
|
|
109
|
-
</p>
|
|
99
|
+
<img width="100%" src="docs/assets/diagrams/agent-orchestration.svg" alt="Diagram of one parent session directing bounded map, implementation, and verification work and receiving evidence back">
|
|
110
100
|
|
|
111
101
|
Bring in help without losing the thread. Focused package-owned Pi agents can map a codebase, implement a bounded change, or verify it, while one parent stays accountable for the scope, the decisions, and the final summary.
|
|
112
102
|
|
|
113
|
-
**[→
|
|
114
|
-
|
|
115
|
-
- `orchestrator_session_id`, `orchestrator_list`, and `orchestrator_send_message` provide local-profile session notifications. List results advertise IDs only and reachability remains unknown. Sending selects the sole advertised peer or asks the user to choose; a successful ACK means the peer accepted the notification for delivery, not that it read or completed work. This is notification-and-ACK transport only: it has no cross-session queries, offline queue, retries, broadcasts, or read/completion guarantees. On Unix, presence records remain in the profile's private transport directory while socket endpoints use a private, profile-hashed directory below the canonical system temporary directory, keeping endpoint length independent of the profile path and at most 100 encoded bytes. The shared system temporary parent is only validated (current-user-owned without group/other write, or root/current-user-owned, world-writable, and sticky); it is never claimed, permissioned, or cleaned up by gentle-pi. On Windows, the transport selects a package-local PowerShell helper for a Windows named pipe; availability and delivery depend on the helper's bounded startup and pipe checks.
|
|
103
|
+
**[Docs →](docs/readme-reference.md#how-the-harness-decides-what-to-do)**
|
|
116
104
|
|
|
117
105
|
---
|
|
118
106
|
|
|
119
107
|
### ODD — The everyday workflow
|
|
120
108
|
|
|
121
|
-
|
|
109
|
+
<img width="100%" src="docs/assets/diagrams/odd-workflow.svg" alt="Organic Driven Development as seven numbered steps: Authorize, Explore, Resolve uncertainty, and Classify across the top row; Classify forks, so small understood work stays light while substantial work gets step five, Track, with one feature document; both paths converge on Implement task by task and then Close, above a dashed band marking that one feature document mirrored in Engram lets work resume across sessions">
|
|
110
|
+
|
|
111
|
+
**Organic Driven Development (ODD)** is the everyday path: the agent explores before changing anything, clarifies only real decisions, and keeps small understood work small. Substantial, authorized work gets one recoverable feature document — mirrored in memory when available — so progress, evidence, and the next step survive an interruption; checks follow the configured TDD mode.
|
|
122
112
|
|
|
123
|
-
|
|
113
|
+
**[Docs →](docs/readme-reference.md#organic-driven-development)**
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
---
|
|
126
116
|
|
|
127
|
-
|
|
117
|
+
### Native review — Review the exact change
|
|
118
|
+
|
|
119
|
+
<img width="100%" src="docs/assets/diagrams/native-review.svg" alt="Diagram showing one frozen candidate passing through risk-scoped native review to an outcome, while human delivery choices stay separate">
|
|
120
|
+
|
|
121
|
+
Review the exact change, not a moving target. Native review keeps one candidate in view, returns risk-scoped evidence, and can surface a bounded correction path. You still decide what happens next in your repository.
|
|
128
122
|
|
|
129
|
-
**[→
|
|
123
|
+
**[Docs →](docs/review-integration.md)**
|
|
130
124
|
|
|
131
125
|
---
|
|
132
126
|
|
|
133
|
-
###
|
|
127
|
+
### Gentle Changes — Every edit, attributed and reviewable
|
|
134
128
|
|
|
135
|
-
<
|
|
136
|
-
<img src="docs/assets/diagrams/sdd-cycle.svg" width="1200" alt="Diagram of an optional specification-driven development cycle from explore through archive, with TDD evidence attached to apply when available">
|
|
137
|
-
</p>
|
|
129
|
+
<img width="100%" src="docs/assets/features/changes-view.png" alt="Gentle Changes viewer: worktree accordion with per-file status on the left, the captured diff with line counts on the right, and a keyboard hint row">
|
|
138
130
|
|
|
139
|
-
|
|
131
|
+
You should not have to run `git status` to find out what your agent did. Gentle Changes captures the successful write and edit tool calls from the current session and its owned subagents — no repository scans, no background polling — and shows them in a two-pane viewer with per-file line counts and an honest **diff unavailable** when an external edit breaks continuity. Coverage stops at those tools, so shell commands and failed runs leave no row, and a missing entry never proves a clean tree. `alt+g` opens it; `o` drops the real file into your editor.
|
|
140
132
|
|
|
141
|
-
**[→
|
|
133
|
+
**[Docs →](docs/gentle-shell.md#browse-captured-diffs)**
|
|
142
134
|
|
|
143
135
|
---
|
|
144
136
|
|
|
145
|
-
###
|
|
137
|
+
### Gentle Agents — Parallel work with a live view
|
|
146
138
|
|
|
147
|
-
<
|
|
148
|
-
<img src="docs/assets/diagrams/native-review.svg" width="1200" alt="Diagram showing one frozen candidate passing through risk-scoped native review to an outcome, while human delivery choices stay separate">
|
|
149
|
-
</p>
|
|
139
|
+
<img width="100%" src="docs/assets/features/agents-view.png" alt="Gentle Agents overlay showing a completed subagent thread with model, tokens, and elapsed columns, and the structured handoff it returned">
|
|
150
140
|
|
|
151
|
-
|
|
141
|
+
Delegating work should not mean losing it. Every subagent runs as its own process with a live card above the editor — model, tokens, cost, elapsed — and `alt+a` opens the full view with retained threads, stop controls, and history restored on resume. A child can ask you a question as an ordinary dialog, and background results come back as cards that start a new turn — nothing polls.
|
|
152
142
|
|
|
153
|
-
**[→
|
|
143
|
+
**[Docs →](docs/gentle-shell.md#gentle-agents)**
|
|
154
144
|
|
|
155
145
|
---
|
|
156
146
|
|
|
157
|
-
###
|
|
147
|
+
### Profiles and model routing — One deliberate decision per knob
|
|
158
148
|
|
|
159
|
-
|
|
149
|
+
<img width="100%" src="docs/assets/features/profiles-routing.png" alt="Profiles view: profile list on the left, orchestrator model and effort on the right, with per-role profile routing and effective current routing">
|
|
160
150
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
151
|
+
Model, effort, and who does what should be choices, not accidents. Named profiles route the orchestrator atomically and independently from packaged and review roles; a repository can pin its profile so its subagents stop following the globally active one, and the panel always shows the routing the runtime actually uses.
|
|
152
|
+
|
|
153
|
+
**[Docs →](docs/readme-reference.md#agent-model-profiles)**
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Command palette — Every command, one keystroke away
|
|
158
|
+
|
|
159
|
+
<img width="100%" src="docs/assets/features/command-palette.png" alt="Command palette with a search field and grouped entries: Configuration, Session, Diagnostics, SDD, and Skills">
|
|
160
|
+
|
|
161
|
+
Extension commands are only useful if you can find them. `alt+k` opens a curated, grouped palette — Configuration, Session, Diagnostics, SDD, and Skills — searchable by label, command name, or description, showing entries only when they are actually registered.
|
|
162
|
+
|
|
163
|
+
**[Docs →](docs/gentle-shell.md#command-palette)**
|
|
164
164
|
|
|
165
165
|
---
|
|
166
166
|
|
|
167
167
|
### Also in the box
|
|
168
168
|
|
|
169
|
-
|
|
|
170
|
-
|
|
|
169
|
+
| Component | What it does |
|
|
170
|
+
| :--- | :--- |
|
|
171
171
|
| Startup and runtime panel | A configurable gentle-shell entry point and visible runtime state for Pi. |
|
|
172
172
|
| Skills and delivery guidance | Package skills for documentation, issue work, PRs, reviews, and reviewable work units. |
|
|
173
173
|
| Model, effort, persona, and profile controls | Explicit knobs for how Pi routes and presents work. |
|
|
174
174
|
| Safety boundaries | Guards around destructive operations and sensitive-path handling. |
|
|
175
175
|
| Optional companion packages | Extra capabilities you may choose to add; persistent memory is **not** bundled with `gentle-pi`. |
|
|
176
|
+
| Fullscreen workspace layout | Header row plus a scrolling Status → Changes → TODO rail on wide terminals. |
|
|
177
|
+
| Live status bar and prompt petal | One-line gauge, cost, and statuses; the petal shows `working` and `queued`. |
|
|
178
|
+
| Parent ↔ subagent communication | Delegate, steer, reply, and cross-session notification within your local profile. |
|
|
179
|
+
| Native interactive tools | Built-in questions, choices, and review captures — no third-party dependency. |
|
|
180
|
+
| Gentle Todo | A plan card that turns amber when the model lets it go stale. |
|
|
181
|
+
| Subscription usage | Per-window meters and resets for supported provider accounts. |
|
|
182
|
+
| Gentle notices | Gentle AI calls and review reminders as cards in the transcript. |
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
<summary><strong>Optional companions, when they fit your setup</strong></summary>
|
|
184
|
+
> **Every component, skill and preset: [Full breakdown →](docs/gentle-shell.md)**
|
|
179
185
|
|
|
180
|
-
|
|
186
|
+
---
|
|
181
187
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
| `gentle-engram` | Persistent memory, separately installed and configured. |
|
|
186
|
-
| `pi-web-access` | Web access when a task needs it and your policy allows it. |
|
|
187
|
-
| `pi-lens` | Additional inspection surfaces. |
|
|
188
|
-
| `@juicesharp/rpiv-ask-user-question` | Interactive choice support. |
|
|
188
|
+
### What's new in v2.6.0
|
|
189
|
+
|
|
190
|
+
The [v2.6.0 release](https://github.com/Gentleman-Programming/gentle-pi/releases/tag/v2.6.0) brings a more persistent, inspectable Pi workspace:
|
|
189
191
|
|
|
190
|
-
|
|
192
|
+
- **Shell:** `/gentle:changes` groups captured write/edit changes from the current agent session and its subagents, without startup repository scans; fullscreen navigation, sidebars, and mouse support stay available. See the [capture limits and shell-command coverage](docs/gentle-shell.md#what-appears-in-changes).
|
|
193
|
+
- **Agents and profiles:** the Agents view shows orchestrator/session hierarchy, retained completion, abort, and lost-exit history, parent-child handoff, and model, effort, and usage observability. Named `/gentle:profiles` atomically route the orchestrator independently from packaged and review roles; applying one replaces the routing of every agent, a repository can be pinned to a profile with `p` so its subagent launches stop following the globally active profile, and the panel shows the routing the runtime actually uses even when `models.json` is sparse.
|
|
194
|
+
- **Control and recovery:** native SDD requires parent-confirmed preflight; native review supports intended-untracked selection, consent, and provider continuations. Subsystems install with explicit recovery guidance when npm lifecycle scripts were skipped; Pi Git installs are recognized globally; custom ask responses are opt-in. Windows keeps child consoles hidden and fixes ownership mode; Gentle Todo keeps the next pending task visible when collapsed.
|
|
191
195
|
|
|
192
|
-
|
|
196
|
+
---
|
|
193
197
|
|
|
194
198
|
<p align="right"><a href="#top">Back to top ↑</a></p>
|
|
195
199
|
|
|
@@ -225,7 +229,32 @@ See the [v2.6.0 release notes](https://github.com/Gentleman-Programming/gentle-p
|
|
|
225
229
|
|
|
226
230
|
> **Fullscreen installation note:** a recognized global installation persists Pi’s `"tuiMode": "fullscreen"` setting. Project-local and other install paths do not receive that change.
|
|
227
231
|
|
|
228
|
-
|
|
232
|
+
> **Interactive RPC hosts:** the desktop app sets `GENTLE_SHELL_INTERACTIVE_HOST=1` automatically, without touching your Pi config — see the [installation reference](docs/readme-reference.md#interactive-rpc-hosts).
|
|
233
|
+
|
|
234
|
+
For prerequisites, source-checkout instructions, full install behavior, and release policy, use the **[installation reference](docs/readme-reference.md#install)**. For everyday work, describe the outcome and follow [ODD](#odd--the-everyday-workflow).
|
|
235
|
+
|
|
236
|
+
### Without touching your pi
|
|
237
|
+
|
|
238
|
+
`gentle-shell` opens Pi with the Gentle Shell package loaded, without installing it into your pi agent or editing its `settings.json`.
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
npm i -g gentle-pi
|
|
242
|
+
|
|
243
|
+
# Own home, never touches your pi install
|
|
244
|
+
gentle-shell
|
|
245
|
+
|
|
246
|
+
# Reuse your pi sign-ins, models and chats instead
|
|
247
|
+
gentle-shell --link
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`gentle-shell` alone starts in its own home, `~/.gentle-shell/agent`. `gentle-shell --link` reuses `~/.pi/agent` as-is.
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# Make --link the default
|
|
254
|
+
gentle-shell home link
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Every other argument is forwarded to pi unchanged, for example `gentle-shell --mode rpc` or `gentle-shell -p "..."`. Full flags, env vars, and modes: **[launcher reference](docs/readme-reference.md#gentle-shell-launcher)**.
|
|
229
258
|
|
|
230
259
|
<p align="right"><a href="#top">Back to top ↑</a></p>
|
|
231
260
|
|
|
@@ -203,7 +203,7 @@ When the policy is on and `subagent_run` is available:
|
|
|
203
203
|
|
|
204
204
|
- The runtime already defaults `subagent_run` to `mode: "background"` under this policy in interactive and RPC sessions, so omit `mode` for ordinary delegation. It returns a task id at once; the terminal stays free and the human keeps typing. Pass a `label` of three to six words naming the work.
|
|
205
205
|
- A child `agent_end` retains its latest answer but is not completion: Pi may still retry, compact, or run a queued follow-up. Treat the task as finished only at `agent_settled`; only then release its queue slot, publish its background result, or terminate it. If it exits first, report failure with its retained answer as diagnostics.
|
|
206
|
-
- When a background task settles, its result arrives as a message in this session (custom type `gentle-agents.result`, one per task) and starts a new turn if you are idle. Wait for it: end the turn once launches and any non-overlapping work are done. Never
|
|
206
|
+
- When a background task settles, its result arrives as a message in this session (custom type `gentle-agents.result`, one per task) and starts a new turn if you are idle. Wait for it: end the turn once launches and any non-overlapping work are done. Never sleep or periodically poll `subagent_status`/`subagent_result` for completion or cache maintenance. Retain the task ID. Use `subagent_status` only at a real orchestration decision boundary: user-requested inspection, relevant scope change, input request, or suspected abnormal behavior. Never relaunch equivalent work merely because it is queued or running. Cache warming belongs to Pi's native runtime, never to model-driven maintenance turns.
|
|
207
207
|
- Do not claim an implementation ready or RDD-ready while its required verification or correction follow-up remains queued. Run the required focused verification before that claim, and retain legitimate post-correction verification. This does not invent a universal full-suite requirement or make a receipt a delivery gate.
|
|
208
208
|
- Use `mode: "task"` only when the subagent must ask the human something mid-flight (task-mode dialogs reach the human; background dialogs are dismissed) or when the human asked to wait.
|
|
209
209
|
- Launch as many independent tasks as the work has; the runner queues beyond `max_concurrency`. Do not duplicate launches or work, and do not overlap files or topics. Never run parallel writers in one worktree.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin process/fs/exec glue around lib/gentle-shell-launcher.ts (built to
|
|
3
|
+
// runtime/gentle-shell-launcher.mjs). All decision logic — argv parsing, home
|
|
4
|
+
// resolution, pi resolution order, the version gate, and the pi invocation —
|
|
5
|
+
// lives in that pure, unit-tested module; this file only wires it to the real
|
|
6
|
+
// process, filesystem, and child process.
|
|
7
|
+
import { accessSync, constants as fsConstants, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { createRequire } from "node:module";
|
|
9
|
+
import { constants as osConstants, homedir } from "node:os";
|
|
10
|
+
import { delimiter, dirname, join, resolve as resolvePath } from "node:path";
|
|
11
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import {
|
|
14
|
+
buildPiInvocation,
|
|
15
|
+
checkPiVersion,
|
|
16
|
+
describeVersion,
|
|
17
|
+
helpText,
|
|
18
|
+
launcherConfigPath,
|
|
19
|
+
missingPiMessage,
|
|
20
|
+
parseLauncherArgs,
|
|
21
|
+
parseLauncherConfig,
|
|
22
|
+
planSpawn,
|
|
23
|
+
resolveHome,
|
|
24
|
+
resolvePiRuntime,
|
|
25
|
+
settingsDeclareGentlePi,
|
|
26
|
+
} from "../runtime/gentle-shell-launcher.mjs";
|
|
27
|
+
import { installIsolatedTuiModeSetting } from "../scripts/install-tui-mode-setting.mjs";
|
|
28
|
+
|
|
29
|
+
const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
30
|
+
|
|
31
|
+
function fail(message, code) {
|
|
32
|
+
process.stderr.write(`${message}\n`);
|
|
33
|
+
process.exit(code);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function readJsonIfExists(path) {
|
|
37
|
+
try {
|
|
38
|
+
return readFileSync(path, "utf8");
|
|
39
|
+
} catch (error) {
|
|
40
|
+
if (error.code === "ENOENT") return undefined;
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// @earendil-works/pi-coding-agent ships as an optional peer dependency: it may
|
|
46
|
+
// not be installed at all, so a resolution failure here is expected, not an error.
|
|
47
|
+
function resolveBundledCli() {
|
|
48
|
+
try {
|
|
49
|
+
const require = createRequire(import.meta.url);
|
|
50
|
+
const pkgJsonPath = require.resolve("@earendil-works/pi-coding-agent/package.json");
|
|
51
|
+
const cliPath = join(dirname(pkgJsonPath), "dist", "bundle", "cli.js");
|
|
52
|
+
return existsSync(cliPath) ? cliPath : undefined;
|
|
53
|
+
} catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function findOnPath(name) {
|
|
59
|
+
const dirs = (process.env.PATH || "").split(delimiter).filter((entry) => entry.length > 0);
|
|
60
|
+
const extensions = process.platform === "win32" ? (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";") : [""];
|
|
61
|
+
for (const dir of dirs) {
|
|
62
|
+
for (const extension of extensions) {
|
|
63
|
+
const candidate = join(dir, `${name}${extension}`);
|
|
64
|
+
try {
|
|
65
|
+
accessSync(candidate, fsConstants.X_OK);
|
|
66
|
+
return candidate;
|
|
67
|
+
} catch {
|
|
68
|
+
// keep scanning
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function signalExitCode(signal) {
|
|
76
|
+
const number = osConstants.signals[signal];
|
|
77
|
+
return 128 + (typeof number === "number" ? number : 0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function ownPackageVersion() {
|
|
81
|
+
const packageJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"));
|
|
82
|
+
return packageJson.version;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function emptyArgs() {
|
|
86
|
+
return { link: false, isolated: false, home: undefined, help: false, version: false, command: undefined, commandArgs: [], passthrough: [], error: undefined };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function loadConfig() {
|
|
90
|
+
const configPath = launcherConfigPath(homedir());
|
|
91
|
+
const text = readJsonIfExists(configPath);
|
|
92
|
+
return text === undefined ? undefined : parseLauncherConfig(text);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function handleHomeCommand(commandArgs) {
|
|
96
|
+
if (commandArgs.length === 0) {
|
|
97
|
+
const resolved = resolveHome({ args: emptyArgs(), env: process.env, homedir: homedir(), config: loadConfig() });
|
|
98
|
+
process.stdout.write(`${resolved.mode} ${resolved.dir}\n`);
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
if (commandArgs.length > 1) fail("gentle-shell home accepts at most one argument. Run 'gentle-shell --help'.", 2);
|
|
102
|
+
const [value] = commandArgs;
|
|
103
|
+
if (value.length === 0) fail("gentle-shell home requires a non-empty argument. Run 'gentle-shell --help'.", 2);
|
|
104
|
+
|
|
105
|
+
const configPath = launcherConfigPath(homedir());
|
|
106
|
+
const configDir = dirname(configPath);
|
|
107
|
+
if (!existsSync(configDir)) mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
108
|
+
|
|
109
|
+
if (value === "link" || value === "isolated") {
|
|
110
|
+
writeFileSync(configPath, `${JSON.stringify({ home: value }, null, 2)}\n`, "utf8");
|
|
111
|
+
process.stdout.write(`Saved home: ${value}\n`);
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
const dir = resolvePath(value);
|
|
115
|
+
writeFileSync(configPath, `${JSON.stringify({ home: dir }, null, 2)}\n`, "utf8");
|
|
116
|
+
process.stdout.write(`Saved home: path ${dir}\n`);
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function main() {
|
|
121
|
+
const args = parseLauncherArgs(process.argv.slice(2));
|
|
122
|
+
if (args.error !== undefined) fail(`${args.error}\nRun 'gentle-shell --help' for usage.`, 2);
|
|
123
|
+
if (args.help) {
|
|
124
|
+
process.stdout.write(`${helpText()}\n`);
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
if (args.command === "home") {
|
|
128
|
+
handleHomeCommand(args.commandArgs);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const config = loadConfig();
|
|
133
|
+
let home = resolveHome({ args, env: process.env, homedir: homedir(), config });
|
|
134
|
+
if (home.mode === "path") home = { ...home, dir: resolvePath(home.dir) };
|
|
135
|
+
|
|
136
|
+
const runtime = resolvePiRuntime({
|
|
137
|
+
env: process.env,
|
|
138
|
+
resolveBundledCli,
|
|
139
|
+
findOnPath,
|
|
140
|
+
nodeExecPath: process.execPath,
|
|
141
|
+
});
|
|
142
|
+
if (runtime === undefined) fail(missingPiMessage(), 1);
|
|
143
|
+
|
|
144
|
+
const versionProbePlan = planSpawn({ command: runtime.command, args: [...runtime.args, "--version"], platform: process.platform });
|
|
145
|
+
const versionProbe = spawnSync(versionProbePlan.command, versionProbePlan.args, {
|
|
146
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
147
|
+
timeout: 15000,
|
|
148
|
+
encoding: "utf8",
|
|
149
|
+
shell: versionProbePlan.shell,
|
|
150
|
+
});
|
|
151
|
+
if (versionProbe.error) fail(`Could not run the pi runtime at "${runtime.command}": ${versionProbe.error.message}`, 1);
|
|
152
|
+
const versionCheck = checkPiVersion(versionProbe.stdout ?? "");
|
|
153
|
+
if (!versionCheck.ok) fail(versionCheck.message, 1);
|
|
154
|
+
|
|
155
|
+
if (args.version) {
|
|
156
|
+
process.stdout.write(`${describeVersion({ gentlePiVersion: ownPackageVersion(), piVersion: versionCheck.version, home })}\n`);
|
|
157
|
+
process.exit(0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Isolated-home bootstrap: only on a home gentle-shell has not seen before
|
|
161
|
+
// (link never bootstraps — it reuses the user's own pi agent home as-is).
|
|
162
|
+
if ((home.mode === "isolated" || home.mode === "path") && !existsSync(home.dir)) {
|
|
163
|
+
mkdirSync(home.dir, { recursive: true });
|
|
164
|
+
await installIsolatedTuiModeSetting(home.dir);
|
|
165
|
+
process.stderr.write(`gentle-shell: using a separate home at ${home.dir}. Run 'gentle-shell --link' to reuse your pi sign-ins and chats.\n`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let linkDeclaresGentlePi = false;
|
|
169
|
+
if (home.mode === "link") {
|
|
170
|
+
const settingsText = readJsonIfExists(join(home.dir, "settings.json"));
|
|
171
|
+
linkDeclaresGentlePi = settingsDeclareGentlePi(settingsText);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const invocation = buildPiInvocation({
|
|
175
|
+
runtime,
|
|
176
|
+
home,
|
|
177
|
+
packageRoot,
|
|
178
|
+
settingsDeclareGentlePi: home.mode === "link" ? linkDeclaresGentlePi : false,
|
|
179
|
+
passthrough: args.passthrough,
|
|
180
|
+
piSubcommand: args.piSubcommand,
|
|
181
|
+
baseEnv: process.env,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const launchPlan = planSpawn({ command: invocation.command, args: invocation.args, platform: process.platform });
|
|
185
|
+
const child = spawn(launchPlan.command, launchPlan.args, { stdio: "inherit", env: invocation.env, shell: launchPlan.shell });
|
|
186
|
+
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
187
|
+
process.on(signal, () => child.kill(signal));
|
|
188
|
+
}
|
|
189
|
+
child.on("error", (error) => fail(`Could not start pi: ${error.message}`, 1));
|
|
190
|
+
child.on("exit", (code, signal) => {
|
|
191
|
+
process.exit(signal ? signalExitCode(signal) : (code ?? 1));
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
main().catch((error) => {
|
|
196
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="760" viewBox="0 0 960 760" role="img" aria-labelledby="odd-title odd-desc">
|
|
2
|
+
<title id="odd-title">Organic Driven Development workflow</title>
|
|
3
|
+
<desc id="odd-desc">One feature moves through the seven ODD protocol steps. Authorize, explore, resolve uncertainty, then classify: small understood work stays light with no durable artifacts, while substantial work is tracked in one feature document before the first write. Both paths implement task by task and close with verified proof. The same feature document carries progress across sessions so work resumes instead of restarting.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="odd-bg" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#100c15"/><stop offset="1" stop-color="#21101f"/></linearGradient>
|
|
6
|
+
<marker id="odd-arrow" markerUnits="userSpaceOnUse" markerWidth="10" markerHeight="10" viewBox="0 0 10 10" refX="10" refY="5" orient="auto"><path d="M0 0 10 5 0 10z" fill="#f095c8"/></marker>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="960" height="760" rx="20" fill="url(#odd-bg)"/>
|
|
9
|
+
<text x="40" y="65" fill="#fff7f1" font-family="Arial, Helvetica, sans-serif" font-size="44" font-weight="700">Explore, track, implement.</text>
|
|
10
|
+
<text x="40" y="120" fill="#d7a0b8" font-family="Arial, Helvetica, sans-serif" font-size="44" font-weight="700">Resume without ceremony.</text>
|
|
11
|
+
<g fill="#1c1420" stroke="#d7a0b8" stroke-width="2">
|
|
12
|
+
<rect x="40" y="170" width="196" height="120" rx="16"/>
|
|
13
|
+
<rect x="268" y="170" width="196" height="120" rx="16"/>
|
|
14
|
+
<rect x="496" y="170" width="196" height="120" rx="16"/>
|
|
15
|
+
<rect x="724" y="170" width="196" height="120" rx="16"/>
|
|
16
|
+
<rect x="724" y="330" width="196" height="120" rx="16" fill="#2a1426" stroke="#f095c8" stroke-width="3"/>
|
|
17
|
+
<rect x="610" y="490" width="196" height="120" rx="16"/>
|
|
18
|
+
<rect x="268" y="490" width="196" height="120" rx="16"/>
|
|
19
|
+
</g>
|
|
20
|
+
<rect x="496" y="330" width="196" height="120" rx="16" fill="#18121b" stroke="#d7a0b8" stroke-width="2" stroke-dasharray="6 6"/>
|
|
21
|
+
<g fill="none" stroke="#f095c8" stroke-width="3" stroke-linecap="round" marker-end="url(#odd-arrow)">
|
|
22
|
+
<path d="M236 230H268"/>
|
|
23
|
+
<path d="M464 230H496"/>
|
|
24
|
+
<path d="M692 230H724"/>
|
|
25
|
+
<path d="M822 290V330"/>
|
|
26
|
+
<path d="M822 290V310H594V330"/>
|
|
27
|
+
<path d="M708 470V490"/>
|
|
28
|
+
<path d="M610 550H464"/>
|
|
29
|
+
</g>
|
|
30
|
+
<g fill="none" stroke="#f095c8" stroke-width="3" stroke-linecap="round">
|
|
31
|
+
<path d="M594 450V470H708"/>
|
|
32
|
+
<path d="M822 450V470H708"/>
|
|
33
|
+
</g>
|
|
34
|
+
<g font-family="Arial, Helvetica, sans-serif" font-size="20" fill="#d7a0b8" opacity="0.85">
|
|
35
|
+
<text x="56" y="198">01</text>
|
|
36
|
+
<text x="284" y="198">02</text>
|
|
37
|
+
<text x="512" y="198">03</text>
|
|
38
|
+
<text x="740" y="198">04</text>
|
|
39
|
+
<text x="740" y="358">05</text>
|
|
40
|
+
<text x="626" y="518">06</text>
|
|
41
|
+
<text x="284" y="518">07</text>
|
|
42
|
+
</g>
|
|
43
|
+
<g font-family="Arial, Helvetica, sans-serif" text-anchor="middle">
|
|
44
|
+
<g fill="#fff7f1" font-size="30" font-weight="700">
|
|
45
|
+
<text x="138" y="222">Authorize</text>
|
|
46
|
+
<text x="366" y="222">Explore</text>
|
|
47
|
+
<text x="594" y="222">Resolve</text>
|
|
48
|
+
<text x="822" y="222">Classify</text>
|
|
49
|
+
<text x="822" y="382">Track</text>
|
|
50
|
+
<text x="594" y="382">Stay light</text>
|
|
51
|
+
<text x="708" y="542">Implement</text>
|
|
52
|
+
<text x="366" y="542">Close</text>
|
|
53
|
+
</g>
|
|
54
|
+
<g fill="#d7a0b8" font-size="22">
|
|
55
|
+
<text x="138" y="262">read-only</text>
|
|
56
|
+
<text x="366" y="262">code and needs</text>
|
|
57
|
+
<text x="594" y="262">uncertainty</text>
|
|
58
|
+
<text x="822" y="262">substantial?</text>
|
|
59
|
+
<text x="822" y="422">one document</text>
|
|
60
|
+
<text x="594" y="422">small work</text>
|
|
61
|
+
<text x="708" y="582">task by task</text>
|
|
62
|
+
<text x="366" y="582">verified proof</text>
|
|
63
|
+
</g>
|
|
64
|
+
</g>
|
|
65
|
+
<g font-family="Arial, Helvetica, sans-serif" font-size="22" fill="#d7a0b8">
|
|
66
|
+
<text x="708" y="302" text-anchor="middle">small</text>
|
|
67
|
+
<text x="838" y="316" text-anchor="start">substantial</text>
|
|
68
|
+
</g>
|
|
69
|
+
<rect x="40" y="650" width="880" height="90" rx="16" fill="#18121b" stroke="#d7a0b8" stroke-width="2" stroke-dasharray="8 7"/>
|
|
70
|
+
<g font-family="Arial, Helvetica, sans-serif" text-anchor="middle">
|
|
71
|
+
<text x="480" y="686" fill="#fff7f1" font-size="34" font-weight="700">Resume where you stopped</text>
|
|
72
|
+
<text x="480" y="722" fill="#d7a0b8" font-size="26">One feature document, mirrored in Engram across sessions.</text>
|
|
73
|
+
</g>
|
|
74
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|