@harness-engineering/cli 1.25.1 → 1.25.3

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startServer
4
- } from "../chunk-RX7TUMBR.js";
4
+ } from "../chunk-IAMXXLUT.js";
5
5
  import "../chunk-FES2YEQU.js";
6
6
  import "../chunk-UV3BZMGT.js";
7
7
  import "../chunk-F23H3U5U.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createProgram,
4
4
  printFirstRunWelcome
5
- } from "../chunk-CJXVNDZZ.js";
5
+ } from "../chunk-6WFSSYZG.js";
6
6
  import "../chunk-5BQ5BOJL.js";
7
7
  import "../chunk-EHRZMOQ2.js";
8
8
  import "../chunk-XTITAVUR.js";
@@ -19,7 +19,7 @@ import "../chunk-P7PANON5.js";
19
19
  import "../chunk-4NK7Z3BP.js";
20
20
  import {
21
21
  dispatchSkillsFromGit
22
- } from "../chunk-RX7TUMBR.js";
22
+ } from "../chunk-IAMXXLUT.js";
23
23
  import "../chunk-FES2YEQU.js";
24
24
  import "../chunk-UV3BZMGT.js";
25
25
  import "../chunk-F23H3U5U.js";
@@ -113,6 +113,96 @@ ${message}
113
113
  }
114
114
  }
115
115
 
116
+ // src/bin/command-telemetry.ts
117
+ import { existsSync, readFileSync, mkdirSync, appendFileSync, writeFileSync } from "fs";
118
+ import { join, parse as parsePath, resolve } from "path";
119
+ import { spawn } from "child_process";
120
+ var EXCLUDED_COMMANDS = /* @__PURE__ */ new Set(["help", "completion"]);
121
+ function findProjectRoot(cwd) {
122
+ let dir = resolve(cwd);
123
+ const { root } = parsePath(dir);
124
+ while (dir !== root) {
125
+ if (existsSync(join(dir, "harness.config.json"))) return dir;
126
+ dir = resolve(dir, "..");
127
+ }
128
+ return cwd;
129
+ }
130
+ var commandName = "";
131
+ var startTime = 0;
132
+ var recorded = false;
133
+ function installCommandTelemetry(program, cwd) {
134
+ if (typeof program.hook !== "function") return;
135
+ const projectRoot = findProjectRoot(cwd);
136
+ flushTelemetryBackground(projectRoot);
137
+ program.hook("preAction", (thisCommand) => {
138
+ commandName = resolveCommandName(thisCommand);
139
+ startTime = Date.now();
140
+ });
141
+ process.on("exit", (code) => {
142
+ if (recorded || !commandName || EXCLUDED_COMMANDS.has(commandName)) return;
143
+ recorded = true;
144
+ const duration = Date.now() - startTime;
145
+ const outcome = code === 0 ? "completed" : "failed";
146
+ writeCommandRecordSync(projectRoot, commandName, duration, outcome);
147
+ });
148
+ }
149
+ function resolveCommandName(cmd) {
150
+ const parts = [];
151
+ let current = cmd;
152
+ while (current) {
153
+ const name = current.name();
154
+ if (name && name !== "harness") {
155
+ parts.unshift(name);
156
+ }
157
+ current = current.parent;
158
+ }
159
+ return parts.length > 0 ? `cli/${parts.join(".")}` : "";
160
+ }
161
+ function writeCommandRecordSync(cwd, command, duration, outcome) {
162
+ try {
163
+ const metricsDir = join(cwd, ".harness", "metrics");
164
+ mkdirSync(metricsDir, { recursive: true });
165
+ const record = {
166
+ skill: command,
167
+ session: `cli-${Date.now()}`,
168
+ startedAt: new Date(Date.now() - duration).toISOString(),
169
+ duration,
170
+ outcome,
171
+ phasesReached: []
172
+ };
173
+ const adoptionFile = join(metricsDir, "adoption.jsonl");
174
+ appendFileSync(adoptionFile, JSON.stringify(record) + "\n");
175
+ } catch {
176
+ }
177
+ }
178
+ function flushTelemetryBackground(cwd) {
179
+ try {
180
+ const adoptionFile = join(cwd, ".harness", "metrics", "adoption.jsonl");
181
+ if (!existsSync(adoptionFile)) return;
182
+ const configPath = join(cwd, "harness.config.json");
183
+ if (existsSync(configPath)) {
184
+ try {
185
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
186
+ if (config?.telemetry?.enabled === false) return;
187
+ } catch {
188
+ }
189
+ }
190
+ if (process.env.DO_NOT_TRACK === "1") return;
191
+ if (process.env.HARNESS_TELEMETRY_OPTOUT === "1") return;
192
+ const reporterPath = join(cwd, ".harness", "hooks", "telemetry-reporter.js");
193
+ if (!existsSync(reporterPath)) return;
194
+ const child = spawn(process.execPath, [reporterPath], {
195
+ cwd,
196
+ stdio: ["pipe", "ignore", "ignore"],
197
+ detached: true
198
+ });
199
+ child.stdin?.write("{}");
200
+ child.stdin?.end();
201
+ child.unref();
202
+ } catch {
203
+ }
204
+ }
205
+
116
206
  // src/skill/dispatch-session.ts
