@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.
Files changed (144) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ablate.d.ts +96 -0
  3. package/dist/ablate.js +440 -0
  4. package/dist/ablate.js.map +1 -0
  5. package/dist/apply.d.ts +2 -0
  6. package/dist/apply.js +19 -0
  7. package/dist/apply.js.map +1 -0
  8. package/dist/bin.d.ts +2 -0
  9. package/dist/bin.js +80 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/board-page.d.ts +15 -0
  12. package/dist/board-page.js +27 -0
  13. package/dist/board-page.js.map +1 -0
  14. package/dist/board-serve-process.d.ts +24 -0
  15. package/dist/board-serve-process.js +227 -0
  16. package/dist/board-serve-process.js.map +1 -0
  17. package/dist/board-serve.d.ts +9 -0
  18. package/dist/board-serve.js +302 -0
  19. package/dist/board-serve.js.map +1 -0
  20. package/dist/board.d.ts +6 -0
  21. package/dist/board.js +515 -0
  22. package/dist/board.js.map +1 -0
  23. package/dist/detect/fs.d.ts +6 -0
  24. package/dist/detect/fs.js +50 -0
  25. package/dist/detect/fs.js.map +1 -0
  26. package/dist/detect/index.d.ts +3 -0
  27. package/dist/detect/index.js +13 -0
  28. package/dist/detect/index.js.map +1 -0
  29. package/dist/detect/node.d.ts +3 -0
  30. package/dist/detect/node.js +179 -0
  31. package/dist/detect/node.js.map +1 -0
  32. package/dist/detect/python.d.ts +2 -0
  33. package/dist/detect/python.js +388 -0
  34. package/dist/detect/python.js.map +1 -0
  35. package/dist/detect/repo.d.ts +2 -0
  36. package/dist/detect/repo.js +102 -0
  37. package/dist/detect/repo.js.map +1 -0
  38. package/dist/detect/types.d.ts +98 -0
  39. package/dist/detect/types.js +2 -0
  40. package/dist/detect/types.js.map +1 -0
  41. package/dist/diff.d.ts +12 -0
  42. package/dist/diff.js +105 -0
  43. package/dist/diff.js.map +1 -0
  44. package/dist/generate/agents.d.ts +19 -0
  45. package/dist/generate/agents.js +184 -0
  46. package/dist/generate/agents.js.map +1 -0
  47. package/dist/generate/claude-md.d.ts +9 -0
  48. package/dist/generate/claude-md.js +111 -0
  49. package/dist/generate/claude-md.js.map +1 -0
  50. package/dist/generate/config.d.ts +51 -0
  51. package/dist/generate/config.js +155 -0
  52. package/dist/generate/config.js.map +1 -0
  53. package/dist/generate/proposal.d.ts +11 -0
  54. package/dist/generate/proposal.js +175 -0
  55. package/dist/generate/proposal.js.map +1 -0
  56. package/dist/generate/settings.d.ts +35 -0
  57. package/dist/generate/settings.js +213 -0
  58. package/dist/generate/settings.js.map +1 -0
  59. package/dist/generate/skills.d.ts +8 -0
  60. package/dist/generate/skills.js +264 -0
  61. package/dist/generate/skills.js.map +1 -0
  62. package/dist/init.d.ts +10 -0
  63. package/dist/init.js +69 -0
  64. package/dist/init.js.map +1 -0
  65. package/dist/trace.d.ts +9 -0
  66. package/dist/trace.js +106 -0
  67. package/dist/trace.js.map +1 -0
  68. package/node_modules/@dougharness/flow/.claude-plugin/plugin.json +10 -0
  69. package/node_modules/@dougharness/flow/LICENSE +21 -0
  70. package/node_modules/@dougharness/flow/agents/adversary-claude.md +33 -0
  71. package/node_modules/@dougharness/flow/agents/adversary.md +29 -0
  72. package/node_modules/@dougharness/flow/agents/implementer.md +23 -0
  73. package/node_modules/@dougharness/flow/agents/lead.md +35 -0
  74. package/node_modules/@dougharness/flow/agents/planner.md +70 -0
  75. package/node_modules/@dougharness/flow/agents/researcher.md +31 -0
  76. package/node_modules/@dougharness/flow/agents/reviewer.md +26 -0
  77. package/node_modules/@dougharness/flow/agents/verifier.md +24 -0
  78. package/node_modules/@dougharness/flow/lib/board.mjs +840 -0
  79. package/node_modules/@dougharness/flow/lib/code-index.mjs +629 -0
  80. package/node_modules/@dougharness/flow/lib/cost.mjs +392 -0
  81. package/node_modules/@dougharness/flow/lib/decisions.mjs +314 -0
  82. package/node_modules/@dougharness/flow/lib/embeddings.mjs +539 -0
  83. package/node_modules/@dougharness/flow/lib/land.mjs +219 -0
  84. package/node_modules/@dougharness/flow/lib/learn.mjs +742 -0
  85. package/node_modules/@dougharness/flow/lib/memory-import.mjs +145 -0
  86. package/node_modules/@dougharness/flow/lib/memory.mjs +1641 -0
  87. package/node_modules/@dougharness/flow/lib/models.mjs +148 -0
  88. package/node_modules/@dougharness/flow/lib/plan.mjs +773 -0
  89. package/node_modules/@dougharness/flow/lib/rehearse.mjs +825 -0
  90. package/node_modules/@dougharness/flow/lib/worktrees.mjs +215 -0
  91. package/node_modules/@dougharness/flow/package.json +19 -0
  92. package/node_modules/@dougharness/flow/scripts/board.mjs +260 -0
  93. package/node_modules/@dougharness/flow/scripts/cost.mjs +66 -0
  94. package/node_modules/@dougharness/flow/scripts/learn.mjs +161 -0
  95. package/node_modules/@dougharness/flow/scripts/memory.mjs +1274 -0
  96. package/node_modules/@dougharness/flow/scripts/plan.mjs +547 -0
  97. package/node_modules/@dougharness/flow/scripts/rehearse.mjs +129 -0
  98. package/node_modules/@dougharness/flow/skills/core-next/SKILL.md +92 -0
  99. package/node_modules/@dougharness/flow/skills/doug-approve/SKILL.md +15 -0
  100. package/node_modules/@dougharness/flow/skills/doug-decide/SKILL.md +26 -0
  101. package/node_modules/@dougharness/flow/skills/doug-implement/SKILL.md +22 -0
  102. package/node_modules/@dougharness/flow/skills/doug-learn/SKILL.md +20 -0
  103. package/node_modules/@dougharness/flow/skills/doug-next/SKILL.md +87 -0
  104. package/node_modules/@dougharness/flow/skills/doug-plan/SKILL.md +22 -0
  105. package/node_modules/@dougharness/flow/skills/doug-swarm/SKILL.md +55 -0
  106. package/node_modules/@dougharness/flow/skills/harness-fix/SKILL.md +85 -0
  107. package/node_modules/@dougharness/flow/skills/research/SKILL.md +41 -0
  108. package/node_modules/@dougharness/flow/skills/run-report/SKILL.md +51 -0
  109. package/node_modules/@dougharness/flow/skills/swarm-launch/SKILL.md +27 -0
  110. package/node_modules/@dougharness/flow/workflows/doug-implement.js +2687 -0
  111. package/node_modules/@dougharness/gates/.claude-plugin/plugin.json +10 -0
  112. package/node_modules/@dougharness/gates/LICENSE +21 -0
  113. package/node_modules/@dougharness/gates/hooks/hooks.json +184 -0
  114. package/node_modules/@dougharness/gates/lib/agent-context.mjs +111 -0
  115. package/node_modules/@dougharness/gates/lib/anchor.mjs +110 -0
  116. package/node_modules/@dougharness/gates/lib/baseline.mjs +160 -0
  117. package/node_modules/@dougharness/gates/lib/bash-rules.mjs +1522 -0
  118. package/node_modules/@dougharness/gates/lib/block-ledger.mjs +127 -0
  119. package/node_modules/@dougharness/gates/lib/checkpoint.mjs +97 -0
  120. package/node_modules/@dougharness/gates/lib/config.mjs +168 -0
  121. package/node_modules/@dougharness/gates/lib/evidence.mjs +59 -0
  122. package/node_modules/@dougharness/gates/lib/glob.mjs +86 -0
  123. package/node_modules/@dougharness/gates/lib/io.mjs +91 -0
  124. package/node_modules/@dougharness/gates/lib/paths.mjs +101 -0
  125. package/node_modules/@dougharness/gates/lib/proposals.mjs +201 -0
  126. package/node_modules/@dougharness/gates/lib/run.mjs +147 -0
  127. package/node_modules/@dougharness/gates/lib/scope.mjs +117 -0
  128. package/node_modules/@dougharness/gates/lib/secret-rules.mjs +268 -0
  129. package/node_modules/@dougharness/gates/lib/state.mjs +114 -0
  130. package/node_modules/@dougharness/gates/lib/trace.mjs +196 -0
  131. package/node_modules/@dougharness/gates/package.json +17 -0
  132. package/node_modules/@dougharness/gates/scripts/edit-loop.mjs +39 -0
  133. package/node_modules/@dougharness/gates/scripts/format-on-edit.mjs +45 -0
  134. package/node_modules/@dougharness/gates/scripts/guard-bash.mjs +32 -0
  135. package/node_modules/@dougharness/gates/scripts/protect-paths.mjs +49 -0
  136. package/node_modules/@dougharness/gates/scripts/reanchor.mjs +81 -0
  137. package/node_modules/@dougharness/gates/scripts/research-cap.mjs +295 -0
  138. package/node_modules/@dougharness/gates/scripts/secret-scan.mjs +26 -0
  139. package/node_modules/@dougharness/gates/scripts/session-start-baseline.mjs +57 -0
  140. package/node_modules/@dougharness/gates/scripts/statusline.mjs +133 -0
  141. package/node_modules/@dougharness/gates/scripts/stop-gate.mjs +1422 -0
  142. package/node_modules/@dougharness/gates/scripts/trace.mjs +75 -0
  143. package/package.json +33 -0
  144. package/templates/board-app.js +533 -0
