@glrs-dev/cli 2.0.1 → 2.2.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 (48) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/chunk-SB3MLROC.js +113 -0
  3. package/dist/cli.js +21 -0
  4. package/dist/lib/auto-update.d.ts +23 -0
  5. package/dist/lib/auto-update.js +7 -0
  6. package/dist/vendor/harness-opencode/dist/agents/prompts/build.md +18 -4
  7. package/dist/vendor/harness-opencode/dist/agents/prompts/build.open.md +18 -4
  8. package/dist/vendor/harness-opencode/dist/agents/prompts/{qa-thorough.md → code-reviewer-thorough.md} +34 -19
  9. package/dist/vendor/harness-opencode/dist/agents/prompts/code-reviewer.md +80 -0
  10. package/dist/vendor/harness-opencode/dist/agents/prompts/code-reviewer.open.md +68 -0
  11. package/dist/vendor/harness-opencode/dist/agents/prompts/gap-analyzer.md +2 -0
  12. package/dist/vendor/harness-opencode/dist/agents/prompts/plan-reviewer.md +3 -0
  13. package/dist/vendor/harness-opencode/dist/agents/prompts/plan.md +23 -4
  14. package/dist/vendor/harness-opencode/dist/agents/prompts/prime.md +146 -87
  15. package/dist/vendor/harness-opencode/dist/agents/prompts/research-auto.md +1 -1
  16. package/dist/vendor/harness-opencode/dist/agents/prompts/research-local.md +1 -1
  17. package/dist/vendor/harness-opencode/dist/agents/prompts/research-web.md +1 -1
  18. package/dist/vendor/harness-opencode/dist/agents/prompts/research.md +2 -0
  19. package/dist/vendor/harness-opencode/dist/agents/prompts/spec-reviewer.md +54 -0
  20. package/dist/vendor/harness-opencode/dist/agents/prompts/spec-reviewer.open.md +57 -0
  21. package/dist/vendor/harness-opencode/dist/agents/shared/index.ts +1 -0
  22. package/dist/vendor/harness-opencode/dist/agents/shared/ui-evaluation-ladder.md +50 -0
  23. package/dist/vendor/harness-opencode/dist/agents/shared/workflow-mechanics.md +5 -5
  24. package/dist/vendor/harness-opencode/dist/autopilot/prompt-template.md +80 -0
  25. package/dist/vendor/harness-opencode/dist/{chunk-VJUETC6A.js → chunk-PDMXYZM4.js} +53 -1
  26. package/dist/vendor/harness-opencode/dist/cli.js +1333 -1646
  27. package/dist/vendor/harness-opencode/dist/commands/prompts/fresh.md +27 -24
  28. package/dist/vendor/harness-opencode/dist/commands/prompts/review.md +3 -3
  29. package/dist/vendor/harness-opencode/dist/commands/prompts/ship.md +2 -0
  30. package/dist/vendor/harness-opencode/dist/index.js +106 -627
  31. package/dist/vendor/harness-opencode/dist/skills/adversarial-review-rubric/SKILL.md +47 -0
  32. package/dist/vendor/harness-opencode/dist/skills/code-quality/SKILL.md +1 -1
  33. package/dist/vendor/harness-opencode/dist/skills/root-cause-diagnosis/SKILL.md +24 -0
  34. package/dist/vendor/harness-opencode/dist/skills/spear-protocol/SKILL.md +166 -0
  35. package/dist/vendor/harness-opencode/package.json +1 -1
  36. package/package.json +1 -1
  37. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-assessor.md +0 -77
  38. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-builder.md +0 -40
  39. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-planner.md +0 -56
  40. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-scoper.md +0 -58
  41. package/dist/vendor/harness-opencode/dist/agents/prompts/qa-reviewer.md +0 -68
  42. package/dist/vendor/harness-opencode/dist/agents/prompts/qa-reviewer.open.md +0 -58
  43. package/dist/vendor/harness-opencode/dist/chunk-6CZPRUMJ.js +0 -869
  44. package/dist/vendor/harness-opencode/dist/chunk-DZG4D3OH.js +0 -54
  45. package/dist/vendor/harness-opencode/dist/chunk-OYRKOEXK.js +0 -88
  46. package/dist/vendor/harness-opencode/dist/commands/prompts/autopilot.md +0 -96
  47. package/dist/vendor/harness-opencode/dist/install-6775ZBDG.js +0 -13
  48. package/dist/vendor/harness-opencode/dist/paths-WZ23ZQOV.js +0 -18
@@ -1,12 +1,10 @@
1
- import {
2
- formatModelOverrideWarning,
3
- validateModelOverride
4
- } from "./chunk-DZG4D3OH.js";
5
1
  import {
6
2
  PACKAGE_NAME,
3
+ formatModelOverrideWarning,
7
4
  readOurPackageVersion,
8
- refreshPluginCache
9
- } from "./chunk-VJUETC6A.js";
5
+ refreshPluginCache,
6
+ validateModelOverride
7
+ } from "./chunk-PDMXYZM4.js";
10
8
 
11
9
  // src/config-hook.ts
12
10
  import * as fs from "fs";
@@ -36,6 +34,7 @@ function readMd(name) {
36
34
  throw new Error(`Could not find shared file: ${name}`);
37
35
  }
38
36
  var WORKFLOW_MECHANICS_RULE = readMd("workflow-mechanics.md");
37
+ var UI_EVALUATION_LADDER = readMd("ui-evaluation-ladder.md");
39
38
 
40
39
  // src/agents/index.ts
41
40
  import { readFileSync as readFileSync2 } from "fs";
@@ -63,9 +62,11 @@ var primePrompt = readPrompt("prime.md");
63
62
  var planPrompt = readPrompt("plan.md");
64
63
  var buildPrompt = readPrompt("build.md");
65
64
  var buildOpenPrompt = readPrompt("build.open.md");
66
- var qaReviewerPrompt = readPrompt("qa-reviewer.md");
67
- var qaReviewerOpenPrompt = readPrompt("qa-reviewer.open.md");
68
- var qaThoroughPrompt = readPrompt("qa-thorough.md");
65
+ var specReviewerPrompt = readPrompt("spec-reviewer.md");
66
+ var specReviewerOpenPrompt = readPrompt("spec-reviewer.open.md");
67
+ var codeReviewerPrompt = readPrompt("code-reviewer.md");
68
+ var codeReviewerOpenPrompt = readPrompt("code-reviewer.open.md");
69
+ var codeReviewerThoroughPrompt = readPrompt("code-reviewer-thorough.md");
69
70
  var planReviewerPrompt = readPrompt("plan-reviewer.md");
70
71
  var codeSearcherPrompt = readPrompt("code-searcher.md");
71
72
  var gapAnalyzerPrompt = readPrompt("gap-analyzer.md");
@@ -73,18 +74,14 @@ var architectureAdvisorPrompt = readPrompt("architecture-advisor.md");
73
74
  var docsMaintainerPrompt = readPrompt("docs-maintainer.md");
74
75
  var libReaderPrompt = readPrompt("lib-reader.md");
75
76
  var agentsMdWriterPrompt = readPrompt("agents-md-writer.md");
76
- var pilotScopePrompt = readPrompt("pilot-scoper.md");
77
- var pilotPlannerPrompt = readPrompt("pilot-planner.md");
78
- var pilotBuilderPrompt = readPrompt("pilot-builder.md");
79
- var pilotAssessorPrompt = readPrompt("pilot-assessor.md");
80
77
  var researchPrompt = readPrompt("research.md");
