projectinator 0.3.1 → 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 +7 -6
- package/bin/projectinator.mjs +22 -15
- 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/cli.ts +0 -263
- 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
package/dist/router.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// The Router — deterministic dispatch. No LLM, no network. Given a tagged task
|
|
2
|
+
// and a policy, it resolves backend -> model -> cost, and flags budget overruns.
|
|
3
|
+
//
|
|
4
|
+
// User prompts (which backend? which model on API?) are injected as callbacks so
|
|
5
|
+
// the router stays pure and unit-testable. In the CLI they wrap real prompts;
|
|
6
|
+
// in tests they're stubs.
|
|
7
|
+
import { estimateCost } from "./cost.js";
|
|
8
|
+
import { getModel } from "./models.js";
|
|
9
|
+
import { findEntry, REGISTRY } from "./registry.js";
|
|
10
|
+
import { modelCalibratedTokens } from "./calibration.js";
|
|
11
|
+
const TIERS = ["fast", "mid", "high"];
|
|
12
|
+
/** Resolve which backend to use from the policy (and a prompt, if "ask"). */
|
|
13
|
+
export function resolveBackend(policy, task, prompts) {
|
|
14
|
+
switch (policy.backendMode) {
|
|
15
|
+
case "api":
|
|
16
|
+
return "api";
|
|
17
|
+
case "web":
|
|
18
|
+
return "web";
|
|
19
|
+
case "cost-first":
|
|
20
|
+
// Web-login rides the user's existing subscription -> effectively free.
|
|
21
|
+
return "web";
|
|
22
|
+
case "ask":
|
|
23
|
+
if (!prompts?.chooseBackend) {
|
|
24
|
+
throw new Error('backendMode "ask" requires prompts.chooseBackend');
|
|
25
|
+
}
|
|
26
|
+
return prompts.chooseBackend(task);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function route(task, ctx) {
|
|
30
|
+
const { policy } = ctx;
|
|
31
|
+
const registry = ctx.registry ?? REGISTRY;
|
|
32
|
+
const reasons = [];
|
|
33
|
+
// 1. Backend.
|
|
34
|
+
const backend = resolveBackend(policy, task, ctx.prompts);
|
|
35
|
+
reasons.push(`backend=${backend} (mode=${policy.backendMode})`);
|
|
36
|
+
// 2. Difficulty -> tier (+ escalation).
|
|
37
|
+
const base = policy.difficultyToTier[task.difficulty];
|
|
38
|
+
const tier = TIERS[Math.min(TIERS.length - 1, TIERS.indexOf(base) + (ctx.tierBump ?? 0))];
|
|
39
|
+
reasons.push(`difficulty=${task.difficulty} -> tier=${tier}${tier !== base ? ` (escalated from ${base})` : ""}`);
|
|
40
|
+
// 3. Registry lookup (with tier fallback).
|
|
41
|
+
const { entry, exactTier } = findEntry(task.capability, tier, registry);
|
|
42
|
+
if (!exactTier)
|
|
43
|
+
reasons.push(`no ${task.capability}/${tier} entry, fell back to ${entry.tier}`);
|
|
44
|
+
// 4. Backend-conditional model, with optional per-role prompt on API.
|
|
45
|
+
let modelId = entry.byBackend[backend].model;
|
|
46
|
+
if (backend === "api" && entry.ask && ctx.prompts?.chooseModel) {
|
|
47
|
+
const picked = ctx.prompts.chooseModel(task, entry, backend);
|
|
48
|
+
if (picked && picked !== modelId) {
|
|
49
|
+
reasons.push(`user overrode model ${modelId} -> ${picked}`);
|
|
50
|
+
modelId = picked;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const model = getModel(modelId);
|
|
54
|
+
reasons.push(`model=${model.id} (${model.provider})`);
|
|
55
|
+
// 5. Cost. Once real runs exist for this model, their average beats the PM-time estimate.
|
|
56
|
+
const est = modelCalibratedTokens(task.capability, task.difficulty, model.id) ?? task.estTokens;
|
|
57
|
+
const cost = estimateCost(est, model);
|
|
58
|
+
if (est !== task.estTokens)
|
|
59
|
+
reasons.push(`tokens from measured runs on ${model.id}`);
|
|
60
|
+
const runningTotal = Math.round(((ctx.runningTotalBefore ?? 0) + cost) * 10_000) / 10_000;
|
|
61
|
+
const overCap = runningTotal > policy.budgetCapUSD;
|
|
62
|
+
if (overCap)
|
|
63
|
+
reasons.push(`OVER CAP: running $${runningTotal} > cap $${policy.budgetCapUSD}`);
|
|
64
|
+
return {
|
|
65
|
+
taskId: task.id,
|
|
66
|
+
backend,
|
|
67
|
+
provider: model.provider,
|
|
68
|
+
model,
|
|
69
|
+
tier: entry.tier,
|
|
70
|
+
cost,
|
|
71
|
+
runningTotal,
|
|
72
|
+
overCap,
|
|
73
|
+
reasons,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Route a whole backlog in order, threading the running total. */
|
|
77
|
+
export function routeBacklog(tasks, ctx) {
|
|
78
|
+
const out = [];
|
|
79
|
+
let running = ctx.runningTotalBefore ?? 0;
|
|
80
|
+
for (const task of tasks) {
|
|
81
|
+
const decision = route(task, { ...ctx, runningTotalBefore: running });
|
|
82
|
+
running = decision.runningTotal;
|
|
83
|
+
out.push(decision);
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
/** A sensible default policy. */
|
|
88
|
+
export const DEFAULT_POLICY = {
|
|
89
|
+
backendMode: "cost-first",
|
|
90
|
+
budgetCapUSD: 15,
|
|
91
|
+
difficultyToTier: { trivial: "fast", low: "mid", medium: "mid", high: "high" },
|
|
92
|
+
maxFeedbackRounds: 3,
|
|
93
|
+
taskLimits: { timeoutMs: 10 * 60_000, costCapUSD: 3 },
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,iFAAiF;AACjF,EAAE;AACF,iFAAiF;AACjF,8EAA8E;AAC9E,0BAA0B;AAU1B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAqBzD,MAAM,KAAK,GAAW,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAE9C,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,MAAqB,EAAE,IAAU,EAAE,OAAuB;IACvF,QAAQ,MAAM,CAAC,WAAW,EAAE,CAAC;QAC3B,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf,KAAK,KAAK;YACR,OAAO,KAAK,CAAC;QACf,KAAK,YAAY;YACf,wEAAwE;YACxE,OAAO,KAAK,CAAC;QACf,KAAK,KAAK;YACR,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;gBAC5B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;YACtE,CAAC;YACD,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAU,EAAE,GAAiB;IACjD,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAC1C,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,cAAc;IACd,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,WAAW,OAAO,UAAU,MAAM,CAAC,WAAW,GAAG,CAAC,CAAC;IAEhE,wCAAwC;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC;IAC3F,OAAO,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,UAAU,YAAY,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,oBAAoB,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEjH,2CAA2C;IAC3C,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IACxE,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,IAAI,IAAI,wBAAwB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAEhG,sEAAsE;IACtE,IAAI,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;IAC7C,IAAI,OAAO,KAAK,KAAK,IAAI,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;QAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC7D,IAAI,MAAM,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,uBAAuB,OAAO,OAAO,MAAM,EAAE,CAAC,CAAC;YAC5D,OAAO,GAAG,MAAM,CAAC;QACnB,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,OAAO,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;IAEtD,0FAA0F;IAC1F,MAAM,GAAG,GAAG,qBAAqB,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC;IAChG,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACtC,IAAI,GAAG,KAAK,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,gCAAgC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IACrF,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,kBAAkB,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,MAAM,CAAC;IAC1F,MAAM,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IACnD,IAAI,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,sBAAsB,YAAY,WAAW,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAE9F,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,OAAO;QACP,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,KAAK;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI;QACJ,YAAY;QACZ,OAAO;QACP,OAAO;KACR,CAAC;AACJ,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,GAAiB;IAC3D,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,IAAI,OAAO,GAAG,GAAG,CAAC,kBAAkB,IAAI,CAAC,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,GAAG,GAAG,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC,CAAC;QACtE,OAAO,GAAG,QAAQ,CAAC,YAAY,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iCAAiC;AACjC,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,WAAW,EAAE,YAAY;IACzB,YAAY,EAAE,EAAE;IAChB,gBAAgB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;IAC9E,iBAAiB,EAAE,CAAC;IACpB,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,CAAC,EAAE;CACtD,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Model bake-off CLI — run one task across models, compare cost/latency/quality.
|
|
2
|
+
//
|
|
3
|
+
// npm run bakeoff -- --capability design "Design a pricing page with 3 tiers"
|
|
4
|
+
// npm run bakeoff -- --capability plan "Plan an MVP task list for a URL shortener"
|
|
5
|
+
// npm run bakeoff -- --models claude-opus-4-8,claude-sonnet-4-6,claude-haiku-4-5 "..."
|
|
6
|
+
//
|
|
7
|
+
// Defaults to the three Anthropic tiers (what most people hold a key for). Add
|
|
8
|
+
// --models to compare any model ids; --provider to set their provider.
|
|
9
|
+
import { runBakeoff, bakeoffTask } from "./bakeoff.js";
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
function opt(name) {
|
|
12
|
+
const i = args.indexOf(name);
|
|
13
|
+
return i >= 0 ? args[i + 1] : undefined;
|
|
14
|
+
}
|
|
15
|
+
const capability = (opt("--capability") ?? "design");
|
|
16
|
+
const difficulty = (opt("--difficulty") ?? "medium");
|
|
17
|
+
const provider = (opt("--provider") ?? "anthropic");
|
|
18
|
+
const modelsArg = opt("--models");
|
|
19
|
+
const consumed = new Set(["--capability", capability, "--difficulty", difficulty, "--provider", provider, "--models", modelsArg ?? ""].filter(Boolean));
|
|
20
|
+
const prompt = args.filter((a) => !consumed.has(a)).join(" ").trim();
|
|
21
|
+
if (!prompt) {
|
|
22
|
+
console.log('\n Usage: npm run bakeoff -- --capability design "your task"\n');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
if (capability === "code") {
|
|
26
|
+
console.log("\n Code bake-off isn't supported yet (needs a sandbox + real test scoring per model).");
|
|
27
|
+
console.log(" Try --capability design or plan for now.\n");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const models = (modelsArg ?? "claude-opus-4-8,claude-sonnet-4-6,claude-haiku-4-5").split(",").map((s) => s.trim()).filter(Boolean);
|
|
31
|
+
const candidates = models.map((model) => ({ provider, model }));
|
|
32
|
+
console.log(`\n Bake-off — ${capability}/${difficulty} ${candidates.length} models\n Task: ${prompt}\n`);
|
|
33
|
+
const result = await runBakeoff(bakeoffTask(prompt, capability, difficulty), candidates, {
|
|
34
|
+
onProgress: (m) => console.log(" " + m),
|
|
35
|
+
});
|
|
36
|
+
// ---- report ----
|
|
37
|
+
const scoreOf = new Map(result.scores.map((s) => [s.model, s]));
|
|
38
|
+
const money = (n) => `$${n.toFixed(4)}`;
|
|
39
|
+
console.log("\n --- RESULTS ---");
|
|
40
|
+
console.log(" model".padEnd(30) + "score".padEnd(8) + "cost".padEnd(12) + "time".padEnd(8) + "tokens");
|
|
41
|
+
for (const e of result.entries) {
|
|
42
|
+
const key = `${e.provider}/${e.model}`;
|
|
43
|
+
const sc = scoreOf.get(key);
|
|
44
|
+
const scoreStr = e.error ? "ERR" : sc ? `${sc.score}/10` : "—";
|
|
45
|
+
const line = (" " + e.model).padEnd(30) +
|
|
46
|
+
scoreStr.padEnd(8) +
|
|
47
|
+
(e.error ? "—" : money(e.cost)).padEnd(12) +
|
|
48
|
+
(e.error ? "—" : `${(e.ms / 1000).toFixed(1)}s`).padEnd(8) +
|
|
49
|
+
(e.error ? "" : String(e.outputTokens));
|
|
50
|
+
console.log(line);
|
|
51
|
+
if (e.error)
|
|
52
|
+
console.log(` ↳ ${e.error}`);
|
|
53
|
+
}
|
|
54
|
+
if (result.winner) {
|
|
55
|
+
const w = result.entries.find((e) => `${e.provider}/${e.model}` === result.winner);
|
|
56
|
+
const wc = w?.cost ?? 0;
|
|
57
|
+
const cheapest = result.entries.filter((e) => !e.error).sort((a, b) => a.cost - b.cost)[0];
|
|
58
|
+
console.log(`\n 🏆 Best quality: ${result.winner} (judge: ${result.judge})`);
|
|
59
|
+
if (cheapest && `${cheapest.provider}/${cheapest.model}` !== result.winner) {
|
|
60
|
+
console.log(` 💸 Cheapest: ${cheapest.provider}/${cheapest.model} at ${money(cheapest.cost)} (winner cost ${money(wc)})`);
|
|
61
|
+
}
|
|
62
|
+
for (const s of result.scores.sort((a, b) => b.score - a.score)) {
|
|
63
|
+
console.log(` ${s.score}/10 ${s.model} — ${s.reason}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
console.log("");
|
|
67
|
+
process.exit(0);
|
|
68
|
+
//# sourceMappingURL=run-bakeoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-bakeoff.js","sourceRoot":"","sources":["../src/run-bakeoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Phase 4 entry — run a whole build end to end.
|
|
2
|
+
//
|
|
3
|
+
// npm run build -- "an idea" dry: decompose + toposort + routing plan, NO spend
|
|
4
|
+
// npm run build -- --mini dry: tiny fixed 3-task backlog (design->code->test)
|
|
5
|
+
// npm run build -- --live --mini LIVE: run the mini backlog (cheap end-to-end)
|
|
6
|
+
// npm run build -- --live --lock anthropic "an idea" LIVE: full pipeline on one provider
|
|
7
|
+
//
|
|
8
|
+
// --lock <provider> routes every role to one provider (use the one you hold a key for).
|
|
9
|
+
// Default lock is anthropic.
|
|
10
|
+
import { mkdirSync } from "node:fs";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { dirname, join } from "node:path";
|
|
13
|
+
import { DEFAULT_POLICY } from "./router.js";
|
|
14
|
+
import { toposort, runBacklog } from "./orchestrator.js";
|
|
15
|
+
import { lockRegistryToProvider, makePiExecutor } from "./roles.js";
|
|
16
|
+
import { estimateTokens } from "./estimate.js";
|
|
17
|
+
import { route } from "./router.js";
|
|
18
|
+
import { decomposeIdea } from "./pm.js";
|
|
19
|
+
import { newBuildState, saveState, loadState, completedIds } from "./build-state.js";
|
|
20
|
+
import { initRepo, commitTask } from "./git.js";
|
|
21
|
+
const args = process.argv.slice(2);
|
|
22
|
+
const live = args.includes("--live");
|
|
23
|
+
const mini = args.includes("--mini");
|
|
24
|
+
const fan = args.includes("--fan");
|
|
25
|
+
const resume = args.includes("--resume");
|
|
26
|
+
const lockIdx = args.indexOf("--lock");
|
|
27
|
+
const lockProvider = (lockIdx >= 0 ? args[lockIdx + 1] : "anthropic");
|
|
28
|
+
const concIdx = args.indexOf("--concurrency");
|
|
29
|
+
const concurrency = Math.max(1, parseInt((concIdx >= 0 ? args[concIdx + 1] : "1") ?? "1", 10) || 1);
|
|
30
|
+
const capIdx = args.indexOf("--task-cap");
|
|
31
|
+
const tmoIdx = args.indexOf("--task-timeout");
|
|
32
|
+
const consumed = new Set(["--live", "--mini", "--fan", "--resume", "--lock", lockIdx >= 0 ? args[lockIdx + 1] : "",
|
|
33
|
+
"--concurrency", concIdx >= 0 ? args[concIdx + 1] : "",
|
|
34
|
+
"--task-cap", capIdx >= 0 ? args[capIdx + 1] : "",
|
|
35
|
+
"--task-timeout", tmoIdx >= 0 ? args[tmoIdx + 1] : ""].filter(Boolean));
|
|
36
|
+
const idea = args.filter((a) => !consumed.has(a)).join(" ").trim() ||
|
|
37
|
+
"A one-page site with a headline and a contact form.";
|
|
38
|
+
const money = (n) => `$${n.toFixed(2)}`;
|
|
39
|
+
const registry = lockRegistryToProvider(lockProvider);
|
|
40
|
+
// --task-cap USD / --task-timeout MIN override the per-task limits (0 = unlimited).
|
|
41
|
+
const taskLimits = {
|
|
42
|
+
costCapUSD: capIdx >= 0 ? parseFloat(args[capIdx + 1] ?? "") : DEFAULT_POLICY.taskLimits.costCapUSD,
|
|
43
|
+
timeoutMs: tmoIdx >= 0 ? parseFloat(args[tmoIdx + 1] ?? "") * 60_000 : DEFAULT_POLICY.taskLimits.timeoutMs,
|
|
44
|
+
};
|
|
45
|
+
const policy = { ...DEFAULT_POLICY, backendMode: "api", budgetCapUSD: mini ? 10 : 25, taskLimits };
|
|
46
|
+
// --- a tiny fixed backlog for cheap end-to-end proof ---
|
|
47
|
+
function miniBacklog() {
|
|
48
|
+
const mk = (id, cap, diff, title, deps = []) => ({
|
|
49
|
+
id, title, capability: cap, difficulty: diff, dependsOn: deps, estTokens: estimateTokens(cap, diff),
|
|
50
|
+
});
|
|
51
|
+
return [
|
|
52
|
+
mk("D-1", "design", "low", "Write a short design spec for a centered card that says 'Hello from Projectinator' on a soft gradient background."),
|
|
53
|
+
mk("C-1", "code", "low", "Create index.html implementing the design spec exactly. Single self-contained file with embedded CSS.", ["D-1"]),
|
|
54
|
+
mk("R-1", "review", "trivial", "Review index.html against the design spec: file present, no unresolved references, runs on double-click.", ["C-1"]),
|
|
55
|
+
mk("T-1", "test", "trivial", "Open/read index.html and verify it is valid HTML and matches the design spec (centered card, the headline text, a gradient).", ["R-1"]),
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
// A fan-out backlog with independent branches, to show parallel execution:
|
|
59
|
+
// two design tasks (independent) -> two code tasks -> one test that joins them.
|
|
60
|
+
function fanBacklog() {
|
|
61
|
+
const mk = (id, cap, diff, title, deps = []) => ({
|
|
62
|
+
id, title, capability: cap, difficulty: diff, dependsOn: deps, estTokens: estimateTokens(cap, diff),
|
|
63
|
+
});
|
|
64
|
+
return [
|
|
65
|
+
mk("DA", "design", "low", "Design spec for a 'Newsletter signup' card (email input + button)."),
|
|
66
|
+
mk("DB", "design", "low", "Design spec for an 'FAQ' accordion (3 questions)."),
|
|
67
|
+
mk("CA", "code", "low", "Create newsletter.html from the newsletter design spec.", ["DA"]),
|
|
68
|
+
mk("CB", "code", "low", "Create faq.html from the FAQ design spec.", ["DB"]),
|
|
69
|
+
mk("RA", "review", "trivial", "Review newsletter.html against its spec.", ["CA"]),
|
|
70
|
+
mk("RB", "review", "trivial", "Review faq.html against its spec.", ["CB"]),
|
|
71
|
+
mk("TJ", "test", "trivial", "Verify newsletter.html and faq.html are valid and match their specs.", ["RA", "RB"]),
|
|
72
|
+
];
|
|
73
|
+
}
|
|
74
|
+
async function getTasks() {
|
|
75
|
+
if (fan)
|
|
76
|
+
return fanBacklog();
|
|
77
|
+
if (mini)
|
|
78
|
+
return miniBacklog();
|
|
79
|
+
if (!live) {
|
|
80
|
+
// Dry + full idea: we can't call the PM without spending, so show the mini path.
|
|
81
|
+
console.log(" (Full-idea decomposition needs the PM model. Use --mini for a dry preview, or add --live.)\n");
|
|
82
|
+
return miniBacklog();
|
|
83
|
+
}
|
|
84
|
+
console.log(" Decomposing idea with PM...\n");
|
|
85
|
+
const res = await decomposeIdea(idea, {
|
|
86
|
+
backend: "api",
|
|
87
|
+
modelOverride: { provider: lockProvider, model: lockRegistryToProvider(lockProvider).find((e) => e.capability === "plan").byBackend.api.model },
|
|
88
|
+
});
|
|
89
|
+
console.log(` PM produced ${res.tasks.length} tasks.\n`);
|
|
90
|
+
return res.tasks;
|
|
91
|
+
}
|
|
92
|
+
const variant = fan ? " / fan" : mini ? " / mini" : "";
|
|
93
|
+
console.log(`\n Projectinator — Phase 4 full build [${live ? "LIVE" : "DRY"}${variant}] lock=${lockProvider} concurrency=${concurrency}\n`);
|
|
94
|
+
if (!mini && !fan)
|
|
95
|
+
console.log(` Idea: ${idea}\n`);
|
|
96
|
+
let tasks = await getTasks();
|
|
97
|
+
// Dry: show plan only.
|
|
98
|
+
if (!live) {
|
|
99
|
+
const ordered = toposort(tasks);
|
|
100
|
+
console.log(" Execution order (toposorted):");
|
|
101
|
+
let est = 0;
|
|
102
|
+
for (const t of ordered) {
|
|
103
|
+
const d = route(t, { policy, registry, runningTotalBefore: est });
|
|
104
|
+
est = d.runningTotal;
|
|
105
|
+
const dep = t.dependsOn?.length ? ` <- ${t.dependsOn.join(",")}` : "";
|
|
106
|
+
console.log(` ${t.id.padEnd(6)} [${t.capability}/${t.difficulty}] -> ${d.model.name.padEnd(20)} ${money(d.cost)}${dep}`);
|
|
107
|
+
}
|
|
108
|
+
console.log(`\n Estimated total: ${money(est)} (cap ${money(policy.budgetCapUSD)})`);
|
|
109
|
+
console.log(" Dry run. Add --live to actually build.\n");
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
// Live: key check.
|
|
113
|
+
const envKey = {
|
|
114
|
+
anthropic: ["ANTHROPIC_API_KEY"],
|
|
115
|
+
openai: ["OPENAI_API_KEY"],
|
|
116
|
+
google: ["GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
117
|
+
openrouter: ["OPENROUTER_API_KEY"],
|
|
118
|
+
};
|
|
119
|
+
if (!(envKey[lockProvider] ?? []).some((k) => process.env[k])) {
|
|
120
|
+
console.error(` No API key for ${lockProvider}. Set: ${(envKey[lockProvider] ?? []).join(", ")}\n`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
124
|
+
const workspace = join(projectRoot, ".workspace", fan ? "fan-build" : mini ? "mini-build" : "build");
|
|
125
|
+
mkdirSync(workspace, { recursive: true });
|
|
126
|
+
const statePath = join(workspace, "build-state.json");
|
|
127
|
+
// Resume: load prior state, reuse its saved backlog, seed finished outcomes.
|
|
128
|
+
let state;
|
|
129
|
+
let seedOutcomes = undefined;
|
|
130
|
+
const prior = resume ? loadState(statePath) : undefined;
|
|
131
|
+
if (prior) {
|
|
132
|
+
state = prior;
|
|
133
|
+
state.status = "running";
|
|
134
|
+
tasks = prior.tasks; // authoritative backlog from the interrupted run
|
|
135
|
+
seedOutcomes = prior.outcomes;
|
|
136
|
+
const doneCount = completedIds(prior).size;
|
|
137
|
+
console.log(` Resuming: ${doneCount} task(s) already done, restored ${money(prior.totalCost)}.`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
if (resume)
|
|
141
|
+
console.log(" (No prior state found — starting fresh.)");
|
|
142
|
+
state = newBuildState(fan ? "fan-build" : mini ? "mini-build" : "build", tasks);
|
|
143
|
+
}
|
|
144
|
+
console.log(` Workspace: ${workspace}\n Building...\n`);
|
|
145
|
+
// Version the workspace + commit after each task.
|
|
146
|
+
initRepo(workspace);
|
|
147
|
+
const titleById = new Map(tasks.map((t) => [t.id, t.title]));
|
|
148
|
+
const onEvent = (_e) => { };
|
|
149
|
+
const executor = makePiExecutor({
|
|
150
|
+
workspace,
|
|
151
|
+
backend: "api",
|
|
152
|
+
onEvent,
|
|
153
|
+
onFallback: (info) => console.log(` ↪ ${info.taskId}: ${info.from} failed — fell back to ${info.to}/${info.model}`),
|
|
154
|
+
});
|
|
155
|
+
const onProgress = (e) => {
|
|
156
|
+
if (e.type === "task_start")
|
|
157
|
+
console.log(` ▶ ${e.task.id} [${e.task.capability}] -> ${e.provider}/${e.modelId} (round ${e.round})`);
|
|
158
|
+
else if (e.type === "task_done") {
|
|
159
|
+
const hash = commitTask(workspace, e.outcome.taskId, titleById.get(e.outcome.taskId) ?? e.outcome.taskId);
|
|
160
|
+
console.log(` ✓ ${e.outcome.taskId} ${money(e.outcome.cost)} running ${money(e.runningTotal)}${e.outcome.verdict ? ` verdict=${e.outcome.verdict.passed ? (e.outcome.verdict.runtimeChecked ? "PASS" : "PASS* (app not executed — no Chromium)") : "FAIL"}` : ""}${hash ? ` [${hash}]` : ""}`);
|
|
161
|
+
}
|
|
162
|
+
else if (e.type === "task_failed")
|
|
163
|
+
console.log(` ⛔ ${e.outcome.taskId} ABORTED (${e.outcome.error}) — billed ${money(e.outcome.cost)}, halting`);
|
|
164
|
+
else if (e.type === "task_skipped")
|
|
165
|
+
console.log(` · ${e.taskId} skipped (already done)`);
|
|
166
|
+
else if (e.type === "test_failed")
|
|
167
|
+
console.log(` ✗ ${e.taskId} FAILED (${e.bugs} bugs) — round ${e.round}`);
|
|
168
|
+
else if (e.type === "retry_dev")
|
|
169
|
+
console.log(` ↻ re-running ${e.taskId} to fix ${e.forTest}`);
|
|
170
|
+
else if (e.type === "budget_halt")
|
|
171
|
+
console.log(` ⚠ BUDGET HALT at ${money(e.runningTotal)} (cap ${money(e.cap)})`);
|
|
172
|
+
};
|
|
173
|
+
// Checkpoint after every task so a crash/cancel loses at most one task.
|
|
174
|
+
const onCheckpoint = (outcomes, totalCost) => {
|
|
175
|
+
state.outcomes = outcomes;
|
|
176
|
+
state.totalCost = totalCost;
|
|
177
|
+
saveState(state, statePath);
|
|
178
|
+
};
|
|
179
|
+
const result = await runBacklog(tasks, { policy, execute: executor, registry, onProgress, seedOutcomes, onCheckpoint, concurrency });
|
|
180
|
+
state.outcomes = result.outcomes;
|
|
181
|
+
state.totalCost = result.totalCost;
|
|
182
|
+
state.status = result.halted ? "halted" : "complete";
|
|
183
|
+
state.haltReason = result.haltReason;
|
|
184
|
+
saveState(state, statePath);
|
|
185
|
+
console.log(`\n --- BUILD ${result.halted ? "HALTED" : "COMPLETE"} ---`);
|
|
186
|
+
console.log(` Steps run: ${result.outcomes.length}`);
|
|
187
|
+
console.log(` Total cost: ${money(result.totalCost)}`);
|
|
188
|
+
if (result.haltReason)
|
|
189
|
+
console.log(` Halt reason: ${result.haltReason} (re-run with --resume to continue)`);
|
|
190
|
+
const finalFiles = result.outcomes.at(-1)?.files ?? [];
|
|
191
|
+
console.log(` Files in workspace: ${finalFiles.join(", ") || "(none)"}`);
|
|
192
|
+
console.log(` State saved: ${statePath}\n`);
|
|
193
|
+
//# sourceMappingURL=run-build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-build.js","sourceRoot":"","sources":["../src/run-build.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,77 +4,61 @@
|
|
|
4
4
|
// npm run dev:task -- --live actually run the agent (spends money, needs an API key)
|
|
5
5
|
//
|
|
6
6
|
// Dry mode proves the whole wiring offline. Live mode is opt-in and key-gated.
|
|
7
|
-
|
|
8
7
|
import { mkdirSync } from "node:fs";
|
|
9
8
|
import { fileURLToPath } from "node:url";
|
|
10
9
|
import { dirname, join } from "node:path";
|
|
11
|
-
import type { AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
12
|
-
import type { Task } from "./types.js";
|
|
13
10
|
import { DEFAULT_POLICY, route } from "./router.js";
|
|
14
11
|
import { buildDeveloperPrompt, executeTask, piRuntime, resolvePiModel } from "./executor.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
estTokens: { input: 40_000, output: 12_000, cachedInputFraction: 0.3 },
|
|
12
|
+
const TASK = {
|
|
13
|
+
id: "T-DEV1",
|
|
14
|
+
story: "S-1",
|
|
15
|
+
title: "Create a single-file landing page (index.html) for 'Projectinator' with a hero headline, one-line pitch, and a contact form (name, email, message) styled with embedded CSS. No external assets.",
|
|
16
|
+
capability: "code",
|
|
17
|
+
difficulty: "high",
|
|
18
|
+
estTokens: { input: 40_000, output: 12_000, cachedInputFraction: 0.3 },
|
|
23
19
|
};
|
|
24
|
-
|
|
25
20
|
const live = process.argv.includes("--live");
|
|
26
|
-
|
|
27
21
|
// Route it. Web-login backend isn't built yet -> use API.
|
|
28
|
-
const policy = { ...DEFAULT_POLICY, backendMode: "api"
|
|
22
|
+
const policy = { ...DEFAULT_POLICY, backendMode: "api" };
|
|
29
23
|
const decision = route(TASK, { policy });
|
|
30
|
-
|
|
31
24
|
const piModel = resolvePiModel(await piRuntime(), decision.provider, decision.model.id); // offline, free
|
|
32
|
-
|
|
33
|
-
const money = (n: number) => `$${n.toFixed(2)}`;
|
|
34
|
-
|
|
25
|
+
const money = (n) => `$${n.toFixed(2)}`;
|
|
35
26
|
console.log(`\n Projectinator — Phase 2 developer run [${live ? "LIVE" : "DRY"}]\n`);
|
|
36
27
|
console.log(` Task ${TASK.id}: ${TASK.title.slice(0, 64)}...`);
|
|
37
28
|
console.log(` Routed ${decision.provider}/${decision.model.id} (tier=${decision.tier}, backend=${decision.backend})`);
|
|
38
29
|
console.log(` Pi model resolved: ${piModel.id} ctx=${piModel.contextWindow} in/out=${piModel.cost?.input}/${piModel.cost?.output}`);
|
|
39
30
|
console.log(` Est cost ${money(decision.cost)}\n`);
|
|
40
|
-
|
|
41
31
|
if (!live) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
console.log(" --- developer prompt (not sent) ---");
|
|
33
|
+
console.log(buildDeveloperPrompt(TASK).split("\n").map((l) => " | " + l).join("\n"));
|
|
34
|
+
console.log("\n Dry run only. Wiring verified: task routed, Pi model resolved, prompt built.");
|
|
35
|
+
console.log(" Re-run with --live (and an API key) to actually build.\n");
|
|
36
|
+
process.exit(0);
|
|
47
37
|
}
|
|
48
|
-
|
|
49
38
|
// --- LIVE PATH: spends money ---
|
|
50
|
-
const envKey
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
const envKey = {
|
|
40
|
+
anthropic: ["ANTHROPIC_API_KEY"],
|
|
41
|
+
openai: ["OPENAI_API_KEY"],
|
|
42
|
+
google: ["GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
54
43
|
};
|
|
55
44
|
const keyPresent = (envKey[decision.provider] ?? []).some((k) => !!process.env[k]);
|
|
56
45
|
if (!keyPresent) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
);
|
|
60
|
-
process.exit(1);
|
|
46
|
+
console.error(` No API key for ${decision.provider}. Set one of: ${(envKey[decision.provider] ?? []).join(", ")}\n`);
|
|
47
|
+
process.exit(1);
|
|
61
48
|
}
|
|
62
|
-
|
|
63
49
|
// fileURLToPath decodes %20/%7E etc. — URL.pathname would leave them encoded and
|
|
64
50
|
// create a literally-named "Mobile%20Documents" directory.
|
|
65
51
|
const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
66
52
|
const workspace = join(projectRoot, ".workspace", TASK.id);
|
|
67
53
|
mkdirSync(workspace, { recursive: true });
|
|
68
54
|
console.log(` Workspace: ${workspace}\n Running agent...\n`);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
process.stdout.write(` · ${e.type}\n`);
|
|
55
|
+
const onEvent = (e) => {
|
|
56
|
+
process.stdout.write(` · ${e.type}\n`);
|
|
72
57
|
};
|
|
73
|
-
|
|
74
58
|
const result = await executeTask(TASK, decision, { workspace, onEvent });
|
|
75
|
-
|
|
76
59
|
console.log(`\n --- done ---`);
|
|
77
60
|
console.log(` Files: ${result.files.join(", ") || "(none)"}`);
|
|
78
61
|
console.log(` Tokens: in=${result.actual.input} out=${result.actual.output} cacheRead=${result.actual.cacheRead} total=${result.actual.total}`);
|
|
79
62
|
console.log(` Est: ${money(result.estCost)}`);
|
|
80
63
|
console.log(` Actual: ${money(result.actualCost)} (delta ${money(result.costDelta)})\n`);
|
|
64
|
+
//# sourceMappingURL=run-dev.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-dev.js","sourceRoot":"","sources":["../src/run-dev.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,87 +4,75 @@
|
|
|
4
4
|
// npm run pm -- --live "your idea here" live: decompose + route the backlog
|
|
5
5
|
//
|
|
6
6
|
// Live decomposition needs an API key (PM routes to an OpenAI model by default).
|
|
7
|
-
|
|
8
|
-
import type { AgentSessionEvent } from "@earendil-works/pi-coding-agent";
|
|
9
7
|
import { DEFAULT_POLICY, routeBacklog } from "./router.js";
|
|
10
8
|
import { findEntry } from "./registry.js";
|
|
11
|
-
import { piRuntime, resolvePiModel } from "./executor.js"
|
|
9
|
+
import { piRuntime, resolvePiModel } from "./executor.js";
|
|
12
10
|
import { decomposeIdea, pmSystemPrompt } from "./pm.js";
|
|
13
|
-
|
|
14
11
|
const args = process.argv.slice(2);
|
|
15
12
|
const live = args.includes("--live");
|
|
16
|
-
|
|
17
13
|
// Optional PM model override: --pm <provider/id> (e.g. anthropic/claude-sonnet-4-6).
|
|
18
14
|
// Lets you decompose with whichever provider you hold a key for.
|
|
19
15
|
const pmIdx = args.indexOf("--pm");
|
|
20
16
|
const pmOverride = pmIdx >= 0 ? args[pmIdx + 1] : undefined;
|
|
21
|
-
const consumed = new Set
|
|
17
|
+
const consumed = new Set(["--live", "--pm", pmOverride].filter(Boolean));
|
|
22
18
|
const idea = args.filter((a) => !consumed.has(a)).join(" ").trim() ||
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
const money = (n: number) => `$${n.toFixed(2)}`;
|
|
27
|
-
|
|
19
|
+
"A simple personal task tracker web app: add tasks, mark them done, filter by status.";
|
|
20
|
+
const backend = "api"; // web-login backend not built yet
|
|
21
|
+
const money = (n) => `$${n.toFixed(2)}`;
|
|
28
22
|
const runtime = await piRuntime();
|
|
29
23
|
const { entry } = findEntry("plan", "mid");
|
|
30
24
|
const pick = pmOverride
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
? { provider: pmOverride.split("/")[0], model: pmOverride.split("/").slice(1).join("/") }
|
|
26
|
+
: entry.byBackend[backend];
|
|
33
27
|
const pm = resolvePiModel(runtime, pick.provider, pick.model); // offline
|
|
34
|
-
|
|
35
28
|
console.log(`\n Projectinator — Phase 3 PM decomposer [${live ? "LIVE" : "DRY"}]\n`);
|
|
36
29
|
console.log(` Idea: ${idea}`);
|
|
37
30
|
console.log(` PM model: ${pick.provider}/${pm.id} (tier=${entry.tier}, backend=${backend})\n`);
|
|
38
|
-
|
|
39
31
|
if (!live) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
console.log(" --- PM system prompt (not sent) ---");
|
|
33
|
+
console.log(pmSystemPrompt().split("\n").map((l) => " | " + l).join("\n"));
|
|
34
|
+
console.log("\n Dry run. Re-run with --live (and an API key) to actually decompose.\n");
|
|
35
|
+
process.exit(0);
|
|
44
36
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
google: ["GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
37
|
+
const envKey = {
|
|
38
|
+
anthropic: ["ANTHROPIC_API_KEY"],
|
|
39
|
+
openai: ["OPENAI_API_KEY"],
|
|
40
|
+
google: ["GEMINI_API_KEY", "GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
50
41
|
};
|
|
51
42
|
if (!(envKey[pick.provider] ?? []).some((k) => process.env[k])) {
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
console.error(` No API key for ${pick.provider}. Set: ${(envKey[pick.provider] ?? []).join(", ")}\n`);
|
|
44
|
+
process.exit(1);
|
|
54
45
|
}
|
|
55
|
-
|
|
56
46
|
console.log(" Decomposing...\n");
|
|
57
|
-
const onEvent = (e
|
|
58
|
-
|
|
47
|
+
const onEvent = (e) => {
|
|
48
|
+
if (e.type === "tool_execution_end" || e.type === "agent_end")
|
|
49
|
+
process.stdout.write(` · ${e.type}\n`);
|
|
59
50
|
};
|
|
60
|
-
|
|
61
51
|
const result = await decomposeIdea(idea, {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
52
|
+
backend,
|
|
53
|
+
onEvent,
|
|
54
|
+
modelOverride: pmOverride ? { provider: pick.provider, model: pick.model } : undefined,
|
|
65
55
|
});
|
|
66
|
-
|
|
67
56
|
console.log(`\n --- BACKLOG (${result.provider}/${result.modelId}) ---`);
|
|
68
57
|
for (const t of result.backlog.tasks) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
58
|
+
const dep = (t.dependsOn ?? []).length ? ` <- ${(t.dependsOn ?? []).join(",")}` : "";
|
|
59
|
+
const grp = t.epic ? `${t.epic}${t.story ? "/" + t.story : ""} ` : "";
|
|
60
|
+
console.log(` ${t.id.padEnd(6)} [${t.capability}/${t.difficulty}] ${grp}${t.title}${dep}`);
|
|
72
61
|
}
|
|
73
62
|
if (result.diagnostics.length) {
|
|
74
|
-
|
|
75
|
-
|
|
63
|
+
console.log(`\n Normalizer notes:`);
|
|
64
|
+
for (const d of result.diagnostics)
|
|
65
|
+
console.log(` ! ${d}`);
|
|
76
66
|
}
|
|
77
|
-
|
|
78
67
|
// Route the whole backlog and total the cost.
|
|
79
68
|
const decisions = routeBacklog(result.tasks, { policy: { ...DEFAULT_POLICY, backendMode: backend } });
|
|
80
69
|
console.log(`\n --- ROUTING PLAN ---`);
|
|
81
70
|
console.log(" " + "TASK".padEnd(7) + "CAP/DIFF".padEnd(16) + "MODEL".padEnd(22) + "COST");
|
|
82
71
|
for (const d of decisions) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
d.model.name.padEnd(22) + money(d.cost),
|
|
88
|
-
);
|
|
72
|
+
const t = result.tasks.find((x) => x.id === d.taskId);
|
|
73
|
+
console.log(" " + d.taskId.padEnd(7) +
|
|
74
|
+
`${t.capability}/${t.difficulty}`.padEnd(16) +
|
|
75
|
+
d.model.name.padEnd(22) + money(d.cost));
|
|
89
76
|
}
|
|
90
77
|
console.log(`\n Tasks: ${result.tasks.length} Estimated total: ${money(decisions.at(-1)?.runningTotal ?? 0)}\n`);
|
|
78
|
+
//# sourceMappingURL=run-pm.js.map
|