@uzysjung/agent-harness 26.95.0 → 26.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.ko.md +1 -3
  2. package/README.md +4 -6
  3. package/dist/{chunk-DSWWKCW3.js → chunk-WKXYOTUV.js} +1 -21
  4. package/dist/{chunk-DSWWKCW3.js.map → chunk-WKXYOTUV.js.map} +1 -1
  5. package/dist/index.js +219 -216
  6. package/dist/index.js.map +1 -1
  7. package/dist/trust-tier-drift.js +1 -3
  8. package/dist/trust-tier-drift.js.map +1 -1
  9. package/package.json +1 -1
  10. package/templates/antigravity/AGENTS.md.template +4 -0
  11. package/templates/codex/AGENTS.md.template +4 -0
  12. package/templates/opencode/AGENTS.md.template +4 -0
  13. package/templates/skills/compaction-handoff/SKILL.md +264 -130
  14. package/templates/project-claude/_base.md +0 -23
  15. package/templates/project-claude/fragments/csr-fastapi/active-rules.md +0 -13
  16. package/templates/project-claude/fragments/csr-fastapi/agents.md +0 -5
  17. package/templates/project-claude/fragments/csr-fastapi/boundaries.md +0 -17
  18. package/templates/project-claude/fragments/csr-fastapi/commands.md +0 -5
  19. package/templates/project-claude/fragments/csr-fastapi/plugins.md +0 -2
  20. package/templates/project-claude/fragments/csr-fastapi/skills.md +0 -5
  21. package/templates/project-claude/fragments/csr-fastapi/stack.md +0 -6
  22. package/templates/project-claude/fragments/csr-fastapi/tagline.md +0 -1
  23. package/templates/project-claude/fragments/csr-fastify/active-rules.md +0 -13
  24. package/templates/project-claude/fragments/csr-fastify/agents.md +0 -5
  25. package/templates/project-claude/fragments/csr-fastify/boundaries.md +0 -17
  26. package/templates/project-claude/fragments/csr-fastify/commands.md +0 -5
  27. package/templates/project-claude/fragments/csr-fastify/plugins.md +0 -2
  28. package/templates/project-claude/fragments/csr-fastify/skills.md +0 -5
  29. package/templates/project-claude/fragments/csr-fastify/stack.md +0 -6
  30. package/templates/project-claude/fragments/csr-fastify/tagline.md +0 -1
  31. package/templates/project-claude/fragments/csr-supabase/active-rules.md +0 -12
  32. package/templates/project-claude/fragments/csr-supabase/agents.md +0 -5
  33. package/templates/project-claude/fragments/csr-supabase/boundaries.md +0 -18
  34. package/templates/project-claude/fragments/csr-supabase/commands.md +0 -5
  35. package/templates/project-claude/fragments/csr-supabase/plugins.md +0 -4
  36. package/templates/project-claude/fragments/csr-supabase/skills.md +0 -7
  37. package/templates/project-claude/fragments/csr-supabase/stack.md +0 -6
  38. package/templates/project-claude/fragments/csr-supabase/supabase-auth.md +0 -19
  39. package/templates/project-claude/fragments/csr-supabase/tagline.md +0 -1
  40. package/templates/project-claude/fragments/data/active-rules.md +0 -10
  41. package/templates/project-claude/fragments/data/agents.md +0 -6
  42. package/templates/project-claude/fragments/data/boundaries.md +0 -19
  43. package/templates/project-claude/fragments/data/commands.md +0 -5
  44. package/templates/project-claude/fragments/data/plugins.md +0 -2
  45. package/templates/project-claude/fragments/data/skills.md +0 -3
  46. package/templates/project-claude/fragments/data/stack.md +0 -7
  47. package/templates/project-claude/fragments/data/tagline.md +0 -1
  48. package/templates/project-claude/fragments/executive/active-rules.md +0 -6
  49. package/templates/project-claude/fragments/executive/agents.md +0 -6
  50. package/templates/project-claude/fragments/executive/boundaries.md +0 -16
  51. package/templates/project-claude/fragments/executive/commands.md +0 -10
  52. package/templates/project-claude/fragments/executive/plugins.md +0 -1
  53. package/templates/project-claude/fragments/executive/skills.md +0 -7
  54. package/templates/project-claude/fragments/executive/stack.md +0 -4
  55. package/templates/project-claude/fragments/executive/tagline.md +0 -1
  56. package/templates/project-claude/fragments/executive/workflow.md +0 -9
  57. package/templates/project-claude/fragments/growth-marketing/active-rules.md +0 -7
  58. package/templates/project-claude/fragments/growth-marketing/agents.md +0 -6
  59. package/templates/project-claude/fragments/growth-marketing/boundaries.md +0 -16
  60. package/templates/project-claude/fragments/growth-marketing/commands.md +0 -10
  61. package/templates/project-claude/fragments/growth-marketing/plugins.md +0 -9
  62. package/templates/project-claude/fragments/growth-marketing/skills.md +0 -8
  63. package/templates/project-claude/fragments/growth-marketing/stack.md +0 -7
  64. package/templates/project-claude/fragments/growth-marketing/tagline.md +0 -1
  65. package/templates/project-claude/fragments/growth-marketing/workflow.md +0 -10
  66. package/templates/project-claude/fragments/project-management/active-rules.md +0 -7
  67. package/templates/project-claude/fragments/project-management/agents.md +0 -6
  68. package/templates/project-claude/fragments/project-management/boundaries.md +0 -15
  69. package/templates/project-claude/fragments/project-management/commands.md +0 -9
  70. package/templates/project-claude/fragments/project-management/plugins.md +0 -6
  71. package/templates/project-claude/fragments/project-management/skills.md +0 -5
  72. package/templates/project-claude/fragments/project-management/stack.md +0 -4
  73. package/templates/project-claude/fragments/project-management/tagline.md +0 -1
  74. package/templates/project-claude/fragments/project-management/workflow.md +0 -11
  75. package/templates/project-claude/fragments/ssr-htmx/active-rules.md +0 -11
  76. package/templates/project-claude/fragments/ssr-htmx/agents.md +0 -5
  77. package/templates/project-claude/fragments/ssr-htmx/boundaries.md +0 -19
  78. package/templates/project-claude/fragments/ssr-htmx/commands.md +0 -5
  79. package/templates/project-claude/fragments/ssr-htmx/plugins.md +0 -2
  80. package/templates/project-claude/fragments/ssr-htmx/skills.md +0 -3
  81. package/templates/project-claude/fragments/ssr-htmx/stack.md +0 -6
  82. package/templates/project-claude/fragments/ssr-htmx/tagline.md +0 -1
  83. package/templates/project-claude/fragments/ssr-nextjs/active-rules.md +0 -12
  84. package/templates/project-claude/fragments/ssr-nextjs/agents.md +0 -5
  85. package/templates/project-claude/fragments/ssr-nextjs/boundaries.md +0 -19
  86. package/templates/project-claude/fragments/ssr-nextjs/commands.md +0 -5
  87. package/templates/project-claude/fragments/ssr-nextjs/plugins.md +0 -2
  88. package/templates/project-claude/fragments/ssr-nextjs/skills.md +0 -5
  89. package/templates/project-claude/fragments/ssr-nextjs/stack.md +0 -5
  90. package/templates/project-claude/fragments/ssr-nextjs/tagline.md +0 -1
  91. package/templates/project-claude/fragments/tooling/active-rules.md +0 -11
  92. package/templates/project-claude/fragments/tooling/agents.md +0 -5
  93. package/templates/project-claude/fragments/tooling/boundaries.md +0 -16
  94. package/templates/project-claude/fragments/tooling/commands.md +0 -3
  95. package/templates/project-claude/fragments/tooling/skills.md +0 -4
  96. package/templates/project-claude/fragments/tooling/stack.md +0 -5
  97. package/templates/project-claude/fragments/tooling/tagline.md +0 -1
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  hasUiTrack,
15
15
  init_esm_shims,
