@the-open-engine/zeroshot 5.4.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 (295) hide show
  1. package/CHANGELOG.md +539 -0
  2. package/LICENSE +21 -0
  3. package/README.md +508 -0
  4. package/cli/commands/inspect-render.js +135 -0
  5. package/cli/commands/inspect.js +294 -0
  6. package/cli/commands/providers.js +149 -0
  7. package/cli/index.js +5431 -0
  8. package/cli/lib/first-run.js +211 -0
  9. package/cli/lib/update-checker.js +281 -0
  10. package/cli/message-formatter-utils.js +75 -0
  11. package/cli/message-formatters-normal.js +275 -0
  12. package/cli/message-formatters-watch.js +185 -0
  13. package/cluster-templates/base-templates/debug-workflow.json +422 -0
  14. package/cluster-templates/base-templates/full-workflow.json +727 -0
  15. package/cluster-templates/base-templates/heavy-validation.json +272 -0
  16. package/cluster-templates/base-templates/quick-validation.json +285 -0
  17. package/cluster-templates/base-templates/single-worker.json +71 -0
  18. package/cluster-templates/base-templates/worker-validator.json +230 -0
  19. package/cluster-templates/conductor-bootstrap.json +130 -0
  20. package/docker/zeroshot-cluster/Dockerfile +153 -0
  21. package/docker/zeroshot-cluster/pre-baked-deps.json +28 -0
  22. package/lib/agent-cli-provider/adapters/claude-parser.d.ts +3 -0
  23. package/lib/agent-cli-provider/adapters/claude-parser.d.ts.map +1 -0
  24. package/lib/agent-cli-provider/adapters/claude-parser.js +122 -0
  25. package/lib/agent-cli-provider/adapters/claude-parser.js.map +1 -0
  26. package/lib/agent-cli-provider/adapters/claude-recovery.d.ts +15 -0
  27. package/lib/agent-cli-provider/adapters/claude-recovery.d.ts.map +1 -0
  28. package/lib/agent-cli-provider/adapters/claude-recovery.js +165 -0
  29. package/lib/agent-cli-provider/adapters/claude-recovery.js.map +1 -0
  30. package/lib/agent-cli-provider/adapters/claude.d.ts +3 -0
  31. package/lib/agent-cli-provider/adapters/claude.d.ts.map +1 -0
  32. package/lib/agent-cli-provider/adapters/claude.js +181 -0
  33. package/lib/agent-cli-provider/adapters/claude.js.map +1 -0
  34. package/lib/agent-cli-provider/adapters/codex-parser.d.ts +3 -0
  35. package/lib/agent-cli-provider/adapters/codex-parser.d.ts.map +1 -0
  36. package/lib/agent-cli-provider/adapters/codex-parser.js +192 -0
  37. package/lib/agent-cli-provider/adapters/codex-parser.js.map +1 -0
  38. package/lib/agent-cli-provider/adapters/codex.d.ts +3 -0
  39. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -0
  40. package/lib/agent-cli-provider/adapters/codex.js +151 -0
  41. package/lib/agent-cli-provider/adapters/codex.js.map +1 -0
  42. package/lib/agent-cli-provider/adapters/common.d.ts +28 -0
  43. package/lib/agent-cli-provider/adapters/common.d.ts.map +1 -0
  44. package/lib/agent-cli-provider/adapters/common.js +71 -0
  45. package/lib/agent-cli-provider/adapters/common.js.map +1 -0
  46. package/lib/agent-cli-provider/adapters/gemini.d.ts +3 -0
  47. package/lib/agent-cli-provider/adapters/gemini.d.ts.map +1 -0
  48. package/lib/agent-cli-provider/adapters/gemini.js +176 -0
  49. package/lib/agent-cli-provider/adapters/gemini.js.map +1 -0
  50. package/lib/agent-cli-provider/adapters/index.d.ts +9 -0
  51. package/lib/agent-cli-provider/adapters/index.d.ts.map +1 -0
  52. package/lib/agent-cli-provider/adapters/index.js +95 -0
  53. package/lib/agent-cli-provider/adapters/index.js.map +1 -0
  54. package/lib/agent-cli-provider/adapters/opencode.d.ts +3 -0
  55. package/lib/agent-cli-provider/adapters/opencode.d.ts.map +1 -0
  56. package/lib/agent-cli-provider/adapters/opencode.js +228 -0
  57. package/lib/agent-cli-provider/adapters/opencode.js.map +1 -0
  58. package/lib/agent-cli-provider/contract-actions.d.ts +5 -0
  59. package/lib/agent-cli-provider/contract-actions.d.ts.map +1 -0
  60. package/lib/agent-cli-provider/contract-actions.js +140 -0
  61. package/lib/agent-cli-provider/contract-actions.js.map +1 -0
  62. package/lib/agent-cli-provider/contract-env.d.ts +11 -0
  63. package/lib/agent-cli-provider/contract-env.d.ts.map +1 -0
  64. package/lib/agent-cli-provider/contract-env.js +113 -0
  65. package/lib/agent-cli-provider/contract-env.js.map +1 -0
  66. package/lib/agent-cli-provider/contract-envelope.d.ts +49 -0
  67. package/lib/agent-cli-provider/contract-envelope.d.ts.map +1 -0
  68. package/lib/agent-cli-provider/contract-envelope.js +52 -0
  69. package/lib/agent-cli-provider/contract-envelope.js.map +1 -0
  70. package/lib/agent-cli-provider/contract-errors.d.ts +22 -0
  71. package/lib/agent-cli-provider/contract-errors.d.ts.map +1 -0
  72. package/lib/agent-cli-provider/contract-errors.js +71 -0
  73. package/lib/agent-cli-provider/contract-errors.js.map +1 -0
  74. package/lib/agent-cli-provider/contract-fallback.d.ts +7 -0
  75. package/lib/agent-cli-provider/contract-fallback.d.ts.map +1 -0
  76. package/lib/agent-cli-provider/contract-fallback.js +102 -0
  77. package/lib/agent-cli-provider/contract-fallback.js.map +1 -0
  78. package/lib/agent-cli-provider/contract-invoke.d.ts +5 -0
  79. package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -0
  80. package/lib/agent-cli-provider/contract-invoke.js +89 -0
  81. package/lib/agent-cli-provider/contract-invoke.js.map +1 -0
  82. package/lib/agent-cli-provider/contract-options.d.ts +3 -0
  83. package/lib/agent-cli-provider/contract-options.d.ts.map +1 -0
  84. package/lib/agent-cli-provider/contract-options.js +140 -0
  85. package/lib/agent-cli-provider/contract-options.js.map +1 -0
  86. package/lib/agent-cli-provider/contract-parse.d.ts +15 -0
  87. package/lib/agent-cli-provider/contract-parse.d.ts.map +1 -0
  88. package/lib/agent-cli-provider/contract-parse.js +81 -0
  89. package/lib/agent-cli-provider/contract-parse.js.map +1 -0
  90. package/lib/agent-cli-provider/contract-support.d.ts +18 -0
  91. package/lib/agent-cli-provider/contract-support.d.ts.map +1 -0
  92. package/lib/agent-cli-provider/contract-support.js +154 -0
  93. package/lib/agent-cli-provider/contract-support.js.map +1 -0
  94. package/lib/agent-cli-provider/contract.d.ts +13 -0
  95. package/lib/agent-cli-provider/contract.d.ts.map +1 -0
  96. package/lib/agent-cli-provider/contract.js +30 -0
  97. package/lib/agent-cli-provider/contract.js.map +1 -0
  98. package/lib/agent-cli-provider/env-safety.d.ts +11 -0
  99. package/lib/agent-cli-provider/env-safety.d.ts.map +1 -0
  100. package/lib/agent-cli-provider/env-safety.js +83 -0
  101. package/lib/agent-cli-provider/env-safety.js.map +1 -0
  102. package/lib/agent-cli-provider/errors.d.ts +5 -0
  103. package/lib/agent-cli-provider/errors.d.ts.map +1 -0
  104. package/lib/agent-cli-provider/errors.js +115 -0
  105. package/lib/agent-cli-provider/errors.js.map +1 -0
  106. package/lib/agent-cli-provider/executable.d.ts +3 -0
  107. package/lib/agent-cli-provider/executable.d.ts.map +1 -0
  108. package/lib/agent-cli-provider/executable.js +24 -0
  109. package/lib/agent-cli-provider/executable.js.map +1 -0
  110. package/lib/agent-cli-provider/index.d.ts +8 -0
  111. package/lib/agent-cli-provider/index.d.ts.map +1 -0
  112. package/lib/agent-cli-provider/index.js +31 -0
  113. package/lib/agent-cli-provider/index.js.map +1 -0
  114. package/lib/agent-cli-provider/invoke-evidence.d.ts +4 -0
  115. package/lib/agent-cli-provider/invoke-evidence.d.ts.map +1 -0
  116. package/lib/agent-cli-provider/invoke-evidence.js +17 -0
  117. package/lib/agent-cli-provider/invoke-evidence.js.map +1 -0
  118. package/lib/agent-cli-provider/json.d.ts +16 -0
  119. package/lib/agent-cli-provider/json.d.ts.map +1 -0
  120. package/lib/agent-cli-provider/json.js +110 -0
  121. package/lib/agent-cli-provider/json.js.map +1 -0
  122. package/lib/agent-cli-provider/log-prefix.d.ts +2 -0
  123. package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -0
  124. package/lib/agent-cli-provider/log-prefix.js +22 -0
  125. package/lib/agent-cli-provider/log-prefix.js.map +1 -0
  126. package/lib/agent-cli-provider/process-runner.d.ts +17 -0
  127. package/lib/agent-cli-provider/process-runner.d.ts.map +1 -0
  128. package/lib/agent-cli-provider/process-runner.js +89 -0
  129. package/lib/agent-cli-provider/process-runner.js.map +1 -0
  130. package/lib/agent-cli-provider/redaction.d.ts +9 -0
  131. package/lib/agent-cli-provider/redaction.d.ts.map +1 -0
  132. package/lib/agent-cli-provider/redaction.js +227 -0
  133. package/lib/agent-cli-provider/redaction.js.map +1 -0
  134. package/lib/agent-cli-provider/schema.d.ts +5 -0
  135. package/lib/agent-cli-provider/schema.d.ts.map +1 -0
  136. package/lib/agent-cli-provider/schema.js +136 -0
  137. package/lib/agent-cli-provider/schema.js.map +1 -0
  138. package/lib/agent-cli-provider/single-agent-runtime.d.ts +15 -0
  139. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -0
  140. package/lib/agent-cli-provider/single-agent-runtime.js +228 -0
  141. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -0
  142. package/lib/agent-cli-provider/types.d.ts +194 -0
  143. package/lib/agent-cli-provider/types.d.ts.map +1 -0
  144. package/lib/agent-cli-provider/types.js +12 -0
  145. package/lib/agent-cli-provider/types.js.map +1 -0
  146. package/lib/completion.js +174 -0
  147. package/lib/detached-startup.js +220 -0
  148. package/lib/docker-config.js +220 -0
  149. package/lib/git-remote-utils.js +165 -0
  150. package/lib/id-detector.js +55 -0
  151. package/lib/provider-defaults.js +62 -0
  152. package/lib/provider-detection.js +59 -0
  153. package/lib/provider-names.js +57 -0
  154. package/lib/repo-settings.js +69 -0
  155. package/lib/settings/claude-auth.js +78 -0
  156. package/lib/settings.js +542 -0
  157. package/lib/start-cluster.js +321 -0
  158. package/lib/stream-json-parser.js +67 -0
  159. package/package.json +162 -0
  160. package/scripts/fix-node-pty-permissions.js +75 -0
  161. package/scripts/record-demo.sh +279 -0
  162. package/scripts/setup-merge-queue.sh +170 -0
  163. package/scripts/test-install.sh +40 -0
  164. package/scripts/validate-templates.js +107 -0
  165. package/src/agent/agent-config.js +266 -0
  166. package/src/agent/agent-context-builder.js +189 -0
  167. package/src/agent/agent-context-sections.js +338 -0
  168. package/src/agent/agent-context-sources.js +147 -0
  169. package/src/agent/agent-hook-executor.js +721 -0
  170. package/src/agent/agent-input-injector.js +141 -0
  171. package/src/agent/agent-lifecycle.js +982 -0
  172. package/src/agent/agent-quality-gate-schema.js +93 -0
  173. package/src/agent/agent-quality-gates-context.js +51 -0
  174. package/src/agent/agent-stuck-detector.js +256 -0
  175. package/src/agent/agent-task-executor.js +2028 -0
  176. package/src/agent/agent-trigger-evaluator.js +67 -0
  177. package/src/agent/context-metrics.js +160 -0
  178. package/src/agent/context-pack-builder.js +367 -0
  179. package/src/agent/context-replay-policy.js +51 -0
  180. package/src/agent/guidance-queue.js +77 -0
  181. package/src/agent/output-extraction.js +367 -0
  182. package/src/agent/output-reformatter.js +175 -0
  183. package/src/agent/pr-verification.js +653 -0
  184. package/src/agent/rate-limit-backoff.js +82 -0
  185. package/src/agent/schema-utils.js +146 -0
  186. package/src/agent/validation-platform.js +35 -0
  187. package/src/agent-cli-provider/adapters/claude-parser.ts +133 -0
  188. package/src/agent-cli-provider/adapters/claude-recovery.ts +203 -0
  189. package/src/agent-cli-provider/adapters/claude.ts +247 -0
  190. package/src/agent-cli-provider/adapters/codex-parser.ts +211 -0
  191. package/src/agent-cli-provider/adapters/codex.ts +217 -0
  192. package/src/agent-cli-provider/adapters/common.ts +124 -0
  193. package/src/agent-cli-provider/adapters/gemini.ts +243 -0
  194. package/src/agent-cli-provider/adapters/index.ts +126 -0
  195. package/src/agent-cli-provider/adapters/opencode.ts +286 -0
  196. package/src/agent-cli-provider/contract-actions.ts +150 -0
  197. package/src/agent-cli-provider/contract-env.ts +111 -0
  198. package/src/agent-cli-provider/contract-envelope.ts +110 -0
  199. package/src/agent-cli-provider/contract-errors.ts +66 -0
  200. package/src/agent-cli-provider/contract-fallback.ts +121 -0
  201. package/src/agent-cli-provider/contract-invoke.ts +104 -0
  202. package/src/agent-cli-provider/contract-options.ts +173 -0
  203. package/src/agent-cli-provider/contract-parse.ts +94 -0
  204. package/src/agent-cli-provider/contract-support.ts +167 -0
  205. package/src/agent-cli-provider/contract.ts +56 -0
  206. package/src/agent-cli-provider/env-safety.ts +82 -0
  207. package/src/agent-cli-provider/errors.ts +122 -0
  208. package/src/agent-cli-provider/executable.ts +24 -0
  209. package/src/agent-cli-provider/index.ts +83 -0
  210. package/src/agent-cli-provider/invoke-evidence.ts +18 -0
  211. package/src/agent-cli-provider/json.ts +114 -0
  212. package/src/agent-cli-provider/log-prefix.ts +20 -0
  213. package/src/agent-cli-provider/process-runner.ts +145 -0
  214. package/src/agent-cli-provider/redaction.ts +282 -0
  215. package/src/agent-cli-provider/schema.ts +115 -0
  216. package/src/agent-cli-provider/single-agent-runtime.ts +311 -0
  217. package/src/agent-cli-provider/types.ts +237 -0
  218. package/src/agent-wrapper.js +615 -0
  219. package/src/agents/git-pusher-template.js +705 -0
  220. package/src/attach/attach-client.js +438 -0
  221. package/src/attach/attach-server.js +543 -0
  222. package/src/attach/index.js +37 -0
  223. package/src/attach/protocol.js +220 -0
  224. package/src/attach/ring-buffer.js +121 -0
  225. package/src/attach/send-input.js +88 -0
  226. package/src/attach/socket-discovery.js +267 -0
  227. package/src/claude-task-runner.js +661 -0
  228. package/src/config-router.js +89 -0
  229. package/src/config-validator.js +2202 -0
  230. package/src/copy-worker.js +43 -0
  231. package/src/guidance-topics.js +10 -0
  232. package/src/input-helpers.js +65 -0
  233. package/src/isolation-manager.js +1734 -0
  234. package/src/issue-providers/README.md +305 -0
  235. package/src/issue-providers/azure-devops-provider.js +307 -0
  236. package/src/issue-providers/base-provider.js +232 -0
  237. package/src/issue-providers/github-provider.js +210 -0
  238. package/src/issue-providers/gitlab-provider.js +262 -0
  239. package/src/issue-providers/index.js +196 -0
  240. package/src/issue-providers/jira-provider.js +260 -0
  241. package/src/ledger.js +692 -0
  242. package/src/lib/gc.js +232 -0
  243. package/src/lib/safe-exec.js +88 -0
  244. package/src/logic-engine.js +201 -0
  245. package/src/message-buffer.js +81 -0
  246. package/src/message-bus-bridge.js +144 -0
  247. package/src/message-bus.js +256 -0
  248. package/src/name-generator.js +232 -0
  249. package/src/orchestrator.js +3924 -0
  250. package/src/preflight.js +712 -0
  251. package/src/process-metrics.js +608 -0
  252. package/src/providers/anthropic/index.js +3 -0
  253. package/src/providers/base-provider.js +355 -0
  254. package/src/providers/capabilities.js +60 -0
  255. package/src/providers/google/index.js +3 -0
  256. package/src/providers/index.js +293 -0
  257. package/src/providers/openai/index.js +3 -0
  258. package/src/providers/opencode/index.js +3 -0
  259. package/src/quality-gates.js +143 -0
  260. package/src/schemas/sub-cluster.js +208 -0
  261. package/src/state-snapshot.js +398 -0
  262. package/src/state-snapshotter.js +142 -0
  263. package/src/status-footer.js +1026 -0
  264. package/src/sub-cluster-wrapper.js +693 -0
  265. package/src/task-runner.js +30 -0
  266. package/src/template-resolver.js +425 -0
  267. package/src/template-validation/index.js +338 -0
  268. package/src/template-validation/simulate-consensus-gates.js +324 -0
  269. package/src/template-validation/simulate-random-topology.js +541 -0
  270. package/src/template-validation/simulate-two-stage-validation.js +270 -0
  271. package/src/worktree-claude-config.js +135 -0
  272. package/src/worktree-tooling-env.js +150 -0
  273. package/task-lib/attachable-watcher.js +381 -0
  274. package/task-lib/commands/clean.js +50 -0
  275. package/task-lib/commands/episodes.js +105 -0
  276. package/task-lib/commands/get-log-path.js +23 -0
  277. package/task-lib/commands/kill.js +32 -0
  278. package/task-lib/commands/list.js +105 -0
  279. package/task-lib/commands/logs.js +439 -0
  280. package/task-lib/commands/resume.js +42 -0
  281. package/task-lib/commands/run.js +57 -0
  282. package/task-lib/commands/schedule.js +105 -0
  283. package/task-lib/commands/scheduler-cmd.js +96 -0
  284. package/task-lib/commands/schedules.js +148 -0
  285. package/task-lib/commands/status.js +44 -0
  286. package/task-lib/commands/unschedule.js +16 -0
  287. package/task-lib/completion.js +9 -0
  288. package/task-lib/config.js +11 -0
  289. package/task-lib/name-generator.js +230 -0
  290. package/task-lib/package.json +3 -0
  291. package/task-lib/provider-helper-runtime.js +29 -0
  292. package/task-lib/runner.js +190 -0
  293. package/task-lib/scheduler.js +252 -0
  294. package/task-lib/store.js +529 -0
  295. package/task-lib/watcher.js +305 -0
