@ttfw/envoi 1.0.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.
Files changed (283) hide show
  1. package/README.md +238 -0
  2. package/dist/commands/app.d.ts +2 -0
  3. package/dist/commands/app.d.ts.map +1 -0
  4. package/dist/commands/app.js +31 -0
  5. package/dist/commands/app.js.map +1 -0
  6. package/dist/commands/autonomy.d.ts +6 -0
  7. package/dist/commands/autonomy.d.ts.map +1 -0
  8. package/dist/commands/autonomy.js +89 -0
  9. package/dist/commands/autonomy.js.map +1 -0
  10. package/dist/commands/builder.d.ts +13 -0
  11. package/dist/commands/builder.d.ts.map +1 -0
  12. package/dist/commands/builder.js +142 -0
  13. package/dist/commands/builder.js.map +1 -0
  14. package/dist/commands/idea.d.ts +12 -0
  15. package/dist/commands/idea.d.ts.map +1 -0
  16. package/dist/commands/idea.js +79 -0
  17. package/dist/commands/idea.js.map +1 -0
  18. package/dist/commands/init.d.ts +18 -0
  19. package/dist/commands/init.d.ts.map +1 -0
  20. package/dist/commands/init.js +423 -0
  21. package/dist/commands/init.js.map +1 -0
  22. package/dist/commands/mode.d.ts +13 -0
  23. package/dist/commands/mode.d.ts.map +1 -0
  24. package/dist/commands/mode.js +96 -0
  25. package/dist/commands/mode.js.map +1 -0
  26. package/dist/commands/onboard.d.ts +37 -0
  27. package/dist/commands/onboard.d.ts.map +1 -0
  28. package/dist/commands/onboard.js +743 -0
  29. package/dist/commands/onboard.js.map +1 -0
  30. package/dist/commands/pr-note.d.ts +8 -0
  31. package/dist/commands/pr-note.d.ts.map +1 -0
  32. package/dist/commands/pr-note.js +27 -0
  33. package/dist/commands/pr-note.js.map +1 -0
  34. package/dist/commands/undo.d.ts +7 -0
  35. package/dist/commands/undo.d.ts.map +1 -0
  36. package/dist/commands/undo.js +59 -0
  37. package/dist/commands/undo.js.map +1 -0
  38. package/dist/commands/update.d.ts +24 -0
  39. package/dist/commands/update.d.ts.map +1 -0
  40. package/dist/commands/update.js +248 -0
  41. package/dist/commands/update.js.map +1 -0
  42. package/dist/constants/report_codes.d.ts +29 -0
  43. package/dist/constants/report_codes.d.ts.map +1 -0
  44. package/dist/constants/report_codes.js +69 -0
  45. package/dist/constants/report_codes.js.map +1 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +675 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/lib/autonomy.d.ts +16 -0
  51. package/dist/lib/autonomy.d.ts.map +1 -0
  52. package/dist/lib/autonomy.js +38 -0
  53. package/dist/lib/autonomy.js.map +1 -0
  54. package/dist/lib/blocked.d.ts +87 -0
  55. package/dist/lib/blocked.d.ts.map +1 -0
  56. package/dist/lib/blocked.js +134 -0
  57. package/dist/lib/blocked.js.map +1 -0
  58. package/dist/lib/branding.d.ts +13 -0
  59. package/dist/lib/branding.d.ts.map +1 -0
  60. package/dist/lib/branding.js +19 -0
  61. package/dist/lib/branding.js.map +1 -0
  62. package/dist/lib/claude.d.ts +42 -0
  63. package/dist/lib/claude.d.ts.map +1 -0
  64. package/dist/lib/claude.js +291 -0
  65. package/dist/lib/claude.js.map +1 -0
  66. package/dist/lib/config.d.ts +71 -0
  67. package/dist/lib/config.d.ts.map +1 -0
  68. package/dist/lib/config.js +410 -0
  69. package/dist/lib/config.js.map +1 -0
  70. package/dist/lib/diff.d.ts +150 -0
  71. package/dist/lib/diff.d.ts.map +1 -0
  72. package/dist/lib/diff.js +257 -0
  73. package/dist/lib/diff.js.map +1 -0
  74. package/dist/lib/doctor.d.ts +67 -0
  75. package/dist/lib/doctor.d.ts.map +1 -0
  76. package/dist/lib/doctor.js +211 -0
  77. package/dist/lib/doctor.js.map +1 -0
  78. package/dist/lib/fingerprint.d.ts +27 -0
  79. package/dist/lib/fingerprint.d.ts.map +1 -0
  80. package/dist/lib/fingerprint.js +116 -0
  81. package/dist/lib/fingerprint.js.map +1 -0
  82. package/dist/lib/fs.d.ts +93 -0
  83. package/dist/lib/fs.d.ts.map +1 -0
  84. package/dist/lib/fs.js +179 -0
  85. package/dist/lib/fs.js.map +1 -0
  86. package/dist/lib/git.d.ts +177 -0
  87. package/dist/lib/git.d.ts.map +1 -0
  88. package/dist/lib/git.js +355 -0
  89. package/dist/lib/git.js.map +1 -0
  90. package/dist/lib/git_branching.d.ts +84 -0
  91. package/dist/lib/git_branching.d.ts.map +1 -0
  92. package/dist/lib/git_branching.js +327 -0
  93. package/dist/lib/git_branching.js.map +1 -0
  94. package/dist/lib/gitignore.d.ts +26 -0
  95. package/dist/lib/gitignore.d.ts.map +1 -0
  96. package/dist/lib/gitignore.js +119 -0
  97. package/dist/lib/gitignore.js.map +1 -0
  98. package/dist/lib/guardrails.d.ts +232 -0
  99. package/dist/lib/guardrails.d.ts.map +1 -0
  100. package/dist/lib/guardrails.js +323 -0
  101. package/dist/lib/guardrails.js.map +1 -0
  102. package/dist/lib/history.d.ts +110 -0
  103. package/dist/lib/history.d.ts.map +1 -0
  104. package/dist/lib/history.js +236 -0
  105. package/dist/lib/history.js.map +1 -0
  106. package/dist/lib/index.d.ts +29 -0
  107. package/dist/lib/index.d.ts.map +1 -0
  108. package/dist/lib/index.js +29 -0
  109. package/dist/lib/index.js.map +1 -0
  110. package/dist/lib/json-extract.d.ts +42 -0
  111. package/dist/lib/json-extract.d.ts.map +1 -0
  112. package/dist/lib/json-extract.js +201 -0
  113. package/dist/lib/json-extract.js.map +1 -0
  114. package/dist/lib/judge.d.ts +237 -0
  115. package/dist/lib/judge.d.ts.map +1 -0
  116. package/dist/lib/judge.js +501 -0
  117. package/dist/lib/judge.js.map +1 -0
  118. package/dist/lib/lock.d.ts +79 -0
  119. package/dist/lib/lock.d.ts.map +1 -0
  120. package/dist/lib/lock.js +254 -0
  121. package/dist/lib/lock.js.map +1 -0
  122. package/dist/lib/migration.d.ts +9 -0
  123. package/dist/lib/migration.d.ts.map +1 -0
  124. package/dist/lib/migration.js +74 -0
  125. package/dist/lib/migration.js.map +1 -0
  126. package/dist/lib/paths.d.ts +18 -0
  127. package/dist/lib/paths.d.ts.map +1 -0
  128. package/dist/lib/paths.js +27 -0
  129. package/dist/lib/paths.js.map +1 -0
  130. package/dist/lib/preflight.d.ts +33 -0
  131. package/dist/lib/preflight.d.ts.map +1 -0
  132. package/dist/lib/preflight.js +177 -0
  133. package/dist/lib/preflight.js.map +1 -0
  134. package/dist/lib/prompt_budget.d.ts +18 -0
  135. package/dist/lib/prompt_budget.d.ts.map +1 -0
  136. package/dist/lib/prompt_budget.js +36 -0
  137. package/dist/lib/prompt_budget.js.map +1 -0
  138. package/dist/lib/report.d.ts +102 -0
  139. package/dist/lib/report.d.ts.map +1 -0
  140. package/dist/lib/report.js +347 -0
  141. package/dist/lib/report.js.map +1 -0
  142. package/dist/lib/reviewer-flow.d.ts +80 -0
  143. package/dist/lib/reviewer-flow.d.ts.map +1 -0
  144. package/dist/lib/reviewer-flow.js +138 -0
  145. package/dist/lib/reviewer-flow.js.map +1 -0
  146. package/dist/lib/reviewer.d.ts +53 -0
  147. package/dist/lib/reviewer.d.ts.map +1 -0
  148. package/dist/lib/reviewer.js +199 -0
  149. package/dist/lib/reviewer.js.map +1 -0
  150. package/dist/lib/risk.d.ts +127 -0
  151. package/dist/lib/risk.d.ts.map +1 -0
  152. package/dist/lib/risk.js +192 -0
  153. package/dist/lib/risk.js.map +1 -0
  154. package/dist/lib/rollback.d.ts +143 -0
  155. package/dist/lib/rollback.d.ts.map +1 -0
  156. package/dist/lib/rollback.js +244 -0
  157. package/dist/lib/rollback.js.map +1 -0
  158. package/dist/lib/schema.d.ts +47 -0
  159. package/dist/lib/schema.d.ts.map +1 -0
  160. package/dist/lib/schema.js +91 -0
  161. package/dist/lib/schema.js.map +1 -0
  162. package/dist/lib/scope.d.ts +89 -0
  163. package/dist/lib/scope.d.ts.map +1 -0
  164. package/dist/lib/scope.js +135 -0
  165. package/dist/lib/scope.js.map +1 -0
  166. package/dist/lib/self_update.d.ts +13 -0
  167. package/dist/lib/self_update.d.ts.map +1 -0
  168. package/dist/lib/self_update.js +172 -0
  169. package/dist/lib/self_update.js.map +1 -0
  170. package/dist/lib/state.d.ts +143 -0
  171. package/dist/lib/state.d.ts.map +1 -0
  172. package/dist/lib/state.js +258 -0
  173. package/dist/lib/state.js.map +1 -0
  174. package/dist/lib/tick.d.ts +310 -0
  175. package/dist/lib/tick.d.ts.map +1 -0
  176. package/dist/lib/tick.js +424 -0
  177. package/dist/lib/tick.js.map +1 -0
  178. package/dist/lib/transport.d.ts +145 -0
  179. package/dist/lib/transport.d.ts.map +1 -0
  180. package/dist/lib/transport.js +237 -0
  181. package/dist/lib/transport.js.map +1 -0
  182. package/dist/lib/verdict_labels.d.ts +5 -0
  183. package/dist/lib/verdict_labels.d.ts.map +1 -0
  184. package/dist/lib/verdict_labels.js +25 -0
  185. package/dist/lib/verdict_labels.js.map +1 -0
  186. package/dist/lib/verify-safety.d.ts +63 -0
  187. package/dist/lib/verify-safety.d.ts.map +1 -0
  188. package/dist/lib/verify-safety.js +123 -0
  189. package/dist/lib/verify-safety.js.map +1 -0
  190. package/dist/lib/verify.d.ts +139 -0
  191. package/dist/lib/verify.d.ts.map +1 -0
  192. package/dist/lib/verify.js +311 -0
  193. package/dist/lib/verify.js.map +1 -0
  194. package/dist/lib/workspace_state.d.ts +79 -0
  195. package/dist/lib/workspace_state.d.ts.map +1 -0
  196. package/dist/lib/workspace_state.js +283 -0
  197. package/dist/lib/workspace_state.js.map +1 -0
  198. package/dist/runner/builder.d.ts +58 -0
  199. package/dist/runner/builder.d.ts.map +1 -0
  200. package/dist/runner/builder.js +775 -0
  201. package/dist/runner/builder.js.map +1 -0
  202. package/dist/runner/builder_parse.d.ts +37 -0
  203. package/dist/runner/builder_parse.d.ts.map +1 -0
  204. package/dist/runner/builder_parse.js +76 -0
  205. package/dist/runner/builder_parse.js.map +1 -0
  206. package/dist/runner/index.d.ts +9 -0
  207. package/dist/runner/index.d.ts.map +1 -0
  208. package/dist/runner/index.js +7 -0
  209. package/dist/runner/index.js.map +1 -0
  210. package/dist/runner/loop.d.ts +51 -0
  211. package/dist/runner/loop.d.ts.map +1 -0
  212. package/dist/runner/loop.js +221 -0
  213. package/dist/runner/loop.js.map +1 -0
  214. package/dist/runner/orchestrator.d.ts +67 -0
  215. package/dist/runner/orchestrator.d.ts.map +1 -0
  216. package/dist/runner/orchestrator.js +376 -0
  217. package/dist/runner/orchestrator.js.map +1 -0
  218. package/dist/runner/tick.d.ts +10 -0
  219. package/dist/runner/tick.d.ts.map +1 -0
  220. package/dist/runner/tick.js +1639 -0
  221. package/dist/runner/tick.js.map +1 -0
  222. package/dist/types/blocked.d.ts +52 -0
  223. package/dist/types/blocked.d.ts.map +1 -0
  224. package/dist/types/blocked.js +8 -0
  225. package/dist/types/blocked.js.map +1 -0
  226. package/dist/types/builder.d.ts +25 -0
  227. package/dist/types/builder.d.ts.map +1 -0
  228. package/dist/types/builder.js +7 -0
  229. package/dist/types/builder.js.map +1 -0
  230. package/dist/types/claude.d.ts +86 -0
  231. package/dist/types/claude.d.ts.map +1 -0
  232. package/dist/types/claude.js +48 -0
  233. package/dist/types/claude.js.map +1 -0
  234. package/dist/types/config.d.ts +384 -0
  235. package/dist/types/config.d.ts.map +1 -0
  236. package/dist/types/config.js +7 -0
  237. package/dist/types/config.js.map +1 -0
  238. package/dist/types/index.d.ts +18 -0
  239. package/dist/types/index.d.ts.map +1 -0
  240. package/dist/types/index.js +8 -0
  241. package/dist/types/index.js.map +1 -0
  242. package/dist/types/lock.d.ts +21 -0
  243. package/dist/types/lock.d.ts.map +1 -0
  244. package/dist/types/lock.js +8 -0
  245. package/dist/types/lock.js.map +1 -0
  246. package/dist/types/preflight.d.ts +49 -0
  247. package/dist/types/preflight.d.ts.map +1 -0
  248. package/dist/types/preflight.js +8 -0
  249. package/dist/types/preflight.js.map +1 -0
  250. package/dist/types/report.d.ts +161 -0
  251. package/dist/types/report.d.ts.map +1 -0
  252. package/dist/types/report.js +8 -0
  253. package/dist/types/report.js.map +1 -0
  254. package/dist/types/reviewer.d.ts +66 -0
  255. package/dist/types/reviewer.d.ts.map +1 -0
  256. package/dist/types/reviewer.js +5 -0
  257. package/dist/types/reviewer.js.map +1 -0
  258. package/dist/types/state.d.ts +124 -0
  259. package/dist/types/state.d.ts.map +1 -0
  260. package/dist/types/state.js +20 -0
  261. package/dist/types/state.js.map +1 -0
  262. package/dist/types/task.d.ts +117 -0
  263. package/dist/types/task.d.ts.map +1 -0
  264. package/dist/types/task.js +7 -0
  265. package/dist/types/task.js.map +1 -0
  266. package/dist/types/workspace_state.d.ts +125 -0
  267. package/dist/types/workspace_state.d.ts.map +1 -0
  268. package/dist/types/workspace_state.js +10 -0
  269. package/dist/types/workspace_state.js.map +1 -0
  270. package/envoi.config.json +191 -0
  271. package/package.json +52 -0
  272. package/relais/prompts/.gitkeep +0 -0
  273. package/relais/prompts/builder.system.txt +13 -0
  274. package/relais/prompts/builder.user.txt +15 -0
  275. package/relais/prompts/orchestrator.system.txt +37 -0
  276. package/relais/prompts/orchestrator.user.txt +34 -0
  277. package/relais/prompts/reviewer.system.txt +33 -0
  278. package/relais/prompts/reviewer.user.txt +35 -0
  279. package/relais/schemas/.gitkeep +0 -0
  280. package/relais/schemas/builder_result.schema.json +29 -0
  281. package/relais/schemas/report.schema.json +195 -0
  282. package/relais/schemas/reviewer_result.schema.json +70 -0
  283. package/relais/schemas/task.schema.json +155 -0
