@harness-engineering/cli 1.13.1 → 1.14.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 (139) hide show
  1. package/dist/agents/skills/claude-code/harness-brainstorming/SKILL.md +39 -0
  2. package/dist/agents/skills/claude-code/harness-code-review/SKILL.md +44 -0
  3. package/dist/agents/skills/claude-code/harness-execution/SKILL.md +44 -0
  4. package/dist/agents/skills/claude-code/harness-planning/SKILL.md +39 -0
  5. package/dist/agents/skills/claude-code/harness-release-readiness/SKILL.md +3 -3
  6. package/dist/agents/skills/claude-code/harness-verification/SKILL.md +35 -0
  7. package/dist/agents/skills/claude-code/initialize-harness-project/SKILL.md +11 -3
  8. package/dist/agents/skills/gemini-cli/harness-brainstorming/SKILL.md +39 -0
  9. package/dist/agents/skills/gemini-cli/harness-code-review/SKILL.md +44 -0
  10. package/dist/agents/skills/gemini-cli/harness-execution/SKILL.md +44 -0
  11. package/dist/agents/skills/gemini-cli/harness-planning/SKILL.md +39 -0
  12. package/dist/agents/skills/gemini-cli/harness-release-readiness/SKILL.md +3 -3
  13. package/dist/agents/skills/gemini-cli/harness-verification/SKILL.md +35 -0
  14. package/dist/agents/skills/gemini-cli/initialize-harness-project/SKILL.md +11 -3
  15. package/dist/agents-md-YTYQDA3P.js +8 -0
  16. package/dist/{architecture-2R5Z4ZAF.js → architecture-JQZYM4US.js} +4 -4
  17. package/dist/bin/harness-mcp.js +14 -14
  18. package/dist/bin/harness.js +24 -24
  19. package/dist/{check-phase-gate-2OFZ7OWW.js → check-phase-gate-L3RADYWO.js} +4 -4
  20. package/dist/{chunk-QY4T6YAZ.js → chunk-3C2MLBPJ.js} +4 -4
  21. package/dist/{chunk-UAX4I5ZE.js → chunk-6KTUUFRN.js} +2 -2
  22. package/dist/{chunk-ND6PNADU.js → chunk-7IP4JIFL.js} +9 -9
  23. package/dist/{chunk-C2ERUR3L.js → chunk-7MJAPE3Z.js} +165 -49
  24. package/dist/{chunk-PQ5YK4AY.js → chunk-ABQHQ6I5.js} +1583 -1169
  25. package/dist/{chunk-QPEH2QPG.js → chunk-DBSOCI3G.js} +53 -54
  26. package/dist/{chunk-MHBMTPW7.js → chunk-ERS5EVUZ.js} +9 -0
  27. package/dist/{chunk-JSTQ3AWB.js → chunk-FIAPHX37.js} +1 -1
  28. package/dist/{chunk-IMFVFNJE.js → chunk-FTMXDOR6.js} +1 -1
  29. package/dist/{chunk-72GHBOL2.js → chunk-GZKSBLQL.js} +1 -1
  30. package/dist/{chunk-K6XAPGML.js → chunk-H7Y5CKTM.js} +1 -1
  31. package/dist/{chunk-4ZMOCPYO.js → chunk-NLVUVUGD.js} +1 -1
  32. package/dist/{chunk-Z77YQRQT.js → chunk-O5OJVPL6.js} +16 -5
  33. package/dist/{chunk-NKDM3FMH.js → chunk-OD3S2NHN.js} +1 -1
  34. package/dist/{chunk-65FRIL4D.js → chunk-OSXBPAMK.js} +1 -1
  35. package/dist/{chunk-DZS7CJKL.js → chunk-OXLLOSSR.js} +45 -47
  36. package/dist/{chunk-TS3XWPW5.js → chunk-RCWZBSK5.js} +1 -1
  37. package/dist/{chunk-NOPU4RZ4.js → chunk-S2FXOWOR.js} +3 -3
  38. package/dist/{chunk-VUCPTQ6G.js → chunk-SD3SQOZ2.js} +1 -1
  39. package/dist/{chunk-IM32EEDM.js → chunk-TPOTOBR7.js} +9 -9
  40. package/dist/{chunk-SSKDAOX5.js → chunk-XKECDXJS.js} +436 -340
  41. package/dist/{chunk-TKJZKICB.js → chunk-YPYGXRDR.js} +7 -7
  42. package/dist/{chunk-Q6AB7W5Z.js → chunk-YQ6KC6TE.js} +1 -1
  43. package/dist/{chunk-NERR4TAO.js → chunk-YZD2MRNQ.js} +972 -747
  44. package/dist/ci-workflow-EQZFVX3P.js +8 -0
  45. package/dist/{dist-HXHWB7SV.js → dist-B26DFXMP.js} +571 -478
  46. package/dist/{dist-L7LAAQAS.js → dist-DZ63LLUD.js} +1 -1
  47. package/dist/{dist-2B363XUH.js → dist-HWXF2C3R.js} +18 -2
  48. package/dist/{dist-D4RYGUZE.js → dist-USY2C5JL.js} +3 -1
  49. package/dist/{docs-FZOPM4GK.js → docs-7ECGYMAV.js} +4 -4
  50. package/dist/engine-EG4EH4IX.js +8 -0
  51. package/dist/{entropy-LVHJMFGH.js → entropy-5USWKLVS.js} +3 -3
  52. package/dist/{feedback-IHLVLMRD.js → feedback-UTBXZZHF.js} +1 -1
  53. package/dist/{generate-agent-definitions-64S3CLEZ.js → generate-agent-definitions-3PM5EU7V.js} +4 -4
  54. package/dist/{graph-loader-GJZ4FN4Y.js → graph-loader-2M2HXDQI.js} +1 -1
  55. package/dist/index.d.ts +148 -9
  56. package/dist/index.js +24 -24
  57. package/dist/loader-ZPALXIVR.js +10 -0
  58. package/dist/{mcp-JQUI7BVZ.js → mcp-362EZHF4.js} +14 -14
  59. package/dist/{performance-ZTVSUANN.js → performance-OQAFMJUD.js} +3 -3
  60. package/dist/{review-pipeline-76JHKGSV.js → review-pipeline-C4GCFVGP.js} +1 -1
  61. package/dist/runtime-7YLVK453.js +9 -0
  62. package/dist/{security-FWQZF2IZ.js → security-PZOX7AQS.js} +1 -1
  63. package/dist/templates/axum/Cargo.toml.hbs +8 -0
  64. package/dist/templates/axum/src/main.rs +12 -0
  65. package/dist/templates/axum/template.json +16 -0
  66. package/dist/templates/django/manage.py.hbs +19 -0
  67. package/dist/templates/django/requirements.txt.hbs +1 -0
  68. package/dist/templates/django/src/settings.py.hbs +44 -0
  69. package/dist/templates/django/src/urls.py +6 -0
  70. package/dist/templates/django/src/wsgi.py.hbs +9 -0
  71. package/dist/templates/django/template.json +21 -0
  72. package/dist/templates/express/package.json.hbs +15 -0
  73. package/dist/templates/express/src/app.ts +12 -0
  74. package/dist/templates/express/src/lib/.gitkeep +0 -0
  75. package/dist/templates/express/template.json +16 -0
  76. package/dist/templates/fastapi/requirements.txt.hbs +2 -0
  77. package/dist/templates/fastapi/src/main.py +8 -0
  78. package/dist/templates/fastapi/template.json +20 -0
  79. package/dist/templates/gin/go.mod.hbs +5 -0
  80. package/dist/templates/gin/main.go +15 -0
  81. package/dist/templates/gin/template.json +19 -0
  82. package/dist/templates/go-base/.golangci.yml +16 -0
  83. package/dist/templates/go-base/AGENTS.md.hbs +35 -0
  84. package/dist/templates/go-base/go.mod.hbs +3 -0
  85. package/dist/templates/go-base/harness.config.json.hbs +17 -0
  86. package/dist/templates/go-base/main.go +7 -0
  87. package/dist/templates/go-base/template.json +14 -0
  88. package/dist/templates/java-base/AGENTS.md.hbs +35 -0
  89. package/dist/templates/java-base/checkstyle.xml +20 -0
  90. package/dist/templates/java-base/harness.config.json.hbs +16 -0
  91. package/dist/templates/java-base/pom.xml.hbs +39 -0
  92. package/dist/templates/java-base/src/main/java/App.java.hbs +5 -0
  93. package/dist/templates/java-base/template.json +13 -0
  94. package/dist/templates/nestjs/nest-cli.json +5 -0
  95. package/dist/templates/nestjs/package.json.hbs +18 -0
  96. package/dist/templates/nestjs/src/app.module.ts +8 -0
  97. package/dist/templates/nestjs/src/lib/.gitkeep +0 -0
  98. package/dist/templates/nestjs/src/main.ts +11 -0
  99. package/dist/templates/nestjs/template.json +16 -0
  100. package/dist/templates/nextjs/template.json +15 -1
  101. package/dist/templates/python-base/.python-version +1 -0
  102. package/dist/templates/python-base/AGENTS.md.hbs +32 -0
  103. package/dist/templates/python-base/harness.config.json.hbs +16 -0
  104. package/dist/templates/python-base/pyproject.toml.hbs +18 -0
  105. package/dist/templates/python-base/ruff.toml +5 -0
  106. package/dist/templates/python-base/src/__init__.py +0 -0
  107. package/dist/templates/python-base/template.json +13 -0
  108. package/dist/templates/react-vite/index.html +12 -0
  109. package/dist/templates/react-vite/package.json.hbs +18 -0
  110. package/dist/templates/react-vite/src/App.tsx +7 -0
  111. package/dist/templates/react-vite/src/lib/.gitkeep +0 -0
  112. package/dist/templates/react-vite/src/main.tsx +9 -0
  113. package/dist/templates/react-vite/template.json +19 -0
  114. package/dist/templates/react-vite/vite.config.ts +6 -0
  115. package/dist/templates/rust-base/AGENTS.md.hbs +35 -0
  116. package/dist/templates/rust-base/Cargo.toml.hbs +6 -0
  117. package/dist/templates/rust-base/clippy.toml +2 -0
  118. package/dist/templates/rust-base/harness.config.json.hbs +17 -0
  119. package/dist/templates/rust-base/src/main.rs +3 -0
  120. package/dist/templates/rust-base/template.json +14 -0
  121. package/dist/templates/spring-boot/pom.xml.hbs +50 -0
  122. package/dist/templates/spring-boot/src/main/java/Application.java.hbs +19 -0
  123. package/dist/templates/spring-boot/template.json +15 -0
  124. package/dist/templates/vue/index.html +12 -0
  125. package/dist/templates/vue/package.json.hbs +16 -0
  126. package/dist/templates/vue/src/App.vue +7 -0
  127. package/dist/templates/vue/src/lib/.gitkeep +0 -0
  128. package/dist/templates/vue/src/main.ts +4 -0
  129. package/dist/templates/vue/template.json +19 -0
  130. package/dist/templates/vue/vite.config.ts +6 -0
  131. package/dist/{validate-GCHZJIL7.js → validate-FD3Z6VJD.js} +4 -4
  132. package/dist/validate-cross-check-WNJM6H2D.js +8 -0
  133. package/package.json +5 -5
  134. package/dist/agents-md-XU3BHE22.js +0 -8
  135. package/dist/ci-workflow-EHV65NQB.js +0 -8
  136. package/dist/engine-OL4T6NZS.js +0 -8
  137. package/dist/loader-DPYFB6R6.js +0 -10
  138. package/dist/runtime-X7U6SC7K.js +0 -9
  139. package/dist/validate-cross-check-STFHYMAZ.js +0 -8
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  detectEntropyDefinition,
3
3
  handleDetectEntropy
4
- } from "./chunk-DZS7CJKL.js";
4
+ } from "./chunk-OXLLOSSR.js";
5
5
  import {
6
6
  checkPerformanceDefinition,
7
7
  getCriticalPathsDefinition,
@@ -11,7 +11,7 @@ import {
11
11
  handleGetPerfBaselines,
12
12
  handleUpdatePerfBaselines,
13
13
  updatePerfBaselinesDefinition
14
- } from "./chunk-TKJZKICB.js";
14
+ } from "./chunk-YPYGXRDR.js";
15
15
  import {
16
16
  analyzeDiffDefinition,
17
17
  createSelfReviewDefinition,
@@ -19,15 +19,15 @@ import {
19
19
  handleCreateSelfReview,
20
20
  handleRequestPeerReview,
21
21
  requestPeerReviewDefinition
22
- } from "./chunk-IM32EEDM.js";
22
+ } from "./chunk-TPOTOBR7.js";
23
23
  import {
24
24
  handleRunSecurityScan,
25
25
  runSecurityScanDefinition
26
- } from "./chunk-65FRIL4D.js";
26
+ } from "./chunk-OSXBPAMK.js";
27
27
  import {
28
28
  handleRunCodeReview,
29
29
  runCodeReviewDefinition
30
- } from "./chunk-4ZMOCPYO.js";
30
+ } from "./chunk-NLVUVUGD.js";
31
31
  import {
32
32
  GENERATED_HEADER_CLAUDE,
33
33
  GENERATED_HEADER_GEMINI,
@@ -38,24 +38,24 @@ import {
38
38
  import {
39
39
  handleValidateProject,
40
40
  validateToolDefinition
41
- } from "./chunk-NOPU4RZ4.js";
41
+ } from "./chunk-S2FXOWOR.js";
42
42
  import {
43
43
  loadGraphStore
44
- } from "./chunk-IMFVFNJE.js";
44
+ } from "./chunk-FTMXDOR6.js";
45
45
  import {
46
46
  checkDependenciesDefinition,
47
47
  handleCheckDependencies
48
- } from "./chunk-QY4T6YAZ.js";
48
+ } from "./chunk-3C2MLBPJ.js";
49
49
  import {
50
50
  resolveProjectConfig
51
- } from "./chunk-K6XAPGML.js";
51
+ } from "./chunk-H7Y5CKTM.js";
52
52
  import {
53
53
  checkDocsDefinition,
54
54
  handleCheckDocs
55
- } from "./chunk-ND6PNADU.js";
55
+ } from "./chunk-7IP4JIFL.js";
56
56
  import {
57
57
  resolveConfig
58
- } from "./chunk-Z77YQRQT.js";
58
+ } from "./chunk-O5OJVPL6.js";
59
59
  import {
60
60
  resultToMcpResponse
61
61
  } from "./chunk-IDZNPTYD.js";
@@ -82,7 +82,7 @@ import {
82
82
  import {
83
83
  Err,
84
84
  Ok
85
- } from "./chunk-MHBMTPW7.js";
85
+ } from "./chunk-ERS5EVUZ.js";
86
86
 
87
87
  // src/mcp/server.ts
88
88
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -109,7 +109,7 @@ var generateLinterDefinition = {
109
109
  };
