@glrs-dev/cli 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +14 -15
  3. package/dist/chunk-3RG5ZIWI.js +10 -0
  4. package/dist/chunk-6RHN2EDH.js +93 -0
  5. package/dist/chunk-DEODG2LC.js +55 -0
  6. package/dist/chunk-FSAGM22T.js +17 -0
  7. package/dist/chunk-GQBZREK5.js +136 -0
  8. package/dist/chunk-HWMRY35D.js +139 -0
  9. package/dist/chunk-LMRDQ4GW.js +129 -0
  10. package/dist/chunk-NLPX2KOF.js +149 -0
  11. package/dist/chunk-P7PRH4I3.js +177 -0
  12. package/dist/chunk-VCN7RNLU.js +60 -0
  13. package/dist/chunk-VJFNIKQJ.js +120 -0
  14. package/dist/chunk-W37UX3U2.js +35 -0
  15. package/dist/chunk-YBCA3IP6.js +25 -0
  16. package/dist/chunk-YGNDPKIW.js +99 -0
  17. package/dist/cli.d.ts +1 -1
  18. package/dist/cli.js +89 -36
  19. package/dist/commands/cleanup.d.ts +19 -0
  20. package/dist/commands/cleanup.js +11 -0
  21. package/dist/commands/create.d.ts +17 -0
  22. package/dist/commands/create.js +12 -0
  23. package/dist/commands/delete.d.ts +17 -0
  24. package/dist/commands/delete.js +12 -0
  25. package/dist/commands/go.d.ts +4 -0
  26. package/dist/commands/go.js +11 -0
  27. package/dist/commands/list.d.ts +15 -0
  28. package/dist/commands/list.js +12 -0
  29. package/dist/commands/switch.d.ts +11 -0
  30. package/dist/commands/switch.js +12 -0
  31. package/dist/commands/types.d.ts +10 -0
  32. package/dist/commands/types.js +0 -0
  33. package/dist/index.d.ts +16 -19
  34. package/dist/index.js +4 -1
  35. package/dist/lib/config.d.ts +14 -0
  36. package/dist/lib/config.js +14 -0
  37. package/dist/lib/fmt.d.ts +12 -0
  38. package/dist/lib/fmt.js +25 -0
  39. package/dist/lib/git.d.ts +26 -0
  40. package/dist/lib/git.js +25 -0
  41. package/dist/lib/registry.d.ts +14 -0
  42. package/dist/lib/registry.js +13 -0
  43. package/dist/lib/select.d.ts +21 -0
  44. package/dist/lib/select.js +10 -0
  45. package/dist/lib/worktree.d.ts +35 -0
  46. package/dist/lib/worktree.js +17 -0
  47. package/dist/vendor/harness-opencode/dist/agents/prompts/agents-md-writer.md +89 -0
  48. package/dist/vendor/harness-opencode/dist/agents/prompts/architecture-advisor.md +46 -0
  49. package/dist/vendor/harness-opencode/dist/agents/prompts/build.md +93 -0
  50. package/dist/vendor/harness-opencode/dist/agents/prompts/code-searcher.md +54 -0
  51. package/dist/vendor/harness-opencode/dist/agents/prompts/docs-maintainer.md +128 -0
  52. package/dist/vendor/harness-opencode/dist/agents/prompts/gap-analyzer.md +44 -0
  53. package/dist/vendor/harness-opencode/dist/agents/prompts/lib-reader.md +39 -0
  54. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-builder.md +107 -0
  55. package/dist/vendor/harness-opencode/dist/agents/prompts/pilot-planner.md +153 -0
  56. package/dist/vendor/harness-opencode/dist/agents/prompts/plan-reviewer.md +49 -0
  57. package/dist/vendor/harness-opencode/dist/agents/prompts/plan.md +144 -0
  58. package/dist/vendor/harness-opencode/dist/agents/prompts/prime.md +374 -0
  59. package/dist/vendor/harness-opencode/dist/agents/prompts/qa-reviewer.md +68 -0
  60. package/dist/vendor/harness-opencode/dist/agents/prompts/qa-thorough.md +63 -0
  61. package/dist/vendor/harness-opencode/dist/agents/prompts/research.md +138 -0
  62. package/dist/vendor/harness-opencode/dist/agents/shared/index.ts +26 -0
  63. package/dist/vendor/harness-opencode/dist/agents/shared/workflow-mechanics.md +32 -0
  64. package/dist/vendor/harness-opencode/dist/bin/memory-mcp-launcher.sh +145 -0
  65. package/dist/vendor/harness-opencode/dist/bin/plan-check.sh +255 -0
  66. package/dist/vendor/harness-opencode/dist/chunk-VJUETC6A.js +205 -0
  67. package/dist/vendor/harness-opencode/dist/chunk-VVMP6QWS.js +731 -0
  68. package/dist/vendor/harness-opencode/dist/chunk-XCZ3NOXR.js +703 -0
  69. package/dist/vendor/harness-opencode/dist/cli.d.ts +1 -0
  70. package/dist/vendor/harness-opencode/dist/cli.js +5096 -0
  71. package/dist/vendor/harness-opencode/dist/commands/prompts/autopilot.md +96 -0
  72. package/dist/vendor/harness-opencode/dist/commands/prompts/costs.md +94 -0
  73. package/dist/vendor/harness-opencode/dist/commands/prompts/fresh.md +382 -0
  74. package/dist/vendor/harness-opencode/dist/commands/prompts/init-deep.md +196 -0
  75. package/dist/vendor/harness-opencode/dist/commands/prompts/research.md +27 -0
  76. package/dist/vendor/harness-opencode/dist/commands/prompts/review.md +96 -0
  77. package/dist/vendor/harness-opencode/dist/commands/prompts/ship.md +104 -0
  78. package/dist/vendor/harness-opencode/dist/index.d.ts +21 -0
  79. package/dist/vendor/harness-opencode/dist/index.js +2092 -0
  80. package/dist/vendor/harness-opencode/dist/install-4EYR56OR.js +9 -0
  81. package/dist/vendor/harness-opencode/dist/skills/agent-estimation/SKILL.md +159 -0
  82. package/dist/vendor/harness-opencode/dist/skills/paths.ts +18 -0
  83. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/SKILL.md +49 -0
  84. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/dag-shape.md +47 -0
  85. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/decomposition.md +36 -0
  86. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/first-principles.md +29 -0
  87. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/milestones.md +57 -0
  88. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/self-review.md +46 -0
  89. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/task-context.md +47 -0
  90. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/touches-scope.md +47 -0
  91. package/dist/vendor/harness-opencode/dist/skills/pilot-planning/rules/verify-design.md +53 -0
  92. package/dist/vendor/harness-opencode/dist/skills/research/SKILL.md +350 -0
  93. package/dist/vendor/harness-opencode/dist/skills/research-auto/SKILL.md +283 -0
  94. package/dist/vendor/harness-opencode/dist/skills/research-local/SKILL.md +268 -0
  95. package/dist/vendor/harness-opencode/dist/skills/research-web/SKILL.md +119 -0
  96. package/dist/vendor/harness-opencode/dist/skills/review-plan/SKILL.md +32 -0
  97. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/AGENTS.md +946 -0
  98. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/README.md +60 -0
  99. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/SKILL.md +89 -0
  100. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
  101. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
  102. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
  103. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
  104. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
  105. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
  106. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
  107. package/dist/vendor/harness-opencode/dist/skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
  108. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/AGENTS.md +2975 -0
  109. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/README.md +123 -0
  110. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/SKILL.md +137 -0
  111. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  112. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  113. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  114. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  115. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  116. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  117. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  118. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  119. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  120. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  121. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  122. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  123. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  124. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  125. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  126. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  127. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  128. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  129. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  130. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  131. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  132. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  133. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  134. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  135. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  136. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  137. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  138. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  139. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  140. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  141. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  142. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  143. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  144. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  145. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  146. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  147. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  148. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  149. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  150. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  151. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  152. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  153. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  154. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  155. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  156. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  157. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  158. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  159. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  160. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  161. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  162. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  163. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  164. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  165. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  166. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +142 -0
  167. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  168. package/dist/vendor/harness-opencode/dist/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  169. package/dist/vendor/harness-opencode/dist/skills/web-design-guidelines/SKILL.md +39 -0
  170. package/dist/vendor/harness-opencode/package.json +11 -0
  171. package/package.json +20 -15
  172. package/LICENSE +0 -21
  173. package/dist/chunk-TU23AE2F.js +0 -69