package/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # Envoi
2
+
3
+ Deterministic repo-local orchestration for AI implementation loops: **planner -> builder -> checker**.
4
+
5
+ Envoi is for teams that want:
6
+ - fast delivery with AI agents,
7
+ - strict safety boundaries,
8
+ - auditable artifacts per cycle,
9
+ - low-friction human control.
10
+
11
+ ## Product Narrative
12
+ - Product name: **Envoi**.
13
+ - `tick` is the core mechanic: one bounded execution cycle.
14
+ - Human role stays plain: decide, approve, unblock.
15
+ - “Taste” appears in microcopy, not in role names.
16
+
17
+ Human-facing guidance uses:
18
+ - `Needs you: choose direction.`
19
+ - `Your call: accept, adjust, or undo.`
20
+ - `Taste check: does this feel right?` (only when necessary)
21
+ - `Waiting for you`
22
+
23
+ ## Core Invariant
24
+ `envoi tick` executes exactly one finite cycle:
25
+ 1. lock + preflight,
26
+ 2. one planner decision,
27
+ 3. one builder execution,
28
+ 4. one checker pass,
29
+ 5. one persisted `REPORT.json` (+ optional `REPORT.md`).
30
+
31
+ Use `envoi loop` only when you intentionally want multiple ticks.
32
+
33
+ ## Command Surface (7 Verbs)
34
+ - `envoi start` — one-command scaffold + guided onboarding
35
+ - `envoi brief` — onboarding alias (same flow, no tour prompt)
36
+ - `envoi tick` — one bounded cycle (plan -> edit -> verify -> stop)
37
+ - `envoi loop` — run multiple ticks until boundary
38
+ - `envoi status` — current state + context
39
+ - `envoi check` — environment + constraints health
40
+ - `envoi undo` — rollback tracked files to last recorded base snapshot
41
+
42
+ Optional bridge:
43
+ - `envoi app` — open desktop app when available, otherwise show benefits + link
44
+
45
+ ### Compatibility During Transition
46
+ Legacy command aliases are still accepted and automatically mapped to the new command set.
47
+
48
+ Existing installs can move forward with:
49
+ - `envoi update --dry-run`
50
+ - `envoi update --yes`
51
+
52
+ ## Quickstart
53
+ ### One command for Claude/Codex
54
+ ```bash
55
+ npx -y @ttfw/envoi@latest start
56
+ ```
57
+
58
+ This runs Envoi without a global install and starts guided onboarding in the current repo.
59
+
60
+ ### 1) Install
61
+ Development-linked install:
62
+ ```bash
63
+ cd /path/to/envoi
64
+ pnpm build
65
+ pnpm link --global
66
+ ```
67
+
68
+ Repo-local install:
69
+ ```bash
70
+ cd /path/to/target-repo
71
+ pnpm add /path/to/envoi
72
+ ```
73
+
74
+ ### 2) Run guided onboarding
75
+ ```bash
76
+ cd /path/to/target-repo
77
+ envoi start
78
+ ```
79
+
80
+ `envoi start` handles onboarding end-to-end:
81
+ 1. asks `Tour` vs `Setup`,
82
+ 2. captures PRD/context (`--prd-file`, stdin, discovered file, editor, or inline paste),
83
+ 3. configures mode (`task|milestone|autonomous`) and builder (`cursor|claude_code`),
84
+ 4. optionally enables reviewer (`none|codex`),
85
+ 5. runs role connectivity checks,
86
+ 6. writes `ROADMAP.json` from the planner snapshot,
87
+ 7. asks whether to start execution now.
88
+
89
+ ### 3) Run manually later (optional)
90
+ ```bash
91
+ envoi check
92
+ envoi tick
93
+ # or
94
+ envoi loop --mode milestone
95
+ ```
96
+ ## Loop Modes + Follow-up Paths
97
+ - `task`: stops at task completion boundary
98
+ - `milestone`: stops at milestone boundary/completion
99
+ - `autonomous`: continues across milestones until blocked/limit/signal
100
+
101
+ Boundary outputs are explicit:
102
+ - task/milestone => `STANDBY` with next command
103
+ - autonomous => continues unless safety boundary triggers
104
+
105
+ ## PM-Style Idea Intake (No Technical Burden on User)
106
+ Capture new ideas between boundaries:
107
+ ```bash
108
+ envoi idea "Preview changes before publish"
109
+ envoi idea "Need staging validation faster" --testability soon --target-by 2026-03-01
110
+ ```
111
+
112
+ Ideas are persisted in state (`idea_inbox`) and fed into planner decisions.
113
+ Planner should choose sequencing, scope, and timing; user should not be forced into low-level technical choices.
114
+ Planner snapshots are written to ROADMAP.json and refreshed by onboarding when needed.
115
+
116
+ ## Optional Reviewer Gate
117
+ When configured, reviewer can:
118
+ - allow proceed,
119
+ - force stop before build (`STOP_REVIEWER_FORCED_PATCH`),
120
+ - ask product question (`STOP_REVIEWER_ASK_QUESTION`).
121
+
122
+ This reduces rework on touchy tasks while keeping human control clear.
123
+
124
+ ## Verdict Labels (Display Layer)
125
+ Canonical machine values remain unchanged (`success|stop|blocked`, `STOP_*`, `BLOCKED_*`).
126
+ Display labels in CLI/report copy map to:
127
+ - `CLEARED`
128
+ - `STANDBY`
129
+ - `BLOCKED`
130
+ - `OUT_OF_BOUNDS`
131
+ - `LIMIT_HIT`
132
+ - `ROLLED_BACK`
133
+
134
+ ## Token Strategy + Telemetry
135
+ Envoi minimizes context waste by:
136
+ - compacting oversized prompt sections,
137
+ - bounding idea/question payloads,
138
+ - truncating oversized warning payloads,
139
+ - using compact machine contracts for builder dispatch.
140
+
141
+ Token feedback is surfaced at:
142
+ - ORCHESTRATE,
143
+ - BUILD,
144
+ - per tick total,
145
+ - cumulative loop totals.
146
+
147
+ If provider usage metadata is missing, `n/a` is shown.
148
+
149
+ ## Update Strategy
150
+ ```bash
151
+ envoi update --dry-run
152
+ envoi update --yes
153
+ ```
154
+
155
+ Options:
156
+ - `--mode auto|linked|registry`
157
+ - `--manager pnpm|npm|yarn|bun`
158
+ - `--dry-run`
159
+ - `--yes`
160
+
161
+ Linked-install behavior:
162
+ - `envoi tick` and `envoi loop` refresh stale linked builds before execution.
163
+ - if linked source refreshes between loop ticks, loop stops at safe boundary (`self_update`) so next launch uses fresh code.
164
+
165
+ ## Config + Workspace Migration
166
+ New defaults:
167
+ - `envoi.config.json`
168
+ - `envoi/` workspace directory
169
+
170
+ Legacy layout support:
171
+ - Envoi auto-detects prior config/workspace layouts.
172
+ - on load, Envoi migrates prior defaults to new paths and writes `envoi.config.json`.
173
+ - prior config names remain compatible and continue to load.
174
+
175
+ ## Safety vs Speed
176
+ ```bash
177
+ envoi autonomy --set strict
178
+ envoi autonomy --set balanced
179
+ envoi autonomy --set fast
180
+ ```
181
+
182
+ - `strict`: more friction, highest safety bias
183
+ - `balanced`: recommended default
184
+ - `fast`: fewer prompts, still constrained by guardrails
185
+
186
+ Repeated proceed prompts usually come from host CLI safety boundaries (filesystem/network/command risk), not only Envoi itself.
187
+
188
+ ## CLI Reference
189
+ Global option:
190
+ - `envoi -c <path>` / `envoi --config <path>`
191
+
192
+ Commands:
193
+ - `envoi start`
194
+ - `envoi brief`
195
+ - `envoi tick`
196
+ - `envoi loop --mode task|milestone|autonomous --max-ticks <n>`
197
+ - `envoi status`
198
+ - `envoi check`
199
+ - `envoi undo`
200
+ - `envoi app`
201
+ - `envoi mode --set <mode>`
202
+ - `envoi builder --set <builder>`
203
+ - `envoi autonomy --set strict|balanced|fast`
204
+ - `envoi idea "<text>" [--target-by <date>] [--testability soon|later|unknown]`
205
+ - `envoi update`
206
+ - `envoi pr-note`
207
+
208
+ Help:
209
+ - `envoi --help`
210
+ - `envoi <command> --help`
211
+
212
+ ## Runtime Artifacts
213
+ Default runtime files live under `envoi/`:
214
+ - `STATE.json`
215
+ - `TASK.json`
216
+ - `REPORT.json`
217
+ - `REPORT.md` (optional)
218
+ - `BLOCKED.json`
219
+ - `history/<run_id>/...`
220
+
221
+ ## PR Attribution
222
+ ```bash
223
+ envoi pr-note
224
+ envoi pr-note --format text
225
+ ```
226
+
227
+ ## Development
228
+ ```bash
229
+ pnpm build
230
+ pnpm test
231
+ pnpm typecheck
232
+ ```
233
+
234
+ ## Additional Docs
235
+ - `docs/DOGFOOD.md`
236
+ - `docs/NEW-PLAN.md`
237
+ - `ROADMAP.json`
238
+ - `pilot/` (legacy workflow docs)
@@ -0,0 +1,2 @@
1
+ export declare function appCommand(): Promise<void>;
2
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/commands/app.ts"],"names":[],"mappings":"AAoBA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAYhD"}
@@ -0,0 +1,31 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { spawnSync } from 'node:child_process';
3
+ const APP_URL = 'https://envoi.app';
4
+ function openDesktopApp() {
5
+ if (process.platform === 'darwin') {
6
+ const hasBundle = existsSync('/Applications/Envoi.app') || existsSync(`${process.env.HOME ?? ''}/Applications/Envoi.app`);
7
+ if (!hasBundle)
8
+ return false;
9
+ const result = spawnSync('open', ['-a', 'Envoi'], { stdio: 'inherit' });
10
+ return result.status === 0;
11
+ }
12
+ if (process.platform === 'win32') {
13
+ const result = spawnSync('cmd', ['/c', 'start', '', 'envoi:'], { stdio: 'ignore' });
14
+ return result.status === 0;
15
+ }
16
+ const result = spawnSync('xdg-open', ['envoi://'], { stdio: 'ignore' });
17
+ return result.status === 0;
18
+ }
19
+ export async function appCommand() {
20
+ if (openDesktopApp()) {
21
+ console.log('Opened Envoi desktop app.');
22
+ return;
23
+ }
24
+ console.log('Envoi desktop app is not installed or not registered on this machine.');
25
+ console.log('Why use it:');
26
+ console.log('- Native timeline for ticks, checkpoints, and rollbacks.');
27
+ console.log('- Faster approvals with a dedicated human-in-the-loop surface.');
28
+ console.log('- Shared team visibility across planner, builder, and checker outcomes.');
29
+ console.log(`Learn more: ${APP_URL}`);
30
+ }
31
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/commands/app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,OAAO,GAAG,mBAAmB,CAAC;AAEpC,SAAS,cAAc;IACrB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,UAAU,CAAC,yBAAyB,CAAC,IAAI,UAAU,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,yBAAyB,CAAC,CAAC;QAC1H,IAAI,CAAC,SAAS;YAAE,OAAO,KAAK,CAAC;QAC7B,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpF,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxE,OAAO,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,cAAc,EAAE,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,uEAAuE,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,0DAA0D,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,yEAAyE,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,EAAE,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function autonomyCommand(options: {
2
+ configPath?: string;
3
+ set?: string;
4
+ json?: boolean;
5
+ }): Promise<void>;
6
+ //# sourceMappingURL=autonomy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autonomy.d.ts","sourceRoot":"","sources":["../../src/commands/autonomy.ts"],"names":[],"mappings":"AAiDA,wBAAsB,eAAe,CAAC,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoDnH"}
@@ -0,0 +1,89 @@
1
+ import { resolve } from 'node:path';
2
+ import readline from 'node:readline/promises';
3
+ import { stdin as input, stdout as output } from 'node:process';
4
+ import { atomicReadJson, atomicWriteJson } from '../lib/fs.js';
5
+ import { CONFIG_FILE_NAME, ConfigError, findConfigFile } from '../lib/config.js';
6
+ import { describeAutonomyProfile } from '../lib/autonomy.js';
7
+ function parseProfile(value) {
8
+ if (!value)
9
+ return null;
10
+ if (value === 'strict' || value === 'balanced' || value === 'fast')
11
+ return value;
12
+ throw new Error(`Invalid profile: ${value}. Must be 'strict', 'balanced', or 'fast'.`);
13
+ }
14
+ async function resolveConfigPath(configPath) {
15
+ if (configPath)
16
+ return resolve(configPath);
17
+ const found = await findConfigFile();
18
+ if (!found) {
19
+ throw new ConfigError(`Configuration file not found. Expected ${CONFIG_FILE_NAME} in current directory or parent directories.`);
20
+ }
21
+ return found;
22
+ }
23
+ async function promptProfile(current) {
24
+ const rl = readline.createInterface({ input, output });
25
+ try {
26
+ const options = ['strict', 'balanced', 'fast'];
27
+ console.log('\nChoose autonomy profile:');
28
+ options.forEach((profile, index) => {
29
+ const suffix = profile === current ? ' (current)' : '';
30
+ console.log(` ${index + 1}. ${profile}${suffix}`);
31
+ console.log(` ${describeAutonomyProfile(profile)}`);
32
+ });
33
+ const answer = (await rl.question(`Profile [1-3] (default ${current}): `)).trim();
34
+ if (!answer)
35
+ return current;
36
+ const index = Number.parseInt(answer, 10);
37
+ if (index >= 1 && index <= options.length)
38
+ return options[index - 1];
39
+ if (answer === 'strict' || answer === 'balanced' || answer === 'fast')
40
+ return answer;
41
+ throw new Error('Invalid selection');
42
+ }
43
+ finally {
44
+ rl.close();
45
+ }
46
+ }
47
+ export async function autonomyCommand(options) {
48
+ const configPath = await resolveConfigPath(options.configPath);
49
+ const raw = await atomicReadJson(configPath);
50
+ const current = (raw.runner.autonomy?.profile ?? 'balanced');
51
+ const selected = parseProfile(options.set) ?? (input.isTTY ? await promptProfile(current) : current);
52
+ raw.runner = {
53
+ ...raw.runner,
54
+ autonomy: {
55
+ profile: selected,
56
+ command_trust: raw.runner.autonomy?.command_trust ?? [],
57
+ fs_policy: raw.runner.autonomy?.fs_policy ?? 'workspace_write',
58
+ network_policy: raw.runner.autonomy?.network_policy ?? 'deny',
59
+ },
60
+ };
61
+ if (selected === 'strict') {
62
+ raw.orchestrator = { ...raw.orchestrator, permission_mode: 'plan' };
63
+ raw.builder = {
64
+ ...raw.builder,
65
+ claude_code: { ...raw.builder.claude_code, permission_mode: 'plan' },
66
+ };
67
+ }
68
+ else if (selected === 'fast') {
69
+ raw.orchestrator = { ...raw.orchestrator, permission_mode: 'bypassPermissions' };
70
+ raw.builder = {
71
+ ...raw.builder,
72
+ claude_code: { ...raw.builder.claude_code, permission_mode: 'bypassPermissions' },
73
+ };
74
+ }
75
+ await atomicWriteJson(configPath, raw);
76
+ if (options.json) {
77
+ console.log(JSON.stringify({
78
+ profile: selected,
79
+ orchestrator_permission_mode: raw.orchestrator.permission_mode,
80
+ builder_permission_mode: raw.builder.claude_code.permission_mode,
81
+ }, null, 2));
82
+ return;
83
+ }
84
+ console.log(`\nAutonomy profile set to: ${selected}`);
85
+ console.log(describeAutonomyProfile(selected));
86
+ console.log(`Orchestrator permission mode: ${raw.orchestrator.permission_mode}`);
87
+ console.log(`Builder permission mode: ${raw.builder.claude_code.permission_mode}`);
88
+ }
89
+ //# sourceMappingURL=autonomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autonomy.js","sourceRoot":"","sources":["../../src/commands/autonomy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Interactive (or flag-based) builder selection.
3
+ *
4
+ * This is the "hands" engine choice:
5
+ * - claude_code: same engine family as orchestrator (works out of the box if Claude CLI is installed)
6
+ * - cursor: external driver (fast / auto-mode), requires builder.cursor config
7
+ */
8
+ export declare function builderCommand(options: {
9
+ configPath?: string;
10
+ set?: string;
11
+ json?: boolean;
12
+ }): Promise<void>;
13
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/commands/builder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4FH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiElH"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Interactive (or flag-based) builder selection.
3
+ *
4
+ * This is the "hands" engine choice:
5
+ * - claude_code: same engine family as orchestrator (works out of the box if Claude CLI is installed)
6
+ * - cursor: external driver (fast / auto-mode), requires builder.cursor config
7
+ */
8
+ import { resolve } from 'node:path';
9
+ import readline from 'node:readline/promises';
10
+ import { stdin as input, stdout as output } from 'node:process';
11
+ import { atomicReadJson, atomicWriteJson } from '../lib/fs.js';
12
+ import { CONFIG_FILE_NAME, ConfigError, findConfigFile, loadConfig, validateConfig } from '../lib/config.js';
13
+ import { CLI_NAME, WORKSPACE_DIR_NAME } from '../lib/branding.js';
14
+ function describeBuilder(choice) {
15
+ switch (choice) {
16
+ case 'cursor':
17
+ return {
18
+ title: 'Cursor agent (auto-mode) — fast + (almost) unlimited (recommended)',
19
+ desc: `Requires a headless driver that reads ${WORKSPACE_DIR_NAME}/TASK.json and writes BUILDER_RESULT.json.`,
20
+ };
21
+ case 'claude_code':
22
+ return {
23
+ title: 'Claude Code builder — same as orchestrator',
24
+ desc: 'Uses your Claude CLI directly. Slower but fewer external moving parts.',
25
+ };
26
+ }
27
+ }
28
+ async function resolveConfigPath(configPath) {
29
+ if (configPath)
30
+ return resolve(configPath);
31
+ const found = await findConfigFile();
32
+ if (!found) {
33
+ throw new ConfigError(`Configuration file not found. Expected ${CONFIG_FILE_NAME} in current directory or parent directories.`);
34
+ }
35
+ return found;
36
+ }
37
+ async function promptForBuilder(current) {
38
+ const rl = readline.createInterface({ input, output });
39
+ try {
40
+ console.log('\nChoose builder:');
41
+ const options = ['cursor', 'claude_code'];
42
+ options.forEach((b, i) => {
43
+ const meta = describeBuilder(b);
44
+ const suffix = current === b ? ' (current)' : '';
45
+ console.log(` ${i + 1}. ${b} — ${meta.title}${suffix}`);
46
+ console.log(` ${meta.desc}`);
47
+ });
48
+ const answer = (await rl.question(`Builder [1-2]${current ? ` (default ${current})` : ''}: `)).trim();
49
+ if (answer === '' && current)
50
+ return current;
51
+ const idx = Number.parseInt(answer, 10);
52
+ if (idx >= 1 && idx <= 2)
53
+ return options[idx - 1];
54
+ if (answer === 'cursor' || answer === 'claude_code')
55
+ return answer;
56
+ throw new Error('Invalid selection');
57
+ }
58
+ finally {
59
+ rl.close();
60
+ }
61
+ }
62
+ async function promptCursorConfig(existing) {
63
+ const rl = readline.createInterface({ input, output });
64
+ try {
65
+ console.log('\nCursor driver config (Cursor Agent):');
66
+ console.log(` This should point to the Cursor CLI executable (usually 'cursor'). ${CLI_NAME} will run: <command> <args...> <prompt>`);
67
+ const command = (await rl.question(` command (Cursor CLI, must support 'agent') [${existing?.command ?? 'cursor'}]: `)).trim() ||
68
+ (existing?.command ?? 'cursor');
69
+ const defaultArgs = existing?.args?.length
70
+ ? existing.args
71
+ : ['agent', '--print', '--output-format', 'text', '--workspace', '.', '--force'];
72
+ const argsLine = (await rl.question(` args (space-separated, no quoting) [${defaultArgs.join(' ')}]: `)).trim();
73
+ const args = argsLine ? argsLine.split(/\s+/).filter(Boolean) : defaultArgs;
74
+ const timeoutStr = (await rl.question(` timeout_seconds [${existing?.timeout_seconds ?? 300}]: `)).trim();
75
+ const timeout_seconds = timeoutStr ? Number.parseInt(timeoutStr, 10) : (existing?.timeout_seconds ?? 300);
76
+ const driverKind = (await rl.question(` driver_kind [${existing?.driver_kind ?? 'cursor_agent'}]: `)).trim() ||
77
+ (existing?.driver_kind ?? 'cursor_agent');
78
+ const output_file = (await rl.question(` output_file (relative to workspace_dir) [${existing?.output_file ?? 'BUILDER_RESULT.json'}]: `)).trim() ||
79
+ (existing?.output_file ?? 'BUILDER_RESULT.json');
80
+ return { driver_kind: driverKind, command, args, timeout_seconds, output_file };
81
+ }
82
+ finally {
83
+ rl.close();
84
+ }
85
+ }
86
+ export async function builderCommand(options) {
87
+ const config = await loadConfig(options.configPath);
88
+ const current = (config.builder.default_mode === 'cursor' ? 'cursor' : 'claude_code');
89
+ let next;
90
+ if (options.set) {
91
+ if (options.set !== 'cursor' && options.set !== 'claude_code') {
92
+ throw new Error(`Invalid builder: ${options.set}. Must be 'cursor' or 'claude_code'.`);
93
+ }
94
+ next = options.set;
95
+ }
96
+ else if (input.isTTY) {
97
+ next = await promptForBuilder(current);
98
+ }
99
+ else {
100
+ throw new Error('No --set provided and stdin is not a TTY (cannot prompt).');
101
+ }
102
+ const configPath = await resolveConfigPath(options.configPath);
103
+ const raw = await atomicReadJson(configPath);
104
+ if (next === 'claude_code') {
105
+ raw.builder = { ...raw.builder, default_mode: 'claude_code' };
106
+ }
107
+ else {
108
+ const cursor = input.isTTY ? await promptCursorConfig(raw.builder.cursor) : raw.builder.cursor;
109
+ if (!cursor) {
110
+ throw new Error('builder.cursor is required for cursor mode (cannot prompt in non-TTY).');
111
+ }
112
+ raw.builder = {
113
+ ...raw.builder,
114
+ default_mode: 'cursor',
115
+ cursor: {
116
+ driver_kind: cursor.driver_kind ?? 'cursor_agent',
117
+ command: cursor.command,
118
+ args: cursor.args,
119
+ timeout_seconds: cursor.timeout_seconds,
120
+ output_file: cursor.output_file,
121
+ },
122
+ };
123
+ }
124
+ // Validate before writing (keeps strict cursor requirements)
125
+ if (!validateConfig(raw)) {
126
+ throw new Error('Updated config is invalid (validateConfig failed).');
127
+ }
128
+ await atomicWriteJson(configPath, raw);
129
+ if (options.json) {
130
+ console.log(JSON.stringify({
131
+ default_mode: raw.builder.default_mode,
132
+ cursor_configured: raw.builder.cursor ? 'yes' : 'no',
133
+ }, null, 2));
134
+ return;
135
+ }
136
+ const meta = describeBuilder(next);
137
+ console.log(`\nBuilder set to: ${next} — ${meta.title}`);
138
+ if (next === 'cursor') {
139
+ console.log(`If your driver isn't installed/configured yet, the next tick will BLOCK until you fix builder.cursor.`);
140
+ }
141
+ }
142
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/commands/builder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,QAAQ,MAAM,wBAAwB,CAAC;AAC9C,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAE7G,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAIlE,SAAS,eAAe,CAAC,MAAqB;IAC5C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO;gBACL,KAAK,EAAE,oEAAoE;gBAC3E,IAAI,EAAE,yCAAyC,kBAAkB,4CAA4C;aAC9G,CAAC;QACJ,KAAK,aAAa;YAChB,OAAO;gBACL,KAAK,EAAE,4CAA4C;gBACnD,IAAI,EAAE,wEAAwE;aAC/E,CAAC;IACN,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,UAAmB;IAClD,IAAI,UAAU;QAAE,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,WAAW,CACnB,0CAA0C,gBAAgB,8CAA8C,CACzG,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,OAAuB;IACrD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,MAAM,OAAO,GAAoB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC3D,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvB,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,GAAG,MAAM,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtG,IAAI,MAAM,KAAK,EAAE,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACxC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,aAAa;YAAE,OAAO,MAAM,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,QAA2C;IAC3E,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,wEAAwE,QAAQ,yCAAyC,CAAC,CAAC;QACvI,MAAM,OAAO,GACX,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iDAAiD,QAAQ,EAAE,OAAO,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;YAC/G,CAAC,QAAQ,EAAE,OAAO,IAAI,QAAQ,CAAC,CAAC;QAClC,MAAM,WAAW,GAAG,QAAQ,EAAE,IAAI,EAAE,MAAM;YACxC,CAAC,CAAC,QAAQ,CAAC,IAAI;YACf,CAAC,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QACnF,MAAM,QAAQ,GACZ,CAAC,MAAM,EAAE,CAAC,QAAQ,CAChB,yCAAyC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CACpE,CAAC,CAAC,IAAI,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAC5E,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,QAAQ,EAAE,eAAe,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3G,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,eAAe,IAAI,GAAG,CAAC,CAAC;QAC1G,MAAM,UAAU,GACd,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,QAAQ,EAAE,WAAW,IAAI,cAAc,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;YAC1F,CAAC,QAAQ,EAAE,WAAW,IAAI,cAAc,CAAC,CAAC;QAC5C,MAAM,WAAW,GACf,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,QAAQ,EAAE,WAAW,IAAI,qBAAqB,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;YAC7H,CAAC,QAAQ,EAAE,WAAW,IAAI,qBAAqB,CAAC,CAAC;QAEnD,OAAO,EAAE,WAAW,EAAE,UAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC;IACzF,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA8D;IACjG,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAkB,CAAC;IAEvG,IAAI,IAAmB,CAAC;IACxB,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,IAAI,OAAO,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,KAAK,aAAa,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,CAAC,GAAG,sCAAsC,CAAC,CAAC;QACzF,CAAC;QACD,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC;IACrB,CAAC;SAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QACvB,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,cAAc,CAAc,UAAU,CAAC,CAAC;IAE1D,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;QAC3B,GAAG,CAAC,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QAC/F,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;QAC5F,CAAC;QACD,GAAG,CAAC,OAAO,GAAG;YACZ,GAAG,GAAG,CAAC,OAAO;YACd,YAAY,EAAE,QAAQ;YACtB,MAAM,EAAE;gBACN,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,cAAc;gBACjD,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,WAAW,EAAE,MAAM,CAAC,WAAW;aAChC;SACF,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,eAAe,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAEvC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;YACE,YAAY,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY;YACtC,iBAAiB,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;SACrD,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACzD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,uGAAuG,CAAC,CAAC;IACvH,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ export interface IdeaCommandOptions {
2
+ text?: string;
3
+ targetBy?: string;
4
+ testability?: string;
5
+ source?: string;
6
+ json?: boolean;
7
+ }
8
+ export declare function ideaCommand(options: IdeaCommandOptions, workspaceDir: string): Promise<{
9
+ saved: boolean;
10
+ count: number;
11
+ }>;
12
+ //# sourceMappingURL=idea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idea.d.ts","sourceRoot":"","sources":["../../src/commands/idea.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAyCD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,EAC3B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoC5C"}
@@ -0,0 +1,79 @@
1
+ import { stdin as input, stdout as output } from 'node:process';
2
+ import readline from 'node:readline/promises';
3
+ import { appendIdeaEntry, readWorkspaceState, writeWorkspaceState } from '../lib/workspace_state.js';
4
+ function normalizeTestability(value) {
5
+ if (!value || value.trim() === '')
6
+ return 'unknown';
7
+ if (value === 'soon' || value === 'later' || value === 'unknown')
8
+ return value;
9
+ throw new Error(`Invalid testability value: ${value}. Must be 'soon', 'later', or 'unknown'.`);
10
+ }
11
+ function normalizeSource(value) {
12
+ if (!value || value.trim() === '')
13
+ return 'cli';
14
+ if (value === 'interactive' || value === 'cli' || value === 'api')
15
+ return value;
16
+ throw new Error(`Invalid source value: ${value}. Must be 'interactive', 'cli', or 'api'.`);
17
+ }
18
+ async function promptIdeaText() {
19
+ if (!input.isTTY)
20
+ return '';
21
+ const rl = readline.createInterface({ input, output });
22
+ try {
23
+ return (await rl.question('Share a new idea for planning (Enter to skip): ')).trim();
24
+ }
25
+ finally {
26
+ rl.close();
27
+ }
28
+ }
29
+ async function promptTestability() {
30
+ if (!input.isTTY)
31
+ return 'unknown';
32
+ const rl = readline.createInterface({ input, output });
33
+ try {
34
+ const answer = (await rl.question('When should this be testable? [soon/later/unknown] (default unknown): '))
35
+ .trim()
36
+ .toLowerCase();
37
+ if (!answer)
38
+ return 'unknown';
39
+ if (answer === 'soon' || answer === 'later' || answer === 'unknown')
40
+ return answer;
41
+ throw new Error("Invalid choice. Use 'soon', 'later', or 'unknown'.");
42
+ }
43
+ finally {
44
+ rl.close();
45
+ }
46
+ }
47
+ export async function ideaCommand(options, workspaceDir) {
48
+ const explicitText = options.text?.trim() ?? '';
49
+ const ideaText = explicitText || (await promptIdeaText());
50
+ if (!ideaText) {
51
+ if (options.json) {
52
+ console.log(JSON.stringify({ saved: false, reason: 'empty_input' }, null, 2));
53
+ return { saved: false, count: 0 };
54
+ }
55
+ console.log('No idea captured.');
56
+ return { saved: false, count: 0 };
57
+ }
58
+ const source = normalizeSource(options.source ?? (explicitText ? 'cli' : 'interactive'));
59
+ const promptedTestability = options.testability === undefined && source === 'interactive' ? await promptTestability() : undefined;
60
+ const testability = normalizeTestability(options.testability ?? promptedTestability);
61
+ const currentState = await readWorkspaceState(workspaceDir);
62
+ const nextState = appendIdeaEntry(currentState, {
63
+ text: ideaText,
64
+ source,
65
+ target_by: options.targetBy ?? null,
66
+ testability_need: testability,
67
+ });
68
+ await writeWorkspaceState(workspaceDir, nextState);
69
+ const count = nextState.idea_inbox?.filter((entry) => entry.status === 'new').length ?? 0;
70
+ if (options.json) {
71
+ console.log(JSON.stringify({ saved: true, pending_new_ideas: count }, null, 2));
72
+ }
73
+ else {
74
+ console.log(`Idea saved to ${workspaceDir}/STATE.json`);
75
+ console.log(`Pending new ideas: ${count}`);
76
+ }
77
+ return { saved: true, count };
78
+ }
79
+ //# sourceMappingURL=idea.js.map