81
78
  var researchWebPrompt = readPrompt("research-web.md");
82
79
  var researchLocalPrompt = readPrompt("research-local.md");
83
80
  var researchAutoPrompt = readPrompt("research-auto.md");
84
81
  var EXECUTOR_VARIANT_AGENTS = {
85
82
  build: { reasoning: buildPrompt, strict: buildOpenPrompt },
86
- "qa-reviewer": { reasoning: qaReviewerPrompt, strict: qaReviewerOpenPrompt },
87
- "pilot-builder": { reasoning: pilotBuilderPrompt, strict: pilotBuilderPrompt }
83
+ "spec-reviewer": { reasoning: specReviewerPrompt, strict: specReviewerOpenPrompt },
84
+ "code-reviewer": { reasoning: codeReviewerPrompt, strict: codeReviewerOpenPrompt }
88
85
  };
89
86
  function getStrictPrompt(agentName) {
90
87
  const variants = EXECUTOR_VARIANT_AGENTS[agentName];
@@ -135,10 +132,13 @@ function parseFrontmatter(md) {
135
132
  function injectWorkflowMechanics(prompt) {
136
133
  return prompt.replace("{WORKFLOW_MECHANICS_RULE}", WORKFLOW_MECHANICS_RULE);
137
134
  }
135
+ function injectUIEvaluationLadder(prompt) {
136
+ return prompt.replace("{UI_EVALUATION_LADDER}", UI_EVALUATION_LADDER);
137
+ }
138
138
  function agentFromPrompt(raw, overrides = {}) {
139
139
  const fm = parseFrontmatter(raw);
140
140
  const body = stripFrontmatter(raw);
141
- const prompt = injectWorkflowMechanics(body);
141
+ const prompt = injectUIEvaluationLadder(injectWorkflowMechanics(body));
142
142
  const base = {
143
143
  description: fm["description"] ?? "",
144
144
  mode: fm["mode"] ?? "subagent",
@@ -214,7 +214,7 @@ var CORE_BASH_ALLOW_LIST = {
214
214
  "eslint *": "allow",
215
215
  "prettier *": "allow",
216
216
  "biome *": "allow",
217
- // Our own CLI — the plan agent and qa-reviewer both call plan-check/plan-dir.
217
+ // Our own CLI — the plan agent and assessor both call plan-check/plan-dir.
218
218
  "bunx @glrs-dev/harness-plugin-opencode *": "allow",
219
219
  "glrs-oc *": "allow",
220
220
  // GitHub CLI — read-only gh calls are fine; destructive `gh pr merge`
@@ -295,7 +295,7 @@ var PLAN_PERMISSIONS = {
295
295
  serena: "allow",
296
296
  memory: "allow",
297
297
  git: "allow",
298
- playwright: "deny",
298
+ playwright: "allow",
299
299
  linear: "allow"
300
300
  };
301
301
  var BUILD_PERMISSIONS = {
@@ -323,15 +323,28 @@ var BUILD_PERMISSIONS = {
323
323
  playwright: "allow",
324
324
  linear: "allow"
325
325
  };
326
- var QA_REVIEWER_PERMISSIONS = {
326
+ var SPEC_REVIEWER_PERMISSIONS = {
327
+ edit: "deny",
328
+ bash: {
329
+ "*": "allow",
330
+ ...CORE_BASH_ALLOW_LIST,
331
+ ...CORE_DESTRUCTIVE_BASH_DENIES
332
+ },
333
+ webfetch: "deny",
334
+ ast_grep: "allow",
335
+ tsc_check: "allow",
336
+ eslint_check: "allow",
337
+ todo_scan: "allow",
338
+ comment_check: "allow",
339
+ question: "allow",
340
+ serena: "allow",
341
+ memory: "deny",
342
+ git: "allow",
343
+ playwright: "allow",
344
+ linear: "deny"
345
+ };
346
+ var CODE_REVIEWER_PERMISSIONS = {
327
347
  edit: "deny",
328
- // Object-form bash: the scalar `"allow"` shape loses to OpenCode's
329
- // upstream subagent-default `{bash, *, ask}` via last-match-wins (see
330
- // the root-cause comment near PRIME_PERMISSIONS). Enumerated
331
- // specific patterns in CORE_BASH_ALLOW_LIST sort AFTER the upstream
332
- // wildcard ask and win for the commands they match. `"*": "allow"`
333
- // is kept as a backstop but may still lose to the upstream rule for
334
- // commands not in the enumerated list; those are the known blind spot.
335
348
  bash: {
336
349
  "*": "allow",
337
350
  ...CORE_BASH_ALLOW_LIST,
@@ -350,12 +363,8 @@ var QA_REVIEWER_PERMISSIONS = {
350
363
  playwright: "allow",
351
364
  linear: "deny"
352
365
  };
353
- var QA_THOROUGH_PERMISSIONS = {
366
+ var CODE_REVIEWER_THOROUGH_PERMISSIONS = {
354
367
  edit: "deny",
355
- // Same object-form as QA_REVIEWER_PERMISSIONS — see the shape rationale
356
- // there. qa-thorough re-runs the full suite unconditionally (per its
357
- // prompt), so it touches the same command surface as qa-reviewer and
358
- // needs the identical bash allow-list.
359
368
  bash: {
360
369
  "*": "allow",
361
370
  ...CORE_BASH_ALLOW_LIST,
@@ -403,7 +412,7 @@ var GAP_ANALYZER_PERMISSIONS = {
403
412
  serena: "allow",
404
413
  memory: "allow",
405
414
  git: "deny",
406
- playwright: "deny",
415
+ playwright: "allow",
407
416
  linear: "allow"
408
417
  };
409
418
  var CODE_SEARCHER_PERMISSIONS = {
@@ -488,13 +497,12 @@ var RESEARCH_PERMISSIONS = {
488
497
  serena: "allow",
489
498
  memory: "allow",
490
499
  git: "allow",
491
- playwright: "deny",
500
+ playwright: "allow",
492
501
  linear: "allow"
493
502
  };
494
503
  var AGENT_TIERS = {
495
504
  prime: "deep",
496
505
  plan: "deep",
497
- "qa-thorough": "deep",
498
506
  "architecture-advisor": "deep",
499
507
  "plan-reviewer": "deep",
500
508
  "gap-analyzer": "deep",
@@ -502,138 +510,15 @@ var AGENT_TIERS = {
502
510
  "research-web": "deep",
503
511
  "research-local": "deep",
504
512
  "research-auto": "deep",
505
- // Pilot v2 agents
506
- "pilot-scoper": "mid",
507
- "pilot-planner": "mid",
508
- "pilot-builder": "mid-execute",
509
- "pilot-assessor": "mid",
510
513
  build: "mid-execute",
511
- "qa-reviewer": "mid-execute",
514
+ "spec-reviewer": "mid-execute",
515
+ "code-reviewer": "mid-execute",
516
+ "code-reviewer-thorough": "deep",
512
517
  "docs-maintainer": "mid",
513
518
  "lib-reader": "mid",
514
519
  "agents-md-writer": "mid",
515
520
  "code-searcher": "fast"
516
521
  };
517
- var PILOT_SCOPER_PERMISSIONS = {
518
- edit: "deny",
519
- bash: {
520
- "*": "deny",
521
- "ls *": "allow",
522
- "cat *": "allow",
523
- "head *": "allow",
524
- "tail *": "allow",
525
- "wc *": "allow",
526
- "grep *": "allow",
527
- "rg *": "allow",
528
- "find *": "allow",
529
- "git status *": "allow",
530
- "git log *": "allow",
531
- "git diff *": "allow",
532
- "git show *": "allow",
533
- "git branch *": "allow",
534
- "git rev-parse *": "allow"
535
- },
536
- webfetch: "deny",
537
- ast_grep: "allow",
538
- tsc_check: "deny",
539
- eslint_check: "deny",
540
- todo_scan: "allow",
541
- comment_check: "allow",
542
- question: "allow",
543
- serena: "allow",
544
- memory: "deny",
545
- git: "allow",
546
- playwright: "deny",
547
- linear: "deny"
548
- };
549
- var PILOT_PLANNER_PERMISSIONS = {
550
- edit: "allow",
551
- bash: {
552
- "*": "deny",
553
- "ls *": "allow",
554
- "cat *": "allow",
555
- "head *": "allow",
556
- "tail *": "allow",
557
- "wc *": "allow",
558
- "grep *": "allow",
559
- "rg *": "allow",
560
- "find *": "allow",
561
- "git status *": "allow",
562
- "git log *": "allow",
563
- "git diff *": "allow",
564
- "git show *": "allow",
565
- "git branch *": "allow",
566
- "git rev-parse *": "allow"
567
- },
568
- webfetch: "deny",
569
- ast_grep: "allow",
570
- tsc_check: "deny",
571
- eslint_check: "deny",
572
- todo_scan: "allow",
573
- comment_check: "allow",
574
- question: "deny",
575
- serena: "allow",
576
- memory: "deny",
577
- git: "allow",
578
- playwright: "deny",
579
- linear: "deny"
580
- };
581
- var PILOT_BUILDER_PERMISSIONS = {
582
- edit: "allow",
583
- bash: {
584
- "*": "allow",
585
- ...CORE_BASH_ALLOW_LIST,
586
- ...CORE_DESTRUCTIVE_BASH_DENIES,
587
- "git commit*": "deny",
588
- "git push*": "deny",
589
- "git tag*": "deny",
590
- "git checkout *": "deny",
591
- "git switch *": "deny",
592
- "git branch *": "deny",
593
- "git restore --source*": "deny",
594
- "git reset *": "deny",
595
- "gh pr *": "deny",
596
- "gh release *": "deny"
597
- },
598
- webfetch: "allow",
599
- ast_grep: "allow",
600
- tsc_check: "allow",
601
- eslint_check: "allow",
602
- todo_scan: "allow",
603
- comment_check: "allow",
604
- question: "deny",
605
- serena: "allow",
606
- memory: "deny",
607
- git: "allow",
608
- playwright: "deny",
609
- linear: "deny"
610
- };
611
- var PILOT_ASSESSOR_PERMISSIONS = {
612
- edit: "allow",
613
- bash: {
614
- "*": "allow",
615
- ...CORE_BASH_ALLOW_LIST,
616
- ...CORE_DESTRUCTIVE_BASH_DENIES,
617
- "git commit*": "deny",
618
- "git push*": "deny",
619
- "git checkout *": "deny",
620
- "git switch *": "deny",
621
- "git reset *": "deny",
622
- "gh pr *": "deny"
623
- },
624
- webfetch: "deny",
625
- ast_grep: "allow",
626
- tsc_check: "allow",
627
- eslint_check: "allow",
628
- todo_scan: "allow",
629
- comment_check: "allow",
630
- question: "deny",
631
- serena: "allow",
632
- memory: "deny",
633
- git: "allow",
634
- playwright: "allow",
635
- linear: "deny"
636
- };
637
522
  function createAgents() {
638
523
  return {
639
524
  // Primary agents
@@ -661,11 +546,14 @@ function createAgents() {
661
546
  // Subagents — model/mode/description from frontmatter, permissions
662
547
  // via overrides (see permission blocks above). docs-maintainer has no
663
548
  // frontmatter permission declaration and keeps that behavior.
664
- "qa-reviewer": agentFromPrompt(qaReviewerPrompt, {
665
- permission: QA_REVIEWER_PERMISSIONS
549
+ "spec-reviewer": agentFromPrompt(specReviewerPrompt, {
550
+ permission: SPEC_REVIEWER_PERMISSIONS
551
+ }),
552
+ "code-reviewer": agentFromPrompt(codeReviewerPrompt, {
553
+ permission: CODE_REVIEWER_PERMISSIONS
666
554
  }),
667
- "qa-thorough": agentFromPrompt(qaThoroughPrompt, {
668
- permission: QA_THOROUGH_PERMISSIONS
555
+ "code-reviewer-thorough": agentFromPrompt(codeReviewerThoroughPrompt, {
556
+ permission: CODE_REVIEWER_THOROUGH_PERMISSIONS
669
557
  }),
670
558
  "plan-reviewer": agentFromPrompt(planReviewerPrompt, {
671
559
  permission: PLAN_REVIEWER_PERMISSIONS
@@ -694,56 +582,30 @@ function createAgents() {
694
582
  temperature: 0.3,
695
583
  permission: RESEARCH_PERMISSIONS
696
584
  }),
697
- // Research subagents — thin shims that load the bundled skills
585
+ // Research subagents — thin shims that load the bundled skills.
586
+ // mode: "subagent" — these are internal implementation details of
587
+ // @research's orchestration; users should invoke @research (mode:all)
588
+ // as the primary entry point, not these directly.
698
589
  "research-web": agentFromPrompt(researchWebPrompt, {
699
590
  description: "Research orchestrator subagent \u2014 Multi-agent web research orchestrator. Decomposes a research question into parallel agent workstreams, launches them, monitors progress, and synthesizes results. Use when user says 'research this topic', 'I need to understand', 'deep dive into', 'investigate the market for', 'what do we know about'. Provide the research topic and context.",
700
- mode: "all",
591
+ mode: "subagent",
701
592
  model: "anthropic/claude-opus-4-7",
702
593
  temperature: 0.3,
703
594
  permission: RESEARCH_PERMISSIONS
704
595
  }),
705
596
  "research-local": agentFromPrompt(researchLocalPrompt, {
706
597
  description: "Research orchestrator subagent \u2014 Deep codebase research using parallel Explore subagents. Decomposes a question about the local codebase into research tasks, launches parallel explorations, reviews for gaps, iterates, and synthesizes findings with specific file paths and line numbers. Use when user says 'how does X work in this codebase', 'where is Y implemented', 'trace the data flow for Z', 'what patterns does this repo use', 'explain the architecture of'. Provide the research topic as arguments.",
707
- mode: "all",
598
+ mode: "subagent",
708
599
  model: "anthropic/claude-opus-4-7",
709
600
  temperature: 0.3,
710
601
  permission: RESEARCH_PERMISSIONS
711
602
  }),
712
603
  "research-auto": agentFromPrompt(researchAutoPrompt, {
713
604
  description: "Research orchestrator subagent \u2014 Autonomous experimentation skill. Agent interviews the user, sets up a lab, then explores freely (think, test, reflect) until stopped or a target is hit. Works for any domain where you can measure or evaluate a result. Use when user says 'optimize this', 'experiment with', 'find the best approach', 'iterate on', 'research mode'. Do NOT use for binary validation tests (use /spec-lab instead). Based on ResearcherSkill v1.4.4 by krzysztofdudek.",
714
- mode: "all",
605
+ mode: "subagent",
715
606
  model: "anthropic/claude-opus-4-7",
716
607
  temperature: 0.3,
717
608
  permission: RESEARCH_PERMISSIONS
718
- }),
719
- // Pilot v2 agents (SPEAR-based autonomous execution)
720
- "pilot-scoper": agentFromPrompt(pilotScopePrompt, {
721
- description: "Pilot v2 scoping agent. Interviews the user to understand their goal, explores the codebase, and produces a scope.json artifact with framing and acceptance criteria.",
722
- mode: "subagent",
723
- model: "anthropic/claude-sonnet-4-6",
724
- temperature: 0.3,
725
- permission: PILOT_SCOPER_PERMISSIONS
726
- }),
727
- "pilot-planner": agentFromPrompt(pilotPlannerPrompt, {
728
- description: "Pilot v2 planning agent. Reads scope.json, surveys the codebase, and produces a plan.json with an ordered task list.",
729
- mode: "subagent",
730
- model: "anthropic/claude-sonnet-4-6",
731
- temperature: 0.2,
732
- permission: PILOT_PLANNER_PERMISSIONS
733
- }),
734
- "pilot-builder": agentFromPrompt(pilotBuilderPrompt, {
735
- description: "Pilot v2 builder agent. Executes a single task from the plan. Makes code changes, runs verify commands, and signals completion.",
736
- mode: "subagent",
737
- model: "anthropic/claude-sonnet-4-6",
738
- temperature: 0.1,
739
- permission: PILOT_BUILDER_PERMISSIONS
740
- }),
741
- "pilot-assessor": agentFromPrompt(pilotAssessorPrompt, {
742
- description: "Pilot v2 assessor agent. Evaluates completed work against acceptance criteria, runs deployment-risk reflection, and produces an assessment report.",
743
- mode: "subagent",
744
- model: "anthropic/claude-sonnet-4-6",
745
- temperature: 0.2,
746
- permission: PILOT_ASSESSOR_PERMISSIONS
747
609
  })
748
610
  };
749
611
  }
@@ -770,7 +632,6 @@ function readPrompt2(name) {
770
632
  }
771
633
  throw new Error(`Could not find command prompt: ${name}`);
772
634
  }
773
- var autopilotPrompt = readPrompt2("autopilot.md");
774
635
  var shipPrompt = readPrompt2("ship.md");
775
636
  var reviewPrompt = readPrompt2("review.md");
776
637
  var initDeepPrompt = readPrompt2("init-deep.md");
@@ -779,10 +640,6 @@ var freshPrompt = readPrompt2("fresh.md");
779
640
  var costsPrompt = readPrompt2("costs.md");
780
641
  function createCommands() {
781
642
  return {
782
- autopilot: {
783
- template: autopilotPrompt,
784
- description: "Self-driving run. Pass a ticket ref (any tracker), a task description, or a question."
785
- },
786
643
  ship: {
787
644
  template: shipPrompt,
788
645
  description: "Finalize, commit, push, and open a PR/MR. Human-gated at each step."
@@ -927,7 +784,7 @@ function resolveHarnessModels(agents, config, pluginOptions) {
927
784
  }
928
785
  }
929
786
  if (midExecuteConfigured) {
930
- const EXECUTOR_AGENTS = ["build", "qa-reviewer", "pilot-builder"];
787
+ const EXECUTOR_AGENTS = ["build", "spec-reviewer", "code-reviewer"];
931
788
  for (const agentName of EXECUTOR_AGENTS) {
932
789
  const agentCfg = agents[agentName];
933
790
  if (!agentCfg) continue;
@@ -1492,311 +1349,8 @@ function loadDotenv(directory) {
1492
1349
  return { filesLoaded, varsSet };
1493
1350
  }
1494
1351
 
1495
- // src/plugins/autopilot.ts
1496
- import { execFile as execFileCb } from "child_process";
1497
- import * as fs3 from "fs/promises";
1498
- import * as path3 from "path";
1499
- import { promisify as promisify6 } from "util";
1500
- var STATE_PATH = ".agent/autopilot-state.json";
1501
- var KILL_SWITCH_PATH = ".agent/autopilot-disable";
1502
- var MAX_ITERATIONS = 20;
1503
- var TARGET_AGENTS = /* @__PURE__ */ new Set(["build", "prime"]);
1504
- var MESSAGE_LIMIT = 40;
1505
- var NUDGE_DEBOUNCE_MS = 3e4;
1506
- var PR_CACHE_MS = 5 * 60 * 1e3;
1507
- var MAX_CONSECUTIVE_STOPS = 2;
1508
- var UMBRELLA_MIN_BYTES = 5e4;
1509
- var UMBRELLA_MIN_LINEAR_IDS = 3;
1510
- var AUTOPILOT_MARKER_RE = /(^|\s)\/autopilot(\s|$)|AUTOPILOT mode/;
1511
- var OPT_OUT_RE = /<!--\s*autopilot:\s*(skip|false)\s*-->/i;
1512
- var UMBRELLA_SECTION_RE = /^##\s+(Chunks|Milestones|Workstreams)\b/m;
1513
- var LINEAR_ID_RE = /\b[A-Z]{2,10}-\d+\b/g;
1514
- var MEASUREMENT_GATE_RE = /\b(7-day|production window|post-deploy|post-launch|SLO|success rate reaches|after deploy|bake time)\b/i;
1515
- var STOP_REPORT_RE = /^STOP[:.\s—]/m;
1516
- var NUDGE_TEXT = "[autopilot] Session idled with unchecked acceptance criteria. Re-read the plan, do the most important unchecked item, check its box when done, then move to the next. When all boxes are `[x]`, print the Phase 5 handoff and stop \u2014 the user runs `/ship` manually.";
1517
- var MAX_ITERATIONS_TEXT = `[autopilot] Stopped: hit max iterations (${MAX_ITERATIONS}). Either the work is complete or the loop is stuck. Review and resume manually; a new \`/autopilot\` session will re-enable nudges.`;
1518
- async function readState(dir) {
1519
- try {
1520
- const raw = await fs3.readFile(path3.join(dir, STATE_PATH), "utf8");
1521
- const parsed = JSON.parse(raw);
1522
- return { sessions: parsed.sessions ?? {} };
1523
- } catch {
1524
- return { sessions: {} };
1525
- }
1526
- }
1527
- async function writeState(dir, state) {
1528
- const p = path3.join(dir, STATE_PATH);
1529
- await fs3.mkdir(path3.dirname(p), { recursive: true });
1530
- await fs3.writeFile(p, JSON.stringify(state, null, 2) + "\n", "utf8");
1531
- }
1532
- function userText(msg) {
1533
- if (msg.info?.role !== "user") return "";
1534
- const parts = msg.parts ?? [];
1535
- return parts.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("\n");
1536
- }
1537
- function latestUserAgent(messages) {
1538
- for (let i = messages.length - 1; i >= 0; i--) {
1539
- const info = messages[i].info;
1540
- if (info?.role === "user" && typeof info.agent === "string") {
1541
- return info.agent;
1542
- }
1543
- }
1544
- return void 0;
1545
- }
1546
- function latestAssistantText(messages) {
1547
- for (let i = messages.length - 1; i >= 0; i--) {
1548
- const msg = messages[i];
1549
- if (msg.info?.role !== "assistant") continue;
1550
- const parts = msg.parts ?? [];
1551
- return parts.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("\n");
1552
- }
1553
- return "";
1554
- }
1555
- function detectActivation(messages) {
1556
- for (const msg of messages) {
1557
- if (msg.info?.role !== "user") continue;
1558
- return AUTOPILOT_MARKER_RE.test(userText(msg));
1559
- }
1560
- return false;
1561
- }
1562
- var PLAN_PATH_RE = /(?:\.agent\/plans\/[\w-]+\.md|(?:\/[^\s`"']*)?\/[\w.-]+\/plans\/[\w-]+\.md)/;
1563
- function findPlanPath(messages) {
1564
- for (let i = messages.length - 1; i >= 0; i--) {
1565
- const parts = messages[i].parts ?? [];
1566
- for (const part of parts) {
1567
- if (part.type === "text" && typeof part.text === "string") {
1568
- const m = part.text.match(PLAN_PATH_RE);
1569
- if (m) return m[0];
1570
- }
1571
- }
1572
- }
1573
- return null;
1574
- }
1575
- function countUnchecked(planContent) {
1576
- const section = /## Acceptance criteria([\s\S]*?)(?=\n##|$)/.exec(planContent);
1577
- if (!section) return 0;
1578
- const matches = section[1].match(/^- \[ \]/gm);
1579
- return matches?.length ?? 0;
1580
- }
1581
- function classifyPlan(content) {
1582
- if (OPT_OUT_RE.test(content)) return "opted-out";
1583
- if (UMBRELLA_SECTION_RE.test(content)) return "umbrella";
1584
- if (content.length > UMBRELLA_MIN_BYTES) return "umbrella";
1585
- const linearIds = content.match(LINEAR_ID_RE) ?? [];
1586
- const unique = new Set(linearIds);
1587
- if (unique.size >= UMBRELLA_MIN_LINEAR_IDS) return "umbrella";
1588
- const acSection = /## Acceptance criteria([\s\S]*?)(?=\n##|$)/.exec(content);
1589
- if (acSection && MEASUREMENT_GATE_RE.test(acSection[1])) {
1590
- return "measurement-gated";
1591
- }
1592
- return "unit";
1593
- }
1594
- function planGoalLinearId(content) {
1595
- const goal = /## Goal([\s\S]*?)(?=\n##|$)/.exec(content);
1596
- if (!goal) return null;
1597
- const m = goal[1].match(LINEAR_ID_RE);
1598
- return m ? m[0] : null;
1599
- }
1600
- function detectStopReport(assistantText) {
1601
- if (!assistantText) return false;
1602
- return STOP_REPORT_RE.test(assistantText);
1603
- }
1604
- var execFile6 = promisify6(execFileCb);
1605
- async function currentBranch(dir) {
1606
- try {
1607
- const { stdout } = await execFile6(
1608
- "git",
1609
- ["-C", dir, "branch", "--show-current"],
1610
- { timeout: 2e3 }
1611
- );
1612
- const branch = stdout.trim();
1613
- return branch.length > 0 ? branch : null;
1614
- } catch {
1615
- return null;
1616
- }
1617
- }
1618
- async function pullRequestState(dir) {
1619
- try {
1620
- const { stdout } = await execFile6(
1621
- "gh",
1622
- ["pr", "view", "--json", "state", "--jq", ".state"],
1623
- { cwd: dir, timeout: 5e3 }
1624
- );
1625
- const state = stdout.trim();
1626
- return state.length > 0 ? state : null;
1627
- } catch {
1628
- return null;
1629
- }
1630
- }
1631
- async function killSwitchEngaged(dir) {
1632
- try {
1633
- await fs3.access(path3.join(dir, KILL_SWITCH_PATH));
1634
- return true;
1635
- } catch {
1636
- return false;
1637
- }
1638
- }
1639
- async function sendNudge(client, sessionID, sessState, text, now = Date.now()) {
1640
- if (sessState.lastNudgeAt !== void 0 && now - sessState.lastNudgeAt < NUDGE_DEBOUNCE_MS) {
1641
- return false;
1642
- }
1643
- await client.session.promptAsync({
1644
- path: { id: sessionID },
1645
- body: { parts: [{ type: "text", text }] }
1646
- });
1647
- sessState.lastNudgeAt = now;
1648
- return true;
1649
- }
1650
- var plugin = async ({ client, directory }) => {
1651
- return {
1652
- event: async ({ event }) => {
1653
- if (event.type !== "session.idle") return;
1654
- const sessionID = event.properties.sessionID;
1655
- const msgsResp = await client.session.messages({
1656
- path: { id: sessionID },
1657
- query: { limit: MESSAGE_LIMIT }
1658
- });
1659
- const messages = msgsResp.data ?? [];
1660
- const agent = latestUserAgent(messages);
1661
- if (!agent || !TARGET_AGENTS.has(agent)) return;
1662
- const state = await readState(directory);
1663
- const sessState = state.sessions[sessionID] ?? {
1664
- iterations: 0
1665
- };
1666
- if (sessState.stopped) return;
1667
- if (!sessState.enabled) {
1668
- if (!detectActivation(messages)) return;
1669
- sessState.enabled = true;
1670
- }
1671
- if (await killSwitchEngaged(directory)) {
1672
- state.sessions[sessionID] = {
1673
- ...sessState,
1674
- stopped: true,
1675
- stopReason: "kill-switch"
1676
- };
1677
- await writeState(directory, state);
1678
- return;
1679
- }
1680
- if (sessState.iterations >= MAX_ITERATIONS) {
1681
- await sendNudge(client, sessionID, sessState, MAX_ITERATIONS_TEXT);
1682
- state.sessions[sessionID] = {
1683
- ...sessState,
1684
- stopped: true,
1685
- stopReason: "max-iterations"
1686
- };
1687
- await writeState(directory, state);
1688
- return;
1689
- }
1690
- const planPath = findPlanPath(messages);
1691
- if (!planPath) return;
1692
- const resolvedPlanPath = path3.isAbsolute(planPath) ? planPath : path3.join(directory, planPath);
1693
- let planContent;
1694
- try {
1695
- planContent = await fs3.readFile(resolvedPlanPath, "utf8");
1696
- } catch {
1697
- return;
1698
- }
1699
- const shape = classifyPlan(planContent);
1700
- if (shape !== "unit") {
1701
- state.sessions[sessionID] = {
1702
- ...sessState,
1703
- stopped: true,
1704
- stopReason: `plan-shape:${shape}`
1705
- };
1706
- await writeState(directory, state);
1707
- return;
1708
- }
1709
- const planLinearId = planGoalLinearId(planContent);
1710
- if (planLinearId) {
1711
- const branch = await currentBranch(directory);
1712
- if (branch && !branch.toLowerCase().includes(planLinearId.toLowerCase())) {
1713
- state.sessions[sessionID] = {
1714
- ...sessState,
1715
- stopped: true,
1716
- stopReason: "branch-mismatch"
1717
- };
1718
- await writeState(directory, state);
1719
- return;
1720
- }
1721
- }
1722
- const now = Date.now();
1723
- let prState = sessState.prState;
1724
- const prExpired = sessState.prCheckedAt === void 0 || now - sessState.prCheckedAt > PR_CACHE_MS;
1725
- if (prExpired) {
1726
- const fetched = await pullRequestState(directory);
1727
- prState = fetched ?? "none";
1728
- sessState.prState = prState;
1729
- sessState.prCheckedAt = now;
1730
- }
1731
- if (prState === "MERGED") {
1732
- state.sessions[sessionID] = {
1733
- ...sessState,
1734
- stopped: true,
1735
- stopReason: "pr-merged"
1736
- };
1737
- await writeState(directory, state);
1738
- return;
1739
- }
1740
- const unchecked = countUnchecked(planContent);
1741
- if (unchecked === 0) {
1742
- state.sessions[sessionID] = {
1743
- ...sessState,
1744
- consecutiveStops: 0,
1745
- lastUncheckedCount: 0
1746
- };
1747
- await writeState(directory, state);
1748
- return;
1749
- }
1750
- const lastUnchecked = sessState.lastUncheckedCount;
1751
- const madeProgress = lastUnchecked !== void 0 && unchecked < lastUnchecked;
1752
- const stopReported = detectStopReport(latestAssistantText(messages));
1753
- let consecutiveStops = sessState.consecutiveStops ?? 0;
1754
- if (madeProgress) {
1755
- consecutiveStops = 0;
1756
- } else if (stopReported) {
1757
- consecutiveStops += 1;
1758
- } else {
1759
- }
1760
- sessState.consecutiveStops = consecutiveStops;
1761
- sessState.lastUncheckedCount = unchecked;
1762
- if (consecutiveStops >= MAX_CONSECUTIVE_STOPS) {
1763
- state.sessions[sessionID] = {
1764
- ...sessState,
1765
- stopped: true,
1766
- stopReason: "agent-stop-report"
1767
- };
1768
- await writeState(directory, state);
1769
- return;
1770
- }
1771
- const sent = await sendNudge(client, sessionID, sessState, NUDGE_TEXT);
1772
- if (sent) {
1773
- state.sessions[sessionID] = {
1774
- ...sessState,
1775
- iterations: sessState.iterations + 1
1776
- };
1777
- await writeState(directory, state);
1778
- } else {
1779
- state.sessions[sessionID] = { ...sessState };
1780
- await writeState(directory, state);
1781
- }
1782
- },
1783
- "chat.message": async ({ sessionID, agent }) => {
1784
- if (!agent || !TARGET_AGENTS.has(agent)) return;
1785
- const state = await readState(directory);
1786
- const existing = state.sessions[sessionID];
1787
- if (!existing?.enabled) return;
1788
- state.sessions[sessionID] = {
1789
- ...existing,
1790
- iterations: 0
1791
- };
1792
- await writeState(directory, state);
1793
- }
1794
- };
1795
- };
1796
- var autopilot_default = plugin;
1797
-
1798
1352
  // src/plugins/notify.ts
1799
- var plugin2 = async ({ $, client }) => {
1353
+ var plugin = async ({ $, client }) => {
1800
1354
  async function notify(title, message) {
1801
1355
  if (process.platform === "darwin") {
1802
1356
  const esc = (s) => s.replace(/"/g, '\\"');
@@ -1819,11 +1373,11 @@ var plugin2 = async ({ $, client }) => {
1819
1373
  }
1820
1374
  };
1821
1375
  };
1822
- var notify_default = plugin2;
1376
+ var notify_default = plugin;
1823
1377
 
1824
1378
  // src/plugins/cost-tracker.ts
1825
- import * as fs4 from "fs/promises";
1826
- import * as path4 from "path";
1379
+ import * as fs3 from "fs/promises";
1380
+ import * as path3 from "path";
1827
1381
  import * as os2 from "os";
1828
1382
  var MAX_LINE_BYTES = 2048;
1829
1383
  var ROLLUP_DEBOUNCE_MS = 5e3;
@@ -1831,11 +1385,11 @@ function resolveDataDir() {
1831
1385
  const override = process.env.GLORIOUS_COST_TRACKER_DIR;
1832
1386
  if (override) {
1833
1387
  if (override.startsWith("~")) {
1834
- return path4.join(os2.homedir(), override.slice(1));
1388
+ return path3.join(os2.homedir(), override.slice(1));
1835
1389
  }
1836
1390
  return override;
1837
1391
  }
1838
- return path4.join(os2.homedir(), ".glorious", "opencode");
1392
+ return path3.join(os2.homedir(), ".glorious", "opencode");
1839
1393
  }
1840
1394
  function zeroTokens() {
1841
1395
  return {
@@ -1902,13 +1456,13 @@ function emptyRollup() {
1902
1456
  byProvider: {}
1903
1457
  };
1904
1458
  }
1905
- var plugin3 = async () => {
1459
+ var plugin2 = async () => {
1906
1460
  if (process.env.GLORIOUS_COST_TRACKER === "0") {
1907
1461
  return {};
1908
1462
  }
1909
1463
  const dataDir = resolveDataDir();
1910
- const jsonlPath = path4.join(dataDir, "costs.jsonl");
1911
- const rollupPath = path4.join(dataDir, "costs.json");
1464
+ const jsonlPath = path3.join(dataDir, "costs.jsonl");
1465
+ const rollupPath = path3.join(dataDir, "costs.json");
1912
1466
  const lastSeen = /* @__PURE__ */ new Map();
1913
1467
  const messageMeta = /* @__PURE__ */ new Map();
1914
1468
  const rollup = emptyRollup();
@@ -1924,7 +1478,7 @@ var plugin3 = async () => {
1924
1478
  async function ensureDir() {
1925
1479
  if (disabled) return false;
1926
1480
  try {
1927
- await fs4.mkdir(dataDir, { recursive: true });
1481
+ await fs3.mkdir(dataDir, { recursive: true });
1928
1482
  return true;
1929
1483
  } catch (err) {
1930
1484
  warnOnce("mkdir", err);
@@ -1973,13 +1527,13 @@ var plugin3 = async () => {
1973
1527
  if (!await ensureDir()) return;
1974
1528
  const tmp = `${rollupPath}.tmp.${process.pid}.${Math.random().toString(36).slice(2, 10)}`;
1975
1529
  try {
1976
- await fs4.writeFile(tmp, JSON.stringify(rollup, null, 2) + "\n", "utf8");
1977
- await fs4.rename(tmp, rollupPath);
1530
+ await fs3.writeFile(tmp, JSON.stringify(rollup, null, 2) + "\n", "utf8");
1531
+ await fs3.rename(tmp, rollupPath);
1978
1532
  lastRollupWriteAt = now;
1979
1533
  } catch (err) {
1980
1534
  warnOnce("rollup-write", err);
1981
1535
  try {
1982
- await fs4.unlink(tmp);
1536
+ await fs3.unlink(tmp);
1983
1537
  } catch {
1984
1538
  }
1985
1539
  }
@@ -1999,14 +1553,14 @@ var plugin3 = async () => {
1999
1553
  return;
2000
1554
  }
2001
1555
  try {
2002
- await fs4.appendFile(jsonlPath, text, "utf8");
1556
+ await fs3.appendFile(jsonlPath, text, "utf8");
2003
1557
  } catch (err) {
2004
1558
  warnOnce("jsonl-append", err);
2005
1559
  }
2006
1560
  }
2007
1561
  async function warmUp() {
2008
1562
  try {
2009
- const raw = await fs4.readFile(jsonlPath, "utf8");
1563
+ const raw = await fs3.readFile(jsonlPath, "utf8");
2010
1564
  const byMsg = /* @__PURE__ */ new Map();
2011
1565
  for (const rawLine of raw.split("\n")) {
2012
1566
  if (!rawLine) continue;
@@ -2140,76 +1694,16 @@ var plugin3 = async () => {
2140
1694
  }
2141
1695
  };
2142
1696
  };
2143
- var cost_tracker_default = plugin3;
2144
-
2145
- // src/plugins/pilot-plugin.ts
2146
- var PILOT_TITLE_PREFIX = "pilot/";
2147
- var BUILDER_DENIED_PATTERNS = [
2148
- /^git\s+commit/,
2149
- /^git\s+push/,
2150
- /^git\s+tag/,
2151
- /^git\s+checkout\s/,
2152
- /^git\s+switch\s/,
2153
- /^git\s+branch\s/,
2154
- /^git\s+restore\s+--source/,
2155
- /^git\s+reset\s/,
2156
- /^gh\s+pr\s/,
2157
- /^gh\s+release\s/
2158
- ];
2159
- var sessionCache = /* @__PURE__ */ new Map();
2160
- async function getSessionPhase(client, sessionId) {
2161
- if (sessionCache.has(sessionId)) {
2162
- return sessionCache.get(sessionId);
2163
- }
2164
- try {
2165
- const session = await client.session.get({ sessionID: sessionId });
2166
- const title = session.title ?? "";
2167
- if (!title.startsWith(PILOT_TITLE_PREFIX)) return null;
2168
- const parts = title.slice(PILOT_TITLE_PREFIX.length).split("/");
2169
- if (parts.length < 2) return null;
2170
- const [workflowId, phase] = parts;
2171
- const result = { phase, workflowId };
2172
- sessionCache.set(sessionId, result);
2173
- return result;
2174
- } catch {
2175
- return null;
2176
- }
2177
- }
2178
- var pilotPlugin = async (input) => {
2179
- return {
2180
- "tool.execute.before": async (toolInput, _output) => {
2181
- const sessionId = toolInput.sessionID;
2182
- if (!sessionId) return;
2183
- const sessionInfo = await getSessionPhase(input.client, sessionId);
2184
- if (!sessionInfo) return;
2185
- const { phase } = sessionInfo;
2186
- const toolName = toolInput.tool ?? "";
2187
- const args = toolInput.args ?? {};
2188
- if (phase === "execute") {
2189
- if (toolName === "bash") {
2190
- const cmd = String(args["command"] ?? "").trim();
2191
- for (const pattern of BUILDER_DENIED_PATTERNS) {
2192
- if (pattern.test(cmd)) {
2193
- throw new Error(
2194
- `pilot-builder: "${cmd}" is not allowed. The orchestrator handles commits and pushes after verify passes.`
2195
- );
2196
- }
2197
- }
2198
- }
2199
- }
2200
- }
2201
- };
2202
- };
2203
- var pilot_plugin_default = pilotPlugin;
1697
+ var cost_tracker_default = plugin2;
2204
1698
 
2205
1699
  // src/plugins/tool-hooks.ts
2206
1700
  import * as crypto from "crypto";
2207
- import * as fs5 from "fs";
2208
- import * as path5 from "path";
1701
+ import * as fs4 from "fs";
1702
+ import * as path4 from "path";
2209
1703
  import * as os3 from "os";
2210
- import { execFile as execFileCb2 } from "child_process";
2211
- import { promisify as promisify7 } from "util";
2212
- var exec6 = promisify7(execFileCb2);
1704
+ import { execFile as execFileCb } from "child_process";
1705
+ import { promisify as promisify6 } from "util";
1706
+ var exec6 = promisify6(execFileCb);
2213
1707
  var EDIT_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "patch", "multiedit"]);
2214
1708
  var TS_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
2215
1709
  var DEFAULT_BACKPRESSURE_THRESHOLD = 6e3;
@@ -2292,8 +1786,8 @@ function resolveConfig(config, pluginOptions) {
2292
1786
  };
2293
1787
  }
2294
1788
  function getToolOutputDir() {
2295
- const stateHome = process.env["XDG_STATE_HOME"] || path5.join(os3.homedir(), ".local", "state");
2296
- return path5.join(stateHome, "harness-opencode", "tool-output");
1789
+ const stateHome = process.env["XDG_STATE_HOME"] || path4.join(os3.homedir(), ".local", "state");
1790
+ return path4.join(stateHome, "harness-opencode", "tool-output");
2297
1791
  }
2298
1792
  function hashContent(content) {
2299
1793
  return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
@@ -2326,9 +1820,9 @@ async function resolveSessionDir(client, sess, sessionID) {
2326
1820
  }
2327
1821
  function isUnderToolOutputDir(filePath) {
2328
1822
  try {
2329
- const abs = path5.resolve(filePath);
2330
- const spillDir = path5.resolve(getToolOutputDir());
2331
- return abs === spillDir || abs.startsWith(spillDir + path5.sep);
1823
+ const abs = path4.resolve(filePath);
1824
+ const spillDir = path4.resolve(getToolOutputDir());
1825
+ return abs === spillDir || abs.startsWith(spillDir + path4.sep);
2332
1826
  } catch {
2333
1827
  return false;
2334
1828
  }
@@ -2362,9 +1856,9 @@ function applyBackpressure(cfg, toolName, callID, output, args) {
2362
1856
  let diskPath = null;
2363
1857
  try {
2364
1858
  const dir = getToolOutputDir();
2365
- fs5.mkdirSync(dir, { recursive: true });
2366
- diskPath = path5.join(dir, `${callID}.txt`);
2367
- fs5.writeFileSync(diskPath, text);
1859
+ fs4.mkdirSync(dir, { recursive: true });
1860
+ diskPath = path4.join(dir, `${callID}.txt`);
1861
+ fs4.writeFileSync(diskPath, text);
2368
1862
  } catch {
2369
1863
  }
2370
1864
  const pathNote = diskPath ? ` Full output saved to: ${diskPath}` : "";
@@ -2410,7 +1904,7 @@ ${tail}`;
2410
1904
  }
2411
1905
  async function runPostEditVerify(cfg, client, sess, sessionID, filePath, output) {
2412
1906
  if (!cfg.enabled) return;
2413
- const ext = path5.extname(filePath).toLowerCase();
1907
+ const ext = path4.extname(filePath).toLowerCase();
2414
1908
  if (!TS_EXTENSIONS.has(ext)) return;
2415
1909
  const now = Date.now();
2416
1910
  if (now - sess.lastVerifyTs < 2e3) return;
@@ -2443,17 +1937,17 @@ ${String(stderr)}`;
2443
1937
  }
2444
1938
  if (!raw.trim()) return;
2445
1939
  const errors = parseTscOutput(raw);
2446
- const normPath = path5.resolve(cwd, filePath);
1940
+ const normPath = path4.resolve(cwd, filePath);
2447
1941
  const fileErrors = errors.filter((e) => {
2448
- const errPath = path5.isAbsolute(e.file) ? e.file : path5.resolve(cwd, e.file);
2449
- return path5.normalize(errPath) === path5.normalize(normPath);
1942
+ const errPath = path4.isAbsolute(e.file) ? e.file : path4.resolve(cwd, e.file);
1943
+ return path4.normalize(errPath) === path4.normalize(normPath);
2450
1944
  });
2451
1945
  if (fileErrors.length === 0) return;
2452
1946
  const { rows } = dedupeAndCap(fileErrors, VERIFY_MAX_ERRORS);
2453
1947
  const lines = rows.map(formatRow);
2454
1948
  output.output += `
2455
1949
 
2456
- --- POST-EDIT DIAGNOSTICS (${fileErrors.length} error${fileErrors.length !== 1 ? "s" : ""} in ${path5.basename(filePath)}) ---
1950
+ --- POST-EDIT DIAGNOSTICS (${fileErrors.length} error${fileErrors.length !== 1 ? "s" : ""} in ${path4.basename(filePath)}) ---
2457
1951
  ` + lines.join("\n") + `
2458
1952
  --- Fix these before proceeding ---`;
2459
1953
  } catch {
@@ -2467,7 +1961,7 @@ function checkEditLoop(cfg, sess, filePath, output) {
2467
1961
  output.output += `
2468
1962
 
2469
1963
  --- LOOP WARNING ---
2470
- You've edited ${path5.basename(filePath)} ${count} times this session. Consider reconsidering your approach \u2014 are you stuck in a loop? Step back and think about whether a different strategy would be more effective.
1964
+ You've edited ${path4.basename(filePath)} ${count} times this session. Consider reconsidering your approach \u2014 are you stuck in a loop? Step back and think about whether a different strategy would be more effective.
2471
1965
  ---`;
2472
1966
  }
2473
1967
  }
@@ -2485,7 +1979,7 @@ function checkReadDedup(cfg, sess, filePath, output) {
2485
1979
  }
2486
1980
  var pluginConfig = null;
2487
1981
  var storedPluginOptions;
2488
- var plugin4 = async ({ client }, options) => {
1982
+ var plugin3 = async ({ client }, options) => {
2489
1983
  storedPluginOptions = options;
2490
1984
  return {
2491
1985
  config: async (config) => {
@@ -2518,7 +2012,7 @@ var plugin4 = async ({ client }, options) => {
2518
2012
  }
2519
2013
  };
2520
2014
  };
2521
- var tool_hooks_default = plugin4;
2015
+ var tool_hooks_default = plugin3;
2522
2016
 
2523
2017
  // src/plugins/telemetry.ts
2524
2018
  import { extname as extname2 } from "path";
@@ -2527,16 +2021,16 @@ import { extname as extname2 } from "path";
2527
2021
  import { createHash as createHash2, randomUUID } from "crypto";
2528
2022
  import { homedir as homedir4 } from "os";
2529
2023
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync } from "fs";
2530
- import { join as join10 } from "path";
2024
+ import { join as join9 } from "path";
2531
2025
  var APP_KEY = "A-US-3617699429";
2532
2026
  var ENDPOINT = "https://us.aptabase.com/api/v0/event";
2533
2027
  var PKG_NAME = "@glrs-dev/harness-plugin-opencode";
2534
- var PKG_VERSION = true ? "2.0.1" : "dev";
2028
+ var PKG_VERSION = true ? "2.2.0" : "dev";
2535
2029
  var DISABLED = process.env.HARNESS_OPENCODE_TELEMETRY === "0" || process.env.HARNESS_OPENCODE_TELEMETRY === "false" || process.env.DO_NOT_TRACK === "1" || process.env.CI === "true";
2536
2030
  var SESSION_ID = randomUUID();
2537
2031
  function getInstallId() {
2538
- const dir = join10(homedir4(), ".config", "harness-opencode");
2539
- const file = join10(dir, "install-id");
2032
+ const dir = join9(homedir4(), ".config", "harness-opencode");
2033
+ const file = join9(dir, "install-id");
2540
2034
  try {
2541
2035
  if (existsSync(file)) return readFileSync5(file, "utf8").trim();
2542
2036
  mkdirSync3(dir, { recursive: true });
@@ -2603,7 +2097,7 @@ function track(eventName, props = {}) {
2603
2097
  }
2604
2098
 
2605
2099
  // src/plugins/telemetry.ts
2606
- var plugin5 = async () => {
2100
+ var plugin4 = async () => {
2607
2101
  if (DISABLED) {
2608
2102
  return {};
2609
2103
  }
@@ -2665,7 +2159,7 @@ var plugin5 = async () => {
2665
2159
  }
2666
2160
  };
2667
2161
  };
2668
- var telemetry_default = plugin5;
2162
+ var telemetry_default = plugin4;
2669
2163
 
2670
2164
  // src/index.ts
2671
2165
  var BUNDLED_VERSION = readOurPackageVersion(import.meta.url);
@@ -2710,22 +2204,19 @@ async function checkForUpdate(client) {
2710
2204
  } catch {
2711
2205
  }
2712
2206
  }
2713
- var plugin6 = async (input, options) => {
2207
+ var plugin5 = async (input, options) => {
2714
2208
  const pluginOptions = options ?? {};
2715
2209
  loadDotenv(input.directory);
2716
2210
  checkForUpdate(input.client).catch(() => {
2717
2211
  });
2718
- const autopilotHooks = await autopilot_default(input);
2719
2212
  const notifyHooks = await notify_default(input);
2720
2213
  const costTrackerHooks = await cost_tracker_default(input);
2721
- const pilotHooks = await pilot_plugin_default(input);
2722
2214
  const toolHooks = await tool_hooks_default(input, pluginOptions);
2723
2215
  const telemetryHooks = await telemetry_default(input);
2724
2216
  const hooks = {
2725
2217
  // Config hook: register agents, commands, MCPs, skills
2726
2218
  config: async (config) => {
2727
2219
  applyConfig(config, pluginOptions);
2728
- if (autopilotHooks.config) await autopilotHooks.config(config);
2729
2220
  if (notifyHooks.config) await notifyHooks.config(config);
2730
2221
  if (costTrackerHooks.config) await costTrackerHooks.config(config);
2731
2222
  if (toolHooks.config) await toolHooks.config(config);
@@ -2734,27 +2225,15 @@ var plugin6 = async (input, options) => {
2734
2225
  tool: createTools(),
2735
2226
  // Event handlers from sub-plugins
2736
2227
  event: async (input2) => {
2737
- if (autopilotHooks.event) await autopilotHooks.event(input2);
2738
2228
  if (notifyHooks.event) await notifyHooks.event(input2);
2739
2229
  if (costTrackerHooks.event) await costTrackerHooks.event(input2);
2740
2230
  if (telemetryHooks.event) await telemetryHooks.event(input2);
2741
2231
  }
2742
2232
  };
2743
- if (autopilotHooks["chat.params"] !== void 0) {
2744
- hooks["chat.params"] = autopilotHooks["chat.params"];
2745
- }
2746
- if (autopilotHooks["chat.message"] !== void 0) {
2747
- hooks["chat.message"] = autopilotHooks["chat.message"];
2748
- }
2749
- if (autopilotHooks["experimental.session.compacting"] !== void 0) {
2750
- hooks["experimental.session.compacting"] = autopilotHooks["experimental.session.compacting"];
2751
- }
2752
2233
  const hasTelemetryBefore = telemetryHooks["tool.execute.before"] !== void 0;
2753
- const hasPilotBefore = pilotHooks["tool.execute.before"] !== void 0;
2754
- if (hasTelemetryBefore || hasPilotBefore) {
2234
+ if (hasTelemetryBefore) {
2755
2235
  hooks["tool.execute.before"] = async (input2, output) => {
2756
2236
  if (hasTelemetryBefore) await telemetryHooks["tool.execute.before"](input2, output);
2757
- if (hasPilotBefore) await pilotHooks["tool.execute.before"](input2, output);
2758
2237
  };
2759
2238
  }
2760
2239
  const hasToolHooksAfter = toolHooks["tool.execute.after"] !== void 0;
@@ -2767,7 +2246,7 @@ var plugin6 = async (input, options) => {
2767
2246
  }
2768
2247
  return hooks;
2769
2248
  };
2770
- var src_default = plugin6;
2249
+ var src_default = plugin5;
2771
2250
  export {
2772
2251
  src_default as default
2773
2252
  };