projectinator 0.3.0 → 0.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 (170) hide show
  1. package/README.md +30 -11
  2. package/bin/projectinator.mjs +56 -11
  3. package/dist/bakeoff.js +163 -0
  4. package/dist/bakeoff.js.map +1 -0
  5. package/dist/build-state.js +26 -0
  6. package/dist/build-state.js.map +1 -0
  7. package/dist/burndown.js +19 -0
  8. package/dist/burndown.js.map +1 -0
  9. package/dist/calibration.js +86 -0
  10. package/dist/calibration.js.map +1 -0
  11. package/dist/cli.js +289 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/cost.js +35 -0
  14. package/dist/cost.js.map +1 -0
  15. package/dist/council.js +147 -0
  16. package/dist/council.js.map +1 -0
  17. package/dist/demo.js +93 -0
  18. package/dist/demo.js.map +1 -0
  19. package/dist/estimate.js +98 -0
  20. package/dist/estimate.js.map +1 -0
  21. package/dist/executor.js +118 -0
  22. package/dist/executor.js.map +1 -0
  23. package/dist/git.js +82 -0
  24. package/dist/git.js.map +1 -0
  25. package/dist/intake.js +98 -0
  26. package/dist/intake.js.map +1 -0
  27. package/dist/models.js +171 -0
  28. package/dist/models.js.map +1 -0
  29. package/dist/narrate.js +76 -0
  30. package/dist/narrate.js.map +1 -0
  31. package/dist/openrouter.js +112 -0
  32. package/dist/openrouter.js.map +1 -0
  33. package/dist/orchestrator.js +273 -0
  34. package/dist/orchestrator.js.map +1 -0
  35. package/dist/pm.js +245 -0
  36. package/dist/pm.js.map +1 -0
  37. package/dist/preview.js +194 -0
  38. package/dist/preview.js.map +1 -0
  39. package/dist/registry-store.js +38 -0
  40. package/dist/registry-store.js.map +1 -0
  41. package/dist/registry.js +115 -0
  42. package/dist/registry.js.map +1 -0
  43. package/dist/research.js +98 -0
  44. package/dist/research.js.map +1 -0
  45. package/dist/retro.js +83 -0
  46. package/dist/retro.js.map +1 -0
  47. package/dist/roles.js +357 -0
  48. package/dist/roles.js.map +1 -0
  49. package/dist/router.js +95 -0
  50. package/dist/router.js.map +1 -0
  51. package/dist/run-bakeoff.js +68 -0
  52. package/dist/run-bakeoff.js.map +1 -0
  53. package/dist/run-build.js +193 -0
  54. package/dist/run-build.js.map +1 -0
  55. package/{src/run-dev.ts → dist/run-dev.js} +23 -39
  56. package/dist/run-dev.js.map +1 -0
  57. package/{src/run-pm.ts → dist/run-pm.js} +34 -46
  58. package/dist/run-pm.js.map +1 -0
  59. package/{src/run-research.ts → dist/run-research.js} +19 -30
  60. package/dist/run-research.js.map +1 -0
  61. package/{src/run-scout.ts → dist/run-scout.js} +17 -27
  62. package/dist/run-scout.js.map +1 -0
  63. package/dist/run-web.js +93 -0
  64. package/dist/run-web.js.map +1 -0
  65. package/dist/scout.js +81 -0
  66. package/dist/scout.js.map +1 -0
  67. package/dist/session-cost.js +15 -0
  68. package/dist/session-cost.js.map +1 -0
  69. package/dist/stack.js +34 -0
  70. package/dist/stack.js.map +1 -0
  71. package/dist/stuck.js +21 -0
  72. package/dist/stuck.js.map +1 -0
  73. package/dist/tui/App.js +1269 -0
  74. package/dist/tui/App.js.map +1 -0
  75. package/dist/tui/BakeOff.js +95 -0
  76. package/dist/tui/BakeOff.js.map +1 -0
  77. package/dist/tui/BoardEditor.js +183 -0
  78. package/dist/tui/BoardEditor.js.map +1 -0
  79. package/dist/tui/EditableBoard.js +140 -0
  80. package/dist/tui/EditableBoard.js.map +1 -0
  81. package/dist/tui/Frame.js +78 -0
  82. package/dist/tui/Frame.js.map +1 -0
  83. package/dist/tui/Intake.js +59 -0
  84. package/dist/tui/Intake.js.map +1 -0
  85. package/dist/tui/Kanban.js +75 -0
  86. package/dist/tui/Kanban.js.map +1 -0
  87. package/dist/tui/Settings.js +299 -0
  88. package/dist/tui/Settings.js.map +1 -0
  89. package/dist/tui/StackPick.js +44 -0
  90. package/dist/tui/StackPick.js.map +1 -0
  91. package/dist/tui/WebAccounts.js +131 -0
  92. package/dist/tui/WebAccounts.js.map +1 -0
  93. package/dist/tui/components.js +178 -0
  94. package/dist/tui/components.js.map +1 -0
  95. package/dist/tui/config.js +129 -0
  96. package/dist/tui/config.js.map +1 -0
  97. package/dist/tui/deploy.js +114 -0
  98. package/dist/tui/deploy.js.map +1 -0
  99. package/dist/tui/engine.js +710 -0
  100. package/dist/tui/engine.js.map +1 -0
  101. package/dist/tui/notify.js +47 -0
  102. package/dist/tui/notify.js.map +1 -0
  103. package/dist/tui/panels.js +42 -0
  104. package/dist/tui/panels.js.map +1 -0
  105. package/dist/tui/templates.js +106 -0
  106. package/dist/tui/templates.js.map +1 -0
  107. package/dist/tui/theme.js +42 -0
  108. package/dist/tui/theme.js.map +1 -0
  109. package/dist/tui/validate.js +51 -0
  110. package/dist/tui/validate.js.map +1 -0
  111. package/{src/tui.tsx → dist/tui.js} +23 -33
  112. package/dist/tui.js.map +1 -0
  113. package/dist/types.js +19 -0
  114. package/dist/types.js.map +1 -0
  115. package/dist/web/oauth-anthropic.js +179 -0
  116. package/dist/web/oauth-anthropic.js.map +1 -0
  117. package/dist/web/session.js +274 -0
  118. package/dist/web/session.js.map +1 -0
  119. package/package.json +5 -4
  120. package/src/bakeoff.ts +0 -214
  121. package/src/build-state.ts +0 -47
  122. package/src/burndown.ts +0 -35
  123. package/src/calibration.ts +0 -88
  124. package/src/cost.ts +0 -43
  125. package/src/council.ts +0 -175
  126. package/src/demo.ts +0 -106
  127. package/src/estimate.ts +0 -111
  128. package/src/executor.ts +0 -169
  129. package/src/git.ts +0 -72
  130. package/src/intake.ts +0 -125
  131. package/src/models.ts +0 -175
  132. package/src/narrate.ts +0 -87
  133. package/src/openrouter.ts +0 -119
  134. package/src/orchestrator.ts +0 -310
  135. package/src/pm.ts +0 -302
  136. package/src/preview.ts +0 -206
  137. package/src/registry-store.ts +0 -41
  138. package/src/registry.ts +0 -132
  139. package/src/research.ts +0 -123
  140. package/src/retro.ts +0 -99
  141. package/src/roles.ts +0 -401
  142. package/src/router.ts +0 -120
  143. package/src/run-bakeoff.ts +0 -77
  144. package/src/run-build.ts +0 -203
  145. package/src/run-web.ts +0 -87
  146. package/src/scout.ts +0 -121
  147. package/src/session-cost.ts +0 -17
  148. package/src/stack.ts +0 -46
  149. package/src/tui/App.tsx +0 -1760
  150. package/src/tui/BakeOff.tsx +0 -190
  151. package/src/tui/BoardEditor.tsx +0 -260
  152. package/src/tui/EditableBoard.tsx +0 -179
  153. package/src/tui/Frame.tsx +0 -142
  154. package/src/tui/Intake.tsx +0 -111
  155. package/src/tui/Kanban.tsx +0 -158
  156. package/src/tui/Settings.tsx +0 -513
  157. package/src/tui/StackPick.tsx +0 -79
  158. package/src/tui/WebAccounts.tsx +0 -197
  159. package/src/tui/components.tsx +0 -340
  160. package/src/tui/config.ts +0 -150
  161. package/src/tui/deploy.ts +0 -137
  162. package/src/tui/engine.ts +0 -749
  163. package/src/tui/notify.ts +0 -21
  164. package/src/tui/panels.tsx +0 -89
  165. package/src/tui/templates.ts +0 -119
  166. package/src/tui/theme.ts +0 -44
  167. package/src/tui/validate.ts +0 -53
  168. package/src/types.ts +0 -208
  169. package/src/web/oauth-anthropic.ts +0 -206
  170. package/src/web/session.ts +0 -299