117
207
  import { execSync } from "child_process";
118
208
  import fs from "fs";
@@ -211,6 +301,7 @@ async function main() {
211
301
  () => ({ dispatched: false })
212
302
  );
213
303
  const program = createProgram();
304
+ installCommandTelemetry(program, process.cwd());
214
305
  try {
215
306
  await program.parseAsync(process.argv);
216
307
  } catch (error) {
@@ -56,7 +56,7 @@ import {
56
56
  loadOrRebuildIndex,
57
57
  persistToolingConfig,
58
58
  recommend
59
- } from "./chunk-RX7TUMBR.js";
59
+ } from "./chunk-IAMXXLUT.js";
60
60
  import {
61
61
  findConfigFile,
62
62
  resolveConfig
@@ -3137,7 +3137,12 @@ function buildSettingsHooks(profile) {
3137
3137
  }
3138
3138
  hooks[script.event].push({
3139
3139
  matcher: script.matcher,
3140
- hooks: [{ type: "command", command: `node .harness/hooks/${script.name}.js` }]
3140
+ hooks: [
3141
+ {
3142
+ type: "command",
3143
+ command: `node "$(git rev-parse --show-toplevel)/.harness/hooks/${script.name}.js"`
3144
+ }
3145
+ ]
3141
3146
  });
3142
3147
  }
3143
3148
  return hooks;
@@ -3355,7 +3360,7 @@ function readJson(p) {
3355
3360
  }