@@ -0,0 +1,111 @@
1
+ // Generates a short CLAUDE.md: verbatim commands, tooling facts, and nothing derivable from the code.
2
+ // Research basis: agents reliably act on tooling instructions; overviews and style guides do not help
3
+ // and cost tokens (docs/reviews/07-tailored-install-research.md).
4
+ export function generateClaudeMd(d, cfg) {
5
+ const n = d.node;
6
+ const p = d.python;
7
+ const lines = [];
8
+ lines.push("# Project instructions");
9
+ lines.push("");
10
+ lines.push("Guardrails are enforced by hooks configured in `.doug/config.json`; this file carries only what hooks cannot.");
11
+ lines.push("");
12
+ const cmds = Object.entries(cfg.commands);
13
+ if (cmds.length) {
14
+ lines.push("## Commands");
15
+ lines.push("");
16
+ lines.push("```sh");
17
+ for (const [name, cmd] of cmds)
18
+ lines.push(`${cmd.padEnd(40)} # ${name}`);
19
+ if (n.singleTestCommand)
20
+ lines.push(`${n.singleTestCommand.padEnd(40)} # single test file`);
21
+ if (p.present && p.singleTestCommand)
22
+ lines.push(`${p.singleTestCommand.padEnd(40)} # single Python test file`);
23
+ lines.push("```");
24
+ lines.push("");
25
+ lines.push("Prefer running a single test file while iterating. Run the full gate before finishing.");
26
+ lines.push("");
27
+ }
28
+ const facts = [];
29
+ if (n.packageManager)
30
+ facts.push(`Package manager is **${n.packageManager}** (${n.packageManagerSource === "packageManager-field" ? "package.json packageManager field" : n.lockfile}). Do not use another one.`);
31
+ if (n.nodeVersion)
32
+ facts.push(`Node ${n.nodeVersion} from ${n.nodeVersionSource}.`);
33
+ if (n.formatter)
34
+ facts.push(`${n.formatter.name} formats files automatically after every edit. Do not hand-format.`);
35
+ if (n.linter)
36
+ facts.push(`Lint with ${n.linter}; the stop gate runs it.`);
37
+ if (n.typescript && n.tsStrict === false)
38
+ facts.push("TypeScript strict mode is off; do not enable it in passing.");
39
+ if (n.monorepo.length)
40
+ facts.push(`Monorepo (${n.monorepo.map((m) => m.tool).join(", ")}). Run scripts from the package you are changing.`);
41
+ if (d.repo.migrationDirs.length)
42
+ facts.push(`Migrations live in ${d.repo.migrationDirs.join(", ")} and are protected. Generate them with the project's migration tool.`);
43
+ if (d.repo.gitHooks.length)
44
+ facts.push(`Git hooks (${d.repo.gitHooks.join(", ")}) run on commit. Never bypass them with --no-verify.`);
45
+ if (d.repo.ci.length)
46
+ facts.push(`CI: ${d.repo.ci.join(", ")}. The stop gate mirrors its checks locally.`);
47
+ if (p.present) {
48
+ if (p.manager && p.managerSource)
49
+ facts.push(`Python package manager is **${p.manager}** (${p.managerSource}). Do not use another Python package manager.`);
50
+ if (p.pythonVersion && p.pythonVersionSource)
51
+ facts.push(`Python ${p.pythonVersion} from ${p.pythonVersionSource}.`);
52
+ if (p.runPrefix)
53
+ facts.push(`Run Python tools through \`${p.runPrefix}\`.`);
54
+ else if (p.venvDir && p.venvBinDir)
55
+ facts.push(`The project's virtualenv is \`${p.venvDir}\`; its executables are in \`${p.venvBinDir}\`.`);
56
+ if (p.linter === "ruff")
57
+ facts.push("ruff replaces black, isort and flake8 here; do not add them.");
58
+ else if (p.formatter?.name === "black")
59
+ facts.push("Formatting is checked with black.");
60
+ if (p.typeChecker === "mypy" && p.typeCheckerConfigFile)
61
+ facts.push(`Type-checked with mypy (${p.typeCheckerConfigFile}).`);
62
+ if (p.migrationDirs.length)
63
+ facts.push(`Python migrations live in ${p.migrationDirs.join(", ")} and are protected. Generate them with the project's migration tool.`);
64
+ }
65
+ if (facts.length) {
66
+ lines.push("## Tooling facts");
67
+ lines.push("");
68
+ for (const f of facts)
69
+ lines.push(`- ${f}`);
70
+ lines.push("");
71
+ }
72
+ lines.push("## Working agreement");
73
+ lines.push("");
74
+ lines.push("- Do what was asked. Do not refactor, rename, or add files beyond the request.");
75
+ lines.push("- Do not claim work is done until the gate passed in this session. Say what you ran.");
76
+ lines.push("- If a hook blocks an action, do not work around it. Report it.");
77
+ lines.push("- While `.doug/plan.json` is approved, change only files its tasks own. The stop gate blocks anything else; widen the plan and have it re-approved instead.");
78
+ lines.push("");
79
+ lines.push("## Gotchas");
80
+ lines.push("");
81
+ lines.push("<!-- Add project-specific pitfalls here, one line each. Keep this file under 60 lines. -->");
82
+ lines.push("");
83
+ lines.push(...MODELS_SECTION);
84
+ return lines.join("\n");
85
+ }
86
+ /**
87
+ * The Models table: which model and effort does which work when doug-flow runs a plan.
88
+ * Parsed deterministically by doug-flow's plan CLI (lib/models.mjs) and resolved into the plan
89
+ * before the workflow runs. "inherit" keeps the session model or the role's default effort.
90
+ */
91
+ export const MODELS_SECTION = [
92
+ "## Models",
93
+ "",
94
+ "Which model does which work when a Doug plan runs. `inherit` = the session model or the role's default effort.",
95
+ "Rows that are not roles are named tiers a task can pick with `\"tier\": \"<name>\"` in the plan.",
96
+ "",
97
+ "| Work | Model | Effort |",
98
+ "|-----------|---------|---------|",
99
+ "| plan | opus | high |",
100
+ "| lead | inherit | high |",
101
+ "| worker | sonnet | medium |",
102
+ "| implement | inherit | inherit |",
103
+ "| verify | inherit | high |",
104
+ "| review | inherit | high |",
105
+ "| adversary | inherit | low |",
106
+ "| integrate | inherit | high |",
107
+ "",
108
+ "The `plan` row is the planner's and the research step's researchers'. The `lead` and `worker` rows are the swarm's (a plan with `swarm` on: the lead splits a task into worker briefs and merges them). `implement`, `verify`, `review`, and `integrate` are the workflow's stages of that name. The `adversary` row runs the adversarial reviewer through `codex-review` (Codex, which must be on PATH), relayed unchanged by a Claude agent; when Codex cannot run, the workflow falls back to `adversary-claude` on the plan's `adversary.fallback` (default Opus, high). The session model is the lead only and never does implement, verify, or review work itself.",
109
+ "",
110
+ ];
111
+ //# sourceMappingURL=claude-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-md.js","sourceRoot":"","sources":["../../src/generate/claude-md.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { Detection } from "../detect/types.js";
2
+ export interface DougConfig {
3
+ version: 1;
4
+ doug: {
5
+ name: string;
6
+ version: string;
7
+ };
8
+ packageManager: string | null;
9
+ commands: Record<string, string>;
10
+ formatter: {
11
+ command: string[];
12
+ extensions: string[];
13
+ } | null;
14
+ protectedPaths: string[];
15
+ allowedOutsidePaths: string[];
16
+ bash: {
17
+ denyNoVerify: boolean;
18
+ denyForcePushTo: string[];
19
+ denyDestructive: boolean;
20
+ packageManagerGuard: boolean;
21
+ };
22
+ secrets: {
23
+ enabled: boolean;
24
+ ignorePaths: string[];
25
+ };
26
+ editLoop: {
27
+ threshold: number;
28
+ windowMinutes: number;
29
+ };
30
+ stopGate: {
31
+ commands: string[];
32
+ onlyIfEdited: boolean;
33
+ timeoutMs: number;
34
+ hookTimeoutSec: number;
35
+ maxBlocks: number;
36
+ ignoreChangedPaths: string[];
37
+ planScope: boolean;
38
+ };
39
+ checkpoint: {
40
+ enabled: boolean;
41
+ mode: "commit" | "tag";
42
+ };
43
+ budget: {
44
+ maxTurns: number | null;
45
+ };
46
+ anchor: string[];
47
+ subagents: {
48
+ maxSpawnDepth: number | null;
49
+ };
50
+ }
51
+ export declare function generateConfig(d: Detection): DougConfig;
@@ -0,0 +1,155 @@
1
+ import { createRequire } from "node:module";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { projectSlug } from "@dougharness/flow/lib/cost.mjs";
5
+ function cliVersion() {
6
+ try {
7
+ const require = createRequire(import.meta.url);
8
+ return require("../../package.json").version;
9
+ }
10
+ catch {
11
+ return "0.0.0";
12
+ }
13
+ }
14
+ export function generateConfig(d) {
15
+ const n = d.node;
16
+ const p = d.python;
17
+ const commands = {};
18
+ if (n.commands.install)
19
+ commands.install = n.commands.install;
20
+ for (const key of ["test", "test:unit", "lint", "typecheck", "build", "format"]) {
21
+ const c = n.commands[key];
22
+ if (c)
23
+ commands[key] = c.command;
24
+ }
25
+ // Snapshot of the Node-only command keys, taken before the Python merge below. The stop gate's Node
26
+ // ordering (computed further down) reads this snapshot, not `commands`, so a Python command landing on a
27
+ // plain key never perturbs the Node gate logic.
28
+ const nodeCommands = { ...commands };
29
+ // Project policy (python-config): a Python command takes the plain key when Node has none of that name;
30
+ // when both stacks have one, Node keeps the plain key and Python's arrives under a "py:" prefix. The plain
31
+ // "format" key always means the checking form (the stop gate runs it to fail on unformatted files, not to
32
+ // rewrite them), so it reads from d.python.commands.formatCheck, not .format.
33
+ if (p.present) {
34
+ const pyByKey = [
35
+ ["install", p.commands.install],
36
+ ["test", p.commands.test],
37
+ ["lint", p.commands.lint],
38
+ ["typecheck", p.commands.typecheck],
39
+ ["format", p.commands.formatCheck],
40
+ ];
41
+ for (const [key, value] of pyByKey) {
42
+ if (!value)
43
+ continue;
44
+ if (commands[key])
45
+ commands[`py:${key}`] = value;
46
+ else
47
+ commands[key] = value;
48
+ }
49
+ }
50
+ const protectedPaths = new Set([".env", ".env.*", ".git/**", "node_modules/**", ".doug/config.json"]);
51
+ if (n.lockfile)
52
+ protectedPaths.add(n.lockfile);
53
+ for (const m of d.repo.migrationDirs)
54
+ protectedPaths.add(`${m}/**`);
55
+ for (const g of d.repo.generatedDirs)
56
+ protectedPaths.add(`${g}/**`);
57
+ for (const path of d.repo.infraPaths)
58
+ protectedPaths.add(path);
59
+ if (p.present) {
60
+ if (p.lockfile)
61
+ protectedPaths.add(p.lockfile);
62
+ for (const m of p.migrationDirs)
63
+ protectedPaths.add(`${m}/**`);
64
+ for (const g of p.generatedDirs)
65
+ protectedPaths.add(`${g}/**`);
66
+ }
67
+ // The project's own Claude Code auto-memory directory is outside the project by construction (it lives under
68
+ // ~/.claude), so an honest Edit/Write there is refused by protect-paths.mjs unless it is allowlisted
69
+ // (docs/decisions/0006).
70
+ const autoMemoryDir = join(homedir(), ".claude", "projects", projectSlug(d.dir), "memory");
71
+ // Stop gate: cheapest reliable checks first. Build is excluded unless it is the only type check. The Node
72
+ // ordering below is computed from `nodeCommands` (the pre-Python snapshot), never from the merged
73
+ // `commands`, so a Python command that took over a plain key (no Node command of that name) cannot change
74
+ // which Node checks the gate runs or their order.
75
+ const gate = [];
76
+ if (nodeCommands.typecheck)
77
+ gate.push("typecheck");
78
+ if (nodeCommands.lint)
79
+ gate.push("lint");
80
+ if (nodeCommands["test:unit"])
81
+ gate.push("test:unit");
82
+ else if (nodeCommands.test)
83
+ gate.push("test");
84
+ if (!nodeCommands.typecheck && n.typescript && nodeCommands.build && /\btsc\b/.test(n.commands.build?.body || ""))
85
+ gate.unshift("build");
86
+ // Python keys appended after the Node ordering above, in typecheck/lint/test order: the plain key when
87
+ // Python owns it outright (no Node command of that name), otherwise the "py:"-prefixed key.
88
+ if (p.present) {
89
+ const pyGateSources = [
90
+ ["typecheck", p.commands.typecheck],
91
+ ["lint", p.commands.lint],
92
+ ["test", p.commands.test],
93
+ ];
94
+ for (const [name, value] of pyGateSources) {
95
+ if (!value)
96
+ continue;
97
+ gate.push(nodeCommands[name] ? `py:${name}` : name);
98
+ }
99
+ }
100
+ const branches = new Set(["main", "master"]);
101
+ if (d.repo.defaultBranch)
102
+ branches.add(d.repo.defaultBranch);
103
+ const anchor = [];
104
+ if (n.packageManager)
105
+ anchor.push(`Use ${n.packageManager} for installs and scripts. Never mix package managers.`);
106
+ if (n.singleTestCommand)
107
+ anchor.push(`Run a single test file with: ${n.singleTestCommand}`);
108
+ if (n.nodeVersion)
109
+ anchor.push(`Node ${n.nodeVersion} (${n.nodeVersionSource}).`);
110
+ // Combined rather than a separate near-duplicate sentence when both stacks have migration dirs.
111
+ const allMigrationDirs = [...new Set([...d.repo.migrationDirs, ...(p.present ? p.migrationDirs : [])])];
112
+ if (allMigrationDirs.length)
113
+ anchor.push(`Never hand-edit ${allMigrationDirs.join(", ")}; generate migrations with the project's tool.`);
114
+ if (p.present) {
115
+ if (p.manager && p.managerSource)
116
+ anchor.push(`Use ${p.manager} for Python installs and runs. Never mix Python package managers.`);
117
+ if (p.singleTestCommand)
118
+ anchor.push(`Run a single Python test file with: ${p.singleTestCommand}`);
119
+ if (p.pythonVersion && p.pythonVersionSource)
120
+ anchor.push(`Python ${p.pythonVersion} (${p.pythonVersionSource}).`);
121
+ }
122
+ return {
123
+ version: 1,
124
+ doug: { name: "Doug", version: cliVersion() },
125
+ packageManager: n.packageManager,
126
+ commands,
127
+ formatter: n.formatter ? { command: n.formatter.command, extensions: n.formatter.extensions } : null,
128
+ protectedPaths: [...protectedPaths],
129
+ allowedOutsidePaths: [autoMemoryDir],
130
+ bash: { denyNoVerify: true, denyForcePushTo: [...branches], denyDestructive: true, packageManagerGuard: !!n.packageManager },
131
+ secrets: { enabled: true, ignorePaths: [] },
132
+ editLoop: { threshold: 6, windowMinutes: 30 },
133
+ stopGate: {
134
+ commands: gate,
135
+ onlyIfEdited: true,
136
+ timeoutMs: 300000,
137
+ // Must equal the stop-gate hook's own `timeout` (plugins/doug-gates/hooks/hooks.json, seconds) on both
138
+ // Stop and SubagentStop, which `doug init` also copies into the generated settings.json (card
139
+ // stop-gate-budget-under-hook-timeout). Nothing else keeps the two in step.
140
+ hookTimeoutSec: 600,
141
+ maxBlocks: 3,
142
+ ignoreChangedPaths: [
143
+ ...(n.lockfile ? [n.lockfile] : []),
144
+ ...(p.present && p.lockfile ? [p.lockfile] : []),
145
+ ".doug/config.json",
146
+ ],
147
+ planScope: true,
148
+ },
149
+ checkpoint: { enabled: false, mode: "commit" },
150
+ budget: { maxTurns: null },
151
+ anchor,
152
+ subagents: { maxSpawnDepth: 1 },
153
+ };
154
+ }
155
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/generate/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Detection } from "../detect/types.js";
2
+ import type { FileChange } from "../diff.js";
3
+ import { type DougConfig } from "./config.js";
4
+ export interface Proposal {
5
+ detection: Detection;
6
+ config: DougConfig;
7
+ changes: FileChange[];
8
+ notes: string[];
9
+ }
10
+ export declare function buildProposal(d: Detection): Proposal;
11
+ export declare function summarize(p: Proposal): string;
@@ -0,0 +1,175 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import { join, relative } from "node:path";
3
+ import { generateConfig } from "./config.js";
4
+ import { generateClaudeMd } from "./claude-md.js";
5
+ import { mergeSettings, gatesSourceDir } from "./settings.js";
6
+ import { generateAgents, isDougAgent, spliceProjectNotes } from "./agents.js";
7
+ import { generateSkills, isDougSkill } from "./skills.js";
8
+ import { newBoard, BOARD_RELPATH, FALLBACK_RELPATH } from "@dougharness/flow/lib/board.mjs";
9
+ function readIfExists(path) {
10
+ try {
11
+ return readFileSync(path, "utf8");
12
+ }
13
+ catch (err) {
14
+ if (err?.code === "ENOENT")
15
+ return null;
16
+ throw err;
17
+ }
18
+ }
19
+ function walk(root, sub, out) {
20
+ for (const name of readdirSync(join(root, sub)).sort()) {
21
+ const rel = join(sub, name);
22
+ const abs = join(root, rel);
23
+ if (statSync(abs).isDirectory())
24
+ walk(root, rel, out);
25
+ else
26
+ out.push({ rel: rel.split("\\").join("/"), abs });
27
+ }
28
+ }
29
+ export function buildProposal(d) {
30
+ const dir = d.dir;
31
+ const notes = [...d.notes];
32
+ const config = generateConfig(d);
33
+ const changes = [];
34
+ // 1. .doug/config.json
35
+ changes.push({
36
+ path: ".doug/config.json",
37
+ before: readIfExists(join(dir, ".doug/config.json")),
38
+ after: JSON.stringify(config, null, 2) + "\n",
39
+ reason: "Gate configuration read by the hooks. Everything in it was detected, not guessed.",
40
+ });
41
+ // 1b. .doug/board.json: only when no board exists yet at either record path.
42
+ if (!existsSync(join(dir, BOARD_RELPATH)) && !existsSync(join(dir, FALLBACK_RELPATH))) {
43
+ changes.push({
44
+ path: ".doug/board.json",
45
+ before: null,
46
+ after: JSON.stringify(newBoard(), null, 2) + "\n",
47
+ reason: "The development board: the queue of scoped cards for the project's work. It starts empty with the default columns (add cards with `doug board add`); /doug-next reads it to pick the next card.",
48
+ });
49
+ }
50
+ // 2. Vendored hook scripts.
51
+ const src = gatesSourceDir();
52
+ const files = [];
53
+ walk(src, "scripts", files);
54
+ walk(src, "lib", files);
55
+ for (const f of files) {
56
+ const target = `.doug/hooks/${f.rel}`;
57
+ changes.push({ path: target, before: readIfExists(join(dir, target)), after: readFileSync(f.abs, "utf8"), reason: "Vendored from @dougharness/gates. Zero dependencies; refreshed by re-running `doug init`." });
58
+ }
59
+ // 3. .claude/settings.json (merge).
60
+ const settingsPath = join(dir, ".claude/settings.json");
61
+ const existingSettingsText = readIfExists(settingsPath);
62
+ let existingSettings = null;
63
+ if (existingSettingsText) {
64
+ try {
65
+ existingSettings = JSON.parse(existingSettingsText);
66
+ }
67
+ catch {
68
+ notes.push(".claude/settings.json exists but is not valid JSON; it will be left untouched. Fix it and rerun.");
69
+ }
70
+ }
71
+ if (!existingSettingsText || existingSettings) {
72
+ const merged = mergeSettings(existingSettings, d, config, src);
73
+ changes.push({ path: ".claude/settings.json", before: existingSettingsText, after: JSON.stringify(merged, null, 2) + "\n", reason: "Hooks wired to the vendored scripts, the status line pointed at the vendored script, plus an allowlist for the detected commands. Existing entries are kept." });
74
+ }
75
+ // 4. CLAUDE.md: create only if absent. Otherwise leave it and say so.
76
+ if (!d.repo.hasClaudeMd) {
77
+ changes.push({ path: "CLAUDE.md", before: null, after: generateClaudeMd(d, config), reason: "Short by design: commands, tooling facts, working agreement. Add gotchas by hand." });
78
+ }
79
+ else {
80
+ notes.push("CLAUDE.md already exists and is left untouched. Consider trimming it to commands, tooling facts, and gotchas.");
81
+ }
82
+ if (d.repo.existingAgentFiles.length) {
83
+ notes.push(`Existing agent config found (${d.repo.existingAgentFiles.join(", ")}). Not imported in this version; consider an @import from CLAUDE.md.`);
84
+ }
85
+ // 4b. .claude/agents/*.md: standard project subagents.
86
+ for (const file of generateAgents(d, config)) {
87
+ const target = join(dir, file.path);
88
+ const existing = readIfExists(target);
89
+ if (existing !== null && !isDougAgent(existing)) {
90
+ notes.push(`${file.path} exists and was not written by doug init; left untouched. Add \`doug: generated\` to the frontmatter to let doug init refresh it.`);
91
+ }
92
+ else {
93
+ const after = existing !== null ? spliceProjectNotes(file.content, existing) : file.content;
94
+ changes.push({
95
+ path: file.path,
96
+ before: existing,
97
+ after,
98
+ reason: `Project subagent for the ${file.path.replace(/^.*\//, "").replace(/\.md$/, "")} role; carries only detected commands. Remove \`doug: generated\` from the frontmatter to stop doug init from refreshing it; the \`## Project notes\` section is yours and survives a refresh.`,
99
+ });
100
+ }
101
+ }
102
+ // 4c. .claude/skills/*: generated project skills, same refresh rule as 4b's agents.
103
+ for (const file of generateSkills(d, config)) {
104
+ const target = join(dir, file.path);
105
+ const existing = readIfExists(target);
106
+ const isSkillMd = file.path.endsWith("SKILL.md");
107
+ if (existing !== null && !isDougSkill(existing)) {
108
+ const addWhat = isSkillMd
109
+ ? "Add `doug: generated` under `metadata:` in the frontmatter to let doug init refresh it."
110
+ : "Add the `# doug: generated` comment line to let doug init refresh it.";
111
+ notes.push(`${file.path} exists and was not written by doug init; left untouched. ${addWhat}`);
112
+ }
113
+ else {
114
+ const after = isSkillMd && existing !== null ? spliceProjectNotes(file.content, existing) : file.content;
115
+ const skillName = file.path.replace(/^\.claude\/skills\//, "").split("/")[0];
116
+ changes.push({
117
+ path: file.path,
118
+ before: existing,
119
+ after,
120
+ reason: `Project skill for ${skillName}; carries only detected commands. Remove \`doug: generated\` from the frontmatter to stop doug init from refreshing it; the \`## Project notes\` section is yours and survives a refresh.`,
121
+ });
122
+ }
123
+ }
124
+ // 5. .gitignore: state dir.
125
+ const gi = readIfExists(join(dir, ".gitignore"));
126
+ if (!gi || !/^\.doug\/\.state\/?$/m.test(gi)) {
127
+ changes.push({ path: ".gitignore", before: gi, after: (gi ? gi.replace(/\n?$/, "\n") : "") + ".doug/.state/\n", reason: "Per-session hook state is local." });
128
+ }
129
+ // Drop no-op changes.
130
+ const effective = changes.filter((c) => c.before !== c.after);
131
+ return { detection: d, config, changes: effective, notes };
132
+ }
133
+ const SKIPPED_SKILL_REASONS = [
134
+ ["run", "no dev, start, or serve script detected"],
135
+ ["test", "no test command detected"],
136
+ ["migrate", "no migration directory detected"],
137
+ ["release", "no release, publish, or version script detected"],
138
+ ["pr", "not a git repository"],
139
+ ["preflight", "no gate commands detected"],
140
+ ["characterization-test", "no test framework detected"],
141
+ ];
142
+ export function summarize(p) {
143
+ const d = p.detection;
144
+ const n = d.node;
145
+ const agentNames = generateAgents(d, p.config).map((f) => f.path.replace(/^.*\//, "").replace(/\.md$/, ""));
146
+ const skillNames = Array.from(new Set(generateSkills(d, p.config)
147
+ .filter((f) => f.path.endsWith("SKILL.md"))
148
+ .map((f) => f.path.replace(/^\.claude\/skills\//, "").replace(/\/SKILL\.md$/, ""))));
149
+ const rows = [
150
+ ["directory", relative(process.cwd(), d.dir) || "."],
151
+ ["package manager", n.packageManager ? `${n.packageManager} (${n.packageManagerSource})` : "none detected"],
152
+ ["test", n.commands.test?.command ?? "none"],
153
+ ["lint", n.commands.lint?.command ?? "none"],
154
+ ["typecheck", n.commands.typecheck?.command ?? "none"],
155
+ ["formatter", n.formatter ? n.formatter.name : "none"],
156
+ ["protected paths", p.config.protectedPaths.join(", ")],
157
+ ["stop gate", p.config.stopGate.commands.length ? p.config.stopGate.commands.join(" → ") : "none (no commands detected)"],
158
+ ["agents", agentNames.length ? agentNames.join(", ") : "none"],
159
+ ["skills", skillNames.join(", ")],
160
+ ];
161
+ if (d.python.present) {
162
+ const py = d.python;
163
+ rows.push(["python manager", py.manager ? `${py.manager} (${py.managerSource ?? "none detected"})` : "none detected"], ["python test", py.commands.test ?? "none"], ["python lint", py.commands.lint ?? "none"], ["python typecheck", py.commands.typecheck ?? "none"]);
164
+ }
165
+ const w = Math.max(...rows.map((r) => r[0].length));
166
+ const lines = rows.map(([k, v]) => ` ${k.padEnd(w)} ${v}`);
167
+ const generated = new Set(skillNames);
168
+ for (const [skill, reason] of SKIPPED_SKILL_REASONS) {
169
+ if (!generated.has(skill)) {
170
+ lines.push(` ${reason}: ${skill} skipped; run /doug-skills when one exists`);
171
+ }
172
+ }
173
+ return lines.join("\n");
174
+ }
175
+ //# sourceMappingURL=proposal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal.js","sourceRoot":"","sources":["../../src/generate/proposal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { Detection } from "../detect/types.js";
2
+ import type { DougConfig } from "./config.js";
3
+ export declare const HOOK_MARK = "\"$CLAUDE_PROJECT_DIR/.doug/hooks/scripts/";
4
+ export declare const STATUSLINE_COMMAND = "node .doug/hooks/scripts/statusline.mjs";
5
+ export declare const SUBAGENT_DEPTH_ENV = "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH";
6
+ type HookObject = {
7
+ type: "command";
8
+ command: string;
9
+ [key: string]: unknown;
10
+ };
11
+ type HookEntry = {
12
+ matcher?: string;
13
+ hooks: HookObject[];
14
+ [key: string]: unknown;
15
+ };
16
+ type Settings = {
17
+ hooks?: Record<string, HookEntry[]>;
18
+ statusLine?: {
19
+ type: string;
20
+ command?: string;
21
+ padding?: number;
22
+ };
23
+ permissions?: {
24
+ allow?: string[];
25
+ deny?: string[];
26
+ ask?: string[];
27
+ };
28
+ env?: Record<string, string>;
29
+ [k: string]: unknown;
30
+ };
31
+ export declare function gatesSourceDir(): string;
32
+ export declare function dougHooks(gatesDir?: string): Record<string, HookEntry[]>;
33
+ export declare function permissionAllow(d: Detection, cfg: DougConfig): string[];
34
+ export declare function mergeSettings(existing: Settings | null, d: Detection, cfg: DougConfig, gatesDir?: string): Settings;
35
+ export {};