16
16
  isAssetSelected
17
- } from "./chunk-DSWWKCW3.js";
17
+ } from "./chunk-WKXYOTUV.js";
18
18
 
19
19
  // node_modules/sisteransi/src/index.js
20
20
  var require_src = __commonJS({
@@ -699,7 +699,7 @@ var cac = (name = "") => new CAC(name);
699
699
  // package.json
700
700
  var package_default = {
701
701
  name: "@uzysjung/agent-harness",
702
- version: "26.95.0",
702
+ version: "26.97.0",
703
703
  description: "Curate vetted AI-coding skills & plugins by your tech stack \u2014 install only what you need, across Claude Code, Codex, OpenCode & Antigravity",
704
704
  type: "module",
705
705
  publishConfig: {
@@ -928,13 +928,13 @@ function padDisplay(s, width) {
928
928
  init_esm_shims();
929
929
  import {
930
930
  chmodSync as chmodSync2,
931
- existsSync as existsSync12,
931
+ existsSync as existsSync11,
932
932
  mkdirSync as mkdirSync4,
933
933
  readdirSync as readdirSync3,
934
- readFileSync as readFileSync12,
934
+ readFileSync as readFileSync11,
935
935
  writeFileSync as writeFileSync9
936
936
  } from "fs";
937
- import { dirname as dirname4, join as join11, resolve } from "path";
937
+ import { basename as basename4, dirname as dirname4, join as join10, resolve } from "path";
938
938
 
939
939
  // src/antigravity/transform.ts
940
940
  init_esm_shims();
@@ -948,7 +948,7 @@ function renameSlashes(text) {
948
948
  }
949
949
  function renderAgentsMd(params) {
950
950
  const body = params.claudeMd.replace(/^#\s+.*\r?\n/, "").trim();
951
- const replaced = params.template.replaceAll("{PROJECT_NAME}", params.projectName).replaceAll("{PROJECT_RULES}", body);
951
+ const replaced = params.template.replaceAll("{PROJECT_NAME}", params.projectName).replaceAll("{PROJECT_RULES}", body).replaceAll("{PROJECT_CONTEXT}", params.projectContext);
952
952
  return renameSlashes(replaced);
953
953
  }
954
954
 
@@ -1048,6 +1048,98 @@ function ensureProjectSkeleton(projectDir) {
1048
1048
  }
1049
1049
  }
1050
1050
 
1051
+ // src/project-claude-merge.ts
1052
+ init_esm_shims();
1053
+ var TRACK_DISPLAY_NAMES = {
1054
+ tooling: "Tooling",
1055
+ "csr-supabase": "CSR Supabase",
1056
+ "csr-fastify": "CSR Fastify",
1057
+ "csr-fastapi": "CSR FastAPI",
1058
+ "ssr-htmx": "SSR HTMX",
1059
+ "ssr-nextjs": "SSR Next.js",
1060
+ data: "Data",
1061
+ executive: "Executive",
1062
+ full: "Full",
1063
+ "project-management": "Project Management",
1064
+ "growth-marketing": "Growth Marketing"
1065
+ };
1066
+ var FULL_EXPANSION = TRACKS.filter((t) => t !== "full");
1067
+ var FILL_SECTIONS = [
1068
+ "identity",
1069
+ "stack",
1070
+ "architecture",
1071
+ "installed-assets",
1072
+ "boundaries",
1073
+ "verify"
1074
+ ];
1075
+ var FILL_SPECS = {
1076
+ identity: {
1077
+ title: "Identity & Purpose",
1078
+ prompt: `Replace the H1 title above with this project's real name, then state in 1-2 plain sentences what it does, who uses it, and why it exists. Sources: README.md, the package.json / pyproject.toml "description", docs/. Do NOT describe the harness itself. Delete this comment when done.`,
1079
+ placeholder: "what this project is, who it is for, and why it exists"
1080
+ },
1081
+ stack: {
1082
+ title: "Stack & Commands",
1083
+ prompt: "Replace the list below with this project's REAL stack. Inspect package.json / pyproject.toml / go.mod / Cargo.toml / Gemfile + lockfiles and any Makefile/justfile/package scripts. List the language(s)+versions, framework(s), package manager, and the exact install/build/test/run commands. Verify each command exists before writing it \u2014 never guess. Delete lines that do not apply, then delete this comment.",
1084
+ placeholder: "languages, runtimes, package manager, and the install/build/test/run commands"
1085
+ },
1086
+ architecture: {
1087
+ title: "Architecture & Layout",
1088
+ prompt: "Map this repository. List each top-level source directory and what it holds, the entry point(s), the 3-5 files a newcomer reads first, and how data/requests flow between the main layers. View the real tree (e.g. `git ls-files | sed 's#/.*##' | sort -u`) \u2014 do not assume a framework's conventional layout. Flag any generated/vendored directories that must never be hand-edited. If this is a single small module, say so in one line. Delete this comment when done.",
1089
+ placeholder: "where things live, the entry points, and how data flows between layers"
1090
+ },
1091
+ "installed-assets": {
1092
+ title: "Installed Harness Assets",
1093
+ prompt: "List the harness assets installed in this project (rules / skills / agents / commands) and add one line each on when to reach for it here. Verify against .claude/rules/*.md, .claude/skills/, .claude/agents/, .claude/commands/ (or this CLI's equivalent) and list ONLY assets whose file exists on disk \u2014 do not invent any. Do NOT restate the universal Rule 1-12 (they live in the rules layer) \u2014 cross-reference them instead. Delete this comment when done.",
1094
+ placeholder: "the installed rules/skills/agents/commands and when to use each"
1095
+ },
1096
+ boundaries: {
1097
+ title: "Boundaries \u2014 Always / Ask First / Never",
1098
+ prompt: `Fill the Always / Ask First / Never lists with this repo's real red lines. Read the CI config, CODEOWNERS, .gitignore, and release/deploy scripts. Never must include secrets, generated files, force-push, and direct commits to the default branch, plus any repo-specific "do not touch" directories. Every entry must be specific and enforceable here. Delete this comment when done.`,
1099
+ placeholder: "what to always do, ask before doing, and never do in this repo"
1100
+ },
1101
+ verify: {
1102
+ title: "Verification Gate",
1103
+ prompt: 'State the single command (or short sequence) that PROVES a change is safe here \u2014 the test/lint/typecheck/build gate you run before committing \u2014 plus the coverage/CI threshold and what "done" means. Sources: package scripts, CI workflow files, CONTRIBUTING. An agent must be able to self-verify without guessing. Delete this comment when done.',
1104
+ placeholder: "the single command that proves a change is safe, and the done bar"
1105
+ }
1106
+ };
1107
+ var SCAFFOLD_BANNER = [
1108
+ "> \u2699\uFE0F **SCAFFOLD \u2014 not filled in yet.** The sections below are a fill-in template for THIS project, not verified facts.",
1109
+ "> To fill: open this file and paste each `<!-- FILL: \u2026 -->` comment's instruction into your coding agent (e.g. Claude Code) \u2014 it will inspect the real repo and write the section. You can also fill them by hand; the comments are the instructions.",
1110
+ "> The universal harness rules (Rule 1\u201312) live in the separate rules layer. This file is **project-specific context only**."
1111
+ ].join("\n");
1112
+ function renderFillScaffold() {
1113
+ const blocks = FILL_SECTIONS.map((id) => {
1114
+ const spec = FILL_SPECS[id];
1115
+ return `## ${spec.title}
1116
+
1117
+ <!-- FILL:${id} \u2014 ${spec.prompt} -->
1118
+
1119
+ _(not filled yet \u2014 ${spec.placeholder})_`;
1120
+ });
1121
+ return `${SCAFFOLD_BANNER}
1122
+
1123
+ ${blocks.join("\n\n")}`;
1124
+ }
1125
+ function mergeProjectClaude(tracks, opts) {
1126
+ const expanded = expandTracks(tracks);
1127
+ const trackList = expanded.map((t) => TRACK_DISPLAY_NAMES[t]).join(", ");
1128
+ const header = `# ${opts.projectName}
1129
+
1130
+ > Active track(s): ${trackList}`;
1131
+ return `${header}
1132
+
1133
+ ${renderFillScaffold()}
1134
+ `;
1135
+ }
1136
+ function expandTracks(tracks) {
1137
+ if (tracks.includes("full")) {
1138
+ return FULL_EXPANSION;
1139
+ }
1140
+ return tracks;
1141
+ }
1142
+
1051
1143
  // src/antigravity/transform.ts
1052
1144
  function runAntigravityTransform(params) {
1053
1145
  const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;
@@ -1077,7 +1169,14 @@ function writeRules(harnessRoot, projectDir) {
1077
1169
  const rulesDir = join2(projectDir, ".agents", "rules");
1078
1170
  ensureDir(rulesDir);
1079
1171
  const target = join2(rulesDir, "uzys-harness.md");
1080
- writeFileSync(target, renderAgentsMd({ template, claudeMd, projectName: basename(projectDir) }));
1172
+ const rulesOut = renderAgentsMd({
1173
+ template,
1174
+ claudeMd,
1175
+ projectName: basename(projectDir),
1176
+ projectContext: renderFillScaffold()
1177
+ });
1178
+ backupFileIfChanged(target, rulesOut);
1179
+ writeFileSync(target, rulesOut);
1081
1180
  return target;
1082
1181
  }
1083
1182
 
@@ -1210,7 +1309,14 @@ function runCodexTransform(params) {
1210
1309
  const mcp = readOptionalJson(join4(harnessRoot, ".mcp.json"));
1211
1310
  const agentsMdPath = join4(projectDir, "AGENTS.md");
1212
1311
  ensureDir(projectDir);
1213
- writeFileSync3(agentsMdPath, renderAgentsMd({ template: agentsTemplate, claudeMd, projectName }));
1312
+ const agentsMdOut = renderAgentsMd({
1313
+ template: agentsTemplate,
1314
+ claudeMd,
1315
+ projectName,
1316
+ projectContext: renderFillScaffold()
1317
+ });
1318
+ backupFileIfChanged(agentsMdPath, agentsMdOut);
1319
+ writeFileSync3(agentsMdPath, agentsMdOut);
1214
1320
  const configTomlPath = join4(projectDir, ".codex/config.toml");
1215
1321
  ensureDir(join4(projectDir, ".codex"));
1216
1322
  writeFileSync3(
@@ -1999,7 +2105,7 @@ function renameSlashes2(text) {
1999
2105
  }
2000
2106
  function renderAgentsMd2(params) {
2001
2107
  const body = params.claudeMd.replace(/^#\s+.*\r?\n/, "").trim();
2002
- const replaced = params.template.replaceAll("{PROJECT_NAME}", params.projectName).replaceAll("{PROJECT_RULES}", body);
2108
+ const replaced = params.template.replaceAll("{PROJECT_NAME}", params.projectName).replaceAll("{PROJECT_RULES}", body).replaceAll("{PROJECT_CONTEXT}", params.projectContext);
2003
2109
  return renameSlashes2(replaced);
2004
2110
  }
2005
2111
 
@@ -2093,7 +2199,14 @@ function runOpencodeTransform(params) {
2093
2199
  const mcp = readOptionalJson2(join8(harnessRoot, ".mcp.json"));
2094
2200
  ensureDir(projectDir);
2095
2201
  const agentsMdPath = join8(projectDir, "AGENTS.md");
2096
- writeFileSync7(agentsMdPath, renderAgentsMd2({ template: agentsTemplate, claudeMd, projectName }));
2202
+ const agentsMdOut = renderAgentsMd2({
2203
+ template: agentsTemplate,
2204
+ claudeMd,
2205
+ projectName,
2206
+ projectContext: renderFillScaffold()
2207
+ });
2208
+ backupFileIfChanged(agentsMdPath, agentsMdOut);
2209
+ writeFileSync7(agentsMdPath, agentsMdOut);
2097
2210
  const opencodeJsonPath = join8(projectDir, "opencode.json");
2098
2211
  writeFileSync7(opencodeJsonPath, renderOpencodeJson({ template: opencodeTemplate, mcp }));
2099
2212
  const cmdDir = join8(projectDir, ".opencode/commands");
@@ -2127,134 +2240,6 @@ function readOptionalJson2(path) {
2127
2240
  }
2128
2241
  }
2129
2242
 
2130
- // src/project-claude-merge.ts
2131
- init_esm_shims();
2132
- import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
2133
- import { join as join9 } from "path";
2134
- var SECTIONS = [
2135
- "stack",
2136
- "workflow",
2137
- "active-rules",
2138
- "agents",
2139
- "skills",
2140
- "plugins",
2141
- "commands",
2142
- "boundaries",
2143
- "supabase-auth"
2144
- ];
2145
- var SECTION_TITLES = {
2146
- stack: "Stack",
2147
- workflow: "Workflow",
2148
- "active-rules": "Active Rules",
2149
- agents: "Agents",
2150
- skills: "Skills",
2151
- plugins: "Plugins",
2152
- commands: "Commands",
2153
- boundaries: "Boundaries",
2154
- "supabase-auth": "Supabase auth configuration"
2155
- };
2156
- var TRACK_DISPLAY_NAMES = {
2157
- tooling: "Tooling",
2158
- "csr-supabase": "CSR Supabase",
2159
- "csr-fastify": "CSR Fastify",
2160
- "csr-fastapi": "CSR FastAPI",
2161
- "ssr-htmx": "SSR HTMX",
2162
- "ssr-nextjs": "SSR Next.js",
2163
- data: "Data",
2164
- executive: "Executive",
2165
- full: "Full",
2166
- "project-management": "Project Management",
2167
- "growth-marketing": "Growth Marketing"
2168
- };
2169
- var FULL_EXPANSION = [
2170
- "tooling",
2171
- "csr-fastapi",
2172
- "csr-fastify",
2173
- "csr-supabase",
2174
- "ssr-htmx",
2175
- "ssr-nextjs",
2176
- "data",
2177
- "executive",
2178
- "project-management",
2179
- "growth-marketing"
2180
- ];
2181
- function mergeProjectClaude(tracks, opts) {
2182
- const expanded = expandTracks(tracks);
2183
- const baseRaw = readFileSync10(join9(opts.baseDir, "_base.md"), "utf8");
2184
- let output = baseRaw;
2185
- output = output.replace("<!-- INSERT: track-list -->", trackList(expanded));
2186
- output = output.replace("<!-- INSERT: tagline -->", taglineList(expanded, opts.baseDir));
2187
- for (const section of SECTIONS) {
2188
- const marker = `<!-- INSERT: ${section} -->`;
2189
- const block = renderSection(section, expanded, opts.baseDir);
2190
- if (block === null) {
2191
- output = stripMarkerLine(output, marker);
2192
- } else {
2193
- output = output.replace(marker, block);
2194
- }
2195
- }
2196
- return `${output.replace(/\n{3,}/g, "\n\n").trimEnd()}
2197
- `;
2198
- }
2199
- function expandTracks(tracks) {
2200
- if (tracks.includes("full")) {
2201
- return FULL_EXPANSION;
2202
- }
2203
- return tracks;
2204
- }
2205
- function trackList(tracks) {
2206
- return tracks.map((t) => TRACK_DISPLAY_NAMES[t]).join(", ");
2207
- }
2208
- function taglineList(tracks, baseDir) {
2209
- const taglines = [];
2210
- for (const t of tracks) {
2211
- const path = join9(baseDir, "fragments", t, "tagline.md");
2212
- if (!existsSync10(path)) {
2213
- continue;
2214
- }
2215
- const body = readFileSync10(path, "utf8").trim();
2216
- if (body) {
2217
- taglines.push(body);
2218
- }
2219
- }
2220
- return taglines.join(" / ");
2221
- }
2222
- function renderSection(section, tracks, baseDir) {
2223
- const present = [];
2224
- for (const t of tracks) {
2225
- const path = join9(baseDir, "fragments", t, `${section}.md`);
2226
- if (!existsSync10(path)) {
2227
- continue;
2228
- }
2229
- const body = readFileSync10(path, "utf8").trim();
2230
- if (body) {
2231
- present.push({ track: t, body });
2232
- }
2233
- }
2234
- if (present.length === 0) {
2235
- return null;
2236
- }
2237
- const title = `## ${SECTION_TITLES[section]}`;
2238
- if (present.length === 1 && present[0]) {
2239
- return `${title}
2240
-
2241
- ${present[0].body}
2242
- `;
2243
- }
2244
- const blocks = present.map(({ track, body }) => `### ${TRACK_DISPLAY_NAMES[track]}
2245
-
2246
- ${body}`);
2247
- return `${title}
2248
-
2249
- ${blocks.join("\n\n")}
2250
- `;
2251
- }
2252
- function stripMarkerLine(text, marker) {
2253
- const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2254
- const pattern = new RegExp(`\\n*${escaped}\\n*`);
2255
- return text.replace(pattern, "\n");
2256
- }
2257
-
2258
2243
  // src/settings-merge.ts
2259
2244
  init_esm_shims();
2260
2245
  function addPreToolUseHook(settings, matcher, command) {
@@ -2283,15 +2268,15 @@ function addPreToolUseHook(settings, matcher, command) {
2283
2268
  init_esm_shims();
2284
2269
  import {
2285
2270
  copyFileSync as copyFileSync2,
2286
- existsSync as existsSync11,
2271
+ existsSync as existsSync10,
2287
2272
  readdirSync as readdirSync2,
2288
- readFileSync as readFileSync11,
2273
+ readFileSync as readFileSync10,
2289
2274
  unlinkSync,
2290
2275
  writeFileSync as writeFileSync8
2291
2276
  } from "fs";
2292
- import { join as join10 } from "path";
2277
+ import { join as join9 } from "path";
2293
2278
  function runUpdateMode(projectDir, templatesDir) {
2294
- const claudeDir = join10(projectDir, ".claude");
2279
+ const claudeDir = join9(projectDir, ".claude");
2295
2280
  const report = {
2296
2281
  updated: {},
2297
2282
  pruned: {},
@@ -2300,26 +2285,26 @@ function runUpdateMode(projectDir, templatesDir) {
2300
2285
  };
2301
2286
  const targets = [
2302
2287
  {
2303
- target: join10(claudeDir, "rules"),
2304
- source: join10(templatesDir, "rules"),
2288
+ target: join9(claudeDir, "rules"),
2289
+ source: join9(templatesDir, "rules"),
2305
2290
  pattern: ".md",
2306
2291
  label: ".claude/rules"
2307
2292
  },
2308
2293
  {
2309
- target: join10(claudeDir, "agents"),
2310
- source: join10(templatesDir, "agents"),
2294
+ target: join9(claudeDir, "agents"),
2295
+ source: join9(templatesDir, "agents"),
2311
2296
  pattern: ".md",
2312
2297
  label: ".claude/agents"
2313
2298
  },
2314
2299
  {
2315
- target: join10(claudeDir, "commands/uzys"),
2316
- source: join10(templatesDir, "commands/uzys"),
2300
+ target: join9(claudeDir, "commands/uzys"),
2301
+ source: join9(templatesDir, "commands/uzys"),
2317
2302
  pattern: ".md",
2318
2303
  label: ".claude/commands/uzys"
2319
2304
  },
2320
2305
  {
2321
- target: join10(claudeDir, "hooks"),
2322
- source: join10(templatesDir, "hooks"),
2306
+ target: join9(claudeDir, "hooks"),
2307
+ source: join9(templatesDir, "hooks"),
2323
2308
  pattern: ".sh",
2324
2309
  label: ".claude/hooks"
2325
2310
  }
@@ -2328,26 +2313,26 @@ function runUpdateMode(projectDir, templatesDir) {
2328
2313
  report.updated[t.label] = updateDir(t.target, t.source, t.pattern);
2329
2314
  report.pruned[t.label] = pruneOrphans(t.target, t.source, t.pattern);
2330
2315
  }
2331
- const claudeMd = join10(claudeDir, "CLAUDE.md");
2332
- const templateMd = join10(templatesDir, "CLAUDE.md");
2333
- if (existsSync11(claudeMd) && existsSync11(templateMd)) {
2316
+ const claudeMd = join9(claudeDir, "CLAUDE.md");
2317
+ const templateMd = join9(templatesDir, "CLAUDE.md");
2318
+ if (existsSync10(claudeMd) && existsSync10(templateMd)) {
2334
2319
  copyFileSync2(templateMd, claudeMd);
2335
2320
  report.claudeMdUpdated = true;
2336
2321
  }
2337
- const settingsPath = join10(claudeDir, "settings.json");
2338
- if (existsSync11(settingsPath)) {
2339
- report.staleHookRefs = cleanStaleHookRefs(settingsPath, join10(claudeDir, "hooks"));
2322
+ const settingsPath = join9(claudeDir, "settings.json");
2323
+ if (existsSync10(settingsPath)) {
2324
+ report.staleHookRefs = cleanStaleHookRefs(settingsPath, join9(claudeDir, "hooks"));
2340
2325
  }
2341
2326
  return report;
2342
2327
  }
2343
2328
  function updateDir(target, source, ext) {
2344
- if (!existsSync11(target) || !existsSync11(source)) return 0;
2329
+ if (!existsSync10(target) || !existsSync10(source)) return 0;
2345
2330
  let count = 0;
2346
2331
  for (const file of readdirSync2(target)) {
2347
2332
  if (!file.endsWith(ext)) continue;
2348
- const targetFile = join10(target, file);
2349
- const sourceFile = join10(source, file);
2350
- if (existsSync11(sourceFile)) {
2333
+ const targetFile = join9(target, file);
2334
+ const sourceFile = join9(source, file);
2335
+ if (existsSync10(sourceFile)) {
2351
2336
  copyFileSync2(sourceFile, targetFile);
2352
2337
  count++;
2353
2338
  }
@@ -2355,13 +2340,13 @@ function updateDir(target, source, ext) {
2355
2340
  return count;
2356
2341
  }
2357
2342
  function pruneOrphans(target, source, ext) {
2358
- if (!existsSync11(target) || !existsSync11(source)) return [];
2343
+ if (!existsSync10(target) || !existsSync10(source)) return [];
2359
2344
  const removed = [];
2360
2345
  for (const file of readdirSync2(target)) {
2361
2346
  if (!file.endsWith(ext)) continue;
2362
- const sourceFile = join10(source, file);
2363
- if (!existsSync11(sourceFile)) {
2364
- const targetFile = join10(target, file);
2347
+ const sourceFile = join9(source, file);
2348
+ if (!existsSync10(sourceFile)) {
2349
+ const targetFile = join9(target, file);
2365
2350
  try {
2366
2351
  unlinkSync(targetFile);
2367
2352
  removed.push(file);
@@ -2374,7 +2359,7 @@ function pruneOrphans(target, source, ext) {
2374
2359
  function cleanStaleHookRefs(settingsPath, hooksDir) {
2375
2360
  let settings;
2376
2361
  try {
2377
- settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
2362
+ settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
2378
2363
  } catch {
2379
2364
  return [];
2380
2365
  }
@@ -2402,7 +2387,7 @@ function keepHookRef(hook, hooksDir, removed) {
2402
2387
  const refMatch = (hook?.command ?? "").match(/\/\.claude\/hooks\/([^"\s/]+\.sh)/);
2403
2388
  if (!refMatch?.[1]) return true;
2404
2389
  const fname = refMatch[1];
2405
- const exists = existsSync11(join10(hooksDir, fname));
2390
+ const exists = existsSync10(join9(hooksDir, fname));
2406
2391
  if (!exists && !removed.includes(fname)) removed.push(fname);
2407
2392
  return exists;
2408
2393
  }
@@ -2413,12 +2398,12 @@ var KARPATHY_ASSET_ID = "karpathy-coder";
2413
2398
  function runInstall(ctx) {
2414
2399
  const { harnessRoot, projectDir, spec } = ctx;
2415
2400
  const mode = ctx.mode ?? "fresh";
2416
- const templatesDir = join11(harnessRoot, "templates");
2417
- if (!existsSync12(templatesDir)) {
2401
+ const templatesDir = join10(harnessRoot, "templates");
2402
+ if (!existsSync11(templatesDir)) {
2418
2403
  throw new Error(`Templates dir not found: ${templatesDir}`);
2419
2404
  }
2420
- const claudeDir = join11(projectDir, ".claude");
2421
- if (mode === "update" && !existsSync12(claudeDir)) {
2405
+ const claudeDir = join10(projectDir, ".claude");
2406
+ if (mode === "update" && !existsSync11(claudeDir)) {
2422
2407
  throw new Error(`Update mode requires existing .claude/ at ${claudeDir}`);
2423
2408
  }
2424
2409
  const backupPath = resolveBackupPath(ctx, mode, claudeDir);
@@ -2426,7 +2411,7 @@ function runInstall(ctx) {
2426
2411
  return runUpdateInstall(ctx, templatesDir, backupPath);
2427
2412
  }
2428
2413
  const manifestSpec = buildManifestSpec(spec);
2429
- const base = spec.cli.includes("claude") ? installClaudeBaseline(manifestSpec, harnessRoot, projectDir, templatesDir) : emptyClaudeBaseline();
2414
+ const base = spec.cli.includes("claude") ? installClaudeBaseline(manifestSpec, projectDir, templatesDir) : emptyClaudeBaseline();
2430
2415
  const mcpResult = composeAndWriteMcp(harnessRoot, projectDir, spec);
2431
2416
  const baseline = {
2432
2417
  filesCopied: base.filesCopied,
@@ -2512,7 +2497,7 @@ function emptyClaudeBaseline() {
2512
2497
  backups: []
2513
2498
  };
2514
2499
  }
2515
- function installClaudeBaseline(manifestSpec, harnessRoot, projectDir, templatesDir) {
2500
+ function installClaudeBaseline(manifestSpec, projectDir, templatesDir) {
2516
2501
  ensureProjectSkeleton(projectDir);
2517
2502
  const result = emptyClaudeBaseline();
2518
2503
  const manifest = buildManifest(manifestSpec);
@@ -2520,15 +2505,15 @@ function installClaudeBaseline(manifestSpec, harnessRoot, projectDir, templatesD
2520
2505
  if (!entry.applies(manifestSpec)) {
2521
2506
  continue;
2522
2507
  }
2523
- const source = join11(templatesDir, entry.source);
2524
- const target = join11(projectDir, entry.target);
2525
- if (!existsSync12(source)) {
2508
+ const source = join10(templatesDir, entry.source);
2509
+ const target = join10(projectDir, entry.target);
2510
+ if (!existsSync11(source)) {
2526
2511
  result.skipped += 1;
2527
2512
  continue;
2528
2513
  }
2529
2514
  if (entry.type === "file") {
2530
2515
  if (entry.target === ".claude/settings.json") {
2531
- const backup = backupFileIfChanged(target, readFileSync12(source, "utf-8"));
2516
+ const backup = backupFileIfChanged(target, readFileSync11(source, "utf-8"));
2532
2517
  if (backup) {
2533
2518
  result.backups.push(backup);
2534
2519
  }
@@ -2541,12 +2526,12 @@ function installClaudeBaseline(manifestSpec, harnessRoot, projectDir, templatesD
2541
2526
  }
2542
2527
  accumulateCategory(result.categories, entry);
2543
2528
  }
2544
- const hookDir = join11(projectDir, ".claude/hooks");
2545
- if (existsSync12(hookDir)) {
2529
+ const hookDir = join10(projectDir, ".claude/hooks");
2530
+ if (existsSync11(hookDir)) {
2546
2531
  chmodHooksSync(hookDir);
2547
2532
  }
2548
2533
  writeInstalledTracks(projectDir, manifestSpec.tracks);
2549
- const rootClaudeMd = writeRootClaudeMd(harnessRoot, projectDir, manifestSpec.tracks);
2534
+ const rootClaudeMd = writeRootClaudeMd(projectDir, manifestSpec.tracks);
2550
2535
  result.rootClaudeMd = { tracks: manifestSpec.tracks };
2551
2536
  result.rootClaudeMdLog = { path: "CLAUDE.md", sha256: hashContent(rootClaudeMd.content) };
2552
2537
  if (rootClaudeMd.backup) {
@@ -2649,10 +2634,10 @@ function wireKarpathyHook(spec, external, harnessRoot, projectDir) {
2649
2634
  if (!karpathyResult?.ok) {
2650
2635
  return { wired: false, reason: "plugin-install-failed" };
2651
2636
  }
2652
- const sourceHook = join11(harnessRoot, "templates/hooks/karpathy-gate.sh");
2653
- const targetHook = join11(projectDir, ".claude/hooks/karpathy-gate.sh");
2637
+ const sourceHook = join10(harnessRoot, "templates/hooks/karpathy-gate.sh");
2638
+ const targetHook = join10(projectDir, ".claude/hooks/karpathy-gate.sh");
2654
2639
  let hookScriptCopied = false;
2655
- if (existsSync12(sourceHook)) {
2640
+ if (existsSync11(sourceHook)) {
2656
2641
  copyFile(sourceHook, targetHook);
2657
2642
  try {
2658
2643
  chmodSync2(targetHook, 493);
@@ -2660,10 +2645,10 @@ function wireKarpathyHook(spec, external, harnessRoot, projectDir) {
2660
2645
  }
2661
2646
  hookScriptCopied = true;
2662
2647
  }
2663
- const settingsPath = join11(projectDir, ".claude/settings.json");
2648
+ const settingsPath = join10(projectDir, ".claude/settings.json");
2664
2649
  let settingsUpdated = false;
2665
- if (existsSync12(settingsPath)) {
2666
- const raw = readFileSync12(settingsPath, "utf8");
2650
+ if (existsSync11(settingsPath)) {
2651
+ const raw = readFileSync11(settingsPath, "utf8");
2667
2652
  let before;
2668
2653
  try {
2669
2654
  before = JSON.parse(raw);
@@ -2682,10 +2667,10 @@ function wireKarpathyHook(spec, external, harnessRoot, projectDir) {
2682
2667
  return { wired: true, settingsUpdated, hookScriptCopied };
2683
2668
  }
2684
2669
  function composeAndWriteMcp(harnessRoot, projectDir, spec) {
2685
- const mcpPath = join11(projectDir, ".mcp.json");
2670
+ const mcpPath = join10(projectDir, ".mcp.json");
2686
2671
  const composed = composeMcpJson({
2687
- templateMcpPath: join11(harnessRoot, "templates/mcp.json"),
2688
- trackMapPath: join11(harnessRoot, "templates/track-mcp-map.tsv"),
2672
+ templateMcpPath: join10(harnessRoot, "templates/mcp.json"),
2673
+ trackMapPath: join10(harnessRoot, "templates/track-mcp-map.tsv"),
2689
2674
  existingPath: mcpPath,
2690
2675
  tracks: spec.tracks
2691
2676
  });
@@ -2711,16 +2696,15 @@ function accumulateCategory(cats, entry) {
2711
2696
  }
2712
2697
  }
2713
2698
  function writeInstalledTracks(projectDir, tracks) {
2714
- const path = join11(projectDir, ".claude/.installed-tracks");
2699
+ const path = join10(projectDir, ".claude/.installed-tracks");
2715
2700
  mkdirSync4(dirname4(path), { recursive: true });
2716
2701
  const sorted = [...new Set(tracks)].sort().join("\n");
2717
2702
  writeFileSync9(path, `${sorted}
2718
2703
  `);
2719
2704
  }
2720
- function writeRootClaudeMd(harnessRoot, projectDir, tracks) {
2721
- const baseDir = join11(harnessRoot, "templates/project-claude");
2722
- const content = mergeProjectClaude(tracks, { baseDir });
2723
- const target = join11(projectDir, "CLAUDE.md");
2705
+ function writeRootClaudeMd(projectDir, tracks) {
2706
+ const content = mergeProjectClaude(tracks, { projectName: basename4(projectDir) });
2707
+ const target = join10(projectDir, "CLAUDE.md");
2724
2708
  const backup = backupFileIfChanged(target, content);
2725
2709
  writeFileSync9(target, content);
2726
2710
  return { content, backup };
@@ -2956,8 +2940,27 @@ function renderFinalSummary(log, spec, report, fromWizard) {
2956
2940
  const primary = (spec.cli.includes("claude") ? "claude" : spec.cli[0]) ?? "claude";
2957
2941
  const label = CLI_SUMMARY_LABELS[primary];
2958
2942
  log(infoRow("NEXT", `Open ${c.bold(label)} \u2014 installed rules & skills are now active`));
2943
+ const scaffoldFiles = scaffoldFilesForCli(spec.cli);
2944
+ if (scaffoldFiles.length > 0) {
2945
+ log(
2946
+ infoRow(
2947
+ "FILL",
2948
+ `${scaffoldFiles.map((f) => c.bold(f)).join(" \xB7 ")} \u2014 a fill-in scaffold. Open and paste each ${c.bold("<!-- FILL: \u2026 -->")} prompt to your agent to tailor it to this project`
2949
+ )
2950
+ );
2951
+ }
2959
2952
  log("");
2960
2953
  }
2954
+ function scaffoldFilesForCli(cli2) {
2955
+ const files = [];
2956
+ if (cli2.includes("claude")) {
2957
+ files.push("CLAUDE.md");
2958
+ }
2959
+ if (cli2.some((target) => target !== "claude")) {
2960
+ files.push("AGENTS.md");
2961
+ }
2962
+ return files;
2963
+ }
2961
2964
  function formatAssetMeta(asset, version) {
2962
2965
  const m = asset.method;
2963
2966
  const v2 = version ? ` ${c.dim(`v${version.replace(/^v/, "")}`)}` : "";
@@ -3065,7 +3068,7 @@ function renderPhase1Rows(log, baseline, verbose = false, withEcc = false) {
3065
3068
  assetRow(
3066
3069
  "success",
3067
3070
  "CLAUDE.md (root)",
3068
- `merged from ${n} track${n > 1 ? "s" : ""}`,
3071
+ `fill-in scaffold \xB7 ${n} track${n > 1 ? "s" : ""} noted`,
3069
3072
  TEMPLATES_COL
3070
3073
  )
3071
3074
  );
@@ -3332,8 +3335,8 @@ function registerInstallCommand(cli2) {
3332
3335
  // src/commands/uninstall.ts
3333
3336
  init_esm_shims();
3334
3337
  import { spawnSync as spawnSync2 } from "child_process";
3335
- import { existsSync as existsSync13, readFileSync as readFileSync13, rmSync } from "fs";
3336
- import { join as join12, resolve as resolve3 } from "path";
3338
+ import { existsSync as existsSync12, readFileSync as readFileSync12, rmSync } from "fs";
3339
+ import { join as join11, resolve as resolve3 } from "path";
3337
3340
  function uninstallAction(options, deps = {}) {
3338
3341
  const log = deps.log ?? console.log;
3339
3342
  const err = deps.err ?? console.error;
@@ -3505,22 +3508,22 @@ function buildGlobalAdvisoryCmd(asset) {
3505
3508
  }
3506
3509
  }
3507
3510
  function removeTemplates(log, projectDir, rm) {
3508
- rm(join12(projectDir, log.templates.claudeDir));
3509
- if (log.templates.codexDir) rm(join12(projectDir, log.templates.codexDir));
3510
- if (log.templates.opencodeDir) rm(join12(projectDir, log.templates.opencodeDir));
3511
+ rm(join11(projectDir, log.templates.claudeDir));
3512
+ if (log.templates.codexDir) rm(join11(projectDir, log.templates.codexDir));
3513
+ if (log.templates.opencodeDir) rm(join11(projectDir, log.templates.opencodeDir));
3511
3514
  const rootMd = log.templates.rootClaudeMd;
3512
3515
  if (rootMd) {
3513
3516
  if (rootClaudeMdModified(log, projectDir)) return { rootClaudeMdKept: true };
3514
- rm(join12(projectDir, rootMd.path));
3517
+ rm(join11(projectDir, rootMd.path));
3515
3518
  }
3516
3519
  return { rootClaudeMdKept: false };
3517
3520
  }
3518
3521
  function rootClaudeMdModified(log, projectDir) {
3519
3522
  const rootMd = log.templates.rootClaudeMd;
3520
3523
  if (!rootMd) return false;
3521
- const path = join12(projectDir, rootMd.path);
3522
- if (!existsSync13(path)) return false;
3523
- return hashContent(readFileSync13(path, "utf8")) !== rootMd.sha256;
3524
+ const path = join11(projectDir, rootMd.path);
3525
+ if (!existsSync12(path)) return false;
3526
+ return hashContent(readFileSync12(path, "utf8")) !== rootMd.sha256;
3524
3527
  }
3525
3528
  function formatTemplateList(log) {
3526
3529
  const items = [log.templates.claudeDir];
@@ -3532,7 +3535,7 @@ function defaultSpawn2(cmd, args) {
3532
3535
  return spawnSync2(cmd, [...args], { encoding: "utf8", stdio: "pipe", timeout: 12e4 });
3533
3536
  }
3534
3537
  function defaultRm(path) {
3535
- if (existsSync13(path)) {
3538
+ if (existsSync12(path)) {
3536
3539
  rmSync(path, { recursive: true, force: true });
3537
3540
  }
3538
3541
  }
@@ -4563,9 +4566,9 @@ function summarizeState(state) {
4563
4566
  if (state.state === "new") {
4564
4567
  return "No prior install detected \u2014 new install flow.";
4565
4568
  }
4566
- const trackList2 = state.tracks.length > 0 ? state.tracks.join(", ") : "(no tracks resolved)";
4569
+ const trackList = state.tracks.length > 0 ? state.tracks.join(", ") : "(no tracks resolved)";
4567
4570
  const sourceLabel = state.source === "metafile" ? "via .claude/.installed-tracks" : state.source === "legacy" ? "via legacy rules/*.md heuristic" : "via no source";
4568
- return `Existing install detected ${sourceLabel}. Tracks: ${trackList2}.`;
4571
+ return `Existing install detected ${sourceLabel}. Tracks: ${trackList}.`;
4569
4572
  }
4570
4573
 
4571
4574
  // src/wizard-steps.ts
@@ -4808,8 +4811,8 @@ Proceed?`,
4808
4811
 
4809
4812
  // src/state.ts
4810
4813
  init_esm_shims();
4811
- import { existsSync as existsSync14, readFileSync as readFileSync14 } from "fs";
4812
- import { join as join13 } from "path";
4814
+ import { existsSync as existsSync13, readFileSync as readFileSync13 } from "fs";
4815
+ import { join as join12 } from "path";
4813
4816
  var META_FILE = ".claude/.installed-tracks";
4814
4817
  var LEGACY_SIGNATURES = [
4815
4818
  { rule: "htmx.md", track: "ssr-htmx" },
@@ -4819,13 +4822,13 @@ var LEGACY_SIGNATURES = [
4819
4822
  { rule: "cli-development.md", track: "tooling" }
4820
4823
  ];
4821
4824
  function detectInstallState(projectDir) {
4822
- const claudeDir = join13(projectDir, ".claude");
4823
- const hasClaudeDir = existsSync14(claudeDir);
4825
+ const claudeDir = join12(projectDir, ".claude");
4826
+ const hasClaudeDir = existsSync13(claudeDir);
4824
4827
  if (!hasClaudeDir) {
4825
4828
  return { state: "new", tracks: [], source: "none", hasClaudeDir: false };
4826
4829
  }
4827
- const metaPath = join13(projectDir, META_FILE);
4828
- if (existsSync14(metaPath)) {
4830
+ const metaPath = join12(projectDir, META_FILE);
4831
+ if (existsSync13(metaPath)) {
4829
4832
  const tracks2 = readMetafile(metaPath);
4830
4833
  return { state: "existing", tracks: tracks2, source: "metafile", hasClaudeDir: true };
4831
4834
  }
@@ -4833,7 +4836,7 @@ function detectInstallState(projectDir) {
4833
4836
  return { state: "existing", tracks, source: "legacy", hasClaudeDir: true };
4834
4837
  }
4835
4838
  function readMetafile(path) {
4836
- const raw = readFileSync14(path, "utf8");
4839
+ const raw = readFileSync13(path, "utf8");
4837
4840
  const seen = /* @__PURE__ */ new Set();
4838
4841
  for (const line of raw.split(/\s+/)) {
4839
4842
  const trimmed = line.trim();
@@ -4844,13 +4847,13 @@ function readMetafile(path) {
4844
4847
  return [...seen].sort();
4845
4848
  }
4846
4849
  function inferFromLegacySignatures(projectDir) {
4847
- const rulesDir = join13(projectDir, ".claude/rules");
4848
- if (!existsSync14(rulesDir)) {
4850
+ const rulesDir = join12(projectDir, ".claude/rules");
4851
+ if (!existsSync13(rulesDir)) {
4849
4852
  return [];
4850
4853
  }
4851
4854
  const found = /* @__PURE__ */ new Set();
4852
4855
  for (const sig of LEGACY_SIGNATURES) {
4853
- if (existsSync14(join13(rulesDir, sig.rule))) {
4856
+ if (existsSync13(join12(rulesDir, sig.rule))) {
4854
4857
  found.add(sig.track);
4855
4858
  }
4856
4859
  }