3356
3361
  function registerHook(s, ev, matcher, name) {
3357
3362
  if (!s.hooks[ev]) s.hooks[ev] = [];
3358
- const cmd = `node .harness/hooks/${name}.js`;
3363
+ const cmd = `node "$(git rev-parse --show-toplevel)/.harness/hooks/${name}.js"`;
3359
3364
  if (!s.hooks[ev].some((e) => e.hooks?.some((h) => h.command === cmd))) {
3360
3365
  s.hooks[ev].push({ matcher, hooks: [{ type: "command", command: cmd }] });
3361
3366
  }
@@ -5418,7 +5423,7 @@ function createMcpCommand() {
5418
5423
  parseBudget
5419
5424
  ).action(async (opts) => {
5420
5425
  const [{ startServer: startServer2, getToolDefinitions: getToolDefinitions2 }, { selectTier }] = await Promise.all([
5421
- import("./mcp-2553PNUC.js"),
5426
+ import("./mcp-PMMA53ZX.js"),
5422
5427
  import("./tool-tiers-7QGZ3FKY.js")
5423
5428
  ]);
5424
5429
  if (opts.tools && opts.tools.length > 0) {
@@ -5444,7 +5449,7 @@ import * as path39 from "path";
5444
5449
  import { Orchestrator, WorkflowLoader, launchTUI } from "@harness-engineering/orchestrator";
5445
5450
  function createOrchestratorCommand() {
5446
5451
  const orchestrator = new Command47("orchestrator");
5447
- orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to WORKFLOW.md", "WORKFLOW.md").option("--headless", "Run without TUI (server-only mode for use with web dashboard)").action(async (opts) => {
5452
+ orchestrator.command("run").description("Run the orchestrator daemon").option("-w, --workflow <path>", "Path to harness.orchestrator.md", "harness.orchestrator.md").option("--headless", "Run without TUI (server-only mode for use with web dashboard)").action(async (opts) => {
5448
5453
  const workflowPath = path39.resolve(process.cwd(), opts.workflow);
5449
5454
  const loader = new WorkflowLoader();
5450
5455
  const result = await loader.loadWorkflow(workflowPath);
@@ -6272,6 +6277,18 @@ function prompt(question) {
6272
6277
  });
6273
6278
  });
6274
6279
  }
6280
+ function promptRaw(question) {
6281
+ const rl = readline.createInterface({
6282
+ input: process.stdin,
6283
+ output: process.stdout
6284
+ });
6285
+ return new Promise((resolve35) => {
6286
+ rl.question(question, (answer) => {
6287
+ rl.close();
6288
+ resolve35(answer.trim());
6289
+ });
6290
+ });
6291
+ }
6275
6292
  function isNo(answer) {
6276
6293
  return answer === "n" || answer === "no";
6277
6294
  }
@@ -6312,11 +6329,11 @@ async function promptIdentity() {
6312
6329
  const answer = await prompt(" Set identity fields? (y/N) ");
6313
6330
  const identity = {};
6314
6331
  if (answer === "y" || answer === "yes") {
6315
- const projectName = await prompt(" Project name: ");
6332
+ const projectName = await promptRaw(" Project name: ");
6316
6333
  if (projectName) identity.project = projectName;
6317
- const teamName = await prompt(" Team name: ");
6334
+ const teamName = await promptRaw(" Team name: ");
6318
6335
  if (teamName) identity.team = teamName;
6319
- const alias = await prompt(" Alias: ");
6336
+ const alias = await promptRaw(" Alias: ");
6320
6337
  if (alias) identity.alias = alias;
6321
6338
  }
6322
6339
  return identity;
@@ -122,6 +122,203 @@ import {
122
122
  ReadResourceRequestSchema
123
123
  } from "@modelcontextprotocol/sdk/types.js";
124
124
 
125
+ // src/templates/post-write.ts
126
+ import * as fs from "fs";
127
+ import * as path from "path";
128
+
129
+ // src/templates/agents-append.ts
130
+ var FRAMEWORK_SECTIONS = {
131
+ nextjs: {
132
+ title: "Next.js Conventions",
133
+ content: [
134
+ "- Use the App Router (`src/app/`) for all routes",
135
+ '- Server Components by default; add `"use client"` only when needed',
136
+ "- Use `next/image` for images and `next/link` for navigation",
137
+ "- API routes go in `src/app/api/`",
138
+ "- Run `next dev` for development, `next build` for production"
139
+ ].join("\n")
140
+ },
141
+ "react-vite": {
142
+ title: "React + Vite Conventions",
143
+ content: [
144
+ "- Component files use `.tsx` extension in `src/`",
145
+ "- Use Vite for dev server and bundling (`npm run dev`)",
146
+ "- Prefer function components with hooks",
147
+ "- CSS modules or styled-components for styling",
148
+ "- Tests use Vitest (`npm test`)"
149
+ ].join("\n")
150
+ },
151
+ vue: {
152
+ title: "Vue Conventions",
153
+ content: [
154
+ "- Single File Components (`.vue`) in `src/`",
155
+ "- Use `<script setup>` with Composition API",
156
+ "- Vite for dev server and bundling (`npm run dev`)",
157
+ "- Vue Router for routing, Pinia for state management",
158
+ "- Tests use Vitest (`npm test`)"
159
+ ].join("\n")
160
+ },
161
+ express: {
162
+ title: "Express Conventions",
163
+ content: [
164
+ "- Entry point at `src/app.ts`",
165
+ "- Routes in `src/routes/`, middleware in `src/middleware/`",
166
+ "- Use `express.json()` for body parsing",
167
+ "- Error handling via centralized error middleware",
168
+ "- Tests use Vitest with supertest (`npm test`)"
169
+ ].join("\n")
170
+ },
171
+ nestjs: {
172
+ title: "NestJS Conventions",
173
+ content: [
174
+ "- Module-based architecture: each feature in its own module",
175
+ "- Use decorators (`@Controller`, `@Injectable`, `@Module`)",
176
+ "- Entry point at `src/main.ts`, root module at `src/app.module.ts`",
177
+ "- Use Nest CLI for generating components (`nest g`)",
178
+ "- Tests use Vitest (`npm test`)"
179
+ ].join("\n")
180
+ },
181
+ fastapi: {
182
+ title: "FastAPI Conventions",
183
+ content: [
184
+ "- Entry point at `src/main.py` with FastAPI app instance",
185
+ "- Use Pydantic models for request/response validation",
186
+ "- Async endpoints preferred; sync is acceptable for CPU-bound work",
187
+ "- Run with `uvicorn src.main:app --reload` for development",
188
+ "- Tests use pytest (`pytest`)"
189
+ ].join("\n")
190
+ },
191
+ django: {
192
+ title: "Django Conventions",
193
+ content: [
194
+ "- Settings at `src/settings.py`, URLs at `src/urls.py`",
195
+ "- Use `manage.py` for management commands",
196
+ "- Apps in `src/` directory; each app has models, views, urls",
197
+ "- Run with `python manage.py runserver` for development",
198
+ "- Tests use pytest with pytest-django (`pytest`)"
199
+ ].join("\n")
200
+ },
201
+ gin: {
202
+ title: "Gin Conventions",
203
+ content: [
204
+ "- Entry point at `main.go` with Gin router setup",
205
+ "- Group routes by feature using `router.Group()`",
206
+ "- Use middleware for logging, auth, error recovery",
207
+ "- Run with `go run main.go` for development",
208
+ "- Tests use `go test ./...`"
209
+ ].join("\n")
210
+ },
211
+ axum: {
212
+ title: "Axum Conventions",
213
+ content: [
214
+ "- Entry point at `src/main.rs` with Axum router",
215
+ "- Use extractors for request parsing (`Path`, `Query`, `Json`)",
216
+ "- Shared state via `Extension` or `State`",
217
+ "- Run with `cargo run` for development",
218
+ "- Tests use `cargo test`"
219
+ ].join("\n")
220
+ },
221
+ "spring-boot": {
222
+ title: "Spring Boot Conventions",
223
+ content: [
224
+ "- Entry point annotated with `@SpringBootApplication`",
225
+ "- Controllers in `controller/` package, services in `service/`",
226
+ "- Use constructor injection for dependencies",
227
+ "- Run with `mvn spring-boot:run` for development",
228
+ "- Tests use JUnit 5 with Spring Boot Test (`mvn test`)"
229
+ ].join("\n")
230
+ }
231
+ };
232
+ function buildFrameworkSection(framework) {
233
+ const entry = FRAMEWORK_SECTIONS[framework];
234
+ if (!entry) return "";
235
+ return `## ${entry.title}
236
+
237
+ <!-- framework: ${framework} -->
238
+ ${entry.content}
239
+ `;
240
+ }
241
+ function appendFrameworkSection(existingContent, framework, _language) {
242
+ if (!framework) return existingContent;
243
+ const startMarker = `<!-- harness:framework-conventions:${framework} -->`;
244
+ const endMarker = `<!-- /harness:framework-conventions:${framework} -->`;
245
+ if (existingContent.includes(startMarker)) return existingContent;
246
+ const section = buildFrameworkSection(framework);
247
+ if (!section) return existingContent;
248
+ const block = `
249
+ ${startMarker}
250
+ ${section}${endMarker}
251
+ `;
252
+ return existingContent.trimEnd() + "\n" + block;
253
+ }
254
+
255
+ // src/templates/post-write.ts
256
+ function persistToolingConfig(targetDir, resolveResult, framework) {
257
+ const configPath = path.join(targetDir, "harness.config.json");
258
+ if (!fs.existsSync(configPath)) return;
259
+ try {
260
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
261
+ const overlayMeta = resolveResult.overlayMetadata;
262
+ if (framework) {
263
+ config.template = config.template || {};
264
+ config.template.framework = framework;
265
+ }
266
+ if (overlayMeta?.tooling) {
267
+ config.tooling = { ...config.tooling, ...overlayMeta.tooling };
268
+ delete config.tooling.lockFile;
269
+ } else if (resolveResult.metadata.tooling && !config.tooling) {
270
+ config.tooling = { ...resolveResult.metadata.tooling };
271
+ delete config.tooling.lockFile;
272
+ }
273
+ if (config.template?.level === null || config.template?.level === void 0) {
274
+ delete config.template.level;
275
+ }
276
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
277
+ } catch {
278
+ }
279
+ }
280
+ function ensureHarnessGitignore(targetDir) {
281
+ const gitignorePath = path.join(targetDir, ".harness", ".gitignore");
282
+ const content = `# Runtime artifacts (generated, ephemeral, session-scoped)
283
+ graph/
284
+ debug/
285
+ hooks/
286
+ security/
287
+ sessions/
288
+ state.json
289
+ state/
290
+ handoff.json
291
+ handoff-*.json
292
+ autopilot-state.json
293
+ session-taint-*.json
294
+ dispatch-last-head.txt
295
+ health-snapshot.json
296
+ release-readiness.json
297
+ skills-index.json
298
+ stack-profile.json
299
+ metrics/
300
+ events.jsonl
301
+ .install-id
302
+ telemetry.json
303
+ .telemetry-notice-shown
304
+ `;
305
+ fs.mkdirSync(path.dirname(gitignorePath), { recursive: true });
306
+ fs.writeFileSync(gitignorePath, content);
307
+ }
308
+ function appendFrameworkAgents(targetDir, framework, language) {
309
+ if (!framework) return;
310
+ const agentsPath = path.join(targetDir, "AGENTS.md");
311
+ if (!fs.existsSync(agentsPath)) return;
312
+ try {
313
+ const existing = fs.readFileSync(agentsPath, "utf-8");
314
+ const updated = appendFrameworkSection(existing, framework, language);
315
+ if (updated !== existing) {
316
+ fs.writeFileSync(agentsPath, updated);
317
+ }
318
+ } catch {
319
+ }
320
+ }
321
+
125
322
  // src/mcp/middleware/injection-guard.ts
126
323
  init_dist();
127
324
  import { realpathSync } from "fs";
@@ -402,204 +599,6 @@ async function handleValidateLinterConfig(input) {
402
599
  // src/mcp/tools/init.ts
403
600
  import * as path2 from "path";
404
601
  import * as fs2 from "fs";
405
-
406
- // src/templates/post-write.ts
407
- import * as fs from "fs";
408
- import * as path from "path";
409
-
410
- // src/templates/agents-append.ts
411
- var FRAMEWORK_SECTIONS = {
412
- nextjs: {
413
- title: "Next.js Conventions",
414
- content: [
415
- "- Use the App Router (`src/app/`) for all routes",
416
- '- Server Components by default; add `"use client"` only when needed',
417
- "- Use `next/image` for images and `next/link` for navigation",
418
- "- API routes go in `src/app/api/`",
419
- "- Run `next dev` for development, `next build` for production"
420
- ].join("\n")
421
- },
422
- "react-vite": {
423
- title: "React + Vite Conventions",
424
- content: [
425
- "- Component files use `.tsx` extension in `src/`",
426
- "- Use Vite for dev server and bundling (`npm run dev`)",
427
- "- Prefer function components with hooks",
428
- "- CSS modules or styled-components for styling",
429
- "- Tests use Vitest (`npm test`)"
430
- ].join("\n")
431
- },
432
- vue: {
433
- title: "Vue Conventions",
434
- content: [
435
- "- Single File Components (`.vue`) in `src/`",
436
- "- Use `<script setup>` with Composition API",
437
- "- Vite for dev server and bundling (`npm run dev`)",
438
- "- Vue Router for routing, Pinia for state management",
439
- "- Tests use Vitest (`npm test`)"
440
- ].join("\n")
441
- },
442
- express: {
443
- title: "Express Conventions",
444
- content: [
445
- "- Entry point at `src/app.ts`",
446
- "- Routes in `src/routes/`, middleware in `src/middleware/`",
447
- "- Use `express.json()` for body parsing",
448
- "- Error handling via centralized error middleware",
449
- "- Tests use Vitest with supertest (`npm test`)"
450
- ].join("\n")
451
- },
452
- nestjs: {
453
- title: "NestJS Conventions",
454
- content: [
455
- "- Module-based architecture: each feature in its own module",
456
- "- Use decorators (`@Controller`, `@Injectable`, `@Module`)",
457
- "- Entry point at `src/main.ts`, root module at `src/app.module.ts`",
458
- "- Use Nest CLI for generating components (`nest g`)",
459
- "- Tests use Vitest (`npm test`)"
460
- ].join("\n")
461
- },
462
- fastapi: {
463
- title: "FastAPI Conventions",
464
- content: [
465
- "- Entry point at `src/main.py` with FastAPI app instance",
466
- "- Use Pydantic models for request/response validation",
467
- "- Async endpoints preferred; sync is acceptable for CPU-bound work",
468
- "- Run with `uvicorn src.main:app --reload` for development",
469
- "- Tests use pytest (`pytest`)"
470
- ].join("\n")
471
- },
472
- django: {
473
- title: "Django Conventions",
474
- content: [
475
- "- Settings at `src/settings.py`, URLs at `src/urls.py`",
476
- "- Use `manage.py` for management commands",
477
- "- Apps in `src/` directory; each app has models, views, urls",
478
- "- Run with `python manage.py runserver` for development",
479
- "- Tests use pytest with pytest-django (`pytest`)"
480
- ].join("\n")
481
- },
482
- gin: {
483
- title: "Gin Conventions",
484
- content: [
485
- "- Entry point at `main.go` with Gin router setup",
486
- "- Group routes by feature using `router.Group()`",
487
- "- Use middleware for logging, auth, error recovery",
488
- "- Run with `go run main.go` for development",
489
- "- Tests use `go test ./...`"
490
- ].join("\n")
491
- },
492
- axum: {
493
- title: "Axum Conventions",
494
- content: [
495
- "- Entry point at `src/main.rs` with Axum router",
496
- "- Use extractors for request parsing (`Path`, `Query`, `Json`)",
497
- "- Shared state via `Extension` or `State`",
498
- "- Run with `cargo run` for development",
499
- "- Tests use `cargo test`"
500
- ].join("\n")
501
- },
502
- "spring-boot": {
503
- title: "Spring Boot Conventions",
504
- content: [
505
- "- Entry point annotated with `@SpringBootApplication`",
506
- "- Controllers in `controller/` package, services in `service/`",
507
- "- Use constructor injection for dependencies",
508
- "- Run with `mvn spring-boot:run` for development",
509
- "- Tests use JUnit 5 with Spring Boot Test (`mvn test`)"
510
- ].join("\n")
511
- }
512
- };
513
- function buildFrameworkSection(framework) {
514
- const entry = FRAMEWORK_SECTIONS[framework];
515
- if (!entry) return "";
516
- return `## ${entry.title}
517
-
518
- <!-- framework: ${framework} -->
519
- ${entry.content}
520
- `;
521
- }
522
- function appendFrameworkSection(existingContent, framework, _language) {
523
- if (!framework) return existingContent;
524
- const startMarker = `<!-- harness:framework-conventions:${framework} -->`;
525
- const endMarker = `<!-- /harness:framework-conventions:${framework} -->`;
526
- if (existingContent.includes(startMarker)) return existingContent;
527
- const section = buildFrameworkSection(framework);
528
- if (!section) return existingContent;
529
- const block = `
530
- ${startMarker}
531
- ${section}${endMarker}
532
- `;
533
- return existingContent.trimEnd() + "\n" + block;
534
- }
535
-
536
- // src/templates/post-write.ts
537
- function persistToolingConfig(targetDir, resolveResult, framework) {
538
- const configPath = path.join(targetDir, "harness.config.json");
539
- if (!fs.existsSync(configPath)) return;
540
- try {
541
- const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
542
- const overlayMeta = resolveResult.overlayMetadata;
543
- if (framework) {
544
- config.template = config.template || {};
545
- config.template.framework = framework;
546
- }
547
- if (overlayMeta?.tooling) {
548
- config.tooling = { ...config.tooling, ...overlayMeta.tooling };
549
- delete config.tooling.lockFile;
550
- } else if (resolveResult.metadata.tooling && !config.tooling) {
551
- config.tooling = { ...resolveResult.metadata.tooling };
552
- delete config.tooling.lockFile;
553
- }
554
- if (config.template?.level === null || config.template?.level === void 0) {
555
- delete config.template.level;
556
- }
557
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
558
- } catch {
559
- }
560
- }
561
- function ensureHarnessGitignore(targetDir) {
562
- const gitignorePath = path.join(targetDir, ".harness", ".gitignore");
563
- if (fs.existsSync(gitignorePath)) return;
564
- const content = `# Runtime artifacts (generated, ephemeral, session-scoped)
565
- graph/
566
- debug/
567
- sessions/
568
- state.json
569
- state/
570
- handoff.json
571
- handoff-*.json
572
- autopilot-state.json
573
- session-taint-*.json
574
- dispatch-last-head.txt
575
- health-snapshot.json
576
- release-readiness.json
577
- skills-index.json
578
- stack-profile.json
579
- metrics/
580
- events.jsonl
581
- .install-id
582
- telemetry.json
583
- .telemetry-notice-shown
584
- `;
585
- fs.mkdirSync(path.dirname(gitignorePath), { recursive: true });
586
- fs.writeFileSync(gitignorePath, content);
587
- }
588
- function appendFrameworkAgents(targetDir, framework, language) {
589
- if (!framework) return;
590
- const agentsPath = path.join(targetDir, "AGENTS.md");
591
- if (!fs.existsSync(agentsPath)) return;
592
- try {
593
- const existing = fs.readFileSync(agentsPath, "utf-8");
594
- const updated = appendFrameworkSection(existing, framework, language);
595
- if (updated !== existing) {
596
- fs.writeFileSync(agentsPath, updated);
597
- }
598
- } catch {
599
- }
600
- }
601
-
602
- // src/mcp/tools/init.ts
603
602
  var initProjectDefinition = {
604
603
  name: "init_project",
605
604
  description: "Scaffold a new harness engineering project from a template",
@@ -7512,6 +7511,7 @@ async function handleReadResource(uri, resolvedRoot) {
7512
7511
  }
7513
7512
  function createHarnessServer(projectRoot, toolFilter) {
7514
7513
  const resolvedRoot = projectRoot ?? process.cwd();
7514
+ ensureHarnessGitignore(resolvedRoot);
7515
7515
  const { definitions, handlers } = buildFilteredTools(toolFilter);
7516
7516
  const trustedOutputTools = new Set(
7517
7517
  definitions.filter((t) => t.trustedOutput === true).map((t) => t.name)
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  runSnapshotCapture,
13
13
  runUninstall,
14
14
  runUninstallConstraints
15
- } from "./chunk-CJXVNDZZ.js";
15
+ } from "./chunk-6WFSSYZG.js";
16
16
  import {
17
17
  generateAgentsMd
18
18
  } from "./chunk-5BQ5BOJL.js";
@@ -66,7 +66,7 @@ import {
66
66
  generateSlashCommands,
67
67
  getToolDefinitions,
68
68
  startServer
69
- } from "./chunk-RX7TUMBR.js";
69
+ } from "./chunk-IAMXXLUT.js";
70
70
  import "./chunk-FES2YEQU.js";
71
71
  import "./chunk-UV3BZMGT.js";
72
72
  import "./chunk-F23H3U5U.js";
@@ -2,7 +2,7 @@ import {
2
2
  createHarnessServer,
3
3
  getToolDefinitions,
4
4
  startServer
5
- } from "./chunk-RX7TUMBR.js";
5
+ } from "./chunk-IAMXXLUT.js";
6
6
  import "./chunk-FES2YEQU.js";
7
7
  import "./chunk-UV3BZMGT.js";
8
8
  import "./chunk-F23H3U5U.js";
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrator",
3
- "description": "Standard WORKFLOW.md for the Harness Orchestrator",
3
+ "description": "Standard harness.orchestrator.md for the Harness Orchestrator",
4
4
  "level": "basic",
5
5
  "extends": "base",
6
6
  "version": 1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/cli",
3
- "version": "1.25.1",
3
+ "version": "1.25.3",
4
4
  "description": "CLI for Harness Engineering toolkit",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,11 +38,11 @@
38
38
  "yaml": "^2.8.3",
39
39
  "zod": "^3.25.76",
40
40
  "@harness-engineering/core": "0.22.0",
41
- "@harness-engineering/dashboard": "0.1.5",
42
41
  "@harness-engineering/graph": "0.4.3",
43
- "@harness-engineering/orchestrator": "0.2.8",
44
42
  "@harness-engineering/linter-gen": "0.1.6",
45
- "@harness-engineering/types": "0.9.2"
43
+ "@harness-engineering/orchestrator": "0.2.9",
44
+ "@harness-engineering/types": "0.9.2",
45
+ "@harness-engineering/dashboard": "0.1.5"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^22.19.15",