110
110
  async function handleGenerateLinter(input) {
111
111
  try {
112
- const { generate } = await import("./dist-L7LAAQAS.js");
112
+ const { generate } = await import("./dist-DZ63LLUD.js");
113
113
  const result = await generate({
114
114
  configPath: sanitizePath(input.configPath),
115
115
  ...input.outputDir !== void 0 && { outputDir: sanitizePath(input.outputDir) }
@@ -143,7 +143,7 @@ var validateLinterConfigDefinition = {
143
143
  };
144
144
  async function handleValidateLinterConfig(input) {
145
145
  try {
146
- const { validate } = await import("./dist-L7LAAQAS.js");
146
+ const { validate } = await import("./dist-DZ63LLUD.js");
147
147
  const result = await validate({ configPath: sanitizePath(input.configPath) });
148
148
  if ("success" in result && result.success) {
149
149
  return { content: [{ type: "text", text: JSON.stringify(result) }] };
@@ -163,7 +163,179 @@ async function handleValidateLinterConfig(input) {
163
163
  }
164
164
 
165
165
  // src/mcp/tools/init.ts
166
+ import * as path2 from "path";
167
+ import * as fs2 from "fs";
168
+
169
+ // src/templates/post-write.ts
170
+ import * as fs from "fs";
166
171
  import * as path from "path";
172
+
173
+ // src/templates/agents-append.ts
174
+ var FRAMEWORK_SECTIONS = {
175
+ nextjs: {
176
+ title: "Next.js Conventions",
177
+ content: [
178
+ "- Use the App Router (`src/app/`) for all routes",
179
+ '- Server Components by default; add `"use client"` only when needed',
180
+ "- Use `next/image` for images and `next/link` for navigation",
181
+ "- API routes go in `src/app/api/`",
182
+ "- Run `next dev` for development, `next build` for production"
183
+ ].join("\n")
184
+ },
185
+ "react-vite": {
186
+ title: "React + Vite Conventions",
187
+ content: [
188
+ "- Component files use `.tsx` extension in `src/`",
189
+ "- Use Vite for dev server and bundling (`npm run dev`)",
190
+ "- Prefer function components with hooks",
191
+ "- CSS modules or styled-components for styling",
192
+ "- Tests use Vitest (`npm test`)"
193
+ ].join("\n")
194
+ },
195
+ vue: {
196
+ title: "Vue Conventions",
197
+ content: [
198
+ "- Single File Components (`.vue`) in `src/`",
199
+ "- Use `<script setup>` with Composition API",
200
+ "- Vite for dev server and bundling (`npm run dev`)",
201
+ "- Vue Router for routing, Pinia for state management",
202
+ "- Tests use Vitest (`npm test`)"
203
+ ].join("\n")
204
+ },
205
+ express: {
206
+ title: "Express Conventions",
207
+ content: [
208
+ "- Entry point at `src/app.ts`",
209
+ "- Routes in `src/routes/`, middleware in `src/middleware/`",
210
+ "- Use `express.json()` for body parsing",
211
+ "- Error handling via centralized error middleware",
212
+ "- Tests use Vitest with supertest (`npm test`)"
213
+ ].join("\n")
214
+ },
215
+ nestjs: {
216
+ title: "NestJS Conventions",
217
+ content: [
218
+ "- Module-based architecture: each feature in its own module",
219
+ "- Use decorators (`@Controller`, `@Injectable`, `@Module`)",
220
+ "- Entry point at `src/main.ts`, root module at `src/app.module.ts`",
221
+ "- Use Nest CLI for generating components (`nest g`)",
222
+ "- Tests use Vitest (`npm test`)"
223
+ ].join("\n")
224
+ },
225
+ fastapi: {
226
+ title: "FastAPI Conventions",
227
+ content: [
228
+ "- Entry point at `src/main.py` with FastAPI app instance",
229
+ "- Use Pydantic models for request/response validation",
230
+ "- Async endpoints preferred; sync is acceptable for CPU-bound work",
231
+ "- Run with `uvicorn src.main:app --reload` for development",
232
+ "- Tests use pytest (`pytest`)"
233
+ ].join("\n")
234
+ },
235
+ django: {
236
+ title: "Django Conventions",
237
+ content: [
238
+ "- Settings at `src/settings.py`, URLs at `src/urls.py`",
239
+ "- Use `manage.py` for management commands",
240
+ "- Apps in `src/` directory; each app has models, views, urls",
241
+ "- Run with `python manage.py runserver` for development",
242
+ "- Tests use pytest with pytest-django (`pytest`)"
243
+ ].join("\n")
244
+ },
245
+ gin: {
246
+ title: "Gin Conventions",
247
+ content: [
248
+ "- Entry point at `main.go` with Gin router setup",
249
+ "- Group routes by feature using `router.Group()`",
250
+ "- Use middleware for logging, auth, error recovery",
251
+ "- Run with `go run main.go` for development",
252
+ "- Tests use `go test ./...`"
253
+ ].join("\n")
254
+ },
255
+ axum: {
256
+ title: "Axum Conventions",
257
+ content: [
258
+ "- Entry point at `src/main.rs` with Axum router",
259
+ "- Use extractors for request parsing (`Path`, `Query`, `Json`)",
260
+ "- Shared state via `Extension` or `State`",
261
+ "- Run with `cargo run` for development",
262
+ "- Tests use `cargo test`"
263
+ ].join("\n")
264
+ },
265
+ "spring-boot": {
266
+ title: "Spring Boot Conventions",
267
+ content: [
268
+ "- Entry point annotated with `@SpringBootApplication`",
269
+ "- Controllers in `controller/` package, services in `service/`",
270
+ "- Use constructor injection for dependencies",
271
+ "- Run with `mvn spring-boot:run` for development",
272
+ "- Tests use JUnit 5 with Spring Boot Test (`mvn test`)"
273
+ ].join("\n")
274
+ }
275
+ };
276
+ function buildFrameworkSection(framework) {
277
+ const entry = FRAMEWORK_SECTIONS[framework];
278
+ if (!entry) return "";
279
+ return `## ${entry.title}
280
+
281
+ <!-- framework: ${framework} -->
282
+ ${entry.content}
283
+ `;
284
+ }
285
+ function appendFrameworkSection(existingContent, framework, _language) {
286
+ if (!framework) return existingContent;
287
+ const startMarker = `<!-- harness:framework-conventions:${framework} -->`;
288
+ const endMarker = `<!-- /harness:framework-conventions:${framework} -->`;
289
+ if (existingContent.includes(startMarker)) return existingContent;
290
+ const section = buildFrameworkSection(framework);
291
+ if (!section) return existingContent;
292
+ const block = `
293
+ ${startMarker}
294
+ ${section}${endMarker}
295
+ `;
296
+ return existingContent.trimEnd() + "\n" + block;
297
+ }
298
+
299
+ // src/templates/post-write.ts
300
+ function persistToolingConfig(targetDir, resolveResult, framework) {
301
+ const configPath = path.join(targetDir, "harness.config.json");
302
+ if (!fs.existsSync(configPath)) return;
303
+ try {
304
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
305
+ const overlayMeta = resolveResult.overlayMetadata;
306
+ if (framework) {
307
+ config.template = config.template || {};
308
+ config.template.framework = framework;
309
+ }
310
+ if (overlayMeta?.tooling) {
311
+ config.tooling = { ...config.tooling, ...overlayMeta.tooling };
312
+ delete config.tooling.lockFile;
313
+ } else if (resolveResult.metadata.tooling && !config.tooling) {
314
+ config.tooling = { ...resolveResult.metadata.tooling };
315
+ delete config.tooling.lockFile;
316
+ }
317
+ if (config.template?.level === null || config.template?.level === void 0) {
318
+ delete config.template.level;
319
+ }
320
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
321
+ } catch {
322
+ }
323
+ }
324
+ function appendFrameworkAgents(targetDir, framework, language) {
325
+ if (!framework) return;
326
+ const agentsPath = path.join(targetDir, "AGENTS.md");
327
+ if (!fs.existsSync(agentsPath)) return;
328
+ try {
329
+ const existing = fs.readFileSync(agentsPath, "utf-8");
330
+ const updated = appendFrameworkSection(existing, framework, language);
331
+ if (updated !== existing) {
332
+ fs.writeFileSync(agentsPath, updated);
333
+ }
334
+ } catch {
335
+ }
336
+ }
337
+
338
+ // src/mcp/tools/init.ts
167
339
  var initProjectDefinition = {
168
340
  name: "init_project",
169
341
  description: "Scaffold a new harness engineering project from a template",
@@ -175,54 +347,109 @@ var initProjectDefinition = {
175
347
  level: {
176
348
  type: "string",
177
349
  enum: ["basic", "intermediate", "advanced"],
178
- description: "Adoption level"
350
+ description: "Adoption level (JS/TS only)"
179
351
  },
180
- framework: { type: "string", description: "Framework overlay (e.g., nextjs)" }
352
+ framework: { type: "string", description: "Framework overlay (e.g., nextjs, fastapi, gin)" },
353
+ language: {
354
+ type: "string",
355
+ enum: ["typescript", "python", "go", "rust", "java"],
356
+ description: "Target language"
357
+ }
181
358
  },
182
359
  required: ["path"]
183
360
  }
184
361
  };
362
+ function mcpText(text, isError = false) {
363
+ return { content: [{ type: "text", text }], isError };
364
+ }
365
+ function findFrameworkLanguage(engine, framework) {
366
+ const templates = engine.listTemplates();
367
+ if (!templates.ok || !templates.value) return void 0;
368
+ return templates.value.find((t) => t.framework === framework)?.language;
369
+ }
370
+ function tryDetectFramework(engine, safePath, input) {
371
+ if (input.framework || input.language || !fs2.existsSync(safePath)) return null;
372
+ const result = engine.detectFramework(safePath);
373
+ if (!result.ok || !result.value || result.value.length === 0) return null;
374
+ const candidates = result.value.map((c) => `${c.framework} (${c.language}, score: ${c.score})`).join(", ");
375
+ return mcpText(
376
+ `Detected frameworks: ${candidates}
377
+
378
+ Re-invoke with --framework <name> to scaffold, or specify --language for a bare scaffold.`
379
+ );
380
+ }
381
+ function checkFrameworkLanguageConflict(engine, input) {
382
+ if (!input.framework || !input.language) return null;
383
+ const fwLang = findFrameworkLanguage(engine, input.framework);
384
+ if (fwLang && fwLang !== input.language) {
385
+ return mcpText(
386
+ `Framework "${input.framework}" is a ${fwLang} framework, but language "${input.language}" was specified. Use language "${fwLang}" instead.`,
387
+ true
388
+ );
389
+ }
390
+ return null;
391
+ }
392
+ function inferLanguage(engine, input) {
393
+ if (input.language) return input.language;
394
+ if (!input.framework) return void 0;
395
+ return findFrameworkLanguage(engine, input.framework);
396
+ }
397
+ function scaffoldMcp(engine, safePath, i, language) {
398
+ const isNonJs = language && language !== "typescript";
399
+ const level = isNonJs ? void 0 : i.level ?? "basic";
400
+ const resolveResult = engine.resolveTemplate(level, i.framework, language);
401
+ if (!resolveResult.ok) return resultToMcpResponse(resolveResult);
402
+ const renderResult = engine.render(resolveResult.value, {
403
+ projectName: i.name ?? path2.basename(safePath),
404
+ level: level ?? "",
405
+ ...i.framework !== void 0 && { framework: i.framework },
406
+ ...language !== void 0 && { language }
407
+ });
408
+ if (!renderResult.ok) return resultToMcpResponse(renderResult);
409
+ const writeResult = engine.write(renderResult.value, safePath, {
410
+ overwrite: false,
411
+ ...language !== void 0 && { language }
412
+ });
413
+ if (writeResult.ok) {
414
+ persistToolingConfig(safePath, resolveResult.value, i.framework);
415
+ appendFrameworkAgents(safePath, i.framework, language);
416
+ }
417
+ if (writeResult.ok && writeResult.value.skippedConfigs.length > 0) {
418
+ const skippedMsg = writeResult.value.skippedConfigs.map((f) => ` - ${f}`).join("\n");
419
+ return mcpText(
420
+ `Files written: ${writeResult.value.written.join(", ")}
421
+
422
+ Skipped existing config files (add harness dependencies manually):
423
+ ${skippedMsg}`
424
+ );
425
+ }
426
+ return resultToMcpResponse(writeResult);
427
+ }
185
428
  async function handleInitProject(input) {
429
+ const i = input;
186
430
  try {
187
- const { TemplateEngine } = await import("./engine-OL4T6NZS.js");
188
- const templatesDir = resolveTemplatesDir();
189
- const engine = new TemplateEngine(templatesDir);
190
- const level = input.level ?? "basic";
191
- const resolveResult = engine.resolveTemplate(level, input.framework);
192
- if (!resolveResult.ok) return resultToMcpResponse(resolveResult);
193
- const safePath = sanitizePath(input.path);
194
- const renderResult = engine.render(resolveResult.value, {
195
- projectName: input.name ?? path.basename(safePath),
196
- level,
197
- ...input.framework !== void 0 && { framework: input.framework }
198
- });
199
- if (!renderResult.ok) return resultToMcpResponse(renderResult);
200
- const writeResult = engine.write(renderResult.value, safePath, {
201
- overwrite: false
202
- });
203
- return resultToMcpResponse(writeResult);
431
+ const { TemplateEngine } = await import("./engine-EG4EH4IX.js");
432
+ const engine = new TemplateEngine(resolveTemplatesDir());
433
+ const safePath = sanitizePath(i.path);
434
+ const detected = tryDetectFramework(engine, safePath, i);
435
+ if (detected) return detected;
436
+ const conflict = checkFrameworkLanguageConflict(engine, i);
437
+ if (conflict) return conflict;
438
+ return scaffoldMcp(engine, safePath, i, inferLanguage(engine, i));
204
439
  } catch (error) {
205
- return {
206
- content: [
207
- {
208
- type: "text",
209
- text: `Init failed: ${error instanceof Error ? error.message : String(error)}`
210
- }
211
- ],
212
- isError: true
213
- };
440
+ return mcpText(`Init failed: ${error instanceof Error ? error.message : String(error)}`, true);
214
441
  }
215
442
  }
216
443
 
217
444
  // src/mcp/tools/persona.ts
218
- import * as path2 from "path";
445
+ import * as path3 from "path";
219
446
  var listPersonasDefinition = {
220
447
  name: "list_personas",
221
448
  description: "List available agent personas",
222
449
  inputSchema: { type: "object", properties: {} }
223
450
  };
224
451
  async function handleListPersonas() {
225
- const { listPersonas } = await import("./loader-DPYFB6R6.js");
452
+ const { listPersonas } = await import("./loader-ZPALXIVR.js");
226
453
  const result = listPersonas(resolvePersonasDir());
227
454
  return resultToMcpResponse(result);
228
455
  }
@@ -246,12 +473,12 @@ async function handleGeneratePersonaArtifacts(input) {
246
473
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.name)) {
247
474
  return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.name}`)));
248
475
  }
249
- const { loadPersona } = await import("./loader-DPYFB6R6.js");
250
- const { generateRuntime } = await import("./runtime-X7U6SC7K.js");
251
- const { generateAgentsMd } = await import("./agents-md-XU3BHE22.js");
252
- const { generateCIWorkflow } = await import("./ci-workflow-EHV65NQB.js");
476
+ const { loadPersona } = await import("./loader-ZPALXIVR.js");
477
+ const { generateRuntime } = await import("./runtime-7YLVK453.js");
478
+ const { generateAgentsMd } = await import("./agents-md-YTYQDA3P.js");
479
+ const { generateCIWorkflow } = await import("./ci-workflow-EQZFVX3P.js");
253
480
  const personasDir = resolvePersonasDir();
254
- const filePath = path2.join(personasDir, `${input.name}.yaml`);
481
+ const filePath = path3.join(personasDir, `${input.name}.yaml`);
255
482
  if (!filePath.startsWith(personasDir)) {
256
483
  return resultToMcpResponse(Err(new Error(`Invalid persona path: ${input.name}`)));
257
484
  }
@@ -304,11 +531,11 @@ async function handleRunPersona(input) {
304
531
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.persona)) {
305
532
  return resultToMcpResponse(Err(new Error(`Invalid persona name: ${input.persona}`)));
306
533
  }
307
- const { loadPersona } = await import("./loader-DPYFB6R6.js");
534
+ const { loadPersona } = await import("./loader-ZPALXIVR.js");
308
535
  const { runPersona } = await import("./runner-VMYLHWOC.js");
309
536
  const { executeSkill } = await import("./skill-executor-XZLYZYAK.js");
310
537
  const personasDir = resolvePersonasDir();
311
- const filePath = path2.join(personasDir, `${input.persona}.yaml`);
538
+ const filePath = path3.join(personasDir, `${input.persona}.yaml`);
312
539
  if (!filePath.startsWith(personasDir)) {
313
540
  return resultToMcpResponse(Err(new Error(`Invalid persona path: ${input.persona}`)));
314
541
  }
@@ -470,8 +697,8 @@ async function handleRunAgentTask(input) {
470
697
  }
471
698
 
472
699
  // src/mcp/tools/skill.ts
473
- import * as fs3 from "fs";
474
- import * as path5 from "path";
700
+ import * as fs5 from "fs";
701
+ import * as path6 from "path";
475
702
 
476
703
  // src/skill/dispatcher.ts
477
704
  var TIER_1_SKILLS = /* @__PURE__ */ new Set([
@@ -546,26 +773,26 @@ function formatSuggestions(suggestions) {
546
773
  }
547
774
 
548
775
  // src/skill/index-builder.ts
549
- import fs from "fs";
550
- import path3 from "path";
776
+ import fs3 from "fs";
777
+ import path4 from "path";
551
778
  import crypto from "crypto";
552
779
  import { parse } from "yaml";
553
780
  function computeSkillsDirHash(skillsDirs) {
554
781
  const hash = crypto.createHash("sha256");
555
782
  for (const dir of skillsDirs) {
556
- if (!fs.existsSync(dir)) continue;
557
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
783
+ if (!fs3.existsSync(dir)) continue;
784
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
558
785
  if (!entry.isDirectory()) continue;
559
- const yamlPath = path3.join(dir, entry.name, "skill.yaml");
560
- if (!fs.existsSync(yamlPath)) continue;
561
- const stat = fs.statSync(yamlPath);
786
+ const yamlPath = path4.join(dir, entry.name, "skill.yaml");
787
+ if (!fs3.existsSync(yamlPath)) continue;
788
+ const stat = fs3.statSync(yamlPath);
562
789
  hash.update(`${yamlPath}:${stat.mtimeMs}`);
563
790
  }
564
791
  }
565
792
  return hash.digest("hex");
566
793
  }
567
794
  function parseSkillEntry(yamlPath, source, tierOverrides) {
568
- const raw = fs.readFileSync(yamlPath, "utf-8");
795
+ const raw = fs3.readFileSync(yamlPath, "utf-8");
569
796
  const parsed = parse(raw);
570
797
  const result = SkillMetadataSchema.safeParse(parsed);
571
798
  if (!result.success) return null;
@@ -584,12 +811,12 @@ function parseSkillEntry(yamlPath, source, tierOverrides) {
584
811
  };
585
812
  }
586
813
  function scanDirectory(dir, source, index, tierOverrides) {
587
- if (!fs.existsSync(dir)) return;
588
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
814
+ if (!fs3.existsSync(dir)) return;
815
+ for (const entry of fs3.readdirSync(dir, { withFileTypes: true })) {
589
816
  if (!entry.isDirectory()) continue;
590
817
  if (index.skills[entry.name]) continue;
591
- const yamlPath = path3.join(dir, entry.name, "skill.yaml");
592
- if (!fs.existsSync(yamlPath)) continue;
818
+ const yamlPath = path4.join(dir, entry.name, "skill.yaml");
819
+ if (!fs3.existsSync(yamlPath)) continue;
593
820
  try {
594
821
  const parsed = parseSkillEntry(yamlPath, source, tierOverrides);
595
822
  if (parsed) index.skills[entry.name] = parsed;
@@ -613,25 +840,25 @@ function buildIndex(platform, _projectRoot, tierOverrides) {
613
840
  return index;
614
841
  }
615
842
  function loadOrRebuildIndex(platform, projectRoot, tierOverrides) {
616
- const indexPath = path3.join(projectRoot, ".harness", "skills-index.json");
843
+ const indexPath = path4.join(projectRoot, ".harness", "skills-index.json");
617
844
  const skillsDirs = resolveAllSkillsDirs(platform);
618
845
  const currentHash = computeSkillsDirHash(skillsDirs);
619
- if (fs.existsSync(indexPath)) {
846
+ if (fs3.existsSync(indexPath)) {
620
847
  try {
621
- const existing = JSON.parse(fs.readFileSync(indexPath, "utf-8"));
848
+ const existing = JSON.parse(fs3.readFileSync(indexPath, "utf-8"));
622
849
  if (existing.hash === currentHash) return existing;
623
850
  } catch {
624
851
  }
625
852
  }
626
853
  const index = buildIndex(platform, projectRoot, tierOverrides);
627
- fs.mkdirSync(path3.dirname(indexPath), { recursive: true });
628
- fs.writeFileSync(indexPath, JSON.stringify(index, null, 2));
854
+ fs3.mkdirSync(path4.dirname(indexPath), { recursive: true });
855
+ fs3.writeFileSync(indexPath, JSON.stringify(index, null, 2));
629
856
  return index;
630
857
  }
631
858
 
632
859
  // src/skill/stack-profile.ts
633
- import fs2 from "fs";
634
- import path4 from "path";
860
+ import fs4 from "fs";
861
+ import path5 from "path";
635
862
  var SIGNAL_DOMAIN_MAP = {
636
863
  "prisma/schema.prisma": ["database"],
637
864
  "drizzle.config.ts": ["database"],
@@ -679,8 +906,8 @@ function generateStackProfile(projectRoot) {
679
906
  const signals = {};
680
907
  const domainSet = /* @__PURE__ */ new Set();
681
908
  for (const [pattern, domains] of Object.entries(SIGNAL_DOMAIN_MAP)) {
682
- const fullPath = path4.join(projectRoot, pattern);
683
- const exists = fs2.existsSync(fullPath);
909
+ const fullPath = path5.join(projectRoot, pattern);
910
+ const exists = fs4.existsSync(fullPath);
684
911
  signals[pattern] = exists;
685
912
  if (exists) {
686
913
  for (const domain of domains) domainSet.add(domain);
@@ -693,16 +920,16 @@ function generateStackProfile(projectRoot) {
693
920
  };
694
921
  }
695
922
  function loadOrGenerateProfile(projectRoot) {
696
- const profilePath = path4.join(projectRoot, ".harness", "stack-profile.json");
697
- if (fs2.existsSync(profilePath)) {
923
+ const profilePath = path5.join(projectRoot, ".harness", "stack-profile.json");
924
+ if (fs4.existsSync(profilePath)) {
698
925
  try {
699
- return JSON.parse(fs2.readFileSync(profilePath, "utf-8"));
926
+ return JSON.parse(fs4.readFileSync(profilePath, "utf-8"));
700
927
  } catch {
701
928
  }
702
929
  }
703
930
  const profile = generateStackProfile(projectRoot);
704
- fs2.mkdirSync(path4.dirname(profilePath), { recursive: true });
705
- fs2.writeFileSync(profilePath, JSON.stringify(profile, null, 2));
931
+ fs4.mkdirSync(path5.dirname(profilePath), { recursive: true });
932
+ fs4.writeFileSync(profilePath, JSON.stringify(profile, null, 2));
706
933
  return profile;
707
934
  }
708
935
 
@@ -731,23 +958,23 @@ async function handleRunSkill(input) {
731
958
  if (!/^[a-z0-9][a-z0-9._-]*$/i.test(input.skill)) {
732
959
  return resultToMcpResponse(Err(new Error(`Invalid skill name: ${input.skill}`)));
733
960
  }
734
- const skillDir = path5.join(skillsDir, input.skill);
961
+ const skillDir = path6.join(skillsDir, input.skill);
735
962
  if (!skillDir.startsWith(skillsDir)) {
736
963
  return resultToMcpResponse(Err(new Error(`Invalid skill path: ${input.skill}`)));
737
964
  }
738
- if (!fs3.existsSync(skillDir)) {
965
+ if (!fs5.existsSync(skillDir)) {
739
966
  return resultToMcpResponse(Err(new Error(`Skill not found: ${input.skill}`)));
740
967
  }
741
- const skillMdPath = path5.join(skillDir, "SKILL.md");
742
- if (!fs3.existsSync(skillMdPath)) {
968
+ const skillMdPath = path6.join(skillDir, "SKILL.md");
969
+ if (!fs5.existsSync(skillMdPath)) {
743
970
  return resultToMcpResponse(Err(new Error(`SKILL.md not found for skill: ${input.skill}`)));
744
971
  }
745
- let content = fs3.readFileSync(skillMdPath, "utf-8");
972
+ let content = fs5.readFileSync(skillMdPath, "utf-8");
746
973
  if (input.path) {
747
974
  const projectPath = sanitizePath(input.path);
748
- const stateFile = path5.join(projectPath, ".harness", "state.json");
749
- if (fs3.existsSync(stateFile)) {
750
- const stateContent = fs3.readFileSync(stateFile, "utf-8");
975
+ const stateFile = path6.join(projectPath, ".harness", "state.json");
976
+ if (fs5.existsSync(stateFile)) {
977
+ const stateContent = fs5.readFileSync(stateFile, "utf-8");
751
978
  content += `
752
979
 
753
980
  ---
@@ -826,22 +1053,22 @@ async function handleCreateSkill(input) {
826
1053
  }
827
1054
 
828
1055
  // src/mcp/resources/skills.ts
829
- import * as fs4 from "fs";
830
- import * as path6 from "path";
1056
+ import * as fs6 from "fs";
1057
+ import * as path7 from "path";
831
1058
  import * as yaml from "yaml";
832
1059
  async function getSkillsResource(projectRoot) {
833
- const skillsDir = path6.join(projectRoot, "agents", "skills", "claude-code");
1060
+ const skillsDir = path7.join(projectRoot, "agents", "skills", "claude-code");
834
1061
  const skills = [];
835
- if (!fs4.existsSync(skillsDir)) {
1062
+ if (!fs6.existsSync(skillsDir)) {
836
1063
  return JSON.stringify(skills, null, 2);
837
1064
  }
838
- const entries = fs4.readdirSync(skillsDir, { withFileTypes: true });
1065
+ const entries = fs6.readdirSync(skillsDir, { withFileTypes: true });
839
1066
  for (const entry of entries) {
840
1067
  if (!entry.isDirectory()) continue;
841
- const skillYamlPath = path6.join(skillsDir, entry.name, "skill.yaml");
842
- if (!fs4.existsSync(skillYamlPath)) continue;
1068
+ const skillYamlPath = path7.join(skillsDir, entry.name, "skill.yaml");
1069
+ if (!fs6.existsSync(skillYamlPath)) continue;
843
1070
  try {
844
- const content = fs4.readFileSync(skillYamlPath, "utf-8");
1071
+ const content = fs6.readFileSync(skillYamlPath, "utf-8");
845
1072
  const parsed = yaml.parse(content);
846
1073
  skills.push({
847
1074
  name: parsed.name,
@@ -857,14 +1084,14 @@ async function getSkillsResource(projectRoot) {
857
1084
  }
858
1085
 
859
1086
  // src/mcp/resources/rules.ts
860
- import * as fs5 from "fs";
861
- import * as path7 from "path";
1087
+ import * as fs7 from "fs";
1088
+ import * as path8 from "path";
862
1089
  async function getRulesResource(projectRoot) {
863
1090
  const rules = [];
864
- const configPath = path7.join(projectRoot, "harness.config.json");
865
- if (fs5.existsSync(configPath)) {
1091
+ const configPath = path8.join(projectRoot, "harness.config.json");
1092
+ if (fs7.existsSync(configPath)) {
866
1093
  try {
867
- const config = JSON.parse(fs5.readFileSync(configPath, "utf-8"));
1094
+ const config = JSON.parse(fs7.readFileSync(configPath, "utf-8"));
868
1095
  if (config.layers) {
869
1096
  rules.push({ type: "layer-enforcement", config: config.layers });
870
1097
  }
@@ -877,10 +1104,10 @@ async function getRulesResource(projectRoot) {
877
1104
  } catch {
878
1105
  }
879
1106
  }
880
- const linterPath = path7.join(projectRoot, ".harness", "linter.json");
881
- if (fs5.existsSync(linterPath)) {
1107
+ const linterPath = path8.join(projectRoot, ".harness", "linter.json");
1108
+ if (fs7.existsSync(linterPath)) {
882
1109
  try {
883
- const linterConfig = JSON.parse(fs5.readFileSync(linterPath, "utf-8"));
1110
+ const linterConfig = JSON.parse(fs7.readFileSync(linterPath, "utf-8"));
884
1111
  rules.push({ type: "linter", config: linterConfig });
885
1112
  } catch {
886
1113
  }
@@ -889,32 +1116,37 @@ async function getRulesResource(projectRoot) {
889
1116
  }
890
1117
 
891
1118
  // src/mcp/resources/project.ts
892
- import * as fs6 from "fs";
893
- import * as path8 from "path";
1119
+ import * as fs8 from "fs";
1120
+ import * as path9 from "path";
894
1121
  async function getProjectResource(projectRoot) {
895
- const agentsPath = path8.join(projectRoot, "AGENTS.md");
896
- if (fs6.existsSync(agentsPath)) {
897
- return fs6.readFileSync(agentsPath, "utf-8");
1122
+ const agentsPath = path9.join(projectRoot, "AGENTS.md");
1123
+ if (fs8.existsSync(agentsPath)) {
1124
+ return fs8.readFileSync(agentsPath, "utf-8");
898
1125
  }
899
1126
  return "# No AGENTS.md found";
900
1127
  }
901
1128
 
902
1129
  // src/mcp/resources/learnings.ts
903
- import * as fs7 from "fs";
904
- import * as path9 from "path";
1130
+ import * as fs9 from "fs";
1131
+ import * as path10 from "path";
905
1132
  async function getLearningsResource(projectRoot) {
906
1133
  const sections = [];
907
- const reviewPath = path9.join(projectRoot, ".harness", "review-learnings.md");
908
- if (fs7.existsSync(reviewPath)) {
909
- sections.push("## Review Learnings\n\n" + fs7.readFileSync(reviewPath, "utf-8"));
1134
+ const reviewPath = path10.join(projectRoot, ".harness", "review-learnings.md");
1135
+ if (fs9.existsSync(reviewPath)) {
1136
+ sections.push("## Review Learnings\n\n" + fs9.readFileSync(reviewPath, "utf-8"));
910
1137
  }
911
- const antiPath = path9.join(projectRoot, ".harness", "anti-patterns.md");
912
- if (fs7.existsSync(antiPath)) {
913
- sections.push("## Anti-Pattern Log\n\n" + fs7.readFileSync(antiPath, "utf-8"));
1138
+ const antiPath = path10.join(projectRoot, ".harness", "anti-patterns.md");
1139
+ if (fs9.existsSync(antiPath)) {
1140
+ sections.push("## Anti-Pattern Log\n\n" + fs9.readFileSync(antiPath, "utf-8"));
914
1141
  }
915
1142
  return sections.length > 0 ? sections.join("\n\n---\n\n") : "No learnings files found.";
916
1143
  }
917
1144
 
1145
+ // src/mcp/utils.ts
1146
+ function mcpError(text) {
1147
+ return { content: [{ type: "text", text }], isError: true };
1148
+ }
1149
+
918
1150
  // src/mcp/tools/state.ts
919
1151
  var manageStateDefinition = {
920
1152
  name: "manage_state",
@@ -933,7 +1165,12 @@ var manageStateDefinition = {
933
1165
  "reset",
934
1166
  "gate",
935
1167
  "save-handoff",
936
- "load-handoff"
1168
+ "load-handoff",
1169
+ "append_entry",
1170
+ "update_entry_status",
1171
+ "read_section",
1172
+ "read_sections",
1173
+ "archive_session"
937
1174
  ],
938
1175
  description: "Action to perform"
939
1176
  },
@@ -950,138 +1187,175 @@ var manageStateDefinition = {
950
1187
  session: {
951
1188
  type: "string",
952
1189
  description: "Session slug for session-scoped state (takes priority over stream when provided)"
1190
+ },
1191
+ section: {
1192
+ type: "string",
1193
+ enum: ["terminology", "decisions", "constraints", "risks", "openQuestions", "evidence"],
1194
+ description: "Session section name (terminology, decisions, constraints, risks, openQuestions, evidence)"
1195
+ },
1196
+ authorSkill: {
1197
+ type: "string",
1198
+ description: "Name of the skill authoring the entry (required for append_entry)"
1199
+ },
1200
+ content: {
1201
+ type: "string",
1202
+ description: "Entry content text (required for append_entry)"
1203
+ },
1204
+ entryId: {
1205
+ type: "string",
1206
+ description: "ID of the entry to update (required for update_entry_status)"
1207
+ },
1208
+ newStatus: {
1209
+ type: "string",
1210
+ enum: ["active", "resolved", "superseded"],
1211
+ description: "New status for the entry: active, resolved, or superseded (required for update_entry_status)"
953
1212
  }
954
1213
  },
955
1214
  required: ["path", "action"]
956
1215
  }
957
1216
  };
1217
+ async function handleShow(projectPath, input) {
1218
+ const { loadState } = await import("./dist-HWXF2C3R.js");
1219
+ return resultToMcpResponse(await loadState(projectPath, input.stream, input.session));
1220
+ }
1221
+ async function handleLearn(projectPath, input) {
1222
+ if (!input.learning) return mcpError("Error: learning is required for learn action");
1223
+ const { appendLearning } = await import("./dist-HWXF2C3R.js");
1224
+ const result = await appendLearning(
1225
+ projectPath,
1226
+ input.learning,
1227
+ input.skillName,
1228
+ input.outcome,
1229
+ input.stream,
1230
+ input.session
1231
+ );
1232
+ if (!result.ok) return resultToMcpResponse(result);
1233
+ return resultToMcpResponse(Ok({ recorded: true }));
1234
+ }
1235
+ async function handleFailure(projectPath, input) {
1236
+ if (!input.description) return mcpError("Error: description is required for failure action");
1237
+ if (!input.failureType) return mcpError("Error: failureType is required for failure action");
1238
+ const { appendFailure } = await import("./dist-HWXF2C3R.js");
1239
+ const result = await appendFailure(
1240
+ projectPath,
1241
+ input.description,
1242
+ input.skillName ?? "unknown",
1243
+ input.failureType,
1244
+ input.stream,
1245
+ input.session
1246
+ );
1247
+ if (!result.ok) return resultToMcpResponse(result);
1248
+ return resultToMcpResponse(Ok({ recorded: true }));
1249
+ }
1250
+ async function handleArchive(projectPath, input) {
1251
+ const { archiveFailures } = await import("./dist-HWXF2C3R.js");
1252
+ const result = await archiveFailures(projectPath, input.stream, input.session);
1253
+ if (!result.ok) return resultToMcpResponse(result);
1254
+ return resultToMcpResponse(Ok({ archived: true }));
1255
+ }
1256
+ async function handleReset(projectPath, input) {
1257
+ const { saveState, DEFAULT_STATE } = await import("./dist-HWXF2C3R.js");
1258
+ const result = await saveState(projectPath, { ...DEFAULT_STATE }, input.stream, input.session);
1259
+ if (!result.ok) return resultToMcpResponse(result);
1260
+ return resultToMcpResponse(Ok({ reset: true }));
1261
+ }
1262
+ async function handleGate(projectPath, _input) {
1263
+ const { runMechanicalGate } = await import("./dist-HWXF2C3R.js");
1264
+ return resultToMcpResponse(await runMechanicalGate(projectPath));
1265
+ }
1266
+ async function handleSaveHandoff(projectPath, input) {
1267
+ if (!input.handoff) return mcpError("Error: handoff is required for save-handoff action");
1268
+ const { saveHandoff } = await import("./dist-HWXF2C3R.js");
1269
+ const result = await saveHandoff(
1270
+ projectPath,
1271
+ input.handoff,
1272
+ input.stream,
1273
+ input.session
1274
+ );
1275
+ return resultToMcpResponse(result.ok ? Ok({ saved: true }) : result);
1276
+ }
1277
+ async function handleLoadHandoff(projectPath, input) {
1278
+ const { loadHandoff } = await import("./dist-HWXF2C3R.js");
1279
+ return resultToMcpResponse(await loadHandoff(projectPath, input.stream, input.session));
1280
+ }
1281
+ async function handleAppendEntry(projectPath, input) {
1282
+ if (!input.session) return mcpError("Error: session is required for append_entry action");
1283
+ if (!input.section) return mcpError("Error: section is required for append_entry action");
1284
+ if (!input.authorSkill) return mcpError("Error: authorSkill is required for append_entry action");
1285
+ if (!input.content) return mcpError("Error: content is required for append_entry action");
1286
+ const { appendSessionEntry } = await import("./dist-HWXF2C3R.js");
1287
+ const result = await appendSessionEntry(
1288
+ projectPath,
1289
+ input.session,
1290
+ input.section,
1291
+ input.authorSkill,
1292
+ input.content
1293
+ );
1294
+ return resultToMcpResponse(result);
1295
+ }
1296
+ async function handleUpdateEntryStatus(projectPath, input) {
1297
+ if (!input.session) return mcpError("Error: session is required for update_entry_status action");
1298
+ if (!input.section) return mcpError("Error: section is required for update_entry_status action");
1299
+ if (!input.entryId) return mcpError("Error: entryId is required for update_entry_status action");
1300
+ if (!input.newStatus)
1301
+ return mcpError("Error: newStatus is required for update_entry_status action");
1302
+ const { updateSessionEntryStatus } = await import("./dist-HWXF2C3R.js");
1303
+ const result = await updateSessionEntryStatus(
1304
+ projectPath,
1305
+ input.session,
1306
+ input.section,
1307
+ input.entryId,
1308
+ input.newStatus
1309
+ );
1310
+ return resultToMcpResponse(result);
1311
+ }
1312
+ async function handleReadSection(projectPath, input) {
1313
+ if (!input.session) return mcpError("Error: session is required for read_section action");
1314
+ if (!input.section) return mcpError("Error: section is required for read_section action");
1315
+ const { readSessionSection } = await import("./dist-HWXF2C3R.js");
1316
+ const result = await readSessionSection(
1317
+ projectPath,
1318
+ input.session,
1319
+ input.section
1320
+ );
1321
+ return resultToMcpResponse(result);
1322
+ }
1323
+ async function handleReadSections(projectPath, input) {
1324
+ if (!input.session) return mcpError("Error: session is required for read_sections action");
1325
+ const { readSessionSections } = await import("./dist-HWXF2C3R.js");
1326
+ const result = await readSessionSections(projectPath, input.session);
1327
+ return resultToMcpResponse(result);
1328
+ }
1329
+ async function handleArchiveSession(projectPath, input) {
1330
+ if (!input.session) return mcpError("Error: session is required for archive_session action");
1331
+ const { archiveSession } = await import("./dist-HWXF2C3R.js");
1332
+ const result = await archiveSession(projectPath, input.session);
1333
+ if (!result.ok) return resultToMcpResponse(result);
1334
+ return resultToMcpResponse(Ok({ archived: true }));
1335
+ }
1336
+ var ACTION_HANDLERS = {
1337
+ show: handleShow,
1338
+ learn: handleLearn,
1339
+ failure: handleFailure,
1340
+ archive: handleArchive,
1341
+ reset: handleReset,
1342
+ gate: handleGate,
1343
+ "save-handoff": handleSaveHandoff,
1344
+ "load-handoff": handleLoadHandoff,
1345
+ append_entry: handleAppendEntry,
1346
+ update_entry_status: handleUpdateEntryStatus,
1347
+ read_section: handleReadSection,
1348
+ read_sections: handleReadSections,
1349
+ archive_session: handleArchiveSession
1350
+ };
958
1351
  async function handleManageState(input) {
959
1352
  try {
960
- const {
961
- loadState,
962
- saveState,
963
- appendLearning,
964
- appendFailure,
965
- archiveFailures,
966
- runMechanicalGate,
967
- DEFAULT_STATE
968
- } = await import("./dist-2B363XUH.js");
969
1353
  const projectPath = sanitizePath(input.path);
970
- switch (input.action) {
971
- case "show": {
972
- const result = await loadState(projectPath, input.stream, input.session);
973
- return resultToMcpResponse(result);
974
- }
975
- case "learn": {
976
- if (!input.learning) {
977
- return {
978
- content: [
979
- { type: "text", text: "Error: learning is required for learn action" }
980
- ],
981
- isError: true
982
- };
983
- }
984
- const result = await appendLearning(
985
- projectPath,
986
- input.learning,
987
- input.skillName,
988
- input.outcome,
989
- input.stream,
990
- input.session
991
- );
992
- if (!result.ok) return resultToMcpResponse(result);
993
- return resultToMcpResponse(Ok({ recorded: true }));
994
- }
995
- case "failure": {
996
- if (!input.description) {
997
- return {
998
- content: [
999
- { type: "text", text: "Error: description is required for failure action" }
1000
- ],
1001
- isError: true
1002
- };
1003
- }
1004
- if (!input.failureType) {
1005
- return {
1006
- content: [
1007
- {
1008
- type: "text",
1009
- text: "Error: failureType is required for failure action"
1010
- }
1011
- ],
1012
- isError: true
1013
- };
1014
- }
1015
- const result = await appendFailure(
1016
- projectPath,
1017
- input.description,
1018
- input.skillName ?? "unknown",
1019
- input.failureType,
1020
- input.stream,
1021
- input.session
1022
- );
1023
- if (!result.ok) return resultToMcpResponse(result);
1024
- return resultToMcpResponse(Ok({ recorded: true }));
1025
- }
1026
- case "archive": {
1027
- const result = await archiveFailures(projectPath, input.stream, input.session);
1028
- if (!result.ok) return resultToMcpResponse(result);
1029
- return resultToMcpResponse(Ok({ archived: true }));
1030
- }
1031
- case "reset": {
1032
- const result = await saveState(
1033
- projectPath,
1034
- { ...DEFAULT_STATE },
1035
- input.stream,
1036
- input.session
1037
- );
1038
- if (!result.ok) return resultToMcpResponse(result);
1039
- return resultToMcpResponse(Ok({ reset: true }));
1040
- }
1041
- case "gate": {
1042
- const result = await runMechanicalGate(projectPath);
1043
- return resultToMcpResponse(result);
1044
- }
1045
- case "save-handoff": {
1046
- if (!input.handoff) {
1047
- return {
1048
- content: [
1049
- { type: "text", text: "Error: handoff is required for save-handoff action" }
1050
- ],
1051
- isError: true
1052
- };
1053
- }
1054
- const { saveHandoff } = await import("./dist-2B363XUH.js");
1055
- const result = await saveHandoff(
1056
- projectPath,
1057
- input.handoff,
1058
- input.stream,
1059
- input.session
1060
- );
1061
- return resultToMcpResponse(result.ok ? Ok({ saved: true }) : result);
1062
- }
1063
- case "load-handoff": {
1064
- const { loadHandoff } = await import("./dist-2B363XUH.js");
1065
- const result = await loadHandoff(projectPath, input.stream, input.session);
1066
- return resultToMcpResponse(result);
1067
- }
1068
- default: {
1069
- return {
1070
- content: [{ type: "text", text: `Error: unknown action` }],
1071
- isError: true
1072
- };
1073
- }
1074
- }
1354
+ const handler = ACTION_HANDLERS[input.action];
1355
+ if (!handler) return mcpError("Error: unknown action");
1356
+ return await handler(projectPath, input);
1075
1357
  } catch (error) {
1076
- return {
1077
- content: [
1078
- {
1079
- type: "text",
1080
- text: `Error: ${error instanceof Error ? error.message : String(error)}`
1081
- }
1082
- ],
1083
- isError: true
1084
- };
1358
+ return mcpError(`Error: ${error instanceof Error ? error.message : String(error)}`);
1085
1359
  }
1086
1360
  }
1087
1361
  var listStreamsDefinition = {
@@ -1097,7 +1371,7 @@ var listStreamsDefinition = {
1097
1371
  };
1098
1372
  async function handleListStreams(input) {
1099
1373
  try {
1100
- const { listStreams, loadStreamIndex } = await import("./dist-2B363XUH.js");
1374
+ const { listStreams, loadStreamIndex } = await import("./dist-HWXF2C3R.js");
1101
1375
  const projectPath = sanitizePath(input.path);
1102
1376
  const indexResult = await loadStreamIndex(projectPath);
1103
1377
  const streamsResult = await listStreams(projectPath);
@@ -1135,7 +1409,7 @@ var checkPhaseGateDefinition = {
1135
1409
  };
1136
1410
  async function handleCheckPhaseGate(input) {
1137
1411
  try {
1138
- const { runCheckPhaseGate } = await import("./check-phase-gate-2OFZ7OWW.js");
1412
+ const { runCheckPhaseGate } = await import("./check-phase-gate-L3RADYWO.js");
1139
1413
  const result = await runCheckPhaseGate({ cwd: sanitizePath(input.path) });
1140
1414
  if (result.ok) {
1141
1415
  return { content: [{ type: "text", text: JSON.stringify(result.value) }] };
@@ -1155,7 +1429,7 @@ async function handleCheckPhaseGate(input) {
1155
1429
  }
1156
1430
 
1157
1431
  // src/mcp/tools/cross-check.ts
1158
- import * as path10 from "path";
1432
+ import * as path11 from "path";
1159
1433
  var validateCrossCheckDefinition = {
1160
1434
  name: "validate_cross_check",
1161
1435
  description: "Validate plan-to-implementation coverage: checks that specs have plans and plans have implementations, detects staleness",
@@ -1191,15 +1465,15 @@ async function handleValidateCrossCheck(input) {
1191
1465
  };
1192
1466
  }
1193
1467
  try {
1194
- const { runCrossCheck } = await import("./validate-cross-check-STFHYMAZ.js");
1195
- const specsDir = path10.resolve(projectPath, input.specsDir ?? "docs/specs");
1468
+ const { runCrossCheck } = await import("./validate-cross-check-WNJM6H2D.js");
1469
+ const specsDir = path11.resolve(projectPath, input.specsDir ?? "docs/specs");
1196
1470
  if (!specsDir.startsWith(projectPath)) {
1197
1471
  return {
1198
1472
  content: [{ type: "text", text: "Error: specsDir escapes project root" }],
1199
1473
  isError: true
1200
1474
  };
1201
1475
  }
1202
- const plansDir = path10.resolve(projectPath, input.plansDir ?? "docs/plans");
1476
+ const plansDir = path11.resolve(projectPath, input.plansDir ?? "docs/plans");
1203
1477
  if (!plansDir.startsWith(projectPath)) {
1204
1478
  return {
1205
1479
  content: [{ type: "text", text: "Error: plansDir escapes project root" }],
@@ -1230,14 +1504,14 @@ async function handleValidateCrossCheck(input) {
1230
1504
 
1231
1505
  // src/commands/generate-slash-commands.ts
1232
1506
  import { Command } from "commander";
1233
- import fs9 from "fs";
1234
- import path12 from "path";
1507
+ import fs11 from "fs";
1508
+ import path13 from "path";
1235
1509
  import os from "os";
1236
1510
  import readline from "readline";
1237
1511
 
1238
1512
  // src/slash-commands/normalize.ts
1239
- import fs8 from "fs";
1240
- import path11 from "path";
1513
+ import fs10 from "fs";
1514
+ import path12 from "path";
1241
1515
  import { parse as parse3 } from "yaml";
1242
1516
 
1243
1517
  // src/slash-commands/normalize-name.ts
@@ -1254,113 +1528,125 @@ function normalizeName(skillName) {
1254
1528
  }
1255
1529
 
1256
1530
  // src/slash-commands/normalize.ts
1531
+ function readSkillYaml(yamlPath) {
1532
+ let raw;
1533
+ try {
1534
+ raw = fs10.readFileSync(yamlPath, "utf-8");
1535
+ } catch {
1536
+ return null;
1537
+ }
1538
+ return SkillMetadataSchema.safeParse(parse3(raw));
1539
+ }
1540
+ function shouldSkipSkill(meta, platforms) {
1541
+ const matchesPlatform = platforms.some((p) => meta.platforms.includes(p));
1542
+ if (!matchesPlatform) return true;
1543
+ if (meta.tier === 3 || meta.internal) return true;
1544
+ return false;
1545
+ }
1546
+ function checkNameCollision(normalized, metaName, source, nameMap) {
1547
+ const existing = nameMap.get(normalized);
1548
+ if (!existing) {
1549
+ nameMap.set(normalized, { skillName: metaName, source });
1550
+ return "ok";
1551
+ }
1552
+ if (existing.source === source) {
1553
+ throw new Error(
1554
+ `Name collision: skills "${existing.skillName}" and "${metaName}" both normalize to "${normalized}"`
1555
+ );
1556
+ }
1557
+ return "skip";
1558
+ }
1559
+ function buildContextLines(meta) {
1560
+ const lines = [];
1561
+ if (meta.cognitive_mode) lines.push(`Cognitive mode: ${meta.cognitive_mode}`);
1562
+ if (meta.type) lines.push(`Type: ${meta.type}`);
1563
+ if (meta.state?.persistent) {
1564
+ const files = meta.state.files?.join(", ") ?? "";
1565
+ lines.push(`State: persistent${files ? ` (files: ${files})` : ""}`);
1566
+ }
1567
+ return lines;
1568
+ }
1569
+ function buildObjectiveLines(meta) {
1570
+ const lines = [meta.description];
1571
+ if (meta.phases && meta.phases.length > 0) {
1572
+ lines.push("", "Phases:");
1573
+ for (const phase of meta.phases) {
1574
+ const req = phase.required !== false ? "" : " (optional)";
1575
+ lines.push(`- ${phase.name}: ${phase.description}${req}`);
1576
+ }
1577
+ }
1578
+ return lines;
1579
+ }
1580
+ function buildProcessLines(meta) {
1581
+ if (meta.mcp?.tool) {
1582
+ return [
1583
+ `1. Try: invoke mcp__harness__${meta.mcp.tool} with skill: "${meta.name}"`,
1584
+ `2. If MCP unavailable: read SKILL.md and follow its workflow directly`,
1585
+ `3. Pass through any arguments provided by the user`
1586
+ ];
1587
+ }
1588
+ return [
1589
+ `1. Read SKILL.md and follow its workflow directly`,
1590
+ `2. Pass through any arguments provided by the user`
1591
+ ];
1592
+ }
1593
+ function buildSpec(meta, normalized, entry, skillsDir, source) {
1594
+ const skillMdPath = path12.join(skillsDir, entry.name, "SKILL.md");
1595
+ const skillMdContent = fs10.existsSync(skillMdPath) ? fs10.readFileSync(skillMdPath, "utf-8") : "";
1596
+ const skillMdRelative = path12.relative(process.cwd(), skillMdPath).replaceAll("\\", "/");
1597
+ const skillYamlRelative = path12.relative(process.cwd(), path12.join(skillsDir, entry.name, "skill.yaml")).replaceAll("\\", "/");
1598
+ const args = (meta.cli?.args ?? []).map((a) => ({
1599
+ name: a.name,
1600
+ description: a.description ?? "",
1601
+ required: a.required ?? false
1602
+ }));
1603
+ const tools = [...meta.tools ?? []];
1604
+ if (!tools.includes("Read")) tools.push("Read");
1605
+ const executionContextLines = [];
1606
+ if (skillMdContent) {
1607
+ executionContextLines.push(`@${skillMdRelative}`, `@${skillYamlRelative}`);
1608
+ }
1609
+ return {
1610
+ name: normalized,
1611
+ namespace: "harness",
1612
+ fullName: `harness:${normalized}`,
1613
+ description: meta.description,
1614
+ version: meta.version,
1615
+ ...meta.cognitive_mode ? { cognitiveMode: meta.cognitive_mode } : {},
1616
+ tools,
1617
+ args,
1618
+ skillYamlName: meta.name,
1619
+ sourceDir: entry.name,
1620
+ skillsBaseDir: skillsDir,
1621
+ source,
1622
+ prompt: {
1623
+ context: buildContextLines(meta).join("\n"),
1624
+ objective: buildObjectiveLines(meta).join("\n"),
1625
+ executionContext: executionContextLines.join("\n"),
1626
+ process: buildProcessLines(meta).join("\n")
1627
+ }
1628
+ };
1629
+ }
1257
1630
  function normalizeSkills(skillSources, platforms) {
1258
1631
  const specs = [];
1259
1632
  const nameMap = /* @__PURE__ */ new Map();
1260
1633
  for (const { dir: skillsDir, source } of skillSources) {
1261
- if (!fs8.existsSync(skillsDir)) continue;
1262
- const entries = fs8.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1634
+ if (!fs10.existsSync(skillsDir)) continue;
1635
+ const entries = fs10.readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory());
1263
1636
  for (const entry of entries) {
1264
- const yamlPath = path11.join(skillsDir, entry.name, "skill.yaml");
1265
- if (!fs8.existsSync(yamlPath)) continue;
1266
- let raw;
1267
- try {
1268
- raw = fs8.readFileSync(yamlPath, "utf-8");
1269
- } catch {
1270
- continue;
1271
- }
1272
- const parsed = parse3(raw);
1273
- const result = SkillMetadataSchema.safeParse(parsed);
1637
+ const yamlPath = path12.join(skillsDir, entry.name, "skill.yaml");
1638
+ if (!fs10.existsSync(yamlPath)) continue;
1639
+ const result = readSkillYaml(yamlPath);
1640
+ if (!result) continue;
1274
1641
  if (!result.success) {
1275
1642
  console.warn(`Skipping ${entry.name}: invalid skill.yaml`);
1276
1643
  continue;
1277
1644
  }
1278
1645
  const meta = result.data;
1279
- const matchesPlatform = platforms.some((p) => meta.platforms.includes(p));
1280
- if (!matchesPlatform) continue;
1281
- const tier = meta.tier;
1282
- const isInternal = meta.internal;
1283
- if (tier === 3 || isInternal) continue;
1646
+ if (shouldSkipSkill(meta, platforms)) continue;
1284
1647
  const normalized = normalizeName(meta.name);
1285
- const existing = nameMap.get(normalized);
1286
- if (existing) {
1287
- if (existing.source === source) {
1288
- throw new Error(
1289
- `Name collision: skills "${existing.skillName}" and "${meta.name}" both normalize to "${normalized}"`
1290
- );
1291
- }
1292
- continue;
1293
- }
1294
- nameMap.set(normalized, { skillName: meta.name, source });
1295
- const skillMdPath = path11.join(skillsDir, entry.name, "SKILL.md");
1296
- const skillMdContent = fs8.existsSync(skillMdPath) ? fs8.readFileSync(skillMdPath, "utf-8") : "";
1297
- const skillMdRelative = path11.relative(process.cwd(), path11.join(skillsDir, entry.name, "SKILL.md")).replaceAll("\\", "/");
1298
- const skillYamlRelative = path11.relative(process.cwd(), path11.join(skillsDir, entry.name, "skill.yaml")).replaceAll("\\", "/");
1299
- const args = (meta.cli?.args ?? []).map((a) => ({
1300
- name: a.name,
1301
- description: a.description ?? "",
1302
- required: a.required ?? false
1303
- }));
1304
- const tools = [...meta.tools ?? []];
1305
- if (!tools.includes("Read")) {
1306
- tools.push("Read");
1307
- }
1308
- const contextLines = [];
1309
- if (meta.cognitive_mode) {
1310
- contextLines.push(`Cognitive mode: ${meta.cognitive_mode}`);
1311
- }
1312
- if (meta.type) {
1313
- contextLines.push(`Type: ${meta.type}`);
1314
- }
1315
- if (meta.state?.persistent) {
1316
- const files = meta.state.files?.join(", ") ?? "";
1317
- contextLines.push(`State: persistent${files ? ` (files: ${files})` : ""}`);
1318
- }
1319
- const objectiveLines = [meta.description];
1320
- if (meta.phases && meta.phases.length > 0) {
1321
- objectiveLines.push("");
1322
- objectiveLines.push("Phases:");
1323
- for (const phase of meta.phases) {
1324
- const req = phase.required !== false ? "" : " (optional)";
1325
- objectiveLines.push(`- ${phase.name}: ${phase.description}${req}`);
1326
- }
1327
- }
1328
- const executionContextLines = [];
1329
- if (skillMdContent) {
1330
- executionContextLines.push(`@${skillMdRelative}`);
1331
- executionContextLines.push(`@${skillYamlRelative}`);
1332
- }
1333
- const processLines = [];
1334
- if (meta.mcp?.tool) {
1335
- processLines.push(
1336
- `1. Try: invoke mcp__harness__${meta.mcp.tool} with skill: "${meta.name}"`
1337
- );
1338
- processLines.push(`2. If MCP unavailable: read SKILL.md and follow its workflow directly`);
1339
- processLines.push(`3. Pass through any arguments provided by the user`);
1340
- } else {
1341
- processLines.push(`1. Read SKILL.md and follow its workflow directly`);
1342
- processLines.push(`2. Pass through any arguments provided by the user`);
1343
- }
1344
- specs.push({
1345
- name: normalized,
1346
- namespace: "harness",
1347
- fullName: `harness:${normalized}`,
1348
- description: meta.description,
1349
- version: meta.version,
1350
- ...meta.cognitive_mode ? { cognitiveMode: meta.cognitive_mode } : {},
1351
- tools,
1352
- args,
1353
- skillYamlName: meta.name,
1354
- sourceDir: entry.name,
1355
- skillsBaseDir: skillsDir,
1356
- source,
1357
- prompt: {
1358
- context: contextLines.join("\n"),
1359
- objective: objectiveLines.join("\n"),
1360
- executionContext: executionContextLines.join("\n"),
1361
- process: processLines.join("\n")
1362
- }
1363
- });
1648
+ if (checkNameCollision(normalized, meta.name, source, nameMap) === "skip") continue;
1649
+ specs.push(buildSpec(meta, normalized, entry, skillsDir, source));
1364
1650
  }
1365
1651
  }
1366
1652
  return specs;
@@ -1460,13 +1746,13 @@ function renderGemini(spec, skillMdContent, skillYamlContent) {
1460
1746
  // src/commands/generate-slash-commands.ts
1461
1747
  function resolveOutputDir(platform, opts) {
1462
1748
  if (opts.output) {
1463
- return path12.join(opts.output, "harness");
1749
+ return path13.join(opts.output, "harness");
1464
1750
  }
1465
1751
  if (opts.global) {
1466
1752
  const home = os.homedir();
1467
- return platform === "claude-code" ? path12.join(home, ".claude", "commands", "harness") : path12.join(home, ".gemini", "commands", "harness");
1753
+ return platform === "claude-code" ? path13.join(home, ".claude", "commands", "harness") : path13.join(home, ".gemini", "commands", "harness");
1468
1754
  }
1469
- return platform === "claude-code" ? path12.join("agents", "commands", "claude-code", "harness") : path12.join("agents", "commands", "gemini-cli", "harness");
1755
+ return platform === "claude-code" ? path13.join("agents", "commands", "claude-code", "harness") : path13.join("agents", "commands", "gemini-cli", "harness");
1470
1756
  }
1471
1757
  function fileExtension(platform) {
1472
1758
  return platform === "claude-code" ? ".md" : ".toml";
@@ -1481,26 +1767,29 @@ Remove ${files.length} orphaned command(s)? (y/N) `, (answer) => {
1481
1767
  });
1482
1768
  });
1483
1769
  }
1484
- function generateSlashCommands(opts) {
1485
- const skillSources = [];
1770
+ function resolveSkillSources(opts) {
1486
1771
  if (opts.skillsDir) {
1487
- skillSources.push({ dir: opts.skillsDir, source: "project" });
1488
- } else {
1489
- const projectDir = resolveProjectSkillsDir();
1490
- if (projectDir) {
1491
- skillSources.push({ dir: projectDir, source: "project" });
1492
- }
1493
- const communityDir = resolveCommunitySkillsDir();
1494
- if (fs9.existsSync(communityDir)) {
1495
- skillSources.push({ dir: communityDir, source: "community" });
1496
- }
1497
- if (opts.includeGlobal || skillSources.length === 0) {
1498
- const globalDir = resolveGlobalSkillsDir();
1499
- if (!projectDir || path12.resolve(globalDir) !== path12.resolve(projectDir)) {
1500
- skillSources.push({ dir: globalDir, source: "global" });
1501
- }
1772
+ return [{ dir: opts.skillsDir, source: "project" }];
1773
+ }
1774
+ const sources = [];
1775
+ const projectDir = resolveProjectSkillsDir();
1776
+ if (projectDir) {
1777
+ sources.push({ dir: projectDir, source: "project" });
1778
+ }
1779
+ const communityDir = resolveCommunitySkillsDir();
1780
+ if (fs11.existsSync(communityDir)) {
1781
+ sources.push({ dir: communityDir, source: "community" });
1782
+ }
1783
+ if (opts.includeGlobal || sources.length === 0) {
1784
+ const globalDir = resolveGlobalSkillsDir();
1785
+ if (!projectDir || path13.resolve(globalDir) !== path13.resolve(projectDir)) {
1786
+ sources.push({ dir: globalDir, source: "global" });
1502
1787
  }
1503
1788
  }
1789
+ return sources;
1790
+ }
1791
+ function generateSlashCommands(opts) {
1792
+ const skillSources = resolveSkillSources(opts);
1504
1793
  const specs = normalizeSkills(skillSources, opts.platforms);
1505
1794
  const results = [];
1506
1795
  for (const platform of opts.platforms) {
@@ -1518,7 +1807,7 @@ function generateSlashCommands(opts) {
1518
1807
  executionContext: spec.prompt.executionContext.split("\n").map((line) => {
1519
1808
  if (line.startsWith("@")) {
1520
1809
  const relPath = line.slice(1);
1521
- return `@${path12.resolve(relPath)}`;
1810
+ return `@${path13.resolve(relPath)}`;
1522
1811
  }
1523
1812
  return line;
1524
1813
  }).join("\n")
@@ -1526,10 +1815,10 @@ function generateSlashCommands(opts) {
1526
1815
  } : spec;
1527
1816
  rendered.set(filename, renderClaudeCode(renderSpec));
1528
1817
  } else {
1529
- const mdPath = path12.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
1530
- const yamlPath = path12.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
1531
- const mdContent = fs9.existsSync(mdPath) ? fs9.readFileSync(mdPath, "utf-8") : "";
1532
- const yamlContent = fs9.existsSync(yamlPath) ? fs9.readFileSync(yamlPath, "utf-8") : "";
1818
+ const mdPath = path13.join(spec.skillsBaseDir, spec.sourceDir, "SKILL.md");
1819
+ const yamlPath = path13.join(spec.skillsBaseDir, spec.sourceDir, "skill.yaml");
1820
+ const mdContent = fs11.existsSync(mdPath) ? fs11.readFileSync(mdPath, "utf-8") : "";
1821
+ const yamlContent = fs11.existsSync(yamlPath) ? fs11.readFileSync(yamlPath, "utf-8") : "";
1533
1822
  rendered.set(filename, renderGemini(spec, mdContent, yamlContent));
1534
1823
  }
1535
1824
  }
@@ -1555,9 +1844,9 @@ async function handleOrphanDeletion(results, opts) {
1555
1844
  const shouldDelete = opts.yes || await confirmDeletion(result.removed);
1556
1845
  if (shouldDelete) {
1557
1846
  for (const filename of result.removed) {
1558
- const filePath = path12.join(result.outputDir, filename);
1559
- if (fs9.existsSync(filePath)) {
1560
- fs9.unlinkSync(filePath);
1847
+ const filePath = path13.join(result.outputDir, filename);
1848
+ if (fs11.existsSync(filePath)) {
1849
+ fs11.unlinkSync(filePath);
1561
1850
  }
1562
1851
  }
1563
1852
  }
@@ -1683,7 +1972,7 @@ async function handleGenerateSlashCommands(input) {
1683
1972
  // src/mcp/resources/state.ts
1684
1973
  async function getStateResource(projectRoot) {
1685
1974
  try {
1686
- const { loadState, migrateToStreams } = await import("./dist-2B363XUH.js");
1975
+ const { loadState, migrateToStreams } = await import("./dist-HWXF2C3R.js");
1687
1976
  await migrateToStreams(projectRoot);
1688
1977
  const result = await loadState(projectRoot);
1689
1978
  if (result.ok) {
@@ -1771,7 +2060,7 @@ async function handleQueryGraph(input) {
1771
2060
  const projectPath = sanitizePath(input.path);
1772
2061
  const store = await loadGraphStore(projectPath);
1773
2062
  if (!store) return graphNotFoundError();
1774
- const { ContextQL } = await import("./dist-HXHWB7SV.js");
2063
+ const { ContextQL } = await import("./dist-B26DFXMP.js");
1775
2064
  const cql = new ContextQL(store);
1776
2065
  const result = cql.execute({
1777
2066
  rootNodeIds: input.rootNodeIds,
@@ -1862,7 +2151,7 @@ async function handleSearchSimilar(input) {
1862
2151
  const projectPath = sanitizePath(input.path);
1863
2152
  const store = await loadGraphStore(projectPath);
1864
2153
  if (!store) return graphNotFoundError();
1865
- const { FusionLayer } = await import("./dist-HXHWB7SV.js");
2154
+ const { FusionLayer } = await import("./dist-B26DFXMP.js");
1866
2155
  const fusion = new FusionLayer(store);
1867
2156
  const results = fusion.search(input.query, input.topK ?? 10);
1868
2157
  if (input.mode === "summary") {
@@ -1917,7 +2206,7 @@ async function handleFindContextFor(input) {
1917
2206
  const projectPath = sanitizePath(input.path);
1918
2207
  const store = await loadGraphStore(projectPath);
1919
2208
  if (!store) return graphNotFoundError();
1920
- const { FusionLayer, ContextQL } = await import("./dist-HXHWB7SV.js");
2209
+ const { FusionLayer, ContextQL } = await import("./dist-B26DFXMP.js");
1921
2210
  const fusion = new FusionLayer(store);
1922
2211
  const cql = new ContextQL(store);
1923
2212
  const tokenBudget = input.tokenBudget ?? 4e3;
@@ -2013,7 +2302,7 @@ async function handleGetRelationships(input) {
2013
2302
  const projectPath = sanitizePath(input.path);
2014
2303
  const store = await loadGraphStore(projectPath);
2015
2304
  if (!store) return graphNotFoundError();
2016
- const { ContextQL } = await import("./dist-HXHWB7SV.js");
2305
+ const { ContextQL } = await import("./dist-B26DFXMP.js");
2017
2306
  const cql = new ContextQL(store);
2018
2307
  const direction = input.direction ?? "both";
2019
2308
  const bidirectional = direction === "both" || direction === "inbound";
@@ -2119,7 +2408,7 @@ async function handleGetImpact(input) {
2119
2408
  const projectPath = sanitizePath(input.path);
2120
2409
  const store = await loadGraphStore(projectPath);
2121
2410
  if (!store) return graphNotFoundError();
2122
- const { ContextQL } = await import("./dist-HXHWB7SV.js");
2411
+ const { ContextQL } = await import("./dist-B26DFXMP.js");
2123
2412
  let targetNodeId = input.nodeId;
2124
2413
  if (!targetNodeId && input.filePath) {
2125
2414
  const fileNodes = store.findNodes({ type: "file" });
@@ -2230,7 +2519,7 @@ async function handleGetImpact(input) {
2230
2519
  }
2231
2520
 
2232
2521
  // src/mcp/tools/graph/ingest-source.ts
2233
- import * as path13 from "path";
2522
+ import * as path14 from "path";
2234
2523
  var ingestSourceDefinition = {
2235
2524
  name: "ingest_source",
2236
2525
  description: "Ingest sources into the project knowledge graph. Supports code analysis, knowledge documents, git history, or all at once.",
@@ -2250,10 +2539,10 @@ var ingestSourceDefinition = {
2250
2539
  async function handleIngestSource(input) {
2251
2540
  try {
2252
2541
  const projectPath = sanitizePath(input.path);
2253
- const graphDir = path13.join(projectPath, ".harness", "graph");
2254
- const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-HXHWB7SV.js");
2255
- const fs12 = await import("fs/promises");
2256
- await fs12.mkdir(graphDir, { recursive: true });
2542
+ const graphDir = path14.join(projectPath, ".harness", "graph");
2543
+ const { GraphStore, CodeIngestor, TopologicalLinker, KnowledgeIngestor, GitIngestor } = await import("./dist-B26DFXMP.js");
2544
+ const fs14 = await import("fs/promises");
2545
+ await fs14.mkdir(graphDir, { recursive: true });
2257
2546
  const store = new GraphStore();
2258
2547
  await store.load(graphDir);
2259
2548
  const results = [];
@@ -2326,7 +2615,7 @@ async function handleDetectAnomalies(input) {
2326
2615
  const projectPath = sanitizePath(input.path);
2327
2616
  const store = await loadGraphStore(projectPath);
2328
2617
  if (!store) return graphNotFoundError();
2329
- const { GraphAnomalyAdapter } = await import("./dist-HXHWB7SV.js");
2618
+ const { GraphAnomalyAdapter } = await import("./dist-B26DFXMP.js");
2330
2619
  const adapter = new GraphAnomalyAdapter(store);
2331
2620
  const report = adapter.detect({
2332
2621
  ...input.threshold !== void 0 && { threshold: input.threshold },
@@ -2366,7 +2655,7 @@ async function handleAskGraph(input) {
2366
2655
  const projectPath = sanitizePath(input.path);
2367
2656
  const store = await loadGraphStore(projectPath);
2368
2657
  if (!store) return graphNotFoundError();
2369
- const { askGraph } = await import("./dist-HXHWB7SV.js");
2658
+ const { askGraph } = await import("./dist-B26DFXMP.js");
2370
2659
  const result = await askGraph(store, input.question);
2371
2660
  return {
2372
2661
  content: [{ type: "text", text: JSON.stringify(result) }]
@@ -2385,8 +2674,8 @@ async function handleAskGraph(input) {
2385
2674
  }
2386
2675
 
2387
2676
  // src/mcp/resources/graph.ts
2388
- import * as fs10 from "fs/promises";
2389
- import * as path14 from "path";
2677
+ import * as fs12 from "fs/promises";
2678
+ import * as path15 from "path";
2390
2679
  var MAX_ITEMS = 5e3;
2391
2680
  function formatStaleness(isoTimestamp) {
2392
2681
  const then = new Date(isoTimestamp).getTime();
@@ -2409,11 +2698,11 @@ async function getGraphResource(projectRoot) {
2409
2698
  message: "No knowledge graph found. Run harness scan to build one."
2410
2699
  });
2411
2700
  }
2412
- const graphDir = path14.join(projectRoot, ".harness", "graph");
2413
- const metadataPath = path14.join(graphDir, "metadata.json");
2701
+ const graphDir = path15.join(projectRoot, ".harness", "graph");
2702
+ const metadataPath = path15.join(graphDir, "metadata.json");
2414
2703
  let lastScanTimestamp = null;
2415
2704
  try {
2416
- const raw = JSON.parse(await fs10.readFile(metadataPath, "utf-8"));
2705
+ const raw = JSON.parse(await fs12.readFile(metadataPath, "utf-8"));
2417
2706
  lastScanTimestamp = raw.lastScanTimestamp ?? null;
2418
2707
  } catch {
2419
2708
  }
@@ -2502,7 +2791,7 @@ var generateAgentDefinitionsDefinition = {
2502
2791
  }
2503
2792
  };
2504
2793
  async function handleGenerateAgentDefinitions(input) {
2505
- const { generateAgentDefinitions } = await import("./generate-agent-definitions-64S3CLEZ.js");
2794
+ const { generateAgentDefinitions } = await import("./generate-agent-definitions-3PM5EU7V.js");
2506
2795
  const platforms = input.platform === "all" || !input.platform ? ["claude-code", "gemini-cli"] : [input.platform];
2507
2796
  const results = generateAgentDefinitions({
2508
2797
  platforms: [...platforms],
@@ -2513,8 +2802,8 @@ async function handleGenerateAgentDefinitions(input) {
2513
2802
  }
2514
2803
 
2515
2804
  // src/mcp/tools/roadmap.ts
2516
- import * as fs11 from "fs";
2517
- import * as path15 from "path";
2805
+ import * as fs13 from "fs";
2806
+ import * as path16 from "path";
2518
2807
  var manageRoadmapDefinition = {
2519
2808
  name: "manage_roadmap",
2520
2809
  description: "Manage the project roadmap: show, add, update, remove, sync features, or query by filter. Reads and writes docs/roadmap.md.",
@@ -2569,21 +2858,21 @@ var manageRoadmapDefinition = {
2569
2858
  }
2570
2859
  };
2571
2860
  function roadmapPath(projectRoot) {
2572
- return path15.join(projectRoot, "docs", "roadmap.md");
2861
+ return path16.join(projectRoot, "docs", "roadmap.md");
2573
2862
  }
2574
2863
  function readRoadmapFile(projectRoot) {
2575
2864
  const filePath = roadmapPath(projectRoot);
2576
2865
  try {
2577
- return fs11.readFileSync(filePath, "utf-8");
2866
+ return fs13.readFileSync(filePath, "utf-8");
2578
2867
  } catch {
2579
2868
  return null;
2580
2869
  }
2581
2870
  }
2582
2871
  function writeRoadmapFile(projectRoot, content) {
2583
2872
  const filePath = roadmapPath(projectRoot);
2584
- const dir = path15.dirname(filePath);
2585
- fs11.mkdirSync(dir, { recursive: true });
2586
- fs11.writeFileSync(filePath, content, "utf-8");
2873
+ const dir = path16.dirname(filePath);
2874
+ fs13.mkdirSync(dir, { recursive: true });
2875
+ fs13.writeFileSync(filePath, content, "utf-8");
2587
2876
  }
2588
2877
  function roadmapNotFoundError() {
2589
2878
  return {
@@ -2596,7 +2885,7 @@ function roadmapNotFoundError() {
2596
2885
  isError: true
2597
2886
  };
2598
2887
  }
2599
- function handleShow(projectPath, input, deps) {
2888
+ function handleShow2(projectPath, input, deps) {
2600
2889
  const { parseRoadmap, Ok: Ok2 } = deps;
2601
2890
  const raw = readRoadmapFile(projectPath);
2602
2891
  if (raw === null) return roadmapNotFoundError();
@@ -2807,13 +3096,13 @@ function handleSync(projectPath, input, deps) {
2807
3096
  }
2808
3097
  async function handleManageRoadmap(input) {
2809
3098
  try {
2810
- const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-2B363XUH.js");
2811
- const { Ok: Ok2 } = await import("./dist-D4RYGUZE.js");
3099
+ const { parseRoadmap, serializeRoadmap, syncRoadmap } = await import("./dist-HWXF2C3R.js");
3100
+ const { Ok: Ok2 } = await import("./dist-USY2C5JL.js");
2812
3101
  const projectPath = sanitizePath(input.path);
2813
3102
  const deps = { parseRoadmap, serializeRoadmap, syncRoadmap, Ok: Ok2 };
2814
3103
  switch (input.action) {
2815
3104
  case "show":
2816
- return handleShow(projectPath, input, deps);
3105
+ return handleShow2(projectPath, input, deps);
2817
3106
  case "add":
2818
3107
  return handleAdd(projectPath, input, deps);
2819
3108
  case "update":
@@ -3193,226 +3482,119 @@ var emitInteractionDefinition = {
3193
3482
  required: ["path", "type"]
3194
3483
  }
3195
3484
  };
3485
+ function formatZodErrors(issues) {
3486
+ return issues.map((i) => i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ");
3487
+ }
3488
+ async function handleQuestion(validInput, projectPath, id) {
3489
+ if (!validInput.question)
3490
+ return mcpError("Error: question payload is required when type is question");
3491
+ const questionResult = InteractionQuestionWithOptionsSchema.safeParse(validInput.question);
3492
+ if (!questionResult.success)
3493
+ return mcpError(`Error: ${formatZodErrors(questionResult.error.issues)}`);
3494
+ const prompt = renderQuestion(questionResult.data);
3495
+ await recordInteraction(projectPath, id, "question", questionResult.data.text, validInput.stream);
3496
+ return { content: [{ type: "text", text: JSON.stringify({ id, prompt }) }] };
3497
+ }
3498
+ async function handleConfirmation(validInput, projectPath, id) {
3499
+ if (!validInput.confirmation)
3500
+ return mcpError("Error: confirmation payload is required when type is confirmation");
3501
+ const confirmResult = InteractionConfirmationSchema.safeParse(validInput.confirmation);
3502
+ if (!confirmResult.success)
3503
+ return mcpError(
3504
+ `Error: ${confirmResult.error.issues.map((i) => i.message).join("; ")}`
3505
+ );
3506
+ const prompt = renderConfirmation(confirmResult.data);
3507
+ await recordInteraction(
3508
+ projectPath,
3509
+ id,
3510
+ "confirmation",
3511
+ confirmResult.data.text,
3512
+ validInput.stream
3513
+ );
3514
+ return { content: [{ type: "text", text: JSON.stringify({ id, prompt }) }] };
3515
+ }
3516
+ async function handleTransition(validInput, projectPath, id) {
3517
+ if (!validInput.transition)
3518
+ return mcpError("Error: transition payload is required when type is transition");
3519
+ const transitionResult = InteractionTransitionSchema.safeParse(validInput.transition);
3520
+ if (!transitionResult.success)
3521
+ return mcpError(
3522
+ `Error: ${transitionResult.error.issues.map((i) => i.message).join("; ")}`
3523
+ );
3524
+ const transition = transitionResult.data;
3525
+ const prompt = renderTransition(transition);
3526
+ try {
3527
+ const { saveHandoff } = await import("./dist-HWXF2C3R.js");
3528
+ await saveHandoff(
3529
+ projectPath,
3530
+ {
3531
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3532
+ fromSkill: "emit_interaction",
3533
+ phase: transition.completedPhase,
3534
+ summary: transition.reason,
3535
+ completed: [transition.completedPhase],
3536
+ pending: [transition.suggestedNext],
3537
+ concerns: [],
3538
+ decisions: [],
3539
+ blockers: [],
3540
+ contextKeywords: []
3541
+ },
3542
+ validInput.stream,
3543
+ validInput.session
3544
+ );
3545
+ } catch {
3546
+ }
3547
+ await recordInteraction(
3548
+ projectPath,
3549
+ id,
3550
+ "transition",
3551
+ `${transition.completedPhase} -> ${transition.suggestedNext}`,
3552
+ validInput.stream
3553
+ );
3554
+ const responsePayload = { id, prompt, handoffWritten: true };
3555
+ if (!transition.requiresConfirmation) {
3556
+ responsePayload.autoTransition = true;
3557
+ responsePayload.nextAction = `Invoke harness-${transition.suggestedNext} skill now`;
3558
+ }
3559
+ return { content: [{ type: "text", text: JSON.stringify(responsePayload) }] };
3560
+ }
3561
+ async function handleBatch(validInput, projectPath, id) {
3562
+ if (!validInput.batch) return mcpError("Error: batch payload is required when type is batch");
3563
+ const batchResult = InteractionBatchSchema.safeParse(validInput.batch);
3564
+ if (!batchResult.success)
3565
+ return mcpError(
3566
+ `Error: ${batchResult.error.issues.map((i) => i.message).join("; ")}`
3567
+ );
3568
+ const prompt = renderBatch(batchResult.data);
3569
+ await recordInteraction(projectPath, id, "batch", batchResult.data.text, validInput.stream);
3570
+ return {
3571
+ content: [{ type: "text", text: JSON.stringify({ id, prompt, batchMode: true }) }]
3572
+ };
3573
+ }
3574
+ var INTERACTION_HANDLERS = {
3575
+ question: handleQuestion,
3576
+ confirmation: handleConfirmation,
3577
+ transition: handleTransition,
3578
+ batch: handleBatch
3579
+ };
3196
3580
  async function handleEmitInteraction(input) {
3197
3581
  try {
3198
3582
  const parseResult = EmitInteractionInputSchema.safeParse(input);
3199
- if (!parseResult.success) {
3200
- return {
3201
- content: [
3202
- {
3203
- type: "text",
3204
- text: `Error: ${parseResult.error.issues.map((i) => i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ")}`
3205
- }
3206
- ],
3207
- isError: true
3208
- };
3209
- }
3583
+ if (!parseResult.success)
3584
+ return mcpError(`Error: ${formatZodErrors(parseResult.error.issues)}`);
3210
3585
  const validInput = parseResult.data;
3211
3586
  const projectPath = sanitizePath(validInput.path);
3212
3587
  const id = randomUUID();
3213
- switch (validInput.type) {
3214
- case "question": {
3215
- if (!validInput.question) {
3216
- return {
3217
- content: [
3218
- {
3219
- type: "text",
3220
- text: "Error: question payload is required when type is question"
3221
- }
3222
- ],
3223
- isError: true
3224
- };
3225
- }
3226
- const questionResult = InteractionQuestionWithOptionsSchema.safeParse(validInput.question);
3227
- if (!questionResult.success) {
3228
- return {
3229
- content: [
3230
- {
3231
- type: "text",
3232
- text: `Error: ${questionResult.error.issues.map((i) => i.path.length > 0 ? `${i.path.join(".")}: ${i.message}` : i.message).join("; ")}`
3233
- }
3234
- ],
3235
- isError: true
3236
- };
3237
- }
3238
- const prompt = renderQuestion(questionResult.data);
3239
- await recordInteraction(
3240
- projectPath,
3241
- id,
3242
- "question",
3243
- questionResult.data.text,
3244
- validInput.stream
3245
- );
3246
- return {
3247
- content: [{ type: "text", text: JSON.stringify({ id, prompt }) }]
3248
- };
3249
- }
3250
- case "confirmation": {
3251
- if (!validInput.confirmation) {
3252
- return {
3253
- content: [
3254
- {
3255
- type: "text",
3256
- text: "Error: confirmation payload is required when type is confirmation"
3257
- }
3258
- ],
3259
- isError: true
3260
- };
3261
- }
3262
- const confirmResult = InteractionConfirmationSchema.safeParse(validInput.confirmation);
3263
- if (!confirmResult.success) {
3264
- return {
3265
- content: [
3266
- {
3267
- type: "text",
3268
- text: `Error: ${confirmResult.error.issues.map((i) => i.message).join("; ")}`
3269
- }
3270
- ],
3271
- isError: true
3272
- };
3273
- }
3274
- const prompt = renderConfirmation(confirmResult.data);
3275
- await recordInteraction(
3276
- projectPath,
3277
- id,
3278
- "confirmation",
3279
- confirmResult.data.text,
3280
- validInput.stream
3281
- );
3282
- return {
3283
- content: [{ type: "text", text: JSON.stringify({ id, prompt }) }]
3284
- };
3285
- }
3286
- case "transition": {
3287
- if (!validInput.transition) {
3288
- return {
3289
- content: [
3290
- {
3291
- type: "text",
3292
- text: "Error: transition payload is required when type is transition"
3293
- }
3294
- ],
3295
- isError: true
3296
- };
3297
- }
3298
- const transitionResult = InteractionTransitionSchema.safeParse(validInput.transition);
3299
- if (!transitionResult.success) {
3300
- return {
3301
- content: [
3302
- {
3303
- type: "text",
3304
- text: `Error: ${transitionResult.error.issues.map((i) => i.message).join("; ")}`
3305
- }
3306
- ],
3307
- isError: true
3308
- };
3309
- }
3310
- const transition = transitionResult.data;
3311
- const prompt = renderTransition(transition);
3312
- try {
3313
- const { saveHandoff } = await import("./dist-2B363XUH.js");
3314
- await saveHandoff(
3315
- projectPath,
3316
- {
3317
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3318
- fromSkill: "emit_interaction",
3319
- phase: transition.completedPhase,
3320
- summary: transition.reason,
3321
- completed: [transition.completedPhase],
3322
- pending: [transition.suggestedNext],
3323
- concerns: [],
3324
- decisions: [],
3325
- blockers: [],
3326
- contextKeywords: []
3327
- },
3328
- validInput.stream,
3329
- validInput.session
3330
- );
3331
- } catch {
3332
- }
3333
- await recordInteraction(
3334
- projectPath,
3335
- id,
3336
- "transition",
3337
- `${transition.completedPhase} -> ${transition.suggestedNext}`,
3338
- validInput.stream
3339
- );
3340
- const responsePayload = { id, prompt, handoffWritten: true };
3341
- if (!transition.requiresConfirmation) {
3342
- responsePayload.autoTransition = true;
3343
- responsePayload.nextAction = `Invoke harness-${transition.suggestedNext} skill now`;
3344
- }
3345
- return {
3346
- content: [
3347
- {
3348
- type: "text",
3349
- text: JSON.stringify(responsePayload)
3350
- }
3351
- ]
3352
- };
3353
- }
3354
- case "batch": {
3355
- if (!validInput.batch) {
3356
- return {
3357
- content: [
3358
- {
3359
- type: "text",
3360
- text: "Error: batch payload is required when type is batch"
3361
- }
3362
- ],
3363
- isError: true
3364
- };
3365
- }
3366
- const batchResult = InteractionBatchSchema.safeParse(validInput.batch);
3367
- if (!batchResult.success) {
3368
- return {
3369
- content: [
3370
- {
3371
- type: "text",
3372
- text: `Error: ${batchResult.error.issues.map((i) => i.message).join("; ")}`
3373
- }
3374
- ],
3375
- isError: true
3376
- };
3377
- }
3378
- const prompt = renderBatch(batchResult.data);
3379
- await recordInteraction(projectPath, id, "batch", batchResult.data.text, validInput.stream);
3380
- return {
3381
- content: [
3382
- {
3383
- type: "text",
3384
- text: JSON.stringify({ id, prompt, batchMode: true })
3385
- }
3386
- ]
3387
- };
3388
- }
3389
- default: {
3390
- return {
3391
- content: [
3392
- {
3393
- type: "text",
3394
- text: `Error: unknown interaction type: ${String(validInput.type)}`
3395
- }
3396
- ],
3397
- isError: true
3398
- };
3399
- }
3400
- }
3588
+ const handler = INTERACTION_HANDLERS[validInput.type];
3589
+ if (!handler) return mcpError(`Error: unknown interaction type: ${String(validInput.type)}`);
3590
+ return await handler(validInput, projectPath, id);
3401
3591
  } catch (error) {
3402
- return {
3403
- content: [
3404
- {
3405
- type: "text",
3406
- text: `Error: ${error instanceof Error ? error.message : String(error)}`
3407
- }
3408
- ],
3409
- isError: true
3410
- };
3592
+ return mcpError(`Error: ${error instanceof Error ? error.message : String(error)}`);
3411
3593
  }
3412
3594
  }
3413
3595
  async function recordInteraction(projectPath, id, type, decision, stream) {
3414
3596
  try {
3415
- const { loadState, saveState } = await import("./dist-2B363XUH.js");
3597
+ const { loadState, saveState } = await import("./dist-HWXF2C3R.js");
3416
3598
  const stateResult = await loadState(projectPath, stream);
3417
3599
  if (stateResult.ok) {
3418
3600
  const state = stateResult.value;
@@ -3430,7 +3612,7 @@ async function recordInteraction(projectPath, id, type, decision, stream) {
3430
3612
  // src/mcp/tools/gather-context.ts
3431
3613
  var gatherContextDefinition = {
3432
3614
  name: "gather_context",
3433
- description: "Assemble all working context an agent needs in a single call: state, learnings, handoff, graph context, and project validation. Runs constituents in parallel.",
3615
+ description: "Assemble all working context an agent needs in a single call: state, learnings, handoff, graph context, project validation, and session sections. Runs constituents in parallel.",
3434
3616
  inputSchema: {
3435
3617
  type: "object",
3436
3618
  properties: {
@@ -3451,7 +3633,7 @@ var gatherContextDefinition = {
3451
3633
  type: "array",
3452
3634
  items: {
3453
3635
  type: "string",
3454
- enum: ["state", "learnings", "handoff", "graph", "validation"]
3636
+ enum: ["state", "learnings", "handoff", "graph", "validation", "sessions"]
3455
3637
  },
3456
3638
  description: "Which constituents to include (default: all)"
3457
3639
  },
@@ -3492,10 +3674,10 @@ async function handleGatherContext(input) {
3492
3674
  input.include ?? ["state", "learnings", "handoff", "graph", "validation"]
3493
3675
  );
3494
3676
  const errors = [];
3495
- const statePromise = includeSet.has("state") ? import("./dist-2B363XUH.js").then(
3677
+ const statePromise = includeSet.has("state") ? import("./dist-HWXF2C3R.js").then(
3496
3678
  (core) => core.loadState(projectPath, void 0, input.session)
3497
3679
  ) : Promise.resolve(null);
3498
- const learningsPromise = includeSet.has("learnings") ? import("./dist-2B363XUH.js").then(
3680
+ const learningsPromise = includeSet.has("learnings") ? import("./dist-HWXF2C3R.js").then(
3499
3681
  (core) => core.loadBudgetedLearnings(projectPath, {
3500
3682
  intent: input.intent,
3501
3683
  tokenBudget: input.learningsBudget ?? 1e3,
@@ -3503,14 +3685,14 @@ async function handleGatherContext(input) {
3503
3685
  ...input.session !== void 0 && { session: input.session }
3504
3686
  })
3505
3687
  ) : Promise.resolve(null);
3506
- const handoffPromise = includeSet.has("handoff") ? import("./dist-2B363XUH.js").then(
3688
+ const handoffPromise = includeSet.has("handoff") ? import("./dist-HWXF2C3R.js").then(
3507
3689
  (core) => core.loadHandoff(projectPath, void 0, input.session)
3508
3690
  ) : Promise.resolve(null);
3509
3691
  const graphPromise = includeSet.has("graph") ? (async () => {
3510
- const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-GJZ4FN4Y.js");
3692
+ const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-2M2HXDQI.js");
3511
3693
  const store = await loadGraphStore2(projectPath);
3512
3694
  if (!store) return null;
3513
- const { FusionLayer, ContextQL } = await import("./dist-HXHWB7SV.js");
3695
+ const { FusionLayer, ContextQL } = await import("./dist-B26DFXMP.js");
3514
3696
  const fusion = new FusionLayer(store);
3515
3697
  const cql = new ContextQL(store);
3516
3698
  const tokenBudget = input.tokenBudget ?? 4e3;
@@ -3547,18 +3729,29 @@ async function handleGatherContext(input) {
3547
3729
  context: contextBlocks
3548
3730
  };
3549
3731
  })() : Promise.resolve(null);
3732
+ const sessionsPromise = includeSet.has("sessions") && input.session ? import("./dist-HWXF2C3R.js").then(
3733
+ (core) => core.readSessionSections(projectPath, input.session)
3734
+ ) : Promise.resolve(null);
3550
3735
  const validationPromise = includeSet.has("validation") ? (async () => {
3551
- const { handleValidateProject: handleValidateProject2 } = await import("./validate-GCHZJIL7.js");
3736
+ const { handleValidateProject: handleValidateProject2 } = await import("./validate-FD3Z6VJD.js");
3552
3737
  const result = await handleValidateProject2({ path: projectPath });
3553
3738
  const first = result.content[0];
3554
3739
  return first ? JSON.parse(first.text) : null;
3555
3740
  })() : Promise.resolve(null);
3556
- const [stateResult, learningsResult, handoffResult, graphResult, validationResult] = await Promise.allSettled([
3741
+ const [
3742
+ stateResult,
3743
+ learningsResult,
3744
+ handoffResult,
3745
+ graphResult,
3746
+ validationResult,
3747
+ sessionsResult
3748
+ ] = await Promise.allSettled([
3557
3749
  statePromise,
3558
3750
  learningsPromise,
3559
3751
  handoffPromise,
3560
3752
  graphPromise,
3561
- validationPromise
3753
+ validationPromise,
3754
+ sessionsPromise
3562
3755
  ]);
3563
3756
  function extract(settled, name) {
3564
3757
  if (settled.status === "rejected") {
@@ -3572,6 +3765,7 @@ async function handleGatherContext(input) {
3572
3765
  const handoffRaw = extract(handoffResult, "handoff");
3573
3766
  const graphContextRaw = extract(graphResult, "graph");
3574
3767
  const validationRaw = extract(validationResult, "validation");
3768
+ const sessionsRaw = extract(sessionsResult, "sessions");
3575
3769
  const state = stateRaw && typeof stateRaw === "object" && "ok" in stateRaw ? stateRaw.ok ? stateRaw.value : (() => {
3576
3770
  errors.push(`state: ${stateRaw.error.message}`);
3577
3771
  return null;
@@ -3588,6 +3782,12 @@ async function handleGatherContext(input) {
3588
3782
  })() : handoffRaw;
3589
3783
  const graphContext = graphContextRaw;
3590
3784
  const validation = validationRaw;
3785
+ const sessionSections = sessionsRaw && typeof sessionsRaw === "object" && "ok" in sessionsRaw ? sessionsRaw.ok ? sessionsRaw.value : (() => {
3786
+ errors.push(
3787
+ `sessions: ${sessionsRaw.error.message}`
3788
+ );
3789
+ return null;
3790
+ })() : sessionsRaw;
3591
3791
  const assembledIn = Date.now() - start;
3592
3792
  const mode = input.mode ?? "summary";
3593
3793
  const outputState = state ?? null;
@@ -3612,6 +3812,7 @@ async function handleGatherContext(input) {
3612
3812
  handoff: outputHandoff,
3613
3813
  graphContext: outputGraphContext,
3614
3814
  validation: outputValidation,
3815
+ sessionSections: sessionSections ?? null,
3615
3816
  meta: {
3616
3817
  assembledIn,
3617
3818
  graphAvailable: graphContext !== null,
@@ -3622,7 +3823,7 @@ async function handleGatherContext(input) {
3622
3823
  };
3623
3824
  if (input.session) {
3624
3825
  try {
3625
- const core = await import("./dist-2B363XUH.js");
3826
+ const core = await import("./dist-HWXF2C3R.js");
3626
3827
  core.updateSessionIndex(
3627
3828
  projectPath,
3628
3829
  input.session,
@@ -3692,7 +3893,7 @@ async function handleAssessProject(input) {
3692
3893
  let validateResult = null;
3693
3894
  if (checksToRun.has("validate")) {
3694
3895
  try {
3695
- const { handleValidateProject: handleValidateProject2 } = await import("./validate-GCHZJIL7.js");
3896
+ const { handleValidateProject: handleValidateProject2 } = await import("./validate-FD3Z6VJD.js");
3696
3897
  const result = await handleValidateProject2({ path: projectPath });
3697
3898
  const first = result.content[0];
3698
3899
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3717,7 +3918,7 @@ async function handleAssessProject(input) {
3717
3918
  parallelChecks.push(
3718
3919
  (async () => {
3719
3920
  try {
3720
- const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-2R5Z4ZAF.js");
3921
+ const { handleCheckDependencies: handleCheckDependencies2 } = await import("./architecture-JQZYM4US.js");
3721
3922
  const result = await handleCheckDependencies2({ path: projectPath });
3722
3923
  const first = result.content[0];
3723
3924
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3744,7 +3945,7 @@ async function handleAssessProject(input) {
3744
3945
  parallelChecks.push(
3745
3946
  (async () => {
3746
3947
  try {
3747
- const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-FZOPM4GK.js");
3948
+ const { handleCheckDocs: handleCheckDocs2 } = await import("./docs-7ECGYMAV.js");
3748
3949
  const result = await handleCheckDocs2({ path: projectPath, scope: "coverage" });
3749
3950
  const first = result.content[0];
3750
3951
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3771,14 +3972,14 @@ async function handleAssessProject(input) {
3771
3972
  parallelChecks.push(
3772
3973
  (async () => {
3773
3974
  try {
3774
- const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-LVHJMFGH.js");
3975
+ const { handleDetectEntropy: handleDetectEntropy2 } = await import("./entropy-5USWKLVS.js");
3775
3976
  const result = await handleDetectEntropy2({ path: projectPath, type: "all" });
3776
3977
  const first = result.content[0];
3777
3978
  const parsed = first ? JSON.parse(first.text) : {};
3778
3979
  const issues = (parsed.drift?.staleReferences?.length ?? 0) + (parsed.drift?.missingTargets?.length ?? 0) + (parsed.deadCode?.unusedImports?.length ?? 0) + (parsed.deadCode?.unusedExports?.length ?? 0) + (parsed.patterns?.violations?.length ?? 0);
3779
3980
  return {
3780
3981
  name: "entropy",
3781
- passed: !result.isError && issues === 0,
3982
+ passed: !("isError" in result && result.isError) && issues === 0,
3782
3983
  issueCount: issues,
3783
3984
  ...issues > 0 ? { topIssue: "Entropy detected -- run detect_entropy for details" } : {},
3784
3985
  ...mode === "detailed" ? { detailed: parsed } : {}
@@ -3798,7 +3999,7 @@ async function handleAssessProject(input) {
3798
3999
  parallelChecks.push(
3799
4000
  (async () => {
3800
4001
  try {
3801
- const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-FWQZF2IZ.js");
4002
+ const { handleRunSecurityScan: handleRunSecurityScan2 } = await import("./security-PZOX7AQS.js");
3802
4003
  const result = await handleRunSecurityScan2({ path: projectPath });
3803
4004
  const first = result.content[0];
3804
4005
  const parsed = first ? JSON.parse(first.text) : {};
@@ -3830,14 +4031,14 @@ async function handleAssessProject(input) {
3830
4031
  parallelChecks.push(
3831
4032
  (async () => {
3832
4033
  try {
3833
- const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-ZTVSUANN.js");
4034
+ const { handleCheckPerformance: handleCheckPerformance2 } = await import("./performance-OQAFMJUD.js");
3834
4035
  const result = await handleCheckPerformance2({ path: projectPath });
3835
4036
  const first = result.content[0];
3836
4037
  const parsed = first ? JSON.parse(first.text) : {};
3837
4038
  const issues = parsed.violations?.length ?? parsed.issues?.length ?? 0;
3838
4039
  return {
3839
4040
  name: "perf",
3840
- passed: !result.isError && issues === 0,
4041
+ passed: !("isError" in result && result.isError) && issues === 0,
3841
4042
  issueCount: issues,
3842
4043
  ...issues > 0 ? { topIssue: "Performance issues detected" } : {},
3843
4044
  ...mode === "detailed" ? { detailed: parsed } : {}
@@ -4004,81 +4205,8 @@ async function handleReviewChanges(input) {
4004
4205
  downgraded = true;
4005
4206
  }
4006
4207
  try {
4007
- if (effectiveDepth === "quick") {
4008
- const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-IHLVLMRD.js");
4009
- const result2 = await handleAnalyzeDiff2({ diff, path: projectPath });
4010
- const firstContent = result2.content[0];
4011
- if (!firstContent) throw new Error("Empty analyze_diff response");
4012
- const parsed2 = JSON.parse(firstContent.text);
4013
- return {
4014
- content: [
4015
- {
4016
- type: "text",
4017
- text: JSON.stringify({
4018
- depth: "quick",
4019
- downgraded,
4020
- findings: parsed2.findings ?? parsed2.warnings ?? [],
4021
- fileCount: parsed2.summary?.filesChanged ?? parsed2.files?.length ?? 0,
4022
- lineCount: diffLines,
4023
- ...result2.isError ? { error: parsed2 } : {}
4024
- })
4025
- }
4026
- ]
4027
- };
4028
- }
4029
- if (effectiveDepth === "standard") {
4030
- const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-IHLVLMRD.js");
4031
- const [diffResult, reviewResult] = await Promise.all([
4032
- handleAnalyzeDiff2({ diff, path: projectPath }),
4033
- handleCreateSelfReview2({ path: projectPath, diff })
4034
- ]);
4035
- const diffContent = diffResult.content[0];
4036
- const reviewContent = reviewResult.content[0];
4037
- if (!diffContent || !reviewContent) throw new Error("Empty review response");
4038
- const diffParsed = JSON.parse(diffContent.text);
4039
- const reviewParsed = JSON.parse(reviewContent.text);
4040
- const findings = [
4041
- ...diffParsed.findings ?? diffParsed.warnings ?? [],
4042
- ...reviewParsed.findings ?? reviewParsed.items ?? []
4043
- ];
4044
- return {
4045
- content: [
4046
- {
4047
- type: "text",
4048
- text: JSON.stringify({
4049
- depth: "standard",
4050
- downgraded,
4051
- findings,
4052
- diffAnalysis: diffParsed,
4053
- selfReview: reviewParsed,
4054
- fileCount: diffParsed.summary?.filesChanged ?? diffParsed.files?.length ?? 0,
4055
- lineCount: diffLines
4056
- })
4057
- }
4058
- ]
4059
- };
4060
- }
4061
- const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-76JHKGSV.js");
4062
- const result = await handleRunCodeReview2({ path: projectPath, diff });
4063
- const deepContent = result.content[0];
4064
- if (!deepContent) throw new Error("Empty code review response");
4065
- const parsed = JSON.parse(deepContent.text);
4066
- return {
4067
- content: [
4068
- {
4069
- type: "text",
4070
- text: JSON.stringify({
4071
- depth: "deep",
4072
- downgraded: false,
4073
- findings: parsed.findings ?? [],
4074
- assessment: parsed.assessment,
4075
- findingCount: parsed.findingCount,
4076
- lineCount: diffLines,
4077
- pipeline: parsed
4078
- })
4079
- }
4080
- ]
4081
- };
4208
+ const reviewFn = DEPTH_HANDLERS[effectiveDepth];
4209
+ return await reviewFn(projectPath, diff, diffLines, downgraded);
4082
4210
  } catch (error) {
4083
4211
  return {
4084
4212
  content: [
@@ -4091,6 +4219,97 @@ async function handleReviewChanges(input) {
4091
4219
  };
4092
4220
  }
4093
4221
  }
4222
+ async function runQuickReview(projectPath, diff, diffLines, downgraded) {
4223
+ const { handleAnalyzeDiff: handleAnalyzeDiff2 } = await import("./feedback-UTBXZZHF.js");
4224
+ const result = await handleAnalyzeDiff2({ diff, path: projectPath });
4225
+ const firstContent = result.content[0];
4226
+ if (!firstContent) throw new Error("Empty analyze_diff response");
4227
+ const parsed = JSON.parse(firstContent.text);
4228
+ return {
4229
+ content: [
4230
+ {
4231
+ type: "text",
4232
+ text: JSON.stringify({
4233
+ depth: "quick",
4234
+ downgraded,
4235
+ findings: parsed.findings ?? parsed.warnings ?? [],
4236
+ fileCount: parsed.summary?.filesChanged ?? parsed.files?.length ?? 0,
4237
+ lineCount: diffLines,
4238
+ ...result.isError ? { error: parsed } : {}
4239
+ })
4240
+ }
4241
+ ]
4242
+ };
4243
+ }
4244
+ function extractFindings(parsed, primaryKey, fallbackKey) {
4245
+ return parsed[primaryKey] ?? parsed[fallbackKey] ?? [];
4246
+ }
4247
+ function extractFileCount(diffParsed) {
4248
+ const summary = diffParsed.summary;
4249
+ if (summary?.filesChanged !== void 0) return summary.filesChanged;
4250
+ const files = diffParsed.files;
4251
+ return files?.length ?? 0;
4252
+ }
4253
+ async function runStandardReview(projectPath, diff, diffLines, downgraded) {
4254
+ const { handleAnalyzeDiff: handleAnalyzeDiff2, handleCreateSelfReview: handleCreateSelfReview2 } = await import("./feedback-UTBXZZHF.js");
4255
+ const [diffResult, reviewResult] = await Promise.all([
4256
+ handleAnalyzeDiff2({ diff, path: projectPath }),
4257
+ handleCreateSelfReview2({ path: projectPath, diff })
4258
+ ]);
4259
+ const diffContent = diffResult.content[0];
4260
+ const reviewContent = reviewResult.content[0];
4261
+ if (!diffContent || !reviewContent) throw new Error("Empty review response");
4262
+ const diffParsed = JSON.parse(diffContent.text);
4263
+ const reviewParsed = JSON.parse(reviewContent.text);
4264
+ const findings = [
4265
+ ...extractFindings(diffParsed, "findings", "warnings"),
4266
+ ...extractFindings(reviewParsed, "findings", "items")
4267
+ ];
4268
+ return {
4269
+ content: [
4270
+ {
4271
+ type: "text",
4272
+ text: JSON.stringify({
4273
+ depth: "standard",
4274
+ downgraded,
4275
+ findings,
4276
+ diffAnalysis: diffParsed,
4277
+ selfReview: reviewParsed,
4278
+ fileCount: extractFileCount(diffParsed),
4279
+ lineCount: diffLines
4280
+ })
4281
+ }
4282
+ ]
4283
+ };
4284
+ }
4285
+ async function runDeepReview(projectPath, diff, diffLines, _downgraded) {
4286
+ const { handleRunCodeReview: handleRunCodeReview2 } = await import("./review-pipeline-C4GCFVGP.js");
4287
+ const result = await handleRunCodeReview2({ path: projectPath, diff });
4288
+ const deepContent = result.content[0];
4289
+ if (!deepContent) throw new Error("Empty code review response");
4290
+ const parsed = JSON.parse(deepContent.text);
4291
+ return {
4292
+ content: [
4293
+ {
4294
+ type: "text",
4295
+ text: JSON.stringify({
4296
+ depth: "deep",
4297
+ downgraded: false,
4298
+ findings: parsed.findings ?? [],
4299
+ assessment: parsed.assessment,
4300
+ findingCount: parsed.findingCount,
4301
+ lineCount: diffLines,
4302
+ pipeline: parsed
4303
+ })
4304
+ }
4305
+ ]
4306
+ };
4307
+ }
4308
+ var DEPTH_HANDLERS = {
4309
+ quick: runQuickReview,
4310
+ standard: runStandardReview,
4311
+ deep: runDeepReview
4312
+ };
4094
4313
 
4095
4314
  // src/mcp/tools/task-independence.ts
4096
4315
  var checkTaskIndependenceDefinition = {
@@ -4135,7 +4354,7 @@ async function handleCheckTaskIndependence(input) {
4135
4354
  try {
4136
4355
  const projectPath = sanitizePath(input.path);
4137
4356
  const store = await loadGraphStore(projectPath);
4138
- const { TaskIndependenceAnalyzer } = await import("./dist-HXHWB7SV.js");
4357
+ const { TaskIndependenceAnalyzer } = await import("./dist-B26DFXMP.js");
4139
4358
  const analyzer = new TaskIndependenceAnalyzer(store ?? void 0);
4140
4359
  const result = analyzer.analyze({
4141
4360
  tasks: input.tasks,
@@ -4223,7 +4442,7 @@ async function handlePredictConflicts(input) {
4223
4442
  try {
4224
4443
  const projectPath = sanitizePath(input.path);
4225
4444
  const store = await loadGraphStore(projectPath);
4226
- const { ConflictPredictor } = await import("./dist-HXHWB7SV.js");
4445
+ const { ConflictPredictor } = await import("./dist-B26DFXMP.js");
4227
4446
  const predictor = new ConflictPredictor(store ?? void 0);
4228
4447
  const result = predictor.predict({
4229
4448
  tasks: input.tasks,
@@ -4329,7 +4548,7 @@ async function handleDetectStaleConstraints(input) {
4329
4548
  isError: true
4330
4549
  };
4331
4550
  }
4332
- const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-GJZ4FN4Y.js");
4551
+ const { loadGraphStore: loadGraphStore2 } = await import("./graph-loader-2M2HXDQI.js");
4333
4552
  const store = await loadGraphStore2(projectPath);
4334
4553
  if (!store) {
4335
4554
  return {
@@ -4350,7 +4569,7 @@ async function handleDetectStaleConstraints(input) {
4350
4569
  ]
4351
4570
  };
4352
4571
  }
4353
- const { detectStaleConstraints } = await import("./dist-2B363XUH.js");
4572
+ const { detectStaleConstraints } = await import("./dist-HWXF2C3R.js");
4354
4573
  const result = detectStaleConstraints(
4355
4574
  store,
4356
4575
  windowDays,
@@ -4607,6 +4826,45 @@ var RESOURCE_HANDLERS = {
4607
4826
  function getToolDefinitions() {
4608
4827
  return TOOL_DEFINITIONS;
4609
4828
  }
4829
+ function readConfigInterval(resolvedRoot) {
4830
+ try {
4831
+ const configResult = resolveProjectConfig(resolvedRoot);
4832
+ if (configResult.ok) {
4833
+ const raw = configResult.value.updateCheckInterval;
4834
+ if (typeof raw === "number" && Number.isInteger(raw) && raw >= 0) {
4835
+ return raw;
4836
+ }
4837
+ }
4838
+ } catch {
4839
+ }
4840
+ return void 0;
4841
+ }
4842
+ async function appendUpdateNotification(result, resolvedRoot) {
4843
+ try {
4844
+ const {
4845
+ getUpdateNotification,
4846
+ isUpdateCheckEnabled,
4847
+ shouldRunCheck,
4848
+ readCheckState,
4849
+ spawnBackgroundCheck
4850
+ } = await import("./dist-HWXF2C3R.js");
4851
+ const { CLI_VERSION } = await import("./version-KFFPOQAX.js");
4852
+ const configInterval = readConfigInterval(resolvedRoot);
4853
+ const DEFAULT_INTERVAL = 864e5;
4854
+ if (!isUpdateCheckEnabled(configInterval)) return;
4855
+ const state = readCheckState();
4856
+ if (shouldRunCheck(state, configInterval ?? DEFAULT_INTERVAL)) {
4857
+ spawnBackgroundCheck(CLI_VERSION);
4858
+ }
4859
+ const notification = getUpdateNotification(CLI_VERSION);
4860
+ if (notification) {
4861
+ result.content.push({ type: "text", text: `
4862
+ ---
4863
+ ${notification}` });
4864
+ }
4865
+ } catch {
4866
+ }
4867
+ }
4610
4868
  function createHarnessServer(projectRoot) {
4611
4869
  const resolvedRoot = projectRoot ?? process.cwd();
4612
4870
  let sessionChecked = false;
@@ -4626,42 +4884,7 @@ function createHarnessServer(projectRoot) {
4626
4884
  const result = await handler(args ?? {});
4627
4885
  if (!sessionChecked) {
4628
4886
  sessionChecked = true;
4629
- try {
4630
- const {
4631
- getUpdateNotification,
4632
- isUpdateCheckEnabled,
4633
- shouldRunCheck,
4634
- readCheckState,
4635
- spawnBackgroundCheck
4636
- } = await import("./dist-2B363XUH.js");
4637
- const { CLI_VERSION: version } = await import("./version-KFFPOQAX.js");
4638
- let CLI_VERSION = version;
4639
- let configInterval;
4640
- try {
4641
- const configResult = resolveProjectConfig(resolvedRoot);
4642
- if (configResult.ok) {
4643
- const raw = configResult.value.updateCheckInterval;
4644
- if (typeof raw === "number" && Number.isInteger(raw) && raw >= 0) {
4645
- configInterval = raw;
4646
- }
4647
- }
4648
- } catch {
4649
- }
4650
- const DEFAULT_INTERVAL = 864e5;
4651
- if (isUpdateCheckEnabled(configInterval)) {
4652
- const state = readCheckState();
4653
- if (shouldRunCheck(state, configInterval ?? DEFAULT_INTERVAL)) {
4654
- spawnBackgroundCheck(CLI_VERSION);
4655
- }
4656
- const notification = getUpdateNotification(CLI_VERSION);
4657
- if (notification) {
4658
- result.content.push({ type: "text", text: `
4659
- ---
4660
- ${notification}` });
4661
- }
4662
- }
4663
- } catch {
4664
- }
4887
+ await appendUpdateNotification(result, resolvedRoot);
4665
4888
  }
4666
4889
  return result;
4667
4890
  });
@@ -4690,6 +4913,8 @@ async function startServer() {
4690
4913
  }
4691
4914
 
4692
4915
  export {
4916
+ persistToolingConfig,
4917
+ appendFrameworkAgents,
4693
4918
  generateSlashCommands,
4694
4919
  handleOrphanDeletion,
4695
4920
  createGenerateSlashCommandsCommand,