@@ -0,0 +1,211 @@
1
+ /**
2
+ * First-Run Setup Wizard
3
+ *
4
+ * Interactive setup on first use:
5
+ * - Welcome banner
6
+ * - Max model ceiling selection (sonnet/opus/haiku)
7
+ * - Auto-update preference
8
+ * - Marks setup as complete
9
+ */
10
+
11
+ const readline = require('readline');
12
+ const { loadSettings, saveSettings } = require('../../lib/settings');
13
+ const { detectProviders } = require('../../src/providers');
14
+
15
+ /**
16
+ * Print welcome banner
17
+ */
18
+ function printWelcome() {
19
+ console.log(`
20
+ ╔═══════════════════════════════════════════════════════════════╗
21
+ ā•‘ ā•‘
22
+ ā•‘ Welcome to Zeroshot! ā•‘
23
+ ā•‘ Multi-agent orchestration engine ā•‘
24
+ ā•‘ ā•‘
25
+ ā•‘ Let's configure a few settings to get started. ā•‘
26
+ ā•‘ ā•‘
27
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
28
+ `);
29
+ }
30
+
31
+ /**
32
+ * Create readline interface
33
+ * @returns {readline.Interface}
34
+ */
35
+ function createReadline() {
36
+ return readline.createInterface({
37
+ input: process.stdin,
38
+ output: process.stdout,
39
+ });
40
+ }
41
+
42
+ /**
43
+ * Prompt for provider selection
44
+ * @param {readline.Interface} rl
45
+ * @param {object} detected
46
+ * @returns {Promise<string>}
47
+ */
48
+ function promptProvider(rl, detected) {
49
+ console.log('\nWhich AI provider would you like to use by default?\n');
50
+
51
+ const available = Object.entries(detected).filter(([_, status]) => status.available);
52
+
53
+ if (available.length === 0) {
54
+ console.log('No AI CLI tools detected. Please install one of:');
55
+ console.log(' - Claude Code: npm install -g @anthropic-ai/claude-code');
56
+ console.log(' - Codex CLI: npm install -g @openai/codex');
57
+ console.log(' - Gemini CLI: npm install -g @google/gemini-cli');
58
+ process.exit(1);
59
+ }
60
+
61
+ available.forEach(([name], i) => {
62
+ console.log(` ${i + 1}) ${name} (installed)`);
63
+ });
64
+
65
+ return new Promise((resolve) => {
66
+ rl.question('\nChoice [1]: ', (answer) => {
67
+ const idx = parseInt(answer) - 1 || 0;
68
+ resolve(available[idx]?.[0] || available[0][0]);
69
+ });
70
+ });
71
+ }
72
+
73
+ /**
74
+ * Prompt for model selection
75
+ * @param {readline.Interface} rl
76
+ * @returns {Promise<string>}
77
+ */
78
+ function promptModel(rl) {
79
+ return new Promise((resolve) => {
80
+ console.log('What is the maximum Claude model agents can use? (cost ceiling)\n');
81
+ console.log(' 1) sonnet - Agents can use sonnet or haiku (recommended)');
82
+ console.log(' 2) opus - Agents can use opus, sonnet, or haiku');
83
+ console.log(' 3) haiku - Agents can only use haiku (lowest cost)\n');
84
+
85
+ rl.question('Enter 1, 2, or 3 [2]: ', (answer) => {
86
+ const choice = answer.trim() || '2';
87
+ switch (choice) {
88
+ case '2':
89
+ resolve('opus');
90
+ break;
91
+ case '3':
92
+ resolve('haiku');
93
+ break;
94
+ default:
95
+ resolve('sonnet');
96
+ }
97
+ });
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Prompt for auto-update preference
103
+ * @param {readline.Interface} rl
104
+ * @returns {Promise<boolean>}
105
+ */
106
+ function promptAutoUpdate(rl) {
107
+ return new Promise((resolve) => {
108
+ console.log('\nWould you like zeroshot to check for updates automatically?');
109
+ console.log('(Checks npm registry every 24 hours)\n');
110
+
111
+ rl.question('Enable auto-update checks? [Y/n]: ', (answer) => {
112
+ const normalized = answer.trim().toLowerCase();
113
+ // Default to yes if empty or starts with 'y'
114
+ resolve(normalized === '' || normalized === 'y' || normalized === 'yes');
115
+ });
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Print completion message
121
+ * @param {object} settings - Saved settings
122
+ */
123
+ function printComplete(settings) {
124
+ console.log(`
125
+ ╔═══════════════════════════════════════════════════════════════╗
126
+ ā•‘ Setup complete! ā•‘
127
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
128
+
129
+ Your settings:
130
+ • Provider: ${settings.defaultProvider}
131
+ • Max model: ${settings.maxModel} (Claude ceiling)
132
+ • Auto-updates: ${settings.autoCheckUpdates ? 'enabled' : 'disabled'}
133
+
134
+ Change anytime with: zeroshot settings set <key> <value>
135
+
136
+ Get started:
137
+ zeroshot run "Fix the bug in auth.js"
138
+ zeroshot run 123 (GitHub issue number)
139
+ zeroshot --help
140
+
141
+ `);
142
+ }
143
+
144
+ /**
145
+ * Check if first-run setup is needed
146
+ * @param {object} settings - Current settings
147
+ * @returns {boolean}
148
+ */
149
+ function detectFirstRun(settings) {
150
+ return !settings.firstRunComplete;
151
+ }
152
+
153
+ /**
154
+ * Main entry point - run first-time setup if needed
155
+ * @param {object} options
156
+ * @param {boolean} options.quiet - Skip interactive prompts
157
+ * @returns {Promise<boolean>} True if setup was run
158
+ */
159
+ async function checkFirstRun(options = {}) {
160
+ const settings = loadSettings();
161
+
162
+ // Already completed setup
163
+ if (!detectFirstRun(settings)) {
164
+ return false;
165
+ }
166
+
167
+ // Quiet mode - use defaults, mark complete
168
+ if (options.quiet) {
169
+ settings.firstRunComplete = true;
170
+ saveSettings(settings);
171
+ return true;
172
+ }
173
+
174
+ // Interactive setup
175
+ printWelcome();
176
+
177
+ const rl = createReadline();
178
+
179
+ try {
180
+ const detected = await detectProviders();
181
+ const provider = await promptProvider(rl, detected);
182
+ settings.defaultProvider = provider;
183
+
184
+ // Model ceiling selection
185
+ const model = await promptModel(rl);
186
+ settings.maxModel = model;
187
+
188
+ // Auto-update preference
189
+ const autoUpdate = await promptAutoUpdate(rl);
190
+ settings.autoCheckUpdates = autoUpdate;
191
+
192
+ // Mark complete
193
+ settings.firstRunComplete = true;
194
+ saveSettings(settings);
195
+
196
+ // Print completion
197
+ printComplete(settings);
198
+
199
+ return true;
200
+ } finally {
201
+ rl.close();
202
+ }
203
+ }
204
+
205
+ module.exports = {
206
+ checkFirstRun,
207
+ // Exported for testing
208
+ detectFirstRun,
209
+ printWelcome,
210
+ printComplete,
211
+ };
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Update Checker - Checks npm registry for newer versions
3
+ *
4
+ * Features:
5
+ * - 24-hour check interval (avoids registry spam)
6
+ * - 5-second timeout (non-blocking if offline)
7
+ * - Interactive prompt for manual update
8
+ * - Respects quiet mode (no prompts in CI/scripts)
9
+ */
10
+
11
+ const https = require('https');
12
+ const { spawn } = require('child_process');
13
+ const readline = require('readline');
14
+ const { loadSettings, saveSettings } = require('../../lib/settings');
15
+
16
+ // 24 hours in milliseconds
17
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
18
+
19
+ // Timeout for npm registry fetch (5 seconds)
20
+ const FETCH_TIMEOUT_MS = 5000;
21
+
22
+ // npm registry URL
23
+ const REGISTRY_URL = 'https://registry.npmjs.org/@the-open-engine/zeroshot/latest';
24
+
25
+ /**
26
+ * Get current package version
27
+ * @returns {string}
28
+ */
29
+ function getCurrentVersion() {
30
+ const pkg = require('../../package.json');
31
+ return pkg.version;
32
+ }
33
+
34
+ /**
35
+ * Compare semver versions
36
+ * @param {string} current - Current version (e.g., "1.5.0")
37
+ * @param {string} latest - Latest version (e.g., "1.6.0")
38
+ * @returns {boolean} True if latest > current
39
+ */
40
+ function isNewerVersion(current, latest) {
41
+ const currentParts = current.split('.').map(Number);
42
+ const latestParts = latest.split('.').map(Number);
43
+
44
+ for (let i = 0; i < 3; i++) {
45
+ const c = currentParts[i] || 0;
46
+ const l = latestParts[i] || 0;
47
+ if (l > c) return true;
48
+ if (l < c) return false;
49
+ }
50
+ return false;
51
+ }
52
+
53
+ /**
54
+ * Fetch latest version from npm registry
55
+ * @returns {Promise<string|null>} Latest version or null on failure
56
+ */
57
+ function fetchLatestVersion() {
58
+ return new Promise((resolve) => {
59
+ const req = https.get(REGISTRY_URL, { timeout: FETCH_TIMEOUT_MS }, (res) => {
60
+ if (res.statusCode !== 200) {
61
+ resolve(null);
62
+ return;
63
+ }
64
+
65
+ let data = '';
66
+ res.on('data', (chunk) => {
67
+ data += chunk;
68
+ });
69
+
70
+ res.on('end', () => {
71
+ try {
72
+ const json = JSON.parse(data);
73
+ resolve(json.version || null);
74
+ } catch {
75
+ resolve(null);
76
+ }
77
+ });
78
+ });
79
+
80
+ req.on('error', () => {
81
+ resolve(null);
82
+ });
83
+
84
+ req.on('timeout', () => {
85
+ req.destroy();
86
+ resolve(null);
87
+ });
88
+
89
+ // Additional safety timeout
90
+ setTimeout(() => {
91
+ req.destroy();
92
+ resolve(null);
93
+ }, FETCH_TIMEOUT_MS + 1000);
94
+ });
95
+ }
96
+
97
+ /**
98
+ * Prompt user for update confirmation
99
+ * @param {string} currentVersion
100
+ * @param {string} latestVersion
101
+ * @returns {Promise<boolean>} True if user wants to update
102
+ */
103
+ function promptForUpdate(currentVersion, latestVersion) {
104
+ return new Promise((resolve) => {
105
+ const rl = readline.createInterface({
106
+ input: process.stdin,
107
+ output: process.stdout,
108
+ });
109
+
110
+ console.log(`\nšŸ“¦ Update available: ${currentVersion} → ${latestVersion}`);
111
+ rl.question(' Install now? [y/N] ', (answer) => {
112
+ rl.close();
113
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
114
+ });
115
+ });
116
+ }
117
+
118
+ /**
119
+ * Check if we have write permission to npm global directory
120
+ * @returns {boolean} True if we can write to npm global prefix
121
+ */
122
+ function canWriteToNpmGlobal() {
123
+ const { execSync } = require('child_process');
124
+ const fs = require('fs');
125
+
126
+ try {
127
+ // Get npm global prefix (e.g., /usr/lib or /home/user/.nvm/versions/node/...)
128
+ const prefix = execSync('npm config get prefix', { encoding: 'utf8' }).trim();
129
+ const globalModulesDir = require('path').join(prefix, 'lib', 'node_modules');
130
+
131
+ // Check if directory exists and is writable
132
+ fs.accessSync(globalModulesDir, fs.constants.W_OK);
133
+ return true;
134
+ } catch {
135
+ return false;
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Run npm install to update the package
141
+ * @returns {Promise<boolean>} True if update succeeded
142
+ */
143
+ function runUpdate() {
144
+ return new Promise((resolve) => {
145
+ // Check permissions BEFORE attempting update
146
+ if (!canWriteToNpmGlobal()) {
147
+ console.log('\nāš ļø Cannot auto-update: no write permission to npm global directory.');
148
+ console.log(' Run manually with sudo:');
149
+ console.log(' sudo npm install -g @the-open-engine/zeroshot@latest\n');
150
+ resolve(false);
151
+ return;
152
+ }
153
+
154
+ console.log('\nšŸ“„ Installing update...');
155
+
156
+ const proc = spawn('npm', ['install', '-g', '@the-open-engine/zeroshot@latest'], {
157
+ stdio: 'inherit',
158
+ shell: true,
159
+ });
160
+
161
+ proc.on('close', (code) => {
162
+ if (code === 0) {
163
+ console.log('āœ… Update installed successfully!');
164
+ console.log(' Restart zeroshot to use the new version.\n');
165
+ resolve(true);
166
+ } else {
167
+ console.log('āŒ Update failed. Try manually:');
168
+ console.log(' sudo npm install -g @the-open-engine/zeroshot@latest\n');
169
+ resolve(false);
170
+ }
171
+ });
172
+
173
+ proc.on('error', () => {
174
+ console.log('āŒ Update failed. Try manually:');
175
+ console.log(' sudo npm install -g @the-open-engine/zeroshot@latest\n');
176
+ resolve(false);
177
+ });
178
+ });
179
+ }
180
+
181
+ /**
182
+ * Check if update check should run
183
+ * @param {object} settings - Current settings
184
+ * @returns {boolean}
185
+ */
186
+ function shouldCheckForUpdates(settings) {
187
+ // Disabled by user
188
+ if (!settings.autoCheckUpdates) {
189
+ return false;
190
+ }
191
+
192
+ // Never checked before
193
+ if (!settings.lastUpdateCheckAt) {
194
+ return true;
195
+ }
196
+
197
+ // Check if 24 hours have passed
198
+ const elapsed = Date.now() - settings.lastUpdateCheckAt;
199
+ return elapsed >= CHECK_INTERVAL_MS;
200
+ }
201
+
202
+ /**
203
+ * Main entry point - check for updates
204
+ * @param {object} options
205
+ * @param {boolean} options.quiet - Skip interactive prompts
206
+ * @returns {Promise<void>}
207
+ */
208
+ async function checkForUpdates(options = {}) {
209
+ const settings = loadSettings();
210
+
211
+ // Skip check if not due
212
+ if (!shouldCheckForUpdates(settings)) {
213
+ return;
214
+ }
215
+
216
+ const currentVersion = getCurrentVersion();
217
+ const latestVersion = await fetchLatestVersion();
218
+
219
+ // Update last check timestamp regardless of result
220
+ settings.lastUpdateCheckAt = Date.now();
221
+ saveSettings(settings);
222
+
223
+ // Network failure - silently skip
224
+ if (!latestVersion) {
225
+ return;
226
+ }
227
+
228
+ // No update available
229
+ if (!isNewerVersion(currentVersion, latestVersion)) {
230
+ return;
231
+ }
232
+
233
+ // Already notified about this version
234
+ if (settings.lastSeenVersion === latestVersion) {
235
+ return;
236
+ }
237
+
238
+ // Update lastSeenVersion so we don't nag about the same version
239
+ settings.lastSeenVersion = latestVersion;
240
+ saveSettings(settings);
241
+
242
+ // Check write permissions upfront
243
+ const hasWriteAccess = canWriteToNpmGlobal();
244
+
245
+ // Quiet mode - just inform, no prompt
246
+ if (options.quiet) {
247
+ console.log(`šŸ“¦ Update available: ${currentVersion} → ${latestVersion}`);
248
+ if (hasWriteAccess) {
249
+ console.log(' Run: npm install -g @the-open-engine/zeroshot@latest\n');
250
+ } else {
251
+ console.log(' Run: sudo npm install -g @the-open-engine/zeroshot@latest\n');
252
+ }
253
+ return;
254
+ }
255
+
256
+ // No write permission - inform user but don't offer interactive prompt
257
+ // (they'd say yes then get an error, which is frustrating UX)
258
+ if (!hasWriteAccess) {
259
+ console.log(`\nšŸ“¦ Update available: ${currentVersion} → ${latestVersion}`);
260
+ console.log(' Run: sudo npm install -g @the-open-engine/zeroshot@latest\n');
261
+ return;
262
+ }
263
+
264
+ // Interactive mode - prompt for update (only if we have write access)
265
+ const wantsUpdate = await promptForUpdate(currentVersion, latestVersion);
266
+ if (wantsUpdate) {
267
+ await runUpdate();
268
+ }
269
+ }
270
+
271
+ module.exports = {
272
+ checkForUpdates,
273
+ // Exported for testing and CLI update command
274
+ getCurrentVersion,
275
+ isNewerVersion,
276
+ fetchLatestVersion,
277
+ runUpdate,
278
+ shouldCheckForUpdates,
279
+ canWriteToNpmGlobal,
280
+ CHECK_INTERVAL_MS,
281
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Message formatting utilities for CLI output
3
+ * Extracted from index.js to reduce complexity
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+
8
+ /**
9
+ * Get color for sender based on consistent hashing
10
+ * @param {string} sender - Sender name
11
+ * @returns {Function} Chalk color function
12
+ */
13
+ function getColorForSender(sender) {
14
+ const colors = [chalk.cyan, chalk.magenta, chalk.yellow, chalk.green, chalk.blue];
15
+ let hash = 0;
16
+ for (let i = 0; i < sender.length; i++) {
17
+ hash = (hash << 5) - hash + sender.charCodeAt(i);
18
+ hash = hash & hash;
19
+ }
20
+ return colors[Math.abs(hash) % colors.length];
21
+ }
22
+
23
+ /**
24
+ * Build message prefix with timestamp, sender, and optional cluster ID
25
+ * @param {Object} msg - Message object
26
+ * @param {boolean} showClusterId - Whether to show cluster ID
27
+ * @param {boolean} isActive - Whether cluster is active
28
+ * @returns {string} Formatted prefix
29
+ */
30
+ function buildMessagePrefix(msg, showClusterId, isActive) {
31
+ const color = isActive ? getColorForSender(msg.sender) : chalk.dim;
32
+
33
+ let senderLabel = msg.sender;
34
+ if (showClusterId && msg.cluster_id) {
35
+ senderLabel = `${msg.cluster_id}/${msg.sender}`;
36
+ }
37
+
38
+ const modelSuffix = msg.sender_model ? chalk.dim(` [${msg.sender_model}]`) : '';
39
+ return color(`${senderLabel.padEnd(showClusterId ? 25 : 15)} |`) + modelSuffix;
40
+ }
41
+
42
+ /**
43
+ * Build cluster prefix for watch mode
44
+ * @param {string} clusterId - Cluster ID
45
+ * @param {boolean} isActive - Whether cluster is active
46
+ * @returns {string} Formatted prefix
47
+ */
48
+ function buildClusterPrefix(clusterId, isActive) {
49
+ return isActive
50
+ ? chalk.white(`${clusterId.padEnd(20)} |`)
51
+ : chalk.dim(`${clusterId.padEnd(20)} |`);
52
+ }
53
+
54
+ /**
55
+ * Parse and normalize data fields (handles string JSON)
56
+ * @param {string|Array} data - Data to parse
57
+ * @returns {Array} Parsed array
58
+ */
59
+ function parseDataField(data) {
60
+ if (typeof data === 'string') {
61
+ try {
62
+ return JSON.parse(data);
63
+ } catch {
64
+ return [];
65
+ }
66
+ }
67
+ return Array.isArray(data) ? data : [];
68
+ }
69
+
70
+ module.exports = {
71
+ getColorForSender,
72
+ buildMessagePrefix,
73
+ buildClusterPrefix,
74
+ parseDataField,
75
+ };