pipcode 0.0.0-stage → 2.1.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 (401) hide show
  1. package/LICENSE +47 -0
  2. package/README.md +44 -2
  3. package/auto.js +40 -0
  4. package/bin/setup.js +31 -0
  5. package/bin/teardown.js +18 -0
  6. package/grammars/tree-sitter-javascript.wasm +0 -0
  7. package/grammars/tree-sitter-python.wasm +0 -0
  8. package/grammars/tree-sitter-tsx.wasm +0 -0
  9. package/grammars/tree-sitter-typescript.wasm +0 -0
  10. package/index.js +39 -0
  11. package/package.json +45 -4
  12. package/src/auth/auth-email.js +32 -0
  13. package/src/auth/trusted-key.js +13 -0
  14. package/src/auto/adjust.js +41 -0
  15. package/src/auto/amnesia.js +37 -0
  16. package/src/auto/anonymize-tasks.js +13 -0
  17. package/src/auto/apply-diff-backed.js +10 -0
  18. package/src/auto/apply-diff.js +60 -0
  19. package/src/auto/ask-guard.js +16 -0
  20. package/src/auto/ask-pause.js +36 -0
  21. package/src/auto/ask-protocol.js +6 -0
  22. package/src/auto/ask-user.js +29 -0
  23. package/src/auto/backup-touched.js +30 -0
  24. package/src/auto/budget.js +52 -0
  25. package/src/auto/cancel.js +20 -0
  26. package/src/auto/constants.js +30 -0
  27. package/src/auto/crypto-util.js +17 -0
  28. package/src/auto/decompose.js +47 -0
  29. package/src/auto/diff.js +19 -0
  30. package/src/auto/fs-list.js +34 -0
  31. package/src/auto/git-base.js +16 -0
  32. package/src/auto/git-init.js +39 -0
  33. package/src/auto/git-restore.js +34 -0
  34. package/src/auto/git-scope.js +10 -0
  35. package/src/auto/git.js +38 -0
  36. package/src/auto/mission-docs.js +29 -0
  37. package/src/auto/mission-line.js +22 -0
  38. package/src/auto/node-check.js +30 -0
  39. package/src/auto/observe.js +23 -0
  40. package/src/auto/orchestrator.js +30 -0
  41. package/src/auto/patch-ask.js +16 -0
  42. package/src/auto/paths.js +18 -0
  43. package/src/auto/plan.js +42 -0
  44. package/src/auto/pricing.js +49 -0
  45. package/src/auto/project-files.js +12 -0
  46. package/src/auto/prompts.js +24 -0
  47. package/src/auto/quote-format.js +33 -0
  48. package/src/auto/retry.js +40 -0
  49. package/src/auto/run-lock.js +40 -0
  50. package/src/auto/run-loop.js +38 -0
  51. package/src/auto/run.js +49 -0
  52. package/src/auto/snapshot-gate.js +51 -0
  53. package/src/auto/snapshot-paths.js +33 -0
  54. package/src/auto/snapshot-restore.js +59 -0
  55. package/src/auto/snapshot-take.js +30 -0
  56. package/src/auto/state.js +52 -0
  57. package/src/auto/step-commit.js +46 -0
  58. package/src/auto/step-green.js +38 -0
  59. package/src/auto/step-loop.js +56 -0
  60. package/src/auto/step-prep.js +60 -0
  61. package/src/auto/step-qa.js +53 -0
  62. package/src/auto/step.js +30 -0
  63. package/src/auto/stop-options.js +34 -0
  64. package/src/auto/stop-report.js +17 -0
  65. package/src/auto/tasks.js +44 -0
  66. package/src/cli/apply-loop.js +29 -0
  67. package/src/cli/apply-toml.js +26 -0
  68. package/src/cli/apply.js +45 -0
  69. package/src/cli/ask-prepare.js +37 -0
  70. package/src/cli/auth-branches.js +53 -0
  71. package/src/cli/auth-interactive.js +46 -0
  72. package/src/cli/auto-ask.js +33 -0
  73. package/src/cli/auto-audit.js +16 -0
  74. package/src/cli/auto-cli.js +46 -0
  75. package/src/cli/auto-consent.js +22 -0
  76. package/src/cli/auto-flags.js +39 -0
  77. package/src/cli/auto-gate-session.js +27 -0
  78. package/src/cli/auto-gate.js +34 -0
  79. package/src/cli/auto-loader.js +17 -0
  80. package/src/cli/auto-plan.js +36 -0
  81. package/src/cli/auto-preflight.js +35 -0
  82. package/src/cli/auto-quote.js +28 -0
  83. package/src/cli/auto-report.js +36 -0
  84. package/src/cli/auto-resume.js +28 -0
  85. package/src/cli/auto-rules.js +20 -0
  86. package/src/cli/auto-run.js +26 -0
  87. package/src/cli/auto-task.js +26 -0
  88. package/src/cli/banner.js +20 -0
  89. package/src/cli/centralize.js +23 -0
  90. package/src/cli/collect-step.js +25 -0
  91. package/src/cli/config-pairs.js +46 -0
  92. package/src/cli/config.js +51 -0
  93. package/src/cli/detect-os.js +11 -0
  94. package/src/cli/dispatch.js +36 -0
  95. package/src/cli/env-file.js +44 -0
  96. package/src/cli/env-load.js +28 -0
  97. package/src/cli/env-parse.js +39 -0
  98. package/src/cli/env-rebuild.js +33 -0
  99. package/src/cli/gitignore-env.js +46 -0
  100. package/src/cli/help.js +28 -0
  101. package/src/cli/ide-entries.js +42 -0
  102. package/src/cli/ide-paths.js +37 -0
  103. package/src/cli/ide-roots.js +25 -0
  104. package/src/cli/interactive.js +26 -0
  105. package/src/cli/jetbrains.js +40 -0
  106. package/src/cli/legacy-entry.js +17 -0
  107. package/src/cli/main.js +42 -0
  108. package/src/cli/memory-cli.js +15 -0
  109. package/src/cli/prompts.js +24 -0
  110. package/src/cli/server-entry.js +42 -0
  111. package/src/cli/setup-args.js +39 -0
  112. package/src/cli/target-manual.js +24 -0
  113. package/src/cli/target-select.js +51 -0
  114. package/src/cli/toml-merge.js +56 -0
  115. package/src/cli/trial-check.js +15 -0
  116. package/src/cli/welcome.js +7 -0
  117. package/src/core/abort-signal.js +38 -0
  118. package/src/core/auto-deps.js +29 -0
  119. package/src/core/cache-ttl.js +21 -0
  120. package/src/core/config-base.js +38 -0
  121. package/src/core/config-cache.js +50 -0
  122. package/src/core/config.js +58 -0
  123. package/src/core/constants.js +31 -0
  124. package/src/core/crypto.js +45 -0
  125. package/src/core/dlp.js +51 -0
  126. package/src/core/doctrine-all.js +31 -0
  127. package/src/core/doctrine-caches.js +10 -0
  128. package/src/core/doctrine-fetch.js +49 -0
  129. package/src/core/doctrine-one.js +18 -0
  130. package/src/core/doctrine.js +39 -0
  131. package/src/core/dual-stream-parser.js +55 -0
  132. package/src/core/exports.js +28 -0
  133. package/src/core/google-route.js +17 -0
  134. package/src/core/identity.js +23 -0
  135. package/src/core/lang.js +19 -0
  136. package/src/core/leak-guard.js +40 -0
  137. package/src/core/llm-builder-anthropic.js +26 -0
  138. package/src/core/llm-builder-gemini.js +22 -0
  139. package/src/core/llm-builder-openai.js +26 -0
  140. package/src/core/llm-call.js +53 -0
  141. package/src/core/llm-config-secondary.js +28 -0
  142. package/src/core/llm-config.js +32 -0
  143. package/src/core/llm-errors.js +25 -0
  144. package/src/core/llm-exchange.js +27 -0
  145. package/src/core/llm-extract.js +52 -0
  146. package/src/core/llm-label.js +33 -0
  147. package/src/core/llm-ollama-request.js +32 -0
  148. package/src/core/llm-ollama.js +42 -0
  149. package/src/core/llm-prompts.js +14 -0
  150. package/src/core/llm-providers.js +26 -0
  151. package/src/core/llm-request.js +17 -0
  152. package/src/core/llm-retry-429.js +23 -0
  153. package/src/core/llm-stream-events.js +29 -0
  154. package/src/core/llm-stream.js +42 -0
  155. package/src/core/llm-unbounded.js +15 -0
  156. package/src/core/llm-warmup.js +44 -0
  157. package/src/core/manifest.js +42 -0
  158. package/src/core/master-prompt.js +11 -0
  159. package/src/core/model-id.js +19 -0
  160. package/src/core/ollama-lines.js +48 -0
  161. package/src/core/ollama.js +43 -0
  162. package/src/core/pkg-manager.js +35 -0
  163. package/src/core/process-guards.js +47 -0
  164. package/src/core/progress-emit.js +25 -0
  165. package/src/core/purge-key.js +20 -0
  166. package/src/core/reasoning-cut.js +19 -0
  167. package/src/core/reasoning-models.js +8 -0
  168. package/src/core/session-net.js +60 -0
  169. package/src/core/session-resilient.js +44 -0
  170. package/src/core/session.js +49 -0
  171. package/src/core/sse-parser.js +25 -0
  172. package/src/core/stdout-guard.js +11 -0
  173. package/src/core/tier.js +48 -0
  174. package/src/core/trial-resolve.js +22 -0
  175. package/src/core/trial-session.js +60 -0
  176. package/src/core/trial-status.js +35 -0
  177. package/src/core/usage-cost.js +25 -0
  178. package/src/core/usage-extract.js +28 -0
  179. package/src/core/usage-meter.js +41 -0
  180. package/src/engine/analyze-need.js +24 -0
  181. package/src/engine/analyze-ux.js +42 -0
  182. package/src/engine/ask-history.js +43 -0
  183. package/src/engine/ask-llm.js +40 -0
  184. package/src/engine/ask-prompt.js +48 -0
  185. package/src/engine/ask-rules.js +13 -0
  186. package/src/engine/ast-call-rules-danger.js +24 -0
  187. package/src/engine/ast-call-rules-inject.js +29 -0
  188. package/src/engine/ast-context.js +28 -0
  189. package/src/engine/ast-import-helpers.js +46 -0
  190. package/src/engine/ast-lang.js +24 -0
  191. package/src/engine/ast-node-helpers.js +51 -0
  192. package/src/engine/ast-rules-calls.js +16 -0
  193. package/src/engine/ast-rules-graph.js +58 -0
  194. package/src/engine/ast-rules-js.js +30 -0
  195. package/src/engine/ast-rules-jsx-py.js +26 -0
  196. package/src/engine/ast-runtime.js +60 -0
  197. package/src/engine/ast-scan.js +48 -0
  198. package/src/engine/audit-citations.js +28 -0
  199. package/src/engine/audit-facts.js +47 -0
  200. package/src/engine/audit-report.js +40 -0
  201. package/src/engine/audit-task.js +37 -0
  202. package/src/engine/cap-cache.js +50 -0
  203. package/src/engine/cap-eval.js +49 -0
  204. package/src/engine/cap-http.js +32 -0
  205. package/src/engine/cap-meta-anthropic.js +15 -0
  206. package/src/engine/cap-meta-ollama.js +15 -0
  207. package/src/engine/cap-meta-openrouter.js +19 -0
  208. package/src/engine/cap-meta.js +19 -0
  209. package/src/engine/cap-probe.js +34 -0
  210. package/src/engine/cap-types.js +29 -0
  211. package/src/engine/chat-doctrine.js +31 -0
  212. package/src/engine/checkpoint-control.js +23 -0
  213. package/src/engine/checkpoint-detect.js +19 -0
  214. package/src/engine/checkpoint-rules.js +19 -0
  215. package/src/engine/code-decls.js +12 -0
  216. package/src/engine/code-graph.js +52 -0
  217. package/src/engine/coerce.js +8 -0
  218. package/src/engine/collect.js +21 -0
  219. package/src/engine/compute-impact.js +17 -0
  220. package/src/engine/context-files.js +42 -0
  221. package/src/engine/context-fit.js +28 -0
  222. package/src/engine/context-margin.js +37 -0
  223. package/src/engine/context-relay.js +60 -0
  224. package/src/engine/control-duo.js +38 -0
  225. package/src/engine/control-phase.js +32 -0
  226. package/src/engine/control-prompt.js +25 -0
  227. package/src/engine/control-verdict.js +36 -0
  228. package/src/engine/default-steps.js +7 -0
  229. package/src/engine/deps-parse-js.js +49 -0
  230. package/src/engine/deps-parse-more.js +30 -0
  231. package/src/engine/deps-parse-other.js +41 -0
  232. package/src/engine/deps-parse.js +31 -0
  233. package/src/engine/det-builders-1.js +38 -0
  234. package/src/engine/det-builders-2.js +50 -0
  235. package/src/engine/detect-domains.js +27 -0
  236. package/src/engine/diff-files.js +35 -0
  237. package/src/engine/doc-suite.js +39 -0
  238. package/src/engine/doctrine-prefix.js +13 -0
  239. package/src/engine/domain-regex.js +11 -0
  240. package/src/engine/exports.js +35 -0
  241. package/src/engine/extract-deterministic.js +33 -0
  242. package/src/engine/extract-llm.js +48 -0
  243. package/src/engine/facts-binary.js +12 -0
  244. package/src/engine/facts-embedded.js +18 -0
  245. package/src/engine/facts-functions.js +21 -0
  246. package/src/engine/facts-html.js +22 -0
  247. package/src/engine/facts-inventory.js +33 -0
  248. package/src/engine/facts-lang.js +34 -0
  249. package/src/engine/facts-measure.js +43 -0
  250. package/src/engine/facts-patterns.js +28 -0
  251. package/src/engine/facts-project.js +26 -0
  252. package/src/engine/facts-size.js +26 -0
  253. package/src/engine/facts-wordpress.js +36 -0
  254. package/src/engine/generate-architecture-guide.js +46 -0
  255. package/src/engine/generate-readme.js +38 -0
  256. package/src/engine/generate-runbook.js +47 -0
  257. package/src/engine/git-facts.js +16 -0
  258. package/src/engine/history-purge.js +16 -0
  259. package/src/engine/json-balance.js +37 -0
  260. package/src/engine/json-safe.js +13 -0
  261. package/src/engine/line-numbers.js +16 -0
  262. package/src/engine/md-build-mid.js +35 -0
  263. package/src/engine/md-build-top.js +58 -0
  264. package/src/engine/md-build.js +36 -0
  265. package/src/engine/md-parse-helpers.js +7 -0
  266. package/src/engine/md-parse-pillars.js +38 -0
  267. package/src/engine/md-parse-ux-design.js +31 -0
  268. package/src/engine/md-parse.js +33 -0
  269. package/src/engine/mission-context-prefix.js +30 -0
  270. package/src/engine/mission-guard.js +36 -0
  271. package/src/engine/mission-helpers.js +23 -0
  272. package/src/engine/mission-log.js +56 -0
  273. package/src/engine/mission-paths.js +7 -0
  274. package/src/engine/mission-store.js +51 -0
  275. package/src/engine/normalize-extraction.js +35 -0
  276. package/src/engine/normalize-impact-design.js +39 -0
  277. package/src/engine/normalize-pillars.js +36 -0
  278. package/src/engine/orchestrate-route.js +39 -0
  279. package/src/engine/orchestrator-build.js +37 -0
  280. package/src/engine/orchestrator-phases.js +55 -0
  281. package/src/engine/orchestrator.js +40 -0
  282. package/src/engine/osv.js +43 -0
  283. package/src/engine/parse-json-loose.js +36 -0
  284. package/src/engine/patch-file-sections.js +28 -0
  285. package/src/engine/patch-scan-cheat.js +52 -0
  286. package/src/engine/patch-scan-prep.js +37 -0
  287. package/src/engine/patch-scan-rules.js +51 -0
  288. package/src/engine/patch-scan.js +38 -0
  289. package/src/engine/patch-secret-guard.js +50 -0
  290. package/src/engine/patch-ui-guard.js +49 -0
  291. package/src/engine/pattern-sanitize.js +23 -0
  292. package/src/engine/plan-draft.js +37 -0
  293. package/src/engine/plan-mission.js +60 -0
  294. package/src/engine/plan-reply-legacy.js +34 -0
  295. package/src/engine/plan-reply-pillars.js +34 -0
  296. package/src/engine/plan-reply-ux.js +17 -0
  297. package/src/engine/plan-reply.js +28 -0
  298. package/src/engine/plan-summary.js +16 -0
  299. package/src/engine/preflight-text.js +27 -0
  300. package/src/engine/preflight.js +27 -0
  301. package/src/engine/project-brief.js +41 -0
  302. package/src/engine/project-context.js +49 -0
  303. package/src/engine/project-instructions.js +19 -0
  304. package/src/engine/py-imports.js +31 -0
  305. package/src/engine/relay-analysis.js +44 -0
  306. package/src/engine/relay-digest.js +42 -0
  307. package/src/engine/route-llm.js +25 -0
  308. package/src/engine/rule-text.js +12 -0
  309. package/src/engine/self-assessment.js +33 -0
  310. package/src/engine/steps-block.js +19 -0
  311. package/src/engine/ux-violations-leak.js +43 -0
  312. package/src/engine/vuln-facts.js +37 -0
  313. package/src/fs/atomic-text.js +45 -0
  314. package/src/fs/atomic-write.js +21 -0
  315. package/src/fs/backup-once.js +27 -0
  316. package/src/fs/config-path.js +39 -0
  317. package/src/fs/config-read.js +23 -0
  318. package/src/fs/config-write.js +60 -0
  319. package/src/fs/home-root.js +55 -0
  320. package/src/fs/load-config.js +36 -0
  321. package/src/fs/os-errors.js +26 -0
  322. package/src/fs/permissions.js +48 -0
  323. package/src/mcp/boot-warmup.js +9 -0
  324. package/src/mcp/call-tool.js +20 -0
  325. package/src/mcp/client-info.js +35 -0
  326. package/src/mcp/engine-rules.js +16 -0
  327. package/src/mcp/handle-dlp.js +37 -0
  328. package/src/mcp/handle-licence.js +46 -0
  329. package/src/mcp/handle-list.js +15 -0
  330. package/src/mcp/handle-memory.js +37 -0
  331. package/src/mcp/handle-skill-fetch.js +50 -0
  332. package/src/mcp/handle-skill.js +38 -0
  333. package/src/mcp/licence-text.js +29 -0
  334. package/src/mcp/prompt-licence.js +11 -0
  335. package/src/mcp/server-create.js +33 -0
  336. package/src/mcp/server-main.js +39 -0
  337. package/src/mcp/tool-dispatch.js +28 -0
  338. package/src/mcp/tool-dlp.js +20 -0
  339. package/src/mcp/tool-licence.js +17 -0
  340. package/src/mcp/tool-memory.js +32 -0
  341. package/src/mcp/tool-skill.js +24 -0
  342. package/src/mcp/tools-list.js +13 -0
  343. package/src/memory/exports.js +5 -0
  344. package/src/memory/memory-filter.js +32 -0
  345. package/src/memory/memory-gate.js +21 -0
  346. package/src/memory/memory-store.js +44 -0
  347. package/src/net/auth-browser.js +49 -0
  348. package/src/net/auth-endpoints.js +33 -0
  349. package/src/net/local-fetch.js +31 -0
  350. package/src/net/loopback.js +8 -0
  351. package/src/net/proxy-env.js +59 -0
  352. package/src/project-memory/batches.js +17 -0
  353. package/src/project-memory/cahiers.js +42 -0
  354. package/src/project-memory/decision-settle.js +15 -0
  355. package/src/project-memory/decisions.js +36 -0
  356. package/src/project-memory/index-build.js +35 -0
  357. package/src/project-memory/memory-build.js +16 -0
  358. package/src/project-memory/memory-tags.js +40 -0
  359. package/src/project-memory/pending.js +24 -0
  360. package/src/project-memory/qa-apply.js +39 -0
  361. package/src/project-memory/qa-tags.js +28 -0
  362. package/src/project-memory/recall.js +38 -0
  363. package/src/project-memory/store.js +37 -0
  364. package/src/project-memory/window.js +13 -0
  365. package/src/rules/rules-advisor.js +17 -0
  366. package/src/rules/rules-frugality.js +17 -0
  367. package/src/rules/rules-load.js +56 -0
  368. package/src/rules/rules-project.js +16 -0
  369. package/src/rules/rules-registry.js +32 -0
  370. package/src/rules/rules-validate-pricing.js +22 -0
  371. package/src/rules/rules-validate-scan.js +45 -0
  372. package/src/rules/rules-validate.js +53 -0
  373. package/src/teardown/consent.js +31 -0
  374. package/src/teardown/flags.js +39 -0
  375. package/src/teardown/main.js +41 -0
  376. package/src/teardown/plan.js +31 -0
  377. package/src/teardown/remove-entry.js +39 -0
  378. package/src/teardown/remove-file.js +37 -0
  379. package/src/teardown/remove-toml.js +33 -0
  380. package/src/teardown/report.js +34 -0
  381. package/src/types/ast.d.ts +40 -0
  382. package/src/types/auto-ask.d.ts +6 -0
  383. package/src/types/auto-orch.d.ts +59 -0
  384. package/src/types/auto.d.ts +45 -0
  385. package/src/types/capability.d.ts +12 -0
  386. package/src/types/cli-auto-gate.d.ts +45 -0
  387. package/src/types/cli-auto.d.ts +42 -0
  388. package/src/types/config.d.ts +53 -0
  389. package/src/types/control.d.ts +56 -0
  390. package/src/types/docs.d.ts +6 -0
  391. package/src/types/doctrine.d.ts +22 -0
  392. package/src/types/llm.d.ts +28 -0
  393. package/src/types/mcp.d.ts +32 -0
  394. package/src/types/memory.d.ts +17 -0
  395. package/src/types/mission.d.ts +46 -0
  396. package/src/types/orchestrator.d.ts +33 -0
  397. package/src/types/routing.d.ts +25 -0
  398. package/src/types/rules.d.ts +30 -0
  399. package/src/types/snapshots.d.ts +25 -0
  400. package/src/types/teardown.d.ts +13 -0
  401. package/src/types/usage.d.ts +30 -0
