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.
- package/README.md +30 -11
- package/bin/projectinator.mjs +56 -11
- package/dist/bakeoff.js +163 -0
- package/dist/bakeoff.js.map +1 -0
- package/dist/build-state.js +26 -0
- package/dist/build-state.js.map +1 -0
- package/dist/burndown.js +19 -0
- package/dist/burndown.js.map +1 -0
- package/dist/calibration.js +86 -0
- package/dist/calibration.js.map +1 -0
- package/dist/cli.js +289 -0
- package/dist/cli.js.map +1 -0
- package/dist/cost.js +35 -0
- package/dist/cost.js.map +1 -0
- package/dist/council.js +147 -0
- package/dist/council.js.map +1 -0
- package/dist/demo.js +93 -0
- package/dist/demo.js.map +1 -0
- package/dist/estimate.js +98 -0
- package/dist/estimate.js.map +1 -0
- package/dist/executor.js +118 -0
- package/dist/executor.js.map +1 -0
- package/dist/git.js +82 -0
- package/dist/git.js.map +1 -0
- package/dist/intake.js +98 -0
- package/dist/intake.js.map +1 -0
- package/dist/models.js +171 -0
- package/dist/models.js.map +1 -0
- package/dist/narrate.js +76 -0
- package/dist/narrate.js.map +1 -0
- package/dist/openrouter.js +112 -0
- package/dist/openrouter.js.map +1 -0
- package/dist/orchestrator.js +273 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/pm.js +245 -0
- package/dist/pm.js.map +1 -0
- package/dist/preview.js +194 -0
- package/dist/preview.js.map +1 -0
- package/dist/registry-store.js +38 -0
- package/dist/registry-store.js.map +1 -0
- package/dist/registry.js +115 -0
- package/dist/registry.js.map +1 -0
- package/dist/research.js +98 -0
- package/dist/research.js.map +1 -0
- package/dist/retro.js +83 -0
- package/dist/retro.js.map +1 -0
- package/dist/roles.js +357 -0
- package/dist/roles.js.map +1 -0
- package/dist/router.js +95 -0
- package/dist/router.js.map +1 -0
- package/dist/run-bakeoff.js +68 -0
- package/dist/run-bakeoff.js.map +1 -0
- package/dist/run-build.js +193 -0
- package/dist/run-build.js.map +1 -0
- package/{src/run-dev.ts → dist/run-dev.js} +23 -39
- package/dist/run-dev.js.map +1 -0
- package/{src/run-pm.ts → dist/run-pm.js} +34 -46
- package/dist/run-pm.js.map +1 -0
- package/{src/run-research.ts → dist/run-research.js} +19 -30
- package/dist/run-research.js.map +1 -0
- package/{src/run-scout.ts → dist/run-scout.js} +17 -27
- package/dist/run-scout.js.map +1 -0
- package/dist/run-web.js +93 -0
- package/dist/run-web.js.map +1 -0
- package/dist/scout.js +81 -0
- package/dist/scout.js.map +1 -0
- package/dist/session-cost.js +15 -0
- package/dist/session-cost.js.map +1 -0
- package/dist/stack.js +34 -0
- package/dist/stack.js.map +1 -0
- package/dist/stuck.js +21 -0
- package/dist/stuck.js.map +1 -0
- package/dist/tui/App.js +1269 -0
- package/dist/tui/App.js.map +1 -0
- package/dist/tui/BakeOff.js +95 -0
- package/dist/tui/BakeOff.js.map +1 -0
- package/dist/tui/BoardEditor.js +183 -0
- package/dist/tui/BoardEditor.js.map +1 -0
- package/dist/tui/EditableBoard.js +140 -0
- package/dist/tui/EditableBoard.js.map +1 -0
- package/dist/tui/Frame.js +78 -0
- package/dist/tui/Frame.js.map +1 -0
- package/dist/tui/Intake.js +59 -0
- package/dist/tui/Intake.js.map +1 -0
- package/dist/tui/Kanban.js +75 -0
- package/dist/tui/Kanban.js.map +1 -0
- package/dist/tui/Settings.js +299 -0
- package/dist/tui/Settings.js.map +1 -0
- package/dist/tui/StackPick.js +44 -0
- package/dist/tui/StackPick.js.map +1 -0
- package/dist/tui/WebAccounts.js +131 -0
- package/dist/tui/WebAccounts.js.map +1 -0
- package/dist/tui/components.js +178 -0
- package/dist/tui/components.js.map +1 -0
- package/dist/tui/config.js +129 -0
- package/dist/tui/config.js.map +1 -0
- package/dist/tui/deploy.js +114 -0
- package/dist/tui/deploy.js.map +1 -0
- package/dist/tui/engine.js +710 -0
- package/dist/tui/engine.js.map +1 -0
- package/dist/tui/notify.js +47 -0
- package/dist/tui/notify.js.map +1 -0
- package/dist/tui/panels.js +42 -0
- package/dist/tui/panels.js.map +1 -0
- package/dist/tui/templates.js +106 -0
- package/dist/tui/templates.js.map +1 -0
- package/dist/tui/theme.js +42 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/validate.js +51 -0
- package/dist/tui/validate.js.map +1 -0
- package/{src/tui.tsx → dist/tui.js} +23 -33
- package/dist/tui.js.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/web/oauth-anthropic.js +179 -0
- package/dist/web/oauth-anthropic.js.map +1 -0
- package/dist/web/session.js +274 -0
- package/dist/web/session.js.map +1 -0
- package/package.json +5 -4
- package/src/bakeoff.ts +0 -214
- package/src/build-state.ts +0 -47
- package/src/burndown.ts +0 -35
- package/src/calibration.ts +0 -88
- package/src/cost.ts +0 -43
- package/src/council.ts +0 -175
- package/src/demo.ts +0 -106
- package/src/estimate.ts +0 -111
- package/src/executor.ts +0 -169
- package/src/git.ts +0 -72
- package/src/intake.ts +0 -125
- package/src/models.ts +0 -175
- package/src/narrate.ts +0 -87
- package/src/openrouter.ts +0 -119
- package/src/orchestrator.ts +0 -310
- package/src/pm.ts +0 -302
- package/src/preview.ts +0 -206
- package/src/registry-store.ts +0 -41
- package/src/registry.ts +0 -132
- package/src/research.ts +0 -123
- package/src/retro.ts +0 -99
- package/src/roles.ts +0 -401
- package/src/router.ts +0 -120
- package/src/run-bakeoff.ts +0 -77
- package/src/run-build.ts +0 -203
- package/src/run-web.ts +0 -87
- package/src/scout.ts +0 -121
- package/src/session-cost.ts +0 -17
- package/src/stack.ts +0 -46
- package/src/tui/App.tsx +0 -1760
- package/src/tui/BakeOff.tsx +0 -190
- package/src/tui/BoardEditor.tsx +0 -260
- package/src/tui/EditableBoard.tsx +0 -179
- package/src/tui/Frame.tsx +0 -142
- package/src/tui/Intake.tsx +0 -111
- package/src/tui/Kanban.tsx +0 -158
- package/src/tui/Settings.tsx +0 -513
- package/src/tui/StackPick.tsx +0 -79
- package/src/tui/WebAccounts.tsx +0 -197
- package/src/tui/components.tsx +0 -340
- package/src/tui/config.ts +0 -150
- package/src/tui/deploy.ts +0 -137
- package/src/tui/engine.ts +0 -749
- package/src/tui/notify.ts +0 -21
- package/src/tui/panels.tsx +0 -89
- package/src/tui/templates.ts +0 -119
- package/src/tui/theme.ts +0 -44
- package/src/tui/validate.ts +0 -53
- package/src/types.ts +0 -208
- package/src/web/oauth-anthropic.ts +0 -206
- 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":"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"}
|
|
@@ -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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"}
|