@@ -0,0 +1,178 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Shared TUI pieces + theme. Kept small and presentational.
3
+ import { useState, useEffect } from "react";
4
+ import { Box, Text, useInput, useStdout } from "ink";
5
+ import Spinner from "ink-spinner";
6
+ import { Select, TextInput as UITextInput, PasswordInput, ProgressBar } from "@inkjs/ui";
7
+ /** Current terminal size (rows), updated on resize. */
8
+ export function useTermRows() {
9
+ const { stdout } = useStdout();
10
+ const [rows, setRows] = useState(stdout?.rows ?? 24);
11
+ useEffect(() => {
12
+ if (!stdout)
13
+ return;
14
+ const onResize = () => setRows(stdout.rows ?? 24);
15
+ stdout.on("resize", onResize);
16
+ return () => { stdout.off("resize", onResize); };
17
+ }, [stdout]);
18
+ return rows;
19
+ }
20
+ /** A vertical menu with dim, non-selectable section headers. Arrow keys move
21
+ * through the selectable items only (headers are skipped); Enter selects.
22
+ * When `maxRows` is smaller than the content, it scrolls, keeping the
23
+ * selection in view, with ↑/↓ hints. */
24
+ export function GroupedMenu({ groups, onSelect, maxRows, }) {
25
+ const flat = groups.flatMap((g) => g.items);
26
+ const [idx, setIdx] = useState(0);
27
+ const cur = Math.min(idx, Math.max(0, flat.length - 1));
28
+ useInput((_input, key) => {
29
+ if (key.upArrow)
30
+ setIdx((i) => (i - 1 + flat.length) % flat.length);
31
+ else if (key.downArrow)
32
+ setIdx((i) => (i + 1) % flat.length);
33
+ else if (key.return) {
34
+ const it = flat[cur];
35
+ if (it)
36
+ onSelect(it);
37
+ }
38
+ });
39
+ // Flatten to display lines (gaps + headers + items) so scrolling is line-exact.
40
+ const lines = [];
41
+ let fi = 0;
42
+ groups.forEach((g, gi) => {
43
+ if (gi)
44
+ lines.push({ kind: "gap" });
45
+ if (g.title)
46
+ lines.push({ kind: "header", text: g.title.toUpperCase() });
47
+ g.items.forEach((it) => { lines.push({ kind: "item", text: it.label, idx: fi }); fi++; });
48
+ });
49
+ const budget = maxRows && maxRows < lines.length ? Math.max(3, maxRows) : lines.length;
50
+ let start = 0;
51
+ let end = lines.length;
52
+ let clipTop = false;
53
+ let clipBot = false;
54
+ if (budget < lines.length) {
55
+ const selLine = lines.findIndex((l) => l.kind === "item" && l.idx === cur);
56
+ start = Math.max(0, Math.min(selLine - Math.floor(budget / 2), lines.length - budget));
57
+ end = start + budget;
58
+ clipTop = start > 0;
59
+ clipBot = end < lines.length;
60
+ }
61
+ const visible = lines.slice(clipTop ? start + 1 : start, clipBot ? end - 1 : end);
62
+ return (_jsxs(Box, { flexDirection: "column", children: [clipTop ? _jsx(Text, { color: C.dim, children: " \u2191 more" }) : null, visible.map((l, i) => {
63
+ if (l.kind === "gap")
64
+ return _jsx(Text, { children: " " }, `g${i}`);
65
+ if (l.kind === "header")
66
+ return _jsx(Text, { color: C.dim, bold: true, children: l.text }, `h${i}`);
67
+ const sel = l.idx === cur;
68
+ return (_jsxs(Text, { color: sel ? C.accent : C.text, wrap: "truncate-end", children: [sel ? "❯ " : " ", l.text] }, `i${l.idx}`));
69
+ }), clipBot ? _jsx(Text, { color: C.dim, children: " \u2193 more" }) : null] }));
70
+ }
71
+ /** SelectInput-shaped wrapper over @inkjs/ui Select (items/onSelect). */
72
+ export function Menu({ items, onSelect, limit, }) {
73
+ return (_jsx(Select, { options: items, visibleOptionCount: limit ?? Math.min(items.length, 16), onChange: (value) => {
74
+ const it = items.find((i) => i.value === value);
75
+ if (it)
76
+ onSelect(it);
77
+ } }));
78
+ }
79
+ /** Controlled-shaped wrapper over @inkjs/ui TextInput (value/onChange/onSubmit). */
80
+ export function TextField({ value, onChange, onSubmit, placeholder, }) {
81
+ return _jsx(UITextInput, { defaultValue: value, placeholder: placeholder, onChange: onChange, onSubmit: () => onSubmit() });
82
+ }
83
+ /** Masked input for secrets. */
84
+ export function Password({ onSubmit, placeholder, }) {
85
+ return _jsx(PasswordInput, { placeholder: placeholder, onSubmit: onSubmit });
86
+ }
87
+ // Semantic theme tokens (OpenCode-style roles). Old keys (accent/dim/good/warn/
88
+ // bad/text) are kept as aliases so every existing call site still works; new
89
+ // screens should prefer the richer roles (textMuted, border, borderActive, …).
90
+ export const C = {
91
+ // brand / primary
92
+ accent: "#e0a72d", // signal amber
93
+ primary: "#e0a72d",
94
+ accentMuted: "#a67c1f", // dimmed amber — secondary emphasis
95
+ // text
96
+ text: "white",
97
+ textMuted: "#9aa0a6", // secondary text
98
+ textSubtle: "#6b7178", // faint / metadata
99
+ dim: "#9aa0a6", // legacy alias — same gray as textMuted so all metadata matches
100
+ // surfaces (for panels / bars)
101
+ bgPanel: "#1b1b1b",
102
+ bgElement: "#242424",
103
+ // borders
104
+ border: "#3a3a3a",
105
+ borderSubtle: "#2a2a2a",
106
+ borderActive: "#e0a72d",
107
+ // status
108
+ good: "green",
109
+ warn: "yellow",
110
+ bad: "red",
111
+ info: "cyan",
112
+ };
113
+ /** Current terminal width (columns), updated on resize. */
114
+ export function useTermCols() {
115
+ const { stdout } = useStdout();
116
+ const [cols, setCols] = useState(stdout?.columns ?? 80);
117
+ useEffect(() => {
118
+ if (!stdout)
119
+ return;
120
+ const onResize = () => setCols(stdout.columns ?? 80);
121
+ stdout.on("resize", onResize);
122
+ return () => { stdout.off("resize", onResize); };
123
+ }, [stdout]);
124
+ return cols;
125
+ }
126
+ /** The one place we render keyboard shortcuts, styled after inkui's KeyHint:
127
+ * each key sits in a small bordered keycap (amber) with its dim action label
128
+ * beside it, keycaps laid out in a wrapping row. Use this everywhere instead
129
+ * of ad-hoc "Enter to save · Esc to back" prose so hints look identical across
130
+ * every screen. */
131
+ export function KeyHint({ hints }) {
132
+ return (_jsx(Box, { flexWrap: "wrap", children: hints.map((h, i) => (_jsxs(Box, { marginRight: 2, alignItems: "center", children: [_jsx(Box, { borderStyle: "round", borderColor: C.dim, paddingX: 1, children: _jsx(Text, { color: C.accent, children: h.keys }) }), _jsx(Text, { color: C.dim, children: ` ${h.label}` })] }, i))) }));
133
+ }
134
+ /** A rounded-border panel with an optional amber title. Frames content sections. */
135
+ export function Panel({ title, borderColor, children, }) {
136
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor ?? C.border, paddingX: 2, paddingY: 1, alignSelf: "flex-start", children: [title ? _jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: C.accent, children: title }) }) : null, children] }));
137
+ }
138
+ /** A quiet, bordered pill — a small status dot + muted label. Replaces loud
139
+ * filled badges for things like connected providers. */
140
+ export function Chip({ label, dotColor, active, }) {
141
+ return (_jsxs(Box, { borderStyle: "round", borderColor: active ? C.borderActive : C.borderSubtle, paddingX: 1, children: [dotColor ? _jsx(Text, { color: dotColor, children: "\u25CF " }) : null, _jsx(Text, { color: active ? C.text : C.textMuted, children: label })] }));
142
+ }
143
+ const CAP_LABEL = {
144
+ plan: "plan", design: "design", code: "code", review: "review", test: "test", ops: "ops",
145
+ };
146
+ /** The AI team: each capability is a role with a friendly name + icon. */
147
+ export const ROLE_META = {
148
+ plan: { emoji: "🧭", label: "Project manager" },
149
+ design: { emoji: "🎨", label: "Designer" },
150
+ code: { emoji: "🧠", label: "Developer" },
151
+ review: { emoji: "🔍", label: "Reviewer" },
152
+ test: { emoji: "🔎", label: "Tester" },
153
+ ops: { emoji: "🚀", label: "Runner" },
154
+ };
155
+ function statusMark(s) {
156
+ switch (s) {
157
+ case "running":
158
+ return (_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }));
159
+ case "done":
160
+ return _jsx(Text, { color: C.good, children: "\u2713" });
161
+ case "failed":
162
+ return _jsx(Text, { color: C.bad, children: "\u2717" });
163
+ case "skipped":
164
+ return _jsx(Text, { color: C.dim, children: "\u00B7" });
165
+ default:
166
+ return _jsx(Text, { color: C.dim, children: "\u25CB" });
167
+ }
168
+ }
169
+ export function TaskRow({ t }) {
170
+ const dim = t.status === "pending" || t.status === "skipped";
171
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 2, children: statusMark(t.status) }), _jsx(Box, { width: 7, children: _jsx(Text, { color: dim ? C.dim : C.accent, children: CAP_LABEL[t.capability] }) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { color: dim ? C.dim : C.text, wrap: "truncate-end", children: t.title }) }), _jsx(Box, { width: 10, justifyContent: "flex-end", children: t.verdict ? (_jsx(Text, { color: t.verdict === "FAIL" ? C.bad : t.verdict === "PASS*" ? C.warn : C.good, children: t.verdict })) : t.cost !== undefined ? (_jsxs(Text, { color: C.dim, children: ["$", t.cost.toFixed(2)] })) : (_jsx(Text, { children: " " })) })] }));
172
+ }
173
+ export function BudgetBar({ spent, cap }) {
174
+ const frac = Math.min(1, cap > 0 ? spent / cap : 0);
175
+ const color = frac > 0.9 ? C.bad : frac > 0.66 ? C.warn : C.good;
176
+ return (_jsxs(Box, { children: [_jsx(Text, { color: C.dim, children: "spent " }), _jsxs(Text, { color: color, bold: true, children: ["$", spent.toFixed(2)] }), _jsxs(Text, { color: C.dim, children: [" / $", cap.toFixed(0), " "] }), _jsx(Box, { width: 30, children: _jsx(ProgressBar, { value: frac * 100 }) })] }));
177
+ }
178
+ //# sourceMappingURL=components.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"components.js","sourceRoot":"","sources":["../../src/tui/components.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ // Persistent app config — API keys + preferences — so the TUI is self-contained
2
+ // (no ~/.zshenv editing). Stored at ~/.projectinator/config.json with 0600 perms.
3
+ // Keys are applied to process.env on launch so Pi's auth picks them up.
4
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
+ export const ENV_VAR = {
8
+ anthropic: "ANTHROPIC_API_KEY",
9
+ openai: "OPENAI_API_KEY",
10
+ google: "GEMINI_API_KEY",
11
+ openrouter: "OPENROUTER_API_KEY",
12
+ };
13
+ function dir() {
14
+ return join(homedir(), ".projectinator");
15
+ }
16
+ export function configPath() {
17
+ return join(dir(), "config.json");
18
+ }
19
+ export function loadConfig() {
20
+ try {
21
+ if (!existsSync(configPath()))
22
+ return { keys: {} };
23
+ const parsed = JSON.parse(readFileSync(configPath(), "utf-8"));
24
+ return {
25
+ keys: parsed.keys ?? {},
26
+ budgetCapUSD: parsed.budgetCapUSD,
27
+ concurrency: parsed.concurrency,
28
+ budgetAlertPct: parsed.budgetAlertPct,
29
+ preferredProvider: parsed.preferredProvider,
30
+ defaultMode: parsed.defaultMode,
31
+ notify: parsed.notify,
32
+ preferredStack: parsed.preferredStack,
33
+ };
34
+ }
35
+ catch {
36
+ return { keys: {} };
37
+ }
38
+ }
39
+ export function getNotify() {
40
+ return loadConfig().notify ?? true;
41
+ }
42
+ export function setNotify(v) {
43
+ const cfg = loadConfig();
44
+ cfg.notify = v;
45
+ saveConfig(cfg);
46
+ }
47
+ export function getWebhookUrl() {
48
+ return loadConfig().webhookUrl ?? "";
49
+ }
50
+ export function setWebhookUrl(url) {
51
+ const cfg = loadConfig();
52
+ const v = url.trim();
53
+ if (v)
54
+ cfg.webhookUrl = v;
55
+ else
56
+ delete cfg.webhookUrl;
57
+ saveConfig(cfg);
58
+ }
59
+ export function getPreferredStack() {
60
+ return loadConfig().preferredStack ?? "ask";
61
+ }
62
+ export function setPreferredStack(v) {
63
+ const cfg = loadConfig();
64
+ cfg.preferredStack = v;
65
+ saveConfig(cfg);
66
+ }
67
+ export function setPreferredProvider(p) {
68
+ const cfg = loadConfig();
69
+ cfg.preferredProvider = p;
70
+ saveConfig(cfg);
71
+ }
72
+ export function getDefaultMode() {
73
+ return loadConfig().defaultMode ?? "auto";
74
+ }
75
+ export function setDefaultMode(m) {
76
+ const cfg = loadConfig();
77
+ cfg.defaultMode = m;
78
+ saveConfig(cfg);
79
+ }
80
+ export function saveConfig(cfg) {
81
+ mkdirSync(dir(), { recursive: true });
82
+ writeFileSync(configPath(), JSON.stringify(cfg, null, 2) + "\n");
83
+ try {
84
+ chmodSync(configPath(), 0o600); // keys are secrets — owner-only
85
+ }
86
+ catch {
87
+ /* best effort */
88
+ }
89
+ }
90
+ /** Put stored keys into process.env (without clobbering ones already set in the shell). */
91
+ export function applyKeysToEnv(cfg = loadConfig()) {
92
+ for (const p of Object.keys(cfg.keys)) {
93
+ const v = cfg.keys[p];
94
+ if (v && !process.env[ENV_VAR[p]])
95
+ process.env[ENV_VAR[p]] = v;
96
+ }
97
+ }
98
+ /** Save a key both to disk and live env so availableProviders() updates immediately. */
99
+ export function setKey(provider, key) {
100
+ const cfg = loadConfig();
101
+ cfg.keys[provider] = key;
102
+ saveConfig(cfg);
103
+ process.env[ENV_VAR[provider]] = key;
104
+ }
105
+ export function getPrefs() {
106
+ const cfg = loadConfig();
107
+ return {
108
+ budgetCapUSD: cfg.budgetCapUSD ?? 25,
109
+ concurrency: cfg.concurrency ?? 3,
110
+ budgetAlertPct: cfg.budgetAlertPct ?? 80,
111
+ taskTimeoutMin: cfg.taskTimeoutMin ?? 10,
112
+ taskCostCapUSD: cfg.taskCostCapUSD ?? 3,
113
+ };
114
+ }
115
+ export function setPrefs(prefs) {
116
+ const cfg = loadConfig();
117
+ if (prefs.budgetCapUSD !== undefined)
118
+ cfg.budgetCapUSD = prefs.budgetCapUSD;
119
+ if (prefs.concurrency !== undefined)
120
+ cfg.concurrency = prefs.concurrency;
121
+ if (prefs.budgetAlertPct !== undefined)
122
+ cfg.budgetAlertPct = prefs.budgetAlertPct;
123
+ if (prefs.taskTimeoutMin !== undefined)
124
+ cfg.taskTimeoutMin = prefs.taskTimeoutMin;
125
+ if (prefs.taskCostCapUSD !== undefined)
126
+ cfg.taskCostCapUSD = prefs.taskCostCapUSD;
127
+ saveConfig(cfg);
128
+ }
129
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/tui/config.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,kFAAkF;AAClF,wEAAwE;AAExE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAyBjC,MAAM,CAAC,MAAM,OAAO,GAA6B;IAC/C,SAAS,EAAE,mBAAmB;IAC9B,MAAM,EAAE,gBAAgB;IACxB,MAAM,EAAE,gBAAgB;IACxB,UAAU,EAAE,oBAAoB;CACjC,CAAC;AAEF,SAAS,GAAG;IACV,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC3C,CAAC;AACD,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,OAAO,CAAC,CAAc,CAAC;QAC5E,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;YACvB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,cAAc,EAAE,MAAM,CAAC,cAAc;YACrC,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,cAAc,EAAE,MAAM,CAAC,cAAc;SACtC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,UAAU,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC;AACrC,CAAC;AACD,MAAM,UAAU,SAAS,CAAC,CAAU;IAClC,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IACf,UAAU,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,EAAE,CAAC,UAAU,IAAI,EAAE,CAAC;AACvC,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC;QAAE,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC;;QACrB,OAAO,GAAG,CAAC,UAAU,CAAC;IAC3B,UAAU,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,UAAU,EAAE,CAAC,cAAc,IAAI,KAAK,CAAC;AAC9C,CAAC;AACD,MAAM,UAAU,iBAAiB,CAAC,CAAqC;IACrE,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,cAAc,GAAG,CAAC,CAAC;IACvB,UAAU,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,CAAuB;IAC1D,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC;IAC1B,UAAU,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU,EAAE,CAAC,WAAW,IAAI,MAAM,CAAC;AAC5C,CAAC;AACD,MAAM,UAAU,cAAc,CAAC,CAAe;IAC5C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC;IACpB,UAAU,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAc;IACvC,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,aAAa,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjE,IAAI,CAAC;QACH,SAAS,CAAC,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,gCAAgC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;AACH,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,cAAc,CAAC,MAAiB,UAAU,EAAE;IAC1D,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAe,EAAE,CAAC;QACpD,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,MAAM,CAAC,QAAkB,EAAE,GAAW;IACpD,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC;IACzB,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,GAAG,CAAC;AACvC,CAAC;AAUD,MAAM,UAAU,QAAQ;IACtB,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,OAAO;QACL,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,EAAE;QACpC,WAAW,EAAE,GAAG,CAAC,WAAW,IAAI,CAAC;QACjC,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,EAAE;QACxC,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,EAAE;QACxC,cAAc,EAAE,GAAG,CAAC,cAAc,IAAI,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAqB;IAC5C,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS;QAAE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IAC5E,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IACzE,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;QAAE,GAAG,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAClF,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;QAAE,GAAG,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAClF,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS;QAAE,GAAG,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;IAClF,UAAU,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,114 @@
1
+ // One-click deploy — ship a built static site to Cloudflare Pages, Vercel, or
2
+ // Netlify by shelling out to that provider's CLI. No secrets stored here: auth
3
+ // comes from the CLI's own login (browser) or a token env var the user sets.
4
+ import { spawn } from "node:child_process";
5
+ import { cpSync, mkdirSync, readdirSync, rmSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ export const DEPLOY_META = {
8
+ cloudflare: {
9
+ label: "Cloudflare Pages",
10
+ cli: "wrangler",
11
+ install: "npm i -g wrangler",
12
+ auth: "wrangler login (or set CLOUDFLARE_API_TOKEN)",
13
+ urlPattern: /https:\/\/[^\s]+\.pages\.dev/g,
14
+ },
15
+ vercel: {
16
+ label: "Vercel",
17
+ cli: "vercel",
18
+ install: "npm i -g vercel",
19
+ auth: "vercel login (or set VERCEL_TOKEN)",
20
+ urlPattern: /https:\/\/[^\s]+\.vercel\.app/g,
21
+ },
22
+ netlify: {
23
+ label: "Netlify",
24
+ cli: "netlify",
25
+ install: "npm i -g netlify-cli",
26
+ auth: "netlify login (or set NETLIFY_AUTH_TOKEN)",
27
+ urlPattern: /https:\/\/[^\s]+\.netlify\.app/g,
28
+ },
29
+ };
30
+ // Project metadata / non-servable files we never want on the public site.
31
+ const INTERNAL = new Set([
32
+ "build-state.json", "DESIGN-SPEC.md", "export.md", "export.csv",
33
+ "jira-import.csv", "trello-import.csv", "node_modules",
34
+ ]);
35
+ /** Sanitise a project name into a deploy-safe slug (Cloudflare/Vercel project id). */
36
+ export function deploySlug(name) {
37
+ return (name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40)) || "projectinator-app";
38
+ }
39
+ /** Copy servable web files into <dir>/.deploy, dropping internal metadata. */
40
+ export function stageForDeploy(dir) {
41
+ const staging = join(dir, ".deploy");
42
+ rmSync(staging, { recursive: true, force: true });
43
+ mkdirSync(staging, { recursive: true });
44
+ let copied = 0;
45
+ for (const name of readdirSync(dir)) {
46
+ if (name.startsWith("."))
47
+ continue; // .deploy, hidden files
48
+ if (INTERNAL.has(name))
49
+ continue;
50
+ cpSync(join(dir, name), join(staging, name), { recursive: true });
51
+ copied++;
52
+ }
53
+ if (copied === 0)
54
+ throw new Error("No web files to deploy — build the app first.");
55
+ return staging;
56
+ }
57
+ function buildArgs(target, staging, slug) {
58
+ switch (target) {
59
+ case "cloudflare":
60
+ return ["pages", "deploy", staging, "--project-name", slug, "--branch", "main", "--commit-dirty=true"];
61
+ case "vercel":
62
+ return [staging, "--prod", "--yes"];
63
+ case "netlify":
64
+ return ["deploy", "--dir", staging, "--prod"];
65
+ }
66
+ }
67
+ /** Run a deploy. Streams output via onLog; resolves with the live URL (if found).
68
+ * Rejects with a helpful message when the CLI is missing or the deploy fails. */
69
+ export function deploy(target, dir, projectName, onLog) {
70
+ return new Promise((resolve, reject) => {
71
+ let staging;
72
+ try {
73
+ staging = stageForDeploy(dir);
74
+ }
75
+ catch (e) {
76
+ reject(e);
77
+ return;
78
+ }
79
+ const meta = DEPLOY_META[target];
80
+ const args = buildArgs(target, staging, deploySlug(projectName));
81
+ const child = spawn(meta.cli, args, { cwd: dir, env: process.env });
82
+ let output = "";
83
+ const onData = (buf) => {
84
+ const text = buf.toString();
85
+ output += text;
86
+ for (const line of text.split("\n")) {
87
+ const t = line.trimEnd();
88
+ if (t)
89
+ onLog(t);
90
+ }
91
+ };
92
+ child.stdout.on("data", onData);
93
+ child.stderr.on("data", onData);
94
+ child.on("error", (err) => {
95
+ if (err.code === "ENOENT") {
96
+ reject(new Error(`${meta.cli} is not installed. Install it:\n ${meta.install}\nthen sign in:\n ${meta.auth}`));
97
+ }
98
+ else {
99
+ reject(err);
100
+ }
101
+ });
102
+ child.on("close", (code) => {
103
+ if (code === 0) {
104
+ const matches = output.match(meta.urlPattern);
105
+ resolve({ url: matches ? matches[matches.length - 1] : undefined, output });
106
+ }
107
+ else {
108
+ const tail = output.trim().split("\n").slice(-8).join("\n");
109
+ reject(new Error(`${meta.label} deploy failed (exit ${code}).\nIf it's an auth error, sign in:\n ${meta.auth}\n\n${tail}`));
110
+ }
111
+ });
112
+ });
113
+ }
114
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/tui/deploy.ts"],"names":[],"mappings":"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"}