@@ -0,0 +1,703 @@
1
+ // src/agents/shared/index.ts
2
+ import { readFileSync } from "fs";
3
+ import { fileURLToPath } from "url";
4
+ import { dirname, join } from "path";
5
+ var HERE = dirname(fileURLToPath(import.meta.url));
6
+ function readMd(name) {
7
+ const candidates = [
8
+ join(HERE, name),
9
+ // dev: src/agents/shared/
10
+ join(HERE, "agents", "shared", name),
11
+ // dist: dist/ → dist/agents/shared/
12
+ join(HERE, "..", "..", "..", "src", "agents", "shared", name)
13
+ // fallback dev
14
+ ];
15
+ for (const p of candidates) {
16
+ try {
17
+ return readFileSync(p, "utf8");
18
+ } catch {
19
+ }
20
+ }
21
+ throw new Error(`Could not find shared file: ${name}`);
22
+ }
23
+ var WORKFLOW_MECHANICS_RULE = readMd("workflow-mechanics.md");
24
+
25
+ // src/agents/index.ts
26
+ import { readFileSync as readFileSync2 } from "fs";
27
+ import { fileURLToPath as fileURLToPath2 } from "url";
28
+ import { dirname as dirname2, join as join2 } from "path";
29
+ var HERE2 = dirname2(fileURLToPath2(import.meta.url));
30
+ function readPrompt(name) {
31
+ const candidates = [
32
+ join2(HERE2, "prompts", name),
33
+ // dev: src/agents/prompts/
34
+ join2(HERE2, "agents", "prompts", name),
35
+ // dist: dist/ → dist/agents/prompts/
36
+ join2(HERE2, "..", "..", "src", "agents", "prompts", name)
37
+ // fallback dev
38
+ ];
39
+ for (const p of candidates) {
40
+ try {
41
+ return readFileSync2(p, "utf8");
42
+ } catch {
43
+ }
44
+ }
45
+ throw new Error(`Could not find prompt file: ${name}`);
46
+ }
47
+ var primePrompt = readPrompt("prime.md");
48
+ var planPrompt = readPrompt("plan.md");
49
+ var buildPrompt = readPrompt("build.md");
50
+ var qaReviewerPrompt = readPrompt("qa-reviewer.md");
51
+ var qaThoroughPrompt = readPrompt("qa-thorough.md");
52
+ var planReviewerPrompt = readPrompt("plan-reviewer.md");
53
+ var codeSearcherPrompt = readPrompt("code-searcher.md");
54
+ var gapAnalyzerPrompt = readPrompt("gap-analyzer.md");
55
+ var architectureAdvisorPrompt = readPrompt("architecture-advisor.md");
56
+ var docsMaintainerPrompt = readPrompt("docs-maintainer.md");
57
+ var libReaderPrompt = readPrompt("lib-reader.md");
58
+ var agentsMdWriterPrompt = readPrompt("agents-md-writer.md");
59
+ var pilotBuilderPrompt = readPrompt("pilot-builder.md");
60
+ var pilotPlannerPrompt = readPrompt("pilot-planner.md");
61
+ var researchPrompt = readPrompt("research.md");
62
+ function stripFrontmatter(md) {
63
+ if (!md.startsWith("---")) return md;
64
+ const end = md.indexOf("\n---", 3);
65
+ if (end === -1) return md;
66
+ return md.slice(end + 4).trimStart();
67
+ }
68
+ function parseFrontmatter(md) {
69
+ if (!md.startsWith("---")) return {};
70
+ const end = md.indexOf("\n---", 3);
71
+ if (end === -1) return {};
72
+ const block = md.slice(4, end);
73
+ const result = {};
74
+ let currentKey = null;
75
+ let currentValue = [];
76
+ const flush = () => {
77
+ if (currentKey) {
78
+ result[currentKey] = currentValue.join(" ").trim();
79
+ }
80
+ };
81
+ for (const line of block.split("\n")) {
82
+ if (currentKey && (line.startsWith(" ") || line.startsWith(" "))) {
83
+ currentValue.push(line.trim());
84
+ continue;
85
+ }
86
+ const colon = line.indexOf(":");
87
+ if (colon === -1) {
88
+ flush();
89
+ currentKey = null;
90
+ currentValue = [];
91
+ continue;
92
+ }
93
+ flush();
94
+ currentKey = line.slice(0, colon).trim();
95
+ const value = line.slice(colon + 1).trim();
96
+ currentValue = value ? [value] : [];
97
+ }
98
+ flush();
99
+ return result;
100
+ }
101
+ function injectWorkflowMechanics(prompt) {
102
+ return prompt.replace("{WORKFLOW_MECHANICS_RULE}", WORKFLOW_MECHANICS_RULE);
103
+ }
104
+ function agentFromPrompt(raw, overrides = {}) {
105
+ const fm = parseFrontmatter(raw);
106
+ const body = stripFrontmatter(raw);
107
+ const prompt = injectWorkflowMechanics(body);
108
+ const base = {
109
+ description: fm["description"] ?? "",
110
+ mode: fm["mode"] ?? "subagent",
111
+ model: fm["model"] ?? void 0,
112
+ prompt
113
+ };
114
+ return { ...base, ...overrides };
115
+ }
116
+ var CORE_BASH_ALLOW_LIST = {
117
+ // File inspection — safe read-only commands the reviewers use heavily.
118
+ "ls *": "allow",
119
+ "cat *": "allow",
120
+ "head *": "allow",
121
+ "tail *": "allow",
122
+ "wc *": "allow",
123
+ "grep *": "allow",
124
+ "rg *": "allow",
125
+ "find *": "allow",
126
+ "file *": "allow",
127
+ "stat *": "allow",
128
+ "which *": "allow",
129
+ "whereis *": "allow",
130
+ "basename *": "allow",
131
+ "dirname *": "allow",
132
+ "realpath *": "allow",
133
+ "readlink *": "allow",
134
+ "diff *": "allow",
135
+ "sort *": "allow",
136
+ "uniq *": "allow",
137
+ "xxd *": "allow",
138
+ "tree *": "allow",
139
+ "date *": "allow",
140
+ "echo *": "allow",
141
+ // Git read-only subcommands (explicit rather than `git *` so we don't
142
+ // accidentally whitelist `git push` variants the destructive-deny
143
+ // table counteracts via longer-pattern matches — but clarity > trust).
144
+ "git status *": "allow",
145
+ "git log *": "allow",
146
+ "git diff *": "allow",
147
+ "git show *": "allow",
148
+ "git branch *": "allow",
149
+ "git merge-base *": "allow",
150
+ "git rev-parse *": "allow",
151
+ "git rev-list *": "allow",
152
+ "git blame *": "allow",
153
+ "git config --get *": "allow",
154
+ "git config --get": "allow",
155
+ "git remote *": "allow",
156
+ "git stash list *": "allow",
157
+ "git stash list": "allow",
158
+ "git ls-files *": "allow",
159
+ "git describe *": "allow",
160
+ "git tag *": "allow",
161
+ "git fetch *": "allow",
162
+ // Package/build tooling — the reviewers run lint/test/typecheck.
163
+ "pnpm lint *": "allow",
164
+ "pnpm test *": "allow",
165
+ "pnpm typecheck *": "allow",
166
+ "pnpm build *": "allow",
167
+ "pnpm run *": "allow",
168
+ "pnpm install *": "allow",
169
+ "pnpm --filter *": "allow",
170
+ "pnpm -w *": "allow",
171
+ "bun run *": "allow",
172
+ "bun test *": "allow",
173
+ "bun install *": "allow",
174
+ "bunx *": "allow",
175
+ "npm run *": "allow",
176
+ "npm test *": "allow",
177
+ "npx *": "allow",
178
+ "yarn *": "allow",
179
+ "tsc *": "allow",
180
+ "eslint *": "allow",
181
+ "prettier *": "allow",
182
+ "biome *": "allow",
183
+ // Our own CLI — the plan agent and qa-reviewer both call plan-check/plan-dir.
184
+ "bunx @glrs-dev/harness-plugin-opencode *": "allow",
185
+ "glrs-oc *": "allow",
186
+ // GitHub CLI — read-only gh calls are fine; destructive `gh pr merge`
187
+ // is gated at the PRIME level by human intent (user runs /ship).
188
+ "gh pr view *": "allow",
189
+ "gh pr list *": "allow",
190
+ "gh issue view *": "allow",
191
+ "gh issue list *": "allow",
192
+ "gh api *": "allow"
193
+ };
194
+ var CORE_DESTRUCTIVE_BASH_DENIES = {
195
+ "rm -rf /*": "deny",
196
+ "rm -rf ~*": "deny",
197
+ "chmod *": "deny",
198
+ "chown *": "deny",
199
+ "sudo *": "deny",
200
+ "git push --force*": "deny",
201
+ "git push -f *": "deny",
202
+ "git push * --force*": "deny",
203
+ "git push * -f": "deny",
204
+ "git push * main*": "deny",
205
+ "git push * master*": "deny",
206
+ // --force-with-lease is the safe variant — explicit allow rule sorts
207
+ // after the broad --force deny so the lease variant survives.
208
+ "git push --force-with-lease*": "allow",
209
+ "git push * --force-with-lease*": "allow"
210
+ };
211
+ var PRIME_PERMISSIONS = {
212
+ edit: "allow",
213
+ bash: {
214
+ "*": "allow",
215
+ ...CORE_BASH_ALLOW_LIST,
216
+ ...CORE_DESTRUCTIVE_BASH_DENIES,
217
+ // git clean & git reset --hard are allowed for prime because
218
+ // /fresh runs them after its own question-tool confirmation gate;
219
+ // a permission-layer prompt on top is redundant noise (see issue #54).
220
+ // BUILD keeps the stricter default (deny/ask).
221
+ "git clean *": "allow",
222
+ "git reset --hard*": "allow"
223
+ },
224
+ webfetch: "allow",
225
+ // Per-tool permissions (index signature on AgentConfig allows these)
226
+ ast_grep: "allow",
227
+ tsc_check: "allow",
228
+ eslint_check: "allow",
229
+ todo_scan: "allow",
230
+ comment_check: "allow",
231
+ question: "allow",
232
+ serena: "allow",
233
+ memory: "allow",
234
+ git: "allow",
235
+ playwright: "allow",
236
+ linear: "allow"
237
+ };
238
+ var PLAN_PERMISSIONS = {
239
+ edit: "allow",
240
+ // Plan agent is read-only aside from writing under the plan dir — but
241
+ // it does need to RESOLVE the plan dir via the `plan-dir` CLI
242
+ // subcommand (returns an absolute path derived from the worktree's
243
+ // repo-folder key; see src/plan-paths.ts and src/cli.ts). The object-
244
+ // form denies bash broadly and re-allows only `bunx
245
+ // @glrs-dev/harness-plugin-opencode plan-dir[...]`. No other bash invocation
246
+ // is permitted, so the read-only-aside-from-plans invariant holds.
247
+ bash: {
248
+ "*": "deny",
249
+ "bunx @glrs-dev/harness-plugin-opencode plan-dir": "allow",
250
+ "bunx @glrs-dev/harness-plugin-opencode plan-dir *": "allow",
251
+ "glrs-oc plan-dir": "allow",
252
+ "glrs-oc plan-dir *": "allow"
253
+ },
254
+ webfetch: "allow",
255
+ ast_grep: "deny",
256
+ tsc_check: "deny",
257
+ eslint_check: "deny",
258
+ todo_scan: "allow",
259
+ comment_check: "allow",
260
+ question: "allow",
261
+ serena: "allow",
262
+ memory: "allow",
263
+ git: "allow",
264
+ playwright: "deny",
265
+ linear: "allow"
266
+ };
267
+ var BUILD_PERMISSIONS = {
268
+ edit: "allow",
269
+ bash: {
270
+ "*": "allow",
271
+ ...CORE_BASH_ALLOW_LIST,
272
+ ...CORE_DESTRUCTIVE_BASH_DENIES,
273
+ // Build is stricter than prime on mutation: no `git clean`
274
+ // (build shouldn't wipe worktree mid-execution), and
275
+ // `git reset --hard` must prompt explicitly.
276
+ "git clean *": "deny",
277
+ "git reset --hard*": "ask"
278
+ },
279
+ webfetch: "allow",
280
+ ast_grep: "allow",
281
+ tsc_check: "allow",
282
+ eslint_check: "allow",
283
+ todo_scan: "allow",
284
+ comment_check: "allow",
285
+ question: "allow",
286
+ serena: "allow",
287
+ memory: "allow",
288
+ git: "allow",
289
+ playwright: "allow",
290
+ linear: "allow"
291
+ };
292
+ var QA_REVIEWER_PERMISSIONS = {
293
+ edit: "deny",
294
+ // Object-form bash: the scalar `"allow"` shape loses to OpenCode's
295
+ // upstream subagent-default `{bash, *, ask}` via last-match-wins (see
296
+ // the root-cause comment near PRIME_PERMISSIONS). Enumerated
297
+ // specific patterns in CORE_BASH_ALLOW_LIST sort AFTER the upstream
298
+ // wildcard ask and win for the commands they match. `"*": "allow"`
299
+ // is kept as a backstop but may still lose to the upstream rule for
300
+ // commands not in the enumerated list; those are the known blind spot.
301
+ bash: {
302
+ "*": "allow",
303
+ ...CORE_BASH_ALLOW_LIST,
304
+ ...CORE_DESTRUCTIVE_BASH_DENIES
305
+ },
306
+ webfetch: "deny",
307
+ ast_grep: "allow",
308
+ tsc_check: "allow",
309
+ eslint_check: "allow",
310
+ todo_scan: "allow",
311
+ comment_check: "allow",
312
+ question: "allow",
313
+ serena: "allow",
314
+ memory: "deny",
315
+ git: "allow",
316
+ playwright: "allow",
317
+ linear: "deny"
318
+ };
319
+ var QA_THOROUGH_PERMISSIONS = {
320
+ edit: "deny",
321
+ // Same object-form as QA_REVIEWER_PERMISSIONS — see the shape rationale
322
+ // there. qa-thorough re-runs the full suite unconditionally (per its
323
+ // prompt), so it touches the same command surface as qa-reviewer and
324
+ // needs the identical bash allow-list.
325
+ bash: {
326
+ "*": "allow",
327
+ ...CORE_BASH_ALLOW_LIST,
328
+ ...CORE_DESTRUCTIVE_BASH_DENIES
329
+ },
330
+ webfetch: "deny",
331
+ ast_grep: "allow",
332
+ tsc_check: "allow",
333
+ eslint_check: "allow",
334
+ todo_scan: "allow",
335
+ comment_check: "allow",
336
+ question: "allow",
337
+ serena: "allow",
338
+ memory: "deny",
339
+ git: "allow",
340
+ playwright: "allow",
341
+ linear: "deny"
342
+ };
343
+ var PLAN_REVIEWER_PERMISSIONS = {
344
+ edit: "deny",
345
+ bash: "deny",
346
+ webfetch: "deny",
347
+ ast_grep: "allow",
348
+ tsc_check: "deny",
349
+ eslint_check: "deny",
350
+ todo_scan: "allow",
351
+ comment_check: "allow",
352
+ question: "allow",
353
+ serena: "allow",
354
+ memory: "deny",
355
+ git: "allow",
356
+ playwright: "deny",
357
+ linear: "deny"
358
+ };
359
+ var GAP_ANALYZER_PERMISSIONS = {
360
+ edit: "deny",
361
+ bash: "deny",
362
+ webfetch: "deny",
363
+ ast_grep: "deny",
364
+ tsc_check: "deny",
365
+ eslint_check: "deny",
366
+ todo_scan: "allow",
367
+ comment_check: "allow",
368
+ question: "allow",
369
+ serena: "allow",
370
+ memory: "allow",
371
+ git: "deny",
372
+ playwright: "deny",
373
+ linear: "allow"
374
+ };
375
+ var CODE_SEARCHER_PERMISSIONS = {
376
+ edit: "deny",
377
+ bash: "deny",
378
+ webfetch: "deny",
379
+ ast_grep: "allow",
380
+ tsc_check: "deny",
381
+ eslint_check: "deny",
382
+ todo_scan: "deny",
383
+ comment_check: "deny",
384
+ question: "allow",
385
+ serena: "allow",
386
+ memory: "deny",
387
+ git: "deny",
388
+ playwright: "deny",
389
+ linear: "deny"
390
+ };
391
+ var ARCHITECTURE_ADVISOR_PERMISSIONS = {
392
+ edit: "deny",
393
+ bash: "deny",
394
+ webfetch: "deny",
395
+ ast_grep: "allow",
396
+ tsc_check: "deny",
397
+ eslint_check: "deny",
398
+ todo_scan: "allow",
399
+ comment_check: "allow",
400
+ question: "allow",
401
+ serena: "allow",
402
+ memory: "allow",
403
+ git: "allow",
404
+ playwright: "deny",
405
+ linear: "allow"
406
+ };
407
+ var LIB_READER_PERMISSIONS = {
408
+ edit: "deny",
409
+ bash: "deny",
410
+ webfetch: "deny",
411
+ ast_grep: "deny",
412
+ tsc_check: "deny",
413
+ eslint_check: "deny",
414
+ todo_scan: "deny",
415
+ comment_check: "deny",
416
+ question: "allow",
417
+ serena: "deny",
418
+ memory: "allow",
419
+ git: "deny",
420
+ playwright: "deny",
421
+ linear: "deny"
422
+ };
423
+ var AGENTS_MD_WRITER_PERMISSIONS = {
424
+ edit: "allow",
425
+ bash: "ask",
426
+ // preserve ask-semantics from frontmatter
427
+ webfetch: "deny",
428
+ ast_grep: "allow",
429
+ tsc_check: "deny",
430
+ eslint_check: "deny",
431
+ todo_scan: "allow",
432
+ comment_check: "allow",
433
+ question: "allow",
434
+ serena: "allow",
435
+ memory: "deny",
436
+ git: "allow",
437
+ playwright: "deny",
438
+ linear: "deny"
439
+ };
440
+ var PILOT_BUILDER_PERMISSIONS = {
441
+ edit: "allow",
442
+ bash: {
443
+ "*": "allow",
444
+ ...CORE_BASH_ALLOW_LIST,
445
+ ...CORE_DESTRUCTIVE_BASH_DENIES,
446
+ // Pilot-specific destructive denies — the builder NEVER commits,
447
+ // pushes, switches branches, or opens PRs. The worker does this
448
+ // for the agent.
449
+ "git commit*": "deny",
450
+ "git push*": "deny",
451
+ "git tag*": "deny",
452
+ "git checkout *": "deny",
453
+ "git switch *": "deny",
454
+ "git branch *": "deny",
455
+ "git restore --source*": "deny",
456
+ "git reset *": "deny",
457
+ "gh pr *": "deny",
458
+ "gh release *": "deny"
459
+ },
460
+ webfetch: "allow",
461
+ ast_grep: "allow",
462
+ tsc_check: "allow",
463
+ eslint_check: "allow",
464
+ todo_scan: "allow",
465
+ comment_check: "allow",
466
+ // Builder is unattended — must never call the question tool. (The
467
+ // worker enforces this via the prompt + STOP protocol; permission
468
+ // denial is a backstop.)
469
+ question: "deny",
470
+ serena: "allow",
471
+ memory: "deny",
472
+ // pilot tasks are stateless; no per-session memory.
473
+ git: "allow",
474
+ // read-only git tools (status, log, diff).
475
+ playwright: "deny",
476
+ linear: "deny"
477
+ };
478
+ var PILOT_PLANNER_PERMISSIONS = {
479
+ edit: "allow",
480
+ bash: {
481
+ "*": "deny",
482
+ // Read-only inspection — same surface as PLAN_PERMISSIONS, plus a few.
483
+ "ls *": "allow",
484
+ "cat *": "allow",
485
+ "head *": "allow",
486
+ "tail *": "allow",
487
+ "wc *": "allow",
488
+ "grep *": "allow",
489
+ "rg *": "allow",
490
+ "find *": "allow",
491
+ "git status *": "allow",
492
+ "git log *": "allow",
493
+ "git diff *": "allow",
494
+ "git show *": "allow",
495
+ "git branch *": "allow",
496
+ "git rev-parse *": "allow",
497
+ // Pilot CLI: validate, plan-dir for self-check + path resolution.
498
+ "bunx @glrs-dev/harness-plugin-opencode pilot validate *": "allow",
499
+ "bunx @glrs-dev/harness-plugin-opencode pilot validate": "allow",
500
+ "bunx @glrs-dev/harness-plugin-opencode pilot plan-dir": "allow",
501
+ "bunx @glrs-dev/harness-plugin-opencode pilot plan-dir *": "allow",
502
+ "bunx @glrs-dev/harness-plugin-opencode plan-dir": "allow",
503
+ "bunx @glrs-dev/harness-plugin-opencode plan-dir *": "allow",
504
+ "glrs-oc pilot validate *": "allow",
505
+ "glrs-oc pilot validate": "allow",
506
+ "glrs-oc pilot plan-dir": "allow",
507
+ "glrs-oc pilot plan-dir *": "allow",
508
+ "glrs-oc plan-dir": "allow",
509
+ "glrs-oc plan-dir *": "allow"
510
+ },
511
+ // No webfetch by default — the planner reads tickets via the linear
512
+ // MCP. If the user invokes with a GitHub URL, they need the linear
513
+ // / webfetch combination explicitly. Mark deny here and the operator
514
+ // can override per-session.
515
+ webfetch: "deny",
516
+ ast_grep: "allow",
517
+ tsc_check: "deny",
518
+ // no need to typecheck; we're writing YAML.
519
+ eslint_check: "deny",
520
+ todo_scan: "allow",
521
+ comment_check: "allow",
522
+ question: "allow",
523
+ // the planner CAN ask the human (interactive).
524
+ serena: "allow",
525
+ memory: "deny",
526
+ git: "allow",
527
+ // read-only git tools.
528
+ playwright: "deny",
529
+ linear: "allow"
530
+ };
531
+ var RESEARCH_PERMISSIONS = {
532
+ edit: "allow",
533
+ bash: {
534
+ "*": "allow",
535
+ ...CORE_BASH_ALLOW_LIST,
536
+ ...CORE_DESTRUCTIVE_BASH_DENIES
537
+ },
538
+ webfetch: "allow",
539
+ ast_grep: "allow",
540
+ tsc_check: "deny",
541
+ eslint_check: "deny",
542
+ todo_scan: "allow",
543
+ comment_check: "allow",
544
+ question: "allow",
545
+ serena: "allow",
546
+ memory: "allow",
547
+ git: "allow",
548
+ playwright: "deny",
549
+ linear: "allow"
550
+ };
551
+ var AGENT_TIERS = {
552
+ prime: "deep",
553
+ plan: "deep",
554
+ "qa-thorough": "deep",
555
+ "architecture-advisor": "deep",
556
+ "plan-reviewer": "deep",
557
+ "gap-analyzer": "deep",
558
+ "pilot-planner": "deep",
559
+ research: "deep",
560
+ build: "mid",
561
+ "qa-reviewer": "mid",
562
+ "docs-maintainer": "mid",
563
+ "lib-reader": "mid",
564
+ "agents-md-writer": "mid",
565
+ "pilot-builder": "mid",
566
+ "code-searcher": "fast"
567
+ };
568
+ function createAgents() {
569
+ return {
570
+ // Primary agents
571
+ prime: agentFromPrompt(primePrompt, {
572
+ description: "End-to-end PRIME (Primary Routing and Intelligence Management Entity). Takes a request from intent to ready-to-ship in one session. Default primary agent.",
573
+ mode: "primary",
574
+ model: "anthropic/claude-opus-4-7",
575
+ temperature: 0.2,
576
+ permission: PRIME_PERMISSIONS
577
+ }),
578
+ plan: agentFromPrompt(planPrompt, {
579
+ description: "Interactive planner. Orchestrates gap analysis and adversarial review. Produces a written plan in the repo-shared plan directory (resolve via `bunx @glrs-dev/harness-plugin-opencode plan-dir`).",
580
+ mode: "all",
581
+ model: "anthropic/claude-opus-4-7",
582
+ temperature: 0.3,
583
+ permission: PLAN_PERMISSIONS
584
+ }),
585
+ build: agentFromPrompt(buildPrompt, {
586
+ description: "Executes a written plan. Runs tests inline, gates completion on QA review.",
587
+ mode: "all",
588
+ model: "anthropic/claude-sonnet-4-6",
589
+ temperature: 0.1,
590
+ permission: BUILD_PERMISSIONS
591
+ }),
592
+ // Subagents — model/mode/description from frontmatter, permissions
593
+ // via overrides (see permission blocks above). docs-maintainer has no
594
+ // frontmatter permission declaration and keeps that behavior.
595
+ "qa-reviewer": agentFromPrompt(qaReviewerPrompt, {
596
+ permission: QA_REVIEWER_PERMISSIONS
597
+ }),
598
+ "qa-thorough": agentFromPrompt(qaThoroughPrompt, {
599
+ permission: QA_THOROUGH_PERMISSIONS
600
+ }),
601
+ "plan-reviewer": agentFromPrompt(planReviewerPrompt, {
602
+ permission: PLAN_REVIEWER_PERMISSIONS
603
+ }),
604
+ "code-searcher": agentFromPrompt(codeSearcherPrompt, {
605
+ permission: CODE_SEARCHER_PERMISSIONS
606
+ }),
607
+ "gap-analyzer": agentFromPrompt(gapAnalyzerPrompt, {
608
+ permission: GAP_ANALYZER_PERMISSIONS
609
+ }),
610
+ "architecture-advisor": agentFromPrompt(architectureAdvisorPrompt, {
611
+ permission: ARCHITECTURE_ADVISOR_PERMISSIONS
612
+ }),
613
+ "docs-maintainer": agentFromPrompt(docsMaintainerPrompt),
614
+ "lib-reader": agentFromPrompt(libReaderPrompt, {
615
+ permission: LIB_READER_PERMISSIONS
616
+ }),
617
+ "agents-md-writer": agentFromPrompt(agentsMdWriterPrompt, {
618
+ permission: AGENTS_MD_WRITER_PERMISSIONS
619
+ }),
620
+ // Pilot subsystem agents (Phase F1 + F2). The frontmatter sets
621
+ // mode/model/description; temperature is passed via override
622
+ // because `agentFromPrompt` doesn't currently parse the
623
+ // temperature field (and we don't want to change that helper for
624
+ // every agent at once — out of scope for F1/F2).
625
+ "pilot-builder": agentFromPrompt(pilotBuilderPrompt, {
626
+ mode: "subagent",
627
+ model: "anthropic/claude-sonnet-4-6",
628
+ temperature: 0.1,
629
+ permission: PILOT_BUILDER_PERMISSIONS
630
+ }),
631
+ "pilot-planner": agentFromPrompt(pilotPlannerPrompt, {
632
+ mode: "subagent",
633
+ model: "anthropic/claude-opus-4-7",
634
+ temperature: 0.3,
635
+ permission: PILOT_PLANNER_PERMISSIONS
636
+ }),
637
+ // Research agent — mode:all for both primary invocation and task-tool dispatch
638
+ research: agentFromPrompt(researchPrompt, {
639
+ description: "Research orchestrator \u2014 decomposes a research query into parallel workstreams, dispatches research skills (research / research-web / research-local / research-auto) as subagents, reviews findings for gaps, iterates, and synthesizes. Use when the user asks to investigate, explore, deep-dive, or understand a complex topic that needs multiple workstreams.",
640
+ mode: "all",
641
+ model: "anthropic/claude-opus-4-7",
642
+ temperature: 0.3,
643
+ permission: RESEARCH_PERMISSIONS
644
+ })
645
+ };
646
+ }
647
+
648
+ // src/model-validator.ts
649
+ var CATWALK_PROVIDER_PATTERN = /^(?:bedrock|vertex|vertexai)\//;
650
+ var LEGACY_PRE_100_PATTERN = /^(bedrock|vertex|vertexai)\/claude-(opus|sonnet|haiku)(-\d+)?$/;
651
+ var LEGACY_TO_MODELS_DEV = {
652
+ // --- Pre-PR-#100 Bedrock (no subpath) ---
653
+ "bedrock/claude-opus": "amazon-bedrock/global.anthropic.claude-opus-4-7",
654
+ "bedrock/claude-opus-4": "amazon-bedrock/global.anthropic.claude-opus-4-7",
655
+ "bedrock/claude-sonnet": "amazon-bedrock/global.anthropic.claude-sonnet-4-6",
656
+ "bedrock/claude-sonnet-4": "amazon-bedrock/global.anthropic.claude-sonnet-4-6",
657
+ "bedrock/claude-haiku": "amazon-bedrock/global.anthropic.claude-haiku-4-5-20251001-v1:0",
658
+ "bedrock/claude-haiku-4": "amazon-bedrock/global.anthropic.claude-haiku-4-5-20251001-v1:0",
659
+ // --- Pre-Models.dev Bedrock (had subpath, but wrong provider prefix) ---
660
+ "bedrock/anthropic.claude-opus-4-6": "amazon-bedrock/global.anthropic.claude-opus-4-7",
661
+ "bedrock/anthropic.claude-opus-4-7": "amazon-bedrock/global.anthropic.claude-opus-4-7",
662
+ "bedrock/anthropic.claude-sonnet-4-6": "amazon-bedrock/global.anthropic.claude-sonnet-4-6",
663
+ "bedrock/anthropic.claude-haiku-4-5-20251001-v1:0": "amazon-bedrock/global.anthropic.claude-haiku-4-5-20251001-v1:0",
664
+ // --- Pre-PR-#100 Vertex (no @date suffix) ---
665
+ "vertex/claude-opus": "google-vertex-anthropic/claude-opus-4-7@default",
666
+ "vertex/claude-opus-4": "google-vertex-anthropic/claude-opus-4-7@default",
667
+ "vertex/claude-sonnet": "google-vertex-anthropic/claude-sonnet-4-6@default",
668
+ "vertex/claude-sonnet-4": "google-vertex-anthropic/claude-sonnet-4-6@default",
669
+ "vertex/claude-haiku": "google-vertex-anthropic/claude-haiku-4-5@20251001",
670
+ "vertex/claude-haiku-4": "google-vertex-anthropic/claude-haiku-4-5@20251001",
671
+ "vertexai/claude-opus": "google-vertex-anthropic/claude-opus-4-7@default",
672
+ "vertexai/claude-opus-4": "google-vertex-anthropic/claude-opus-4-7@default",
673
+ "vertexai/claude-sonnet": "google-vertex-anthropic/claude-sonnet-4-6@default",
674
+ "vertexai/claude-sonnet-4": "google-vertex-anthropic/claude-sonnet-4-6@default",
675
+ "vertexai/claude-haiku": "google-vertex-anthropic/claude-haiku-4-5@20251001",
676
+ "vertexai/claude-haiku-4": "google-vertex-anthropic/claude-haiku-4-5@20251001",
677
+ // --- Pre-Models.dev Vertex (had @date suffix, wrong provider prefix) ---
678
+ "vertexai/claude-opus-4-6@20250610": "google-vertex-anthropic/claude-opus-4-6@default",
679
+ "vertexai/claude-opus-4-7@20250610": "google-vertex-anthropic/claude-opus-4-7@default",
680
+ "vertexai/claude-sonnet-4-6@20250725": "google-vertex-anthropic/claude-sonnet-4-6@default",
681
+ "vertexai/claude-haiku-4-5@20251001": "google-vertex-anthropic/claude-haiku-4-5@20251001"
682
+ };
683
+ function validateModelOverride(id) {
684
+ if (typeof id !== "string") return { valid: true };
685
+ if (id.length === 0) return { valid: true };
686
+ if (CATWALK_PROVIDER_PATTERN.test(id)) {
687
+ const suggestion = LEGACY_TO_MODELS_DEV[id] ?? "run `bunx @glrs-dev/harness-plugin-opencode install` to pick a current preset";
688
+ const reason = LEGACY_PRE_100_PATTERN.test(id) ? `"${id}" is a pre-PR-#100 model ID format that does not resolve in OpenCode. Bedrock IDs need the \`amazon-bedrock\` provider prefix (not \`bedrock\`); Vertex Claude IDs need the \`google-vertex-anthropic\` provider prefix (not \`vertex\` / \`vertexai\`).` : `"${id}" uses a provider prefix (\`${id.split("/")[0]}\`) that does not exist in OpenCode's runtime. AWS Bedrock's provider ID is \`amazon-bedrock\`; Vertex Claude's is \`google-vertex-anthropic\`.`;
689
+ return { valid: false, reason, suggestion };
690
+ }
691
+ return { valid: true };
692
+ }
693
+ function formatModelOverrideWarning(id, source, suggestion) {
694
+ const suggestionText = suggestion ? ` Suggested replacement: \`${suggestion}\`.` : "";
695
+ return `[@glrs-dev/harness-plugin-opencode] Warning: invalid model override "${id}" (from ${source}).${suggestionText} Run \`bunx @glrs-dev/harness-plugin-opencode doctor\` for details.`;
696
+ }
697
+
698
+ export {
699
+ AGENT_TIERS,
700
+ createAgents,
701
+ validateModelOverride,
702
+ formatModelOverrideWarning
703
+ };