@dougharness/cli 1.0.1
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/LICENSE +21 -0
- package/dist/ablate.d.ts +96 -0
- package/dist/ablate.js +440 -0
- package/dist/ablate.js.map +1 -0
- package/dist/apply.d.ts +2 -0
- package/dist/apply.js +19 -0
- package/dist/apply.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +80 -0
- package/dist/bin.js.map +1 -0
- package/dist/board-page.d.ts +15 -0
- package/dist/board-page.js +27 -0
- package/dist/board-page.js.map +1 -0
- package/dist/board-serve-process.d.ts +24 -0
- package/dist/board-serve-process.js +227 -0
- package/dist/board-serve-process.js.map +1 -0
- package/dist/board-serve.d.ts +9 -0
- package/dist/board-serve.js +302 -0
- package/dist/board-serve.js.map +1 -0
- package/dist/board.d.ts +6 -0
- package/dist/board.js +515 -0
- package/dist/board.js.map +1 -0
- package/dist/detect/fs.d.ts +6 -0
- package/dist/detect/fs.js +50 -0
- package/dist/detect/fs.js.map +1 -0
- package/dist/detect/index.d.ts +3 -0
- package/dist/detect/index.js +13 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/detect/node.d.ts +3 -0
- package/dist/detect/node.js +179 -0
- package/dist/detect/node.js.map +1 -0
- package/dist/detect/python.d.ts +2 -0
- package/dist/detect/python.js +388 -0
- package/dist/detect/python.js.map +1 -0
- package/dist/detect/repo.d.ts +2 -0
- package/dist/detect/repo.js +102 -0
- package/dist/detect/repo.js.map +1 -0
- package/dist/detect/types.d.ts +98 -0
- package/dist/detect/types.js +2 -0
- package/dist/detect/types.js.map +1 -0
- package/dist/diff.d.ts +12 -0
- package/dist/diff.js +105 -0
- package/dist/diff.js.map +1 -0
- package/dist/generate/agents.d.ts +19 -0
- package/dist/generate/agents.js +184 -0
- package/dist/generate/agents.js.map +1 -0
- package/dist/generate/claude-md.d.ts +9 -0
- package/dist/generate/claude-md.js +111 -0
- package/dist/generate/claude-md.js.map +1 -0
- package/dist/generate/config.d.ts +51 -0
- package/dist/generate/config.js +155 -0
- package/dist/generate/config.js.map +1 -0
- package/dist/generate/proposal.d.ts +11 -0
- package/dist/generate/proposal.js +175 -0
- package/dist/generate/proposal.js.map +1 -0
- package/dist/generate/settings.d.ts +35 -0
- package/dist/generate/settings.js +213 -0
- package/dist/generate/settings.js.map +1 -0
- package/dist/generate/skills.d.ts +8 -0
- package/dist/generate/skills.js +264 -0
- package/dist/generate/skills.js.map +1 -0
- package/dist/init.d.ts +10 -0
- package/dist/init.js +69 -0
- package/dist/init.js.map +1 -0
- package/dist/trace.d.ts +9 -0
- package/dist/trace.js +106 -0
- package/dist/trace.js.map +1 -0
- package/node_modules/@dougharness/flow/.claude-plugin/plugin.json +10 -0
- package/node_modules/@dougharness/flow/LICENSE +21 -0
- package/node_modules/@dougharness/flow/agents/adversary-claude.md +33 -0
- package/node_modules/@dougharness/flow/agents/adversary.md +29 -0
- package/node_modules/@dougharness/flow/agents/implementer.md +23 -0
- package/node_modules/@dougharness/flow/agents/lead.md +35 -0
- package/node_modules/@dougharness/flow/agents/planner.md +70 -0
- package/node_modules/@dougharness/flow/agents/researcher.md +31 -0
- package/node_modules/@dougharness/flow/agents/reviewer.md +26 -0
- package/node_modules/@dougharness/flow/agents/verifier.md +24 -0
- package/node_modules/@dougharness/flow/lib/board.mjs +840 -0
- package/node_modules/@dougharness/flow/lib/code-index.mjs +629 -0
- package/node_modules/@dougharness/flow/lib/cost.mjs +392 -0
- package/node_modules/@dougharness/flow/lib/decisions.mjs +314 -0
- package/node_modules/@dougharness/flow/lib/embeddings.mjs +539 -0
- package/node_modules/@dougharness/flow/lib/land.mjs +219 -0
- package/node_modules/@dougharness/flow/lib/learn.mjs +742 -0
- package/node_modules/@dougharness/flow/lib/memory-import.mjs +145 -0
- package/node_modules/@dougharness/flow/lib/memory.mjs +1641 -0
- package/node_modules/@dougharness/flow/lib/models.mjs +148 -0
- package/node_modules/@dougharness/flow/lib/plan.mjs +773 -0
- package/node_modules/@dougharness/flow/lib/rehearse.mjs +825 -0
- package/node_modules/@dougharness/flow/lib/worktrees.mjs +215 -0
- package/node_modules/@dougharness/flow/package.json +19 -0
- package/node_modules/@dougharness/flow/scripts/board.mjs +260 -0
- package/node_modules/@dougharness/flow/scripts/cost.mjs +66 -0
- package/node_modules/@dougharness/flow/scripts/learn.mjs +161 -0
- package/node_modules/@dougharness/flow/scripts/memory.mjs +1274 -0
- package/node_modules/@dougharness/flow/scripts/plan.mjs +547 -0
- package/node_modules/@dougharness/flow/scripts/rehearse.mjs +129 -0
- package/node_modules/@dougharness/flow/skills/core-next/SKILL.md +92 -0
- package/node_modules/@dougharness/flow/skills/doug-approve/SKILL.md +15 -0
- package/node_modules/@dougharness/flow/skills/doug-decide/SKILL.md +26 -0
- package/node_modules/@dougharness/flow/skills/doug-implement/SKILL.md +22 -0
- package/node_modules/@dougharness/flow/skills/doug-learn/SKILL.md +20 -0
- package/node_modules/@dougharness/flow/skills/doug-next/SKILL.md +87 -0
- package/node_modules/@dougharness/flow/skills/doug-plan/SKILL.md +22 -0
- package/node_modules/@dougharness/flow/skills/doug-swarm/SKILL.md +55 -0
- package/node_modules/@dougharness/flow/skills/harness-fix/SKILL.md +85 -0
- package/node_modules/@dougharness/flow/skills/research/SKILL.md +41 -0
- package/node_modules/@dougharness/flow/skills/run-report/SKILL.md +51 -0
- package/node_modules/@dougharness/flow/skills/swarm-launch/SKILL.md +27 -0
- package/node_modules/@dougharness/flow/workflows/doug-implement.js +2687 -0
- package/node_modules/@dougharness/gates/.claude-plugin/plugin.json +10 -0
- package/node_modules/@dougharness/gates/LICENSE +21 -0
- package/node_modules/@dougharness/gates/hooks/hooks.json +184 -0
- package/node_modules/@dougharness/gates/lib/agent-context.mjs +111 -0
- package/node_modules/@dougharness/gates/lib/anchor.mjs +110 -0
- package/node_modules/@dougharness/gates/lib/baseline.mjs +160 -0
- package/node_modules/@dougharness/gates/lib/bash-rules.mjs +1522 -0
- package/node_modules/@dougharness/gates/lib/block-ledger.mjs +127 -0
- package/node_modules/@dougharness/gates/lib/checkpoint.mjs +97 -0
- package/node_modules/@dougharness/gates/lib/config.mjs +168 -0
- package/node_modules/@dougharness/gates/lib/evidence.mjs +59 -0
- package/node_modules/@dougharness/gates/lib/glob.mjs +86 -0
- package/node_modules/@dougharness/gates/lib/io.mjs +91 -0
- package/node_modules/@dougharness/gates/lib/paths.mjs +101 -0
- package/node_modules/@dougharness/gates/lib/proposals.mjs +201 -0
- package/node_modules/@dougharness/gates/lib/run.mjs +147 -0
- package/node_modules/@dougharness/gates/lib/scope.mjs +117 -0
- package/node_modules/@dougharness/gates/lib/secret-rules.mjs +268 -0
- package/node_modules/@dougharness/gates/lib/state.mjs +114 -0
- package/node_modules/@dougharness/gates/lib/trace.mjs +196 -0
- package/node_modules/@dougharness/gates/package.json +17 -0
- package/node_modules/@dougharness/gates/scripts/edit-loop.mjs +39 -0
- package/node_modules/@dougharness/gates/scripts/format-on-edit.mjs +45 -0
- package/node_modules/@dougharness/gates/scripts/guard-bash.mjs +32 -0
- package/node_modules/@dougharness/gates/scripts/protect-paths.mjs +49 -0
- package/node_modules/@dougharness/gates/scripts/reanchor.mjs +81 -0
- package/node_modules/@dougharness/gates/scripts/research-cap.mjs +295 -0
- package/node_modules/@dougharness/gates/scripts/secret-scan.mjs +26 -0
- package/node_modules/@dougharness/gates/scripts/session-start-baseline.mjs +57 -0
- package/node_modules/@dougharness/gates/scripts/statusline.mjs +133 -0
- package/node_modules/@dougharness/gates/scripts/stop-gate.mjs +1422 -0
- package/node_modules/@dougharness/gates/scripts/trace.mjs +75 -0
- package/package.json +33 -0
- package/templates/board-app.js +533 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Model tiers: which model and effort does which work. Defined by the user in CLAUDE.md under a
|
|
2
|
+
// "## Models" heading as a table, parsed here deterministically, and resolved into the plan JSON by
|
|
3
|
+
// `plan.mjs json` so the workflow (which cannot read files) receives explicit values per task.
|
|
4
|
+
//
|
|
5
|
+
// ## Models
|
|
6
|
+
//
|
|
7
|
+
// | Work | Model | Effort |
|
|
8
|
+
// |------------|---------|--------|
|
|
9
|
+
// | plan | opus | high | <- the planner agent and the research step's researchers
|
|
10
|
+
// | lead | inherit | high |
|
|
11
|
+
// | worker | sonnet | medium | <- a swarm's workers; the lead row is its lead
|
|
12
|
+
// | implement | sonnet | medium |
|
|
13
|
+
// | verify | inherit | high |
|
|
14
|
+
// | cheap | haiku | low | <- any other row is a named tier a task can reference with "tier"
|
|
15
|
+
//
|
|
16
|
+
// Model: "inherit" (the session's model), an alias (opus, sonnet, haiku, fable), or a full model id.
|
|
17
|
+
// The adversary row may say "codex": the adversarial review runs on Codex through codex-review, and the
|
|
18
|
+
// workflow runs the Claude agent that launches it on haiku; that row's effort is that relay agent's.
|
|
19
|
+
// Effort: inherit | low | medium | high | xhigh | max. "inherit" means the workflow's own default for that role.
|
|
20
|
+
// Precedence for an implementer: task.model/effort > task.tier row > implement row > inherit.
|
|
21
|
+
|
|
22
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
|
|
25
|
+
// `plan` is the row the planner agent and the research step's researchers run on (card doug-next-lead-only).
|
|
26
|
+
// `worker` is the row a swarm's workers run on (card swarm-lead); the lead row is the swarm's lead.
|
|
27
|
+
export const ROLES = ["plan", "lead", "worker", "implement", "verify", "review", "adversary", "integrate"];
|
|
28
|
+
export const EFFORTS = ["inherit", "low", "medium", "high", "xhigh", "max"];
|
|
29
|
+
export const MODELS_HEADING = /^##\s+models\s*$/i;
|
|
30
|
+
|
|
31
|
+
export function isModelName(s) {
|
|
32
|
+
return typeof s === "string" && /^[a-z][a-z0-9.:_-]{0,79}$/.test(s);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Parses the "## Models" table out of CLAUDE.md text. Returns { roles, tiers, errors, present }. */
|
|
36
|
+
export function parseModelsSection(markdown) {
|
|
37
|
+
const out = { roles: {}, tiers: {}, errors: [], present: false };
|
|
38
|
+
if (typeof markdown !== "string") return out;
|
|
39
|
+
const lines = markdown.split(/\r?\n/);
|
|
40
|
+
const start = lines.findIndex((l) => MODELS_HEADING.test(l.trim()));
|
|
41
|
+
if (start < 0) return out;
|
|
42
|
+
out.present = true;
|
|
43
|
+
let rows = 0;
|
|
44
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
45
|
+
const line = lines[i].trim();
|
|
46
|
+
if (/^#{1,6}\s/.test(line)) break; // next section
|
|
47
|
+
if (!line.startsWith("|")) continue;
|
|
48
|
+
const cells = line.split("|").slice(1, -1).map((c) => c.trim());
|
|
49
|
+
if (cells.length < 2) continue;
|
|
50
|
+
if (cells.every((c) => /^:?-{2,}:?$/.test(c))) continue; // separator row
|
|
51
|
+
if (rows === 0 && /^work$/i.test(cells[0]) && /^model$/i.test(cells[1])) {
|
|
52
|
+
rows++;
|
|
53
|
+
continue; // header row
|
|
54
|
+
}
|
|
55
|
+
rows++;
|
|
56
|
+
const work = cells[0].toLowerCase().replace(/`/g, "");
|
|
57
|
+
const model = (cells[1] || "inherit").toLowerCase().replace(/`/g, "") || "inherit";
|
|
58
|
+
const effort = (cells[2] || "inherit").toLowerCase().replace(/`/g, "") || "inherit";
|
|
59
|
+
const where = `CLAUDE.md Models row "${cells[0]}"`;
|
|
60
|
+
if (!/^[a-z][a-z0-9-]{0,39}$/.test(work)) {
|
|
61
|
+
out.errors.push(`${where}: work name must be a role (${ROLES.join(", ")}) or a kebab-case tier name`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (!isModelName(model)) {
|
|
65
|
+
out.errors.push(`${where}: model "${cells[1]}" must be "inherit", an alias, or a model id`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (model === "codex" && work !== "adversary") {
|
|
69
|
+
out.errors.push(`${where}: "codex" is only valid on the adversary row; it names the adversarial reviewer (codex-review), not a Claude model`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (!EFFORTS.includes(effort)) {
|
|
73
|
+
out.errors.push(`${where}: effort "${cells[2]}" must be one of ${EFFORTS.join(", ")}`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const entry = { model, effort };
|
|
77
|
+
if (ROLES.includes(work)) {
|
|
78
|
+
if (out.roles[work]) out.errors.push(`${where}: role "${work}" is defined twice`);
|
|
79
|
+
out.roles[work] = entry;
|
|
80
|
+
} else {
|
|
81
|
+
if (out.tiers[work]) out.errors.push(`${where}: tier "${work}" is defined twice`);
|
|
82
|
+
out.tiers[work] = entry;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Reads <dir>/CLAUDE.md and parses its Models section. Absent file or section yields an empty definition. */
|
|
89
|
+
export function loadModels(dir) {
|
|
90
|
+
const file = join(dir, "CLAUDE.md");
|
|
91
|
+
if (!existsSync(file)) return { roles: {}, tiers: {}, errors: [], present: false, source: null };
|
|
92
|
+
return { ...parseModelsSection(readFileSync(file, "utf8")), source: "CLAUDE.md" };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const INHERIT = Object.freeze({ model: "inherit", effort: "inherit" });
|
|
96
|
+
|
|
97
|
+
/** Errors for task model fields and tier references. Empty when valid. */
|
|
98
|
+
export function validateModelRefs(plan, models) {
|
|
99
|
+
const errors = [];
|
|
100
|
+
if (!plan || !Array.isArray(plan.tasks)) return errors;
|
|
101
|
+
for (const [i, t] of plan.tasks.entries()) {
|
|
102
|
+
if (!t || typeof t !== "object") continue;
|
|
103
|
+
const where = `tasks[${i}]`;
|
|
104
|
+
if (t.model !== undefined && !isModelName(String(t.model).toLowerCase())) errors.push(`${where}.model must be "inherit", an alias, or a model id`);
|
|
105
|
+
if (t.model !== undefined && String(t.model).toLowerCase() === "codex") errors.push(`${where}.model cannot be "codex"; Codex is the adversarial reviewer, not an implementer`);
|
|
106
|
+
if (t.effort !== undefined && !EFFORTS.includes(String(t.effort).toLowerCase())) errors.push(`${where}.effort must be one of ${EFFORTS.join(", ")}`);
|
|
107
|
+
if (t.tier !== undefined) {
|
|
108
|
+
if (typeof t.tier !== "string" || !t.tier.trim()) errors.push(`${where}.tier must be a tier name from the CLAUDE.md Models table`);
|
|
109
|
+
else if (models && !models.tiers[t.tier.toLowerCase()] && !models.roles[t.tier.toLowerCase()]) {
|
|
110
|
+
const known = [...Object.keys(models.tiers), ...Object.keys(models.roles)];
|
|
111
|
+
errors.push(`${where}.tier "${t.tier}" is not defined in the CLAUDE.md Models table${known.length ? ` (known: ${known.join(", ")})` : " (no table found)"}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return errors;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Returns a copy of the plan with `models` (per-role settings) and every task's `model` and `effort`
|
|
120
|
+
* resolved to explicit values. "inherit" is kept as a literal so the workflow can map it to its defaults.
|
|
121
|
+
*/
|
|
122
|
+
export function resolvePlanModels(plan, models) {
|
|
123
|
+
const m = models || { roles: {}, tiers: {}, source: null };
|
|
124
|
+
const roles = {};
|
|
125
|
+
for (const r of ROLES) roles[r] = { ...INHERIT, ...(m.roles[r] || {}) };
|
|
126
|
+
const tasks = (plan.tasks || []).map((t) => {
|
|
127
|
+
const tierName = typeof t.tier === "string" ? t.tier.toLowerCase() : null;
|
|
128
|
+
const tier = tierName ? m.tiers[tierName] || m.roles[tierName] || null : null;
|
|
129
|
+
const base = tier || roles.implement;
|
|
130
|
+
return {
|
|
131
|
+
...t,
|
|
132
|
+
model: (t.model !== undefined ? String(t.model).toLowerCase() : base.model) || "inherit",
|
|
133
|
+
effort: (t.effort !== undefined ? String(t.effort).toLowerCase() : base.effort) || "inherit",
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
return { ...plan, models: { roles, tiers: { ...m.tiers }, source: m.source || null }, tasks };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** One line per role and tier, for `plan show`. */
|
|
140
|
+
export function renderModels(models) {
|
|
141
|
+
const lines = [];
|
|
142
|
+
const roles = models && models.roles ? models.roles : {};
|
|
143
|
+
const tiers = models && models.tiers ? models.tiers : {};
|
|
144
|
+
const fmt = (e) => `${e.model}${e.effort && e.effort !== "inherit" ? ` / ${e.effort}` : ""}`;
|
|
145
|
+
for (const r of ROLES) if (roles[r] && (roles[r].model !== "inherit" || roles[r].effort !== "inherit")) lines.push(` ${r}: ${fmt(roles[r])}`);
|
|
146
|
+
for (const [name, e] of Object.entries(tiers)) lines.push(` tier ${name}: ${fmt(e)}`);
|
|
147
|
+
return lines.length ? lines : [" (all roles inherit the session model)"];
|
|
148
|
+
}
|