@@ -0,0 +1,46 @@
1
+ // src/cli/auto-cli.js — Dispatcher du shell CLI Mode Auto (plan/run/resume/ask).
2
+ // shell CLI sur le même cœur pur que le dispatch MCP. gate licence/session/BYOK →
3
+ // re-gate Lite (chat gratuit ; plan/run/resume restent payants) →
4
+ // appels minces aux handlers → consentement readline (BLOCK avant exécution).
5
+
6
+ import { parseAutoFlags, resolveProjectPath } from "./auto-flags.js";
7
+ import { gateAutoCli } from "./auto-gate.js";
8
+ import { loadAutoShell } from "./auto-loader.js";
9
+ import { LITE_BLOCK_TEXT } from "../core/tier.js";
10
+ import { applyPreflight } from "./auto-preflight.js";
11
+ import { handleAutoPlan } from "./auto-plan.js";
12
+ import { handleAutoRun } from "./auto-run.js";
13
+ import { handleAutoResume } from "./auto-resume.js";
14
+ import { handleAutoAsk } from "./auto-ask.js";
15
+ import { handleAutoAudit } from "./auto-audit.js";
16
+ import { prepareRules } from "./auto-rules.js";
17
+ import { listenForAbort } from "../core/abort-signal.js";
18
+
19
+ // Handler principal du shell CLI Auto. Dispatche vers plan/run/resume/ask après gate.
20
+ /** @param {string} action @param {string[]} argv @returns {Promise<void>} */
21
+ export async function runAutoCli(action, argv) {
22
+ listenForAbort(); // « Stop » de l'interface (canal demandé seulement par l'extension)
23
+ const flags = parseAutoFlags(argv);
24
+ const projectPath = resolveProjectPath(flags);
25
+ const { auto, deps } = await loadAutoShell();
26
+ const g = await gateAutoCli(deps);
27
+ if (!g.ok) { console.error("\n " + g.message); process.exit(1); }
28
+ const gate = /** @type {AutoGateOk} */ (g);
29
+ // Re-gate monétisation : le chat (`ask`) est gratuit à vie ; l'exécution
30
+ // autonome (plan/run/resume) reste débloquée en essai/Pro uniquement.
31
+ if (gate.tier === "lite" && (action === "plan" || action === "run" || action === "resume" || action === "audit")) {
32
+ console.error("\n " + LITE_BLOCK_TEXT);
33
+ process.exit(1);
34
+ }
35
+ const ready = await applyPreflight(gate, flags, action); // capacités requises : arrêt AVANT tout appel modèle.
36
+ if (!ready) return; // arrêt pré-flight : message affiché, code de sortie positionné.
37
+ if (!(await prepareRules(gate.cfg, action))) return; // règles métier du serveur : sinon arrêt AVANT tout appel modèle.
38
+ if (action === "plan") return handleAutoPlan(auto, flags, projectPath, ready);
39
+ if (action === "run") return handleAutoRun(auto, flags, projectPath, ready);
40
+ if (action === "resume") return handleAutoResume(auto, flags, projectPath, ready);
41
+ if (action === "ask") return handleAutoAsk(ready, flags);
42
+ if (action === "audit") return handleAutoAudit(ready, projectPath);
43
+ console.error(`Sous-action auto inconnue : "${action}". Essayez : plan | run | resume | ask | audit`);
44
+ process.exit(2);
45
+ }
46
+ // MODULE_COMPLETE
@@ -0,0 +1,22 @@
1
+ // src/cli/auto-consent.js — Gate de consentement du Mode Auto (Pilier 1).
2
+ // BLOCK avant exécution. --yes confirme sans prompt ; non-TTY sans --yes = exit(2).
3
+ // TTY : prompt Y/n (Entrée = oui).
4
+
5
+ import readline from "node:readline/promises";
6
+ import { stdin, stdout } from "node:process";
7
+
8
+ // Retourne true si l'utilisateur a confirmé l'exécution (Y/n, Entrée = oui).
9
+ /** @param {AutoFlags} flags @returns {Promise<boolean>} */
10
+ export async function confirmConsent(flags) {
11
+ if (flags.yes) return true;
12
+ if (!stdin.isTTY) {
13
+ console.error("\n ✗ Consentement requis (non-TTY). Passez --yes pour confirmer le plan.");
14
+ process.exit(2);
15
+ }
16
+ const rl = readline.createInterface({ input: stdin, output: stdout });
17
+ try {
18
+ const ans = (await rl.question("\n ▶ Lancer l'exécution Auto de ces tâches ? [Y/n] : ")).trim().toLowerCase();
19
+ return (ans === "y" || ans === "yes" || ans === "");
20
+ } finally { rl.close(); }
21
+ }
22
+ // MODULE_COMPLETE
@@ -0,0 +1,39 @@
1
+ // src/cli/auto-flags.js — Parsing des flags CLI du Mode Auto.
2
+ // --need "…" --project ./p --max-steps N --yes|-y (accepte --need="…" --project=./p).
3
+
4
+ import path from "node:path";
5
+
6
+ // Analyse les flags CLI et retourne les valeurs parsées (défauts : maxSteps 50, yes false).
7
+ /** @param {string[]} argv @returns {AutoFlags} */
8
+ export function parseAutoFlags(argv) {
9
+ /** @type {AutoFlags} */ const flags = { need: "", project: "", maxSteps: 50, yes: false };
10
+ for (let i = 0; i < argv.length; i++) {
11
+ const a = argv[i];
12
+ if (a === "--yes" || a === "-y") flags.yes = true;
13
+ else if (a === "--need") flags.need = argv[++i] || "";
14
+ else if (a === "--adjust") flags.adjust = argv[++i] || "";
15
+ else if (a === "--project") flags.project = argv[++i] || "";
16
+ else if (a === "--max-steps") flags.maxSteps = Math.max(1, parseInt(argv[++i], 10) || 50);
17
+ else if (a === "--require") flags.require = argv[++i] || "";
18
+ else if (a.startsWith("--require=")) flags.require = a.slice(10);
19
+ else if (a === "--answer") flags.answer = argv[++i] || "";
20
+ else if (a.startsWith("--answer=")) flags.answer = a.slice(9);
21
+ else if (a === "--task") flags.task = argv[++i] || "";
22
+ else if (a.startsWith("--task=")) flags.task = a.slice(7);
23
+ else if (a.startsWith("--need=")) flags.need = a.slice(7);
24
+ else if (a.startsWith("--project=")) flags.project = a.slice(10);
25
+ else if (a.startsWith("--max-steps=")) flags.maxSteps = Math.max(1, parseInt(a.slice(12), 10) || 50);
26
+ }
27
+ return flags;
28
+ }
29
+
30
+ // Résout le chemin projet et valide la présence de --project (exit(2) si absent).
31
+ /** @param {AutoFlags} flags @returns {string} */
32
+ export function resolveProjectPath(flags) {
33
+ if (!flags.project.trim()) {
34
+ console.error("✗ --project <chemin> requis (le Mode Auto exige un dépôt git).");
35
+ process.exit(2);
36
+ }
37
+ return path.resolve(flags.project);
38
+ }
39
+ // MODULE_COMPLETE
@@ -0,0 +1,27 @@
1
+ // src/cli/auto-gate-session.js — Session Pro du gate Auto CLI + résilience.
2
+ // ensureSession échoue : 402/403/429/no_license → blocage (purge gérée par les
3
+ // gates MCP) ; échec RÉSEAU seulement → retombe sur l'essai serveur /v1/trial
4
+ // (Polar injoinable + essai actif → trial). Jamais de grant local (Zero Trust §3).
5
+
6
+ import { PRO_UPGRADE_URL } from "../core/constants.js";
7
+
8
+ /** @param {(cfg: PlugConfig) => Promise<LicenseSession>} ensureSession @param {PlugConfig} cfg @param {(cfg: PlugConfig) => Promise<SessionResolution>} resolveTrial @returns {Promise<{ ok: true, tier: string } | { ok: false, message: string }>} */
9
+ export async function proSessionGate(ensureSession, cfg, resolveTrial) {
10
+ try {
11
+ await ensureSession(cfg);
12
+ return { ok: true, tier: "pro" };
13
+ } catch (err) {
14
+ const e = /** @type {NodeErr} */ (err);
15
+ if (e && e.code === "no_license") {
16
+ return { ok: false, message: `🔒 Licence requise. Débloquez la version Pro ($14.99 USD à vie, Polar.sh) : ${PRO_UPGRADE_URL}` };
17
+ }
18
+ if (e && (e.status === 402 || e.status === 403 || e.status === 429)) {
19
+ return { ok: false, message: e.message || `Session refusée par le serveur (HTTP ${e.status}).` };
20
+ }
21
+ // Serveur injoinable : l'essai serveur peut rester actif (résilience).
22
+ const t = await resolveTrial(cfg);
23
+ if (t.tier === "trial") return { ok: true, tier: "trial" };
24
+ return { ok: false, message: `Serveur de licence indisponible. ${(e && e.message) || "Erreur inconnue."}` };
25
+ }
26
+ }
27
+ // MODULE_COMPLETE
@@ -0,0 +1,34 @@
1
+ // src/cli/auto-gate.js — Gate licence/session/BYOK du shell CLI Mode Auto.
2
+ // Réplique CLI de gateAuto (index.js). L'essai est TRANCHÉ PAR LE SERVEUR
3
+ // (jeton signé /v1/trial, jamais l'horloge locale — Zero Trust §3) ; Pro exige
4
+ // ensureSession (Ed25519). Sans licence : essai serveur → trial ; refusé (402)
5
+ // OU serveur injoinable → tier "lite" ok — seul `auto ask` passe, le dispatcher
6
+ // (auto-cli.js) re-gate plan/run/resume et le serveur re-gate les fiches Pro
7
+ // (zéro risque monétaire). BYOK exigé dans tous les cas.
8
+
9
+ import { proSessionGate } from "./auto-gate-session.js";
10
+
11
+ // Gate partagée tier + session + BYOK. Retourne {ok, cfg, pcfg, tier} ou {ok:false, message}.
12
+ /** @param {GateAutoDeps} deps @returns {Promise<GateAutoResult>} */
13
+ export async function gateAutoCli({ loadConfig, ensureSession, readProviderConfig, resolveTrial }) {
14
+ const cfg = await loadConfig();
15
+ const hasLicense = !!(process.env.PLUGCTO_LICENSE_KEY || cfg.licenseKey);
16
+ let tier = "trial";
17
+ if (!hasLicense) {
18
+ // Sans licence : essai serveur (jeton /v1/trial) → trial ; sinon Lite (refus
19
+ // 402 OU échec réseau) → ok tier "lite" : le chat gratuit reste ouvert, les
20
+ // fiches Pro restent gates côté serveur (autorité monétaire).
21
+ const t = await resolveTrial(cfg);
22
+ tier = t.tier === "trial" ? "trial" : "lite";
23
+ } else {
24
+ const gated = await proSessionGate(ensureSession, cfg, resolveTrial);
25
+ if (!gated.ok) return { ok: false, message: gated.message };
26
+ tier = gated.tier;
27
+ }
28
+ const pcfg = readProviderConfig();
29
+ if (!pcfg.primary) {
30
+ return { ok: false, message: `🔑 Aucune clé API provider configurée (BYOK). Lancez \`npx pipcode setup\` pour saisir votre clé unique (OpenRouter / OpenAI / Anthropic / Gemini / Ollama / Local / Proxy).` };
31
+ }
32
+ return { ok: true, cfg, pcfg: /** @type {{ primary: ProviderPrimary }} */ (pcfg), tier };
33
+ }
34
+ // MODULE_COMPLETE
@@ -0,0 +1,17 @@
1
+ // src/cli/auto-loader.js — Chargement paresseux du cœur Auto + helpers index.js.
2
+ // Les tests de setup.js ne chargent ni le graphe de gates ni le cœur Auto (aucune
3
+ // régression de la suite existante). auto.js définit son propre AutoDeps ;
4
+ // createAutoDeps() (index.js) y est compatible au runtime mais leurs typedefs JSDoc
5
+ // diffèrent — on cast l'usine vers une signature acceptant unknown + AutoShell typé
6
+ // localement (évite de propager les inférences de auto.js non annoté à zéro).
7
+
8
+ // Charge le cœur Auto + les helpers de gate. Retourne l'orchestrateur + les deps.
9
+ /** @returns {Promise<{ auto: AutoShell, deps: GateAutoDeps }>} */
10
+ export async function loadAutoShell() {
11
+ const { createAutoOrchestrator } = await import("../../auto.js");
12
+ const { createAutoDeps, loadConfig, ensureSession, readProviderConfig, resolveTrialOrLite } = await import("../../index.js");
13
+ const mkAuto = /** @type {(deps: unknown) => AutoShell} */ (/** @type {unknown} */ (createAutoOrchestrator));
14
+ const auto = mkAuto(createAutoDeps());
15
+ return { auto, deps: { loadConfig, ensureSession, readProviderConfig, resolveTrial: resolveTrialOrLite } };
16
+ }
17
+ // MODULE_COMPLETE
@@ -0,0 +1,36 @@
1
+ // src/cli/auto-plan.js — Handler `auto plan` : génère le roadmap + devis (dry-run).
2
+ // Pilier 1 : 1 appel LLM de décomposition. L'exécution reste bloquée (consentement).
3
+ // `--task audit` : besoin = libellé public, protocole serveur transmis à la seule
4
+ // décomposition (jamais affiché ni persisté). Erreurs de tâche : code de sortie
5
+ // positionné + retour (pas de process.exit après du réseau : crash Windows).
6
+
7
+ import { resolveTask } from "./auto-task.js";
8
+
9
+ // @param auto — orchestrateur Auto. @param flags — flags CLI. @param projectPath — résolu.
10
+ /** @param {AutoShell} auto @param {AutoFlags} flags @param {string} projectPath @param {AutoGateOk} g @returns {Promise<void>} */
11
+ export async function handleAutoPlan(auto, flags, projectPath, g) {
12
+ let task;
13
+ try { task = await resolveTask(flags, g.cfg); }
14
+ catch (err) {
15
+ console.error("\n ✗ " + /** @type {Error} */ (err).message);
16
+ process.exitCode = /** @type {{ exitCode?: number }} */ (err).exitCode || 1;
17
+ return;
18
+ }
19
+ if (!task.need.trim()) {
20
+ console.error('✗ --need "<cahier des charges>" requis pour `auto plan`.');
21
+ process.exit(2);
22
+ }
23
+ try {
24
+ const r = await auto.buildAutoPlan({ need: task.need, instructions: task.instructions, adjust: flags.adjust, projectPath, pcfg: g.pcfg, cfg: g.cfg });
25
+ if (r.isError) { console.error("\n " + r.text); process.exit(1); }
26
+ console.log("\n" + r.quote);
27
+ const tasks = /** @type {AutoTask[]} */ (r.tasks);
28
+ console.log(`\n runId: ${r.runId} • ${tasks.length} tâches • status: ${r.status}`);
29
+ console.log(` Pour lancer : npx pipcode auto run --project "${flags.project}"`);
30
+ } catch (err) {
31
+ const e = /** @type {NodeErr} */ (err);
32
+ console.error("\n ✗ Plan Auto échoué :", e.message);
33
+ process.exit(1);
34
+ }
35
+ }
36
+ // MODULE_COMPLETE
@@ -0,0 +1,35 @@
1
+ // src/cli/auto-preflight.js — Branchement du pré-flight de capacités dans le CLI
2
+ // `auto` : `--require vision,tools,media_generation` (ou PLUGCTO_REQUIRE).
3
+ // Appelé APRÈS les gates licence/BYOK et AVANT tout appel du modèle. Aucune
4
+ // capacité requise → no-op total (0 requête). Arrêt = code de sortie 4 + message
5
+ // exact, retour null (l'appelant s'arrête : PAS de process.exit — sous Windows il
6
+ // fait planter Node juste après une requête réseau). Modèle 1 incapable mais
7
+ // Modèle 2 confirmé : `ask` est confié au Modèle 2 ; plan/run/resume demandent le
8
+ // mode Solo Modèle 2.
9
+
10
+ import { parseCaps } from "../engine/cap-types.js";
11
+ import { runPreflight } from "../engine/preflight.js";
12
+ import { readSecondaryProvider } from "../core/llm-config-secondary.js";
13
+
14
+ /** @param {number} code @returns {void} */
15
+ const defaultSetExit = (code) => { process.exitCode = code; };
16
+
17
+ /** @param {AutoGateOk} gate @param {AutoFlags} flags @param {string} action @param {{ env?: Record<string, string | undefined>, setExit?: (code: number) => void }} [deps] @returns {Promise<AutoGateOk | null>} */
18
+ export async function applyPreflight(gate, flags, action, { env = process.env, setExit = defaultSetExit } = {}) {
19
+ /** @type {Capability[]} */ let required = [];
20
+ try { required = parseCaps(flags.require || env.PLUGCTO_REQUIRE); }
21
+ catch (e) { console.error("\n ✗ " + /** @type {Error} */ (e).message); setExit(2); return null; }
22
+ if (required.length === 0) return gate;
23
+ const { secondary } = readSecondaryProvider(env);
24
+ const r = await runPreflight({ required, primary: gate.pcfg.primary, secondary });
25
+ if (!r.ok) { console.error("\n ✗ " + r.message); setExit(4); return null; }
26
+ if (r.runner === "primary") return gate;
27
+ if (action !== "ask" || !secondary) {
28
+ console.error(`\n ✗ ${r.notice} Relancez en mode Solo Modèle 2 pour une tâche d'exécution.`);
29
+ setExit(4);
30
+ return null;
31
+ }
32
+ console.error("\n ℹ " + r.notice);
33
+ return { ...gate, pcfg: { primary: secondary } };
34
+ }
35
+ // MODULE_COMPLETE
@@ -0,0 +1,28 @@
1
+ // src/cli/auto-quote.js — Résolution du devis Auto avant exécution (Pilier 1).
2
+ // Si un besoin est fourni ou aucun plan n'existe → (re)construit le devis (dry-run,
3
+ // 1 appel LLM). Sinon récupère le devis du plan existant (confirmed:false, 1 step).
4
+ // `--task audit` : même résolution que `auto plan` (libellé public + instructions serveur),
5
+ // pour que le plan reconstruit à l'exécution soit IDENTIQUE à celui que l'utilisateur a approuvé.
6
+
7
+ import { resolveTask } from "./auto-task.js";
8
+
9
+ // Retourne le texte du devis. Exit(1) si plan/probe en erreur, exit(2) si besoin absent sans plan.
10
+ /** @param {AutoShell} auto @param {AutoFlags} flags @param {string} projectPath @param {AutoGateOk} g @returns {Promise<string>} */
11
+ export async function resolveAutoQuote(auto, flags, projectPath, g) {
12
+ const existing = await auto.loadAutoState(projectPath);
13
+ const task = await resolveTask(flags, g.cfg);
14
+ if (task.need.trim() || !existing) {
15
+ if (!task.need.trim()) {
16
+ console.error("✗ Aucun plan Auto trouvé. Lancez d'abord `auto plan --need \"…\" --project …`.");
17
+ process.exit(2);
18
+ }
19
+ const plan = await auto.buildAutoPlan({ need: task.need, instructions: task.instructions, projectPath, pcfg: g.pcfg, cfg: g.cfg });
20
+ if (plan.isError) { console.error("\n " + plan.text); process.exit(1); }
21
+ return /** @type {string} */ (plan.quote);
22
+ }
23
+ // Plan existant : on récupère le devis sans exécuter (confirmed:false, maxSteps 1).
24
+ const probe = await auto.runAutoRun({ projectPath, confirmed: false, maxSteps: 1, pcfg: g.pcfg, cfg: g.cfg });
25
+ if (probe.isError) { console.error("\n " + probe.text); process.exit(1); }
26
+ return /** @type {string} */ (probe.quote);
27
+ }
28
+ // MODULE_COMPLETE
@@ -0,0 +1,36 @@
1
+ // src/cli/auto-report.js — Rendu du résultat d'une opération Auto (run/resume).
2
+ // Trois issues : terminé (done), tâche échouée (last.failed → exit 1), ou
3
+ // progression partielle (continue → relancer). `continueVerb` différencie
4
+ // "Auto Mode" (run) de "Reprise Auto" (resume).
5
+
6
+ import { ASK_PREFIX } from "../auto/ask-protocol.js";
7
+ import { CANCEL_EXIT_CODE } from "../auto/cancel.js";
8
+ import { guardQuestion } from "../auto/ask-guard.js";
9
+
10
+ // Affiche l'issue de l'opération. Échec → exit(1) ; done/continue → retour au caller.
11
+ /** @param {AutoOpResult} r @param {AutoFlags} flags @param {string} continueVerb @returns {void} */
12
+ export function reportAutoOutcome(r, flags, continueVerb) {
13
+ const ask = r.asking ? r : r.last?.asking ? r.last : null;
14
+ if (ask) { // pause « ASK_USER » : ni terminé ni échoué — la question est posée, l'exécution reprend avec `auto resume --answer`
15
+ const question = guardQuestion(ask.question ?? null, "") ?? ask.question; // une question enregistrée AVANT le garde-fou (plan resté en pause) est filtrée aussi à la reprise
16
+ console.log(`\n ❓ ${question}`);
17
+ console.log(`${ASK_PREFIX}${JSON.stringify({ question })}`);
18
+ process.exit(3);
19
+ }
20
+ if (r.cancelled || r.last?.cancelled) { // Stop : ni terminé ni échoué — plan en PAUSE, reprise possible
21
+ console.log(`\n 🛑 Exécution interrompue par l'utilisateur. Le plan est en pause (reprise : auto resume).`);
22
+ process.exit(CANCEL_EXIT_CODE);
23
+ }
24
+ if (r.done || r.status === "done") {
25
+ console.log(`\n ✅ Auto Mode terminé : ${r.progress} tâches validées.`);
26
+ if (r.summary) console.log(` ${r.summary}`);
27
+ return;
28
+ }
29
+ if (r.last && r.last.failed) {
30
+ console.error(`\n ⚠️ Tâche échouée : ${r.last.task && r.last.task.id} — ${(r.last.task && r.last.task.error) || r.last.error}`);
31
+ console.error(` Progression : ${r.progress}. Corrigez ou reprenez : npx pipcode auto resume --project "${flags.project}"`);
32
+ process.exit(1);
33
+ }
34
+ console.log(`\n ⏵ ${continueVerb} : ${r.progress} tâches validées (status: ${r.status}). Relancez pour continuer.`);
35
+ }
36
+ // MODULE_COMPLETE
@@ -0,0 +1,28 @@
1
+ // src/cli/auto-resume.js — Handler `auto resume` : reprise après crash/arrêt.
2
+ // Pilier 2 (séquenceur résilient). Si le plan attend un consentement → exit(2).
3
+
4
+ import { reportAutoOutcome } from "./auto-report.js";
5
+
6
+ // Handler de `auto resume`. Reprise → issue. needsConsent → exit(2) (lancer `run`).
7
+ /** @param {AutoShell} auto @param {AutoFlags} flags @param {string} projectPath @param {AutoGateOk} g @returns {Promise<void>} */
8
+ export async function handleAutoResume(auto, flags, projectPath, g) {
9
+ try {
10
+ const r = await auto.resumeAuto({ projectPath, maxSteps: flags.maxSteps, pcfg: g.pcfg, cfg: g.cfg, answer: flags.answer });
11
+ if (r.isError) { console.error("\n " + r.text); process.exit(1); }
12
+ if (r.needsConsent && flags.yes) { // « Reprendre » cliqué = consentement explicite (devis déjà vu et approuvé) : le plan est lancé au lieu de rester en attente
13
+ reportAutoOutcome(await auto.runAutoRun({ projectPath, confirmed: true, maxSteps: flags.maxSteps, pcfg: g.pcfg, cfg: g.cfg }), flags, "Reprise Auto");
14
+ return;
15
+ }
16
+ if (r.needsConsent) {
17
+ console.log("\n" + r.quote);
18
+ console.error("\n ✗ Le plan attend un consentement. Lancez `npx pipcode auto run --project …` pour confirmer.");
19
+ process.exit(2);
20
+ }
21
+ reportAutoOutcome(r, flags, "Reprise Auto");
22
+ } catch (err) {
23
+ const e = /** @type {NodeErr} */ (err);
24
+ console.error("\n ✗ Reprise Auto échouée :", e.message);
25
+ process.exit(1);
26
+ }
27
+ }
28
+ // MODULE_COMPLETE
@@ -0,0 +1,20 @@
1
+ // src/cli/auto-rules.js — Règles métier requises par plan/run/resume : chargées depuis le serveur PipCode
2
+ // AVANT tout appel modèle (0 token si indisponibles). `ask` n'en a pas besoin (conversation pure).
3
+
4
+ import { ensureRules } from "../rules/rules-load.js";
5
+
6
+ export const RULES_EXIT_CODE = 5;
7
+
8
+ /** @param {PlugConfig} cfg @param {string} action @returns {Promise<boolean>} true = on continue */
9
+ export async function prepareRules(cfg, action) {
10
+ if (action !== "plan" && action !== "run" && action !== "resume") return true;
11
+ try {
12
+ await ensureRules(cfg);
13
+ return true;
14
+ } catch (e) {
15
+ console.error("\n ✗ " + /** @type {Error} */ (e).message);
16
+ process.exitCode = RULES_EXIT_CODE;
17
+ return false;
18
+ }
19
+ }
20
+ // MODULE_COMPLETE
@@ -0,0 +1,26 @@
1
+ // src/cli/auto-run.js — Handler `auto run` : exécute le plan Auto après consentement.
2
+ // Pilier 1 (devis) → consentement Y/n (BLOCK) → Pilier 2 (séquenceur résilient).
3
+
4
+ import { resolveAutoQuote } from "./auto-quote.js";
5
+ import { confirmConsent } from "./auto-consent.js";
6
+ import { reportAutoOutcome } from "./auto-report.js";
7
+
8
+ // Handler principal de `auto run`. Devis → consentement → exécution → rendu issue.
9
+ /** @param {AutoShell} auto @param {AutoFlags} flags @param {string} projectPath @param {AutoGateOk} g @returns {Promise<void>} */
10
+ export async function handleAutoRun(auto, flags, projectPath, g) {
11
+ try {
12
+ const quote = await resolveAutoQuote(auto, flags, projectPath, g);
13
+ console.log("\n" + quote);
14
+ // Gate de consentement (Pilier 1) : BLOCK avant exécution.
15
+ const confirmed = await confirmConsent(flags);
16
+ if (!confirmed) { console.log("\n ⏸ Exécution annulée (plan non confirmé)."); return; }
17
+ const r = await auto.runAutoRun({ projectPath, confirmed: true, maxSteps: flags.maxSteps, pcfg: g.pcfg, cfg: g.cfg });
18
+ if (r.isError) { console.error("\n " + r.text); process.exit(1); }
19
+ reportAutoOutcome(r, flags, "Auto Mode");
20
+ } catch (err) {
21
+ const e = /** @type {NodeErr} */ (err);
22
+ console.error("\n ✗ Exécution Auto échouée :", e.message);
23
+ process.exit(1);
24
+ }
25
+ }
26
+ // MODULE_COMPLETE
@@ -0,0 +1,26 @@
1
+ // src/cli/auto-task.js — Besoin effectif de `auto plan` : sans tâche, le --need de
2
+ // l'utilisateur ; avec `--task audit` (ou PLUGCTO_TASK), un LIBELLÉ PUBLIC comme
3
+ // besoin (c'est lui qui est affiché et persisté) et les instructions CONFIDENTIELLES
4
+ // récupérées auprès du serveur, transmises à la seule décomposition. Tâche inconnue
5
+ // → erreur exit 2 ; protocole indisponible → erreur exit 5 (message honnête).
6
+
7
+ import { AUDIT_LABEL, loadAuditInstructions } from "../engine/audit-task.js";
8
+
9
+ /** @typedef {Error & { exitCode?: number }} TaskError */
10
+
11
+ /** @param {string} message @param {number} exitCode @returns {TaskError} */
12
+ function fail(message, exitCode) {
13
+ const e = /** @type {TaskError} */ (new Error(message));
14
+ e.exitCode = exitCode;
15
+ return e;
16
+ }
17
+
18
+ /** @param {AutoFlags} flags @param {PlugConfig} cfg @param {{ env?: Record<string, string | undefined>, load?: typeof loadAuditInstructions }} [deps] @returns {Promise<{ need: string, instructions: string }>} */
19
+ export async function resolveTask(flags, cfg, { env = process.env, load = loadAuditInstructions } = {}) {
20
+ const task = String(flags.task || env.PLUGCTO_TASK || "").trim().toLowerCase();
21
+ if (!task) return { need: flags.need, instructions: "" };
22
+ if (task !== "audit") throw fail(`Tâche inconnue « ${task} » (valeur acceptée : audit).`, 2);
23
+ try { return { need: AUDIT_LABEL, instructions: await load(cfg) }; }
24
+ catch (e) { throw fail(/** @type {Error} */ (e).message, 5); }
25
+ }
26
+ // MODULE_COMPLETE
@@ -0,0 +1,20 @@
1
+ // src/cli/banner.js — Bannière de démarrage + liste des candidats IDE détectés.
2
+ // Affiche l'en-tête PipCode, le système détecté et chaque candidat avec son
3
+ // drapeau de détection (✓ installé / non installé).
4
+
5
+ /** @typedef {{ id: string, name: string, path: string, parentExists: boolean, configExists: boolean, schema?: "mcpServers" | "servers" | "context_servers" | "toml" }} IdeConfigEntry */
6
+
7
+ // Affiche l'en-tête + la liste des candidats IDE (détectés ou non).
8
+ /** @param {string} osName @param {IdeConfigEntry[]} candidates */
9
+ export function printBanner(osName, candidates) {
10
+ console.log("╔══════════════════════════════════════════════════════════╗");
11
+ console.log("║ PipCode — auto-configuration MCP (Zero-Click, BYOK) ║");
12
+ console.log("╚══════════════════════════════════════════════════════════╝");
13
+ console.log(`\n Système détecté : ${osName}`);
14
+ console.log(" IDE candidats :");
15
+ candidates.forEach((c) => {
16
+ const tag = c.parentExists ? "✓ détecté" : " non installé";
17
+ console.log(` • ${c.name.padEnd(16)} ${tag} ${c.path}`);
18
+ });
19
+ }
20
+ // MODULE_COMPLETE
@@ -0,0 +1,23 @@
1
+ // src/cli/centralize.js — Centralisation best-effort du token + email dans
2
+ // ~/.pipcode/config.json (partagé CLI / agents / extension VS Code).
3
+ // Un échec d'écriture n'empêche pas l'inscription MCP (la licence reste dans l'env).
4
+
5
+ import { writeSharedConfig } from "../fs/config-write.js";
6
+
7
+ /** @typedef {{ licenseKey: string, email: string }} CollectedConfig */
8
+
9
+ // Écrit le token + email validés dans la config partagée. Best-effort (log seulement).
10
+ /** @param {CollectedConfig} collected @returns {Promise<void>} */
11
+ export async function centralizeConfig(collected) {
12
+ try {
13
+ const sc = await writeSharedConfig({ licenseKey: collected.licenseKey, email: collected.email });
14
+ if (collected.licenseKey) {
15
+ console.log(` 🔑 Licence centralisée dans ${sc.path} (partagée CLI / agents / extension).`);
16
+ }
17
+ } catch (err) {
18
+ const e = /** @type {Error} */ (err);
19
+ if (collected.licenseKey) throw new Error(`Licence NON enregistrée : impossible d'écrire la config partagée (${e.message})`); // la licence ne vit que là : échec franc plutôt qu'un client sans licence
20
+ console.error(` ⚠️ Impossible de centraliser la config partagée : ${e.message}`);
21
+ }
22
+ }
23
+ // MODULE_COMPLETE
@@ -0,0 +1,25 @@
1
+ // src/cli/collect-step.js — Étape collecte du setup (TTY interactive / non-TTY env).
2
+ // TTY : readline + collectInteractive (config existante lue ; licence et e-mail seulement). Non-TTY : collectFromEnv (licence optionnelle : sans clé, 5 jours d'essai).
3
+
4
+ import readline from "node:readline/promises";
5
+ import { stdin, stdout } from "node:process";
6
+ import { collectInteractive } from "./interactive.js";
7
+ import { collectFromEnv } from "../engine/collect.js";
8
+ import { readSharedConfig } from "../fs/config-read.js";
9
+
10
+ /** @typedef {{ licenseKey: string, email: string }} CollectedConfig */
11
+
12
+ // Collecte : interactive si TTY, sinon env vars (CI/tests). Aucune clé d'IA n'est demandée ni exigée.
13
+ /** @param {boolean} isTTY @returns {Promise<CollectedConfig>} */
14
+ export async function collectForSetup(isTTY) {
15
+ if (isTTY) {
16
+ const rl = readline.createInterface({ input: stdin, output: stdout });
17
+ try {
18
+ const existingConfig = await readSharedConfig().catch(() => ({}));
19
+ return await collectInteractive(rl, { existingConfig });
20
+ } finally { rl.close(); }
21
+ }
22
+ console.log("\n (Mode non-interactif : lecture des variables d'environnement.)");
23
+ return collectFromEnv();
24
+ }
25
+ // MODULE_COMPLETE
@@ -0,0 +1,46 @@
1
+ // src/cli/config-pairs.js — Traduction PURE des réponses de `config` en paires
2
+ // .env : inférence du provider cloud depuis le format de la clé (zéro question
3
+ // supplémentaire), bascule Ollama quand la clé BYOK est laissée vide. La clé
4
+ // de licence réutilise la règle de validation de setup-args.js (zéro doublon).
5
+
6
+ import { KEY_RE } from "./setup-args.js";
7
+
8
+ /** @typedef {Record<string, string>} EnvPairs */
9
+
10
+ // Clé API cloud : préfixes des 3 clouds nommés + forme générique (8-256,
11
+ // alphanum/._- : couvre sk-, sk-ant-, sk-or-, AIza…). Espace = rejet.
12
+ const API_KEY_RE = /^[A-Za-z0-9._-]{8,256}$/;
13
+
14
+ // Inférence du provider : sk-ant- (Anthropic) AVANT le préfixe générique sk-.
15
+ /** @param {string} apiKey @returns {string} */
16
+ export function inferProvider(apiKey) {
17
+ if (apiKey.startsWith("sk-ant-")) return "anthropic";
18
+ if (apiKey.startsWith("AIza")) return "gemini";
19
+ return "openai";
20
+ }
21
+
22
+ /**
23
+ * Réponses des 2 questions → paires .env canoniques. Entrée vide = choix
24
+ * explicite : pas de licence (essai 5 jours puis Lite) / mode local Ollama.
25
+ * Validation Zero Trust aux frontières : formats malformés rejetés proprement.
26
+ * @param {string} licenseKey @param {string} apiKey @returns {EnvPairs}
27
+ */
28
+ export function answersToPairs(licenseKey, apiKey) {
29
+ const license = licenseKey.trim();
30
+ const key = apiKey.trim();
31
+ if (license && !KEY_RE.test(license)) {
32
+ throw new Error("Clé de licence malformée (8-128 caractères alphanumériques, tirets ou underscores). Rien saisir = essai 5 jours.");
33
+ }
34
+ if (key && !API_KEY_RE.test(key)) {
35
+ throw new Error("Clé API malformée (espaces ou caractères inattendus). Rien saisir = Mode Local / Ollama.");
36
+ }
37
+ /** @type {EnvPairs} */ const pairs = {};
38
+ if (license) pairs.PLUGCTO_LICENSE_KEY = license;
39
+ if (!key) pairs.PLUGCTO_PROVIDER_PRIMARY = "ollama";
40
+ else {
41
+ pairs.PLUGCTO_PROVIDER_PRIMARY = inferProvider(key);
42
+ pairs.PLUGCTO_PROVIDER_PRIMARY_KEY = key;
43
+ }
44
+ return pairs;
45
+ }
46
+ // MODULE_COMPLETE
@@ -0,0 +1,51 @@
1
+ // src/cli/config.js — `npx pipcode config` : saisie interactive des 2 clés
2
+ // (licence Polar.sh, BYOK cloud) → .env local à la racine du projet, hors Git.
3
+ // Zéro-IA : les clés ne transitent par AUCUN prompt LLM ni appel réseau au
4
+ // moment de la saisie ; elles ne servent ensuite qu'aux en-têtes HTTP vers le
5
+ // provider choisi. Confirmation sans écho : jamais de clé affichée.
6
+
7
+ import readline from "node:readline/promises";
8
+ import { stdin, stdout } from "node:process";
9
+ import { makePrompts } from "./prompts.js";
10
+ import { answersToPairs } from "./config-pairs.js";
11
+ import { rebuildEnvText } from "./env-rebuild.js";
12
+ import { localEnvPath, readLocalEnvText, writeEnvText } from "./env-file.js";
13
+ import { ensureEnvIgnored } from "./gitignore-env.js";
14
+
15
+ /** @typedef {Record<string, string>} EnvPairs */
16
+
17
+ // Résumé final : libellés uniquement, JAMAIS la moindre valeur de clé.
18
+ /** @param {EnvPairs} pairs @param {string} envPath */
19
+ function printSummary(pairs, envPath) {
20
+ const local = pairs.PLUGCTO_PROVIDER_PRIMARY === "ollama";
21
+ const licence = pairs.PLUGCTO_LICENSE_KEY ? "Pro (clé Polar.sh enregistrée)" : "Essai gratuit 5 jours puis Lite";
22
+ const engine = local ? "Mode Local / Ollama (aucune clé cloud)" : `${pairs.PLUGCTO_PROVIDER_PRIMARY} (clé cloud enregistrée)`;
23
+ console.log(`\n ✅ Enregistré (localement, hors Git) : ${envPath}`);
24
+ console.log(` Licence : ${licence}`);
25
+ console.log(` Moteur IA : ${engine}`);
26
+ console.log("\n Prochaine étape : npx pipcode setup (installation/configuration des IDE).");
27
+ }
28
+
29
+ // Commande interactive : 2 questions readline → paires validées → .env fusionné
30
+ // (lignes tierces préservées) → .gitignore garanti → résumé sans écho.
31
+ /** @param {string} [cwd] @returns {Promise<void>} */
32
+ export async function runConfigCli(cwd = process.cwd()) {
33
+ if (!stdin.isTTY) {
34
+ throw new Error("Commande interactive : lancez `npx pipcode config` dans un terminal. Sans terminal : variables d'environnement ou `npx pipcode setup --key <CLÉ>`.");
35
+ }
36
+ const rl = readline.createInterface({ input: stdin, output: stdout });
37
+ try {
38
+ const p = makePrompts(rl);
39
+ console.log("PipCode — configuration locale des clés (stockées dans .env, jamais committées).");
40
+ const licenseKey = await p.ask("Clé de licence Polar.sh (Entrée = Essai gratuit 5 jours / Lite) : ");
41
+ const apiKey = await p.ask("Clé API Cloud BYOK (Gemini, OpenAI, Anthropic - Entrée = Mode Local / Ollama) : ");
42
+ const pairs = answersToPairs(licenseKey, apiKey);
43
+ const existing = (await readLocalEnvText(cwd)) ?? "";
44
+ await writeEnvText(cwd, rebuildEnvText(existing, pairs));
45
+ await ensureEnvIgnored(cwd);
46
+ printSummary(pairs, localEnvPath(cwd));
47
+ } finally {
48
+ rl.close();
49
+ }
50
+ }
51
+ // MODULE_COMPLETE
@@ -0,0 +1,11 @@
1
+ // src/cli/detect-os.js — Détection de plateforme (leaf pur, zéro import).
2
+ // Mappe process.platform vers un identifiant OS stable utilisé par les modules
3
+ // fs (permissions icacls vs chmod) et cli (localisation des config IDE).
4
+
5
+ /** @param {string} [platform] @returns {"macos" | "windows" | "linux"} */
6
+ export function detectOS(platform = process.platform) {
7
+ if (platform === "darwin") return "macos";
8
+ if (platform === "win32") return "windows";
9
+ return "linux";
10
+ }
11
+ // MODULE_COMPLETE