@glrs-dev/harness-plugin-opencode 2.1.0 → 2.3.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.
- package/CHANGELOG.md +133 -0
- package/README.md +42 -106
- package/SECURITY.md +1 -1
- package/dist/agents/prompts/build.md +34 -4
- package/dist/agents/prompts/build.open.md +18 -4
- package/dist/agents/prompts/code-reviewer-thorough.md +77 -0
- package/dist/agents/prompts/code-reviewer.md +80 -0
- package/dist/agents/prompts/code-reviewer.open.md +68 -0
- package/dist/agents/prompts/debriefer.md +55 -0
- package/dist/agents/prompts/gap-analyzer.md +2 -0
- package/dist/agents/prompts/plan-reviewer.md +5 -1
- package/dist/agents/prompts/plan.md +119 -10
- package/dist/agents/prompts/prime.md +149 -88
- package/dist/agents/prompts/research-auto.md +1 -1
- package/dist/agents/prompts/research-local.md +1 -1
- package/dist/agents/prompts/research-web.md +1 -1
- package/dist/agents/prompts/research.md +2 -0
- package/dist/agents/prompts/scoper.md +129 -0
- package/dist/agents/prompts/spec-reviewer.md +53 -0
- package/dist/agents/prompts/spec-reviewer.open.md +56 -0
- package/dist/agents/shared/index.ts +1 -0
- package/dist/agents/shared/ui-evaluation-ladder.md +50 -0
- package/dist/agents/shared/workflow-mechanics.md +5 -5
- package/dist/autopilot/prompt-template.md +104 -0
- package/dist/chunk-GCWHRUOK.js +259 -0
- package/dist/chunk-MJSMBY2Y.js +87 -0
- package/dist/chunk-NIFAVPNN.js +544 -0
- package/dist/{chunk-VJUETC6A.js → chunk-PDMXYZM4.js} +53 -1
- package/dist/cli.js +1596 -1964
- package/dist/commands/prompts/fresh.md +27 -24
- package/dist/commands/prompts/review.md +3 -3
- package/dist/commands/prompts/ship.md +2 -0
- package/dist/index.js +188 -633
- package/dist/loop-session-J35NILUZ.js +30 -0
- package/dist/opencode-server-KPCDFYAX.js +22 -0
- package/dist/plan-parser-TMHEKT22.js +6 -0
- package/dist/plan-session-7VS32P52.js +117 -0
- package/dist/scoper-S77SOK7X.js +326 -0
- package/dist/skills/adversarial-review-rubric/SKILL.md +47 -0
- package/dist/skills/code-quality/SKILL.md +1 -1
- package/dist/skills/root-cause-diagnosis/SKILL.md +24 -0
- package/dist/skills/spear-protocol/SKILL.md +167 -0
- package/package.json +3 -1
- package/dist/agents/prompts/pilot-assessor.md +0 -77
- package/dist/agents/prompts/pilot-builder.md +0 -40
- package/dist/agents/prompts/pilot-planner.md +0 -56
- package/dist/agents/prompts/pilot-scoper.md +0 -58
- package/dist/agents/prompts/qa-reviewer.md +0 -68
- package/dist/agents/prompts/qa-reviewer.open.md +0 -58
- package/dist/agents/prompts/qa-thorough.md +0 -63
- package/dist/bin/plan-check.sh +0 -255
- package/dist/chunk-6CZPRUMJ.js +0 -869
- package/dist/chunk-DZG4D3OH.js +0 -54
- package/dist/chunk-OYRKOEXK.js +0 -88
- package/dist/commands/prompts/autopilot.md +0 -96
- package/dist/install-6775ZBDG.js +0 -13
- package/dist/paths-WZ23ZQOV.js +0 -18
package/dist/index.js
CHANGED
|
@@ -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
|
-
|
|
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";
|
|
@@ -60,12 +59,15 @@ function readPrompt(name) {
|
|
|
60
59
|
throw new Error(`Could not find prompt file: ${name}`);
|
|
61
60
|
}
|
|
62
61
|
var primePrompt = readPrompt("prime.md");
|
|
62
|
+
var scoperPrompt = readPrompt("scoper.md");
|
|
63
63
|
var planPrompt = readPrompt("plan.md");
|
|
64
64
|
var buildPrompt = readPrompt("build.md");
|
|
65
65
|
var buildOpenPrompt = readPrompt("build.open.md");
|
|
66
|
-
var
|
|
67
|
-
var
|
|
68
|
-
var
|
|
66
|
+
var specReviewerPrompt = readPrompt("spec-reviewer.md");
|
|
67
|
+
var specReviewerOpenPrompt = readPrompt("spec-reviewer.open.md");
|
|
68
|
+
var codeReviewerPrompt = readPrompt("code-reviewer.md");
|
|
69
|
+
var codeReviewerOpenPrompt = readPrompt("code-reviewer.open.md");
|
|
70
|
+
var codeReviewerThoroughPrompt = readPrompt("code-reviewer-thorough.md");
|
|
69
71
|
var planReviewerPrompt = readPrompt("plan-reviewer.md");
|
|
70
72
|
var codeSearcherPrompt = readPrompt("code-searcher.md");
|
|
71
73
|
var gapAnalyzerPrompt = readPrompt("gap-analyzer.md");
|
|
@@ -73,18 +75,15 @@ var architectureAdvisorPrompt = readPrompt("architecture-advisor.md");
|
|
|
73
75
|
var docsMaintainerPrompt = readPrompt("docs-maintainer.md");
|
|
74
76
|
var libReaderPrompt = readPrompt("lib-reader.md");
|
|
75
77
|
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
78
|
var researchPrompt = readPrompt("research.md");
|
|
81
79
|
var researchWebPrompt = readPrompt("research-web.md");
|
|
82
80
|
var researchLocalPrompt = readPrompt("research-local.md");
|
|
83
81
|
var researchAutoPrompt = readPrompt("research-auto.md");
|
|
82
|
+
var debrieferPrompt = readPrompt("debriefer.md");
|
|
84
83
|
var EXECUTOR_VARIANT_AGENTS = {
|
|
85
84
|
build: { reasoning: buildPrompt, strict: buildOpenPrompt },
|
|
86
|
-
"
|
|
87
|
-
"
|
|
85
|
+
"spec-reviewer": { reasoning: specReviewerPrompt, strict: specReviewerOpenPrompt },
|
|
86
|
+
"code-reviewer": { reasoning: codeReviewerPrompt, strict: codeReviewerOpenPrompt }
|
|
88
87
|
};
|
|
89
88
|
function getStrictPrompt(agentName) {
|
|
90
89
|
const variants = EXECUTOR_VARIANT_AGENTS[agentName];
|
|
@@ -135,10 +134,13 @@ function parseFrontmatter(md) {
|
|
|
135
134
|
function injectWorkflowMechanics(prompt) {
|
|
136
135
|
return prompt.replace("{WORKFLOW_MECHANICS_RULE}", WORKFLOW_MECHANICS_RULE);
|
|
137
136
|
}
|
|
137
|
+
function injectUIEvaluationLadder(prompt) {
|
|
138
|
+
return prompt.replace("{UI_EVALUATION_LADDER}", UI_EVALUATION_LADDER);
|
|
139
|
+
}
|
|
138
140
|
function agentFromPrompt(raw, overrides = {}) {
|
|
139
141
|
const fm = parseFrontmatter(raw);
|
|
140
142
|
const body = stripFrontmatter(raw);
|
|
141
|
-
const prompt = injectWorkflowMechanics(body);
|
|
143
|
+
const prompt = injectUIEvaluationLadder(injectWorkflowMechanics(body));
|
|
142
144
|
const base = {
|
|
143
145
|
description: fm["description"] ?? "",
|
|
144
146
|
mode: fm["mode"] ?? "subagent",
|
|
@@ -214,7 +216,7 @@ var CORE_BASH_ALLOW_LIST = {
|
|
|
214
216
|
"eslint *": "allow",
|
|
215
217
|
"prettier *": "allow",
|
|
216
218
|
"biome *": "allow",
|
|
217
|
-
// Our own CLI
|
|
219
|
+
// Our own CLI (install, doctor, autopilot, etc.) — reviewer/build invocations.
|
|
218
220
|
"bunx @glrs-dev/harness-plugin-opencode *": "allow",
|
|
219
221
|
"glrs-oc *": "allow",
|
|
220
222
|
// GitHub CLI — read-only gh calls are fine; destructive `gh pr merge`
|
|
@@ -269,21 +271,33 @@ var PRIME_PERMISSIONS = {
|
|
|
269
271
|
playwright: "allow",
|
|
270
272
|
linear: "allow"
|
|
271
273
|
};
|
|
274
|
+
var SCOPER_PERMISSIONS = {
|
|
275
|
+
...PRIME_PERMISSIONS
|
|
276
|
+
};
|
|
277
|
+
var SCOPER_DISABLED_TOOLS = {
|
|
278
|
+
question: false
|
|
279
|
+
};
|
|
280
|
+
var AUTOPILOT_PRIME_DISABLED_TOOLS = {
|
|
281
|
+
question: false
|
|
282
|
+
};
|
|
272
283
|
var PLAN_PERMISSIONS = {
|
|
273
284
|
edit: "allow",
|
|
274
|
-
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
//
|
|
285
|
+
write: "allow",
|
|
286
|
+
// Plan agent is read-only aside from writing under the plan dir. It
|
|
287
|
+
// resolves the plan dir inline (see src/agents/prompts/plan.md
|
|
288
|
+
// `## 4. Write the plan`): `$HOME/.glorious/opencode/<repo-folder>/plans/`,
|
|
289
|
+
// where `<repo-folder>` comes from
|
|
290
|
+
// `basename(dirname(git rev-parse --git-common-dir))`. The object-form
|
|
291
|
+
// denies bash broadly and re-allows only the four commands that snippet
|
|
292
|
+
// needs. Everything else remains denied, preserving the "plan writes only
|
|
293
|
+
// plan files" invariant (the write-scope constraint is prompt-enforced,
|
|
294
|
+
// not permission-enforced).
|
|
281
295
|
bash: {
|
|
282
296
|
"*": "deny",
|
|
283
|
-
"
|
|
284
|
-
"
|
|
285
|
-
"
|
|
286
|
-
"
|
|
297
|
+
"git rev-parse --git-common-dir": "allow",
|
|
298
|
+
"basename *": "allow",
|
|
299
|
+
"dirname *": "allow",
|
|
300
|
+
"mkdir -p *": "allow"
|
|
287
301
|
},
|
|
288
302
|
webfetch: "allow",
|
|
289
303
|
ast_grep: "deny",
|
|
@@ -295,7 +309,7 @@ var PLAN_PERMISSIONS = {
|
|
|
295
309
|
serena: "allow",
|
|
296
310
|
memory: "allow",
|
|
297
311
|
git: "allow",
|
|
298
|
-
playwright: "
|
|
312
|
+
playwright: "allow",
|
|
299
313
|
linear: "allow"
|
|
300
314
|
};
|
|
301
315
|
var BUILD_PERMISSIONS = {
|
|
@@ -323,15 +337,28 @@ var BUILD_PERMISSIONS = {
|
|
|
323
337
|
playwright: "allow",
|
|
324
338
|
linear: "allow"
|
|
325
339
|
};
|
|
326
|
-
var
|
|
340
|
+
var SPEC_REVIEWER_PERMISSIONS = {
|
|
341
|
+
edit: "deny",
|
|
342
|
+
bash: {
|
|
343
|
+
"*": "allow",
|
|
344
|
+
...CORE_BASH_ALLOW_LIST,
|
|
345
|
+
...CORE_DESTRUCTIVE_BASH_DENIES
|
|
346
|
+
},
|
|
347
|
+
webfetch: "deny",
|
|
348
|
+
ast_grep: "allow",
|
|
349
|
+
tsc_check: "allow",
|
|
350
|
+
eslint_check: "allow",
|
|
351
|
+
todo_scan: "allow",
|
|
352
|
+
comment_check: "allow",
|
|
353
|
+
question: "allow",
|
|
354
|
+
serena: "allow",
|
|
355
|
+
memory: "deny",
|
|
356
|
+
git: "allow",
|
|
357
|
+
playwright: "allow",
|
|
358
|
+
linear: "deny"
|
|
359
|
+
};
|
|
360
|
+
var CODE_REVIEWER_PERMISSIONS = {
|
|
327
361
|
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
362
|
bash: {
|
|
336
363
|
"*": "allow",
|
|
337
364
|
...CORE_BASH_ALLOW_LIST,
|
|
@@ -350,12 +377,8 @@ var QA_REVIEWER_PERMISSIONS = {
|
|
|
350
377
|
playwright: "allow",
|
|
351
378
|
linear: "deny"
|
|
352
379
|
};
|
|
353
|
-
var
|
|
380
|
+
var CODE_REVIEWER_THOROUGH_PERMISSIONS = {
|
|
354
381
|
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
382
|
bash: {
|
|
360
383
|
"*": "allow",
|
|
361
384
|
...CORE_BASH_ALLOW_LIST,
|
|
@@ -403,7 +426,7 @@ var GAP_ANALYZER_PERMISSIONS = {
|
|
|
403
426
|
serena: "allow",
|
|
404
427
|
memory: "allow",
|
|
405
428
|
git: "deny",
|
|
406
|
-
playwright: "
|
|
429
|
+
playwright: "allow",
|
|
407
430
|
linear: "allow"
|
|
408
431
|
};
|
|
409
432
|
var CODE_SEARCHER_PERMISSIONS = {
|
|
@@ -488,151 +511,59 @@ var RESEARCH_PERMISSIONS = {
|
|
|
488
511
|
serena: "allow",
|
|
489
512
|
memory: "allow",
|
|
490
513
|
git: "allow",
|
|
491
|
-
playwright: "
|
|
514
|
+
playwright: "allow",
|
|
492
515
|
linear: "allow"
|
|
493
516
|
};
|
|
494
|
-
var
|
|
495
|
-
prime: "deep",
|
|
496
|
-
plan: "deep",
|
|
497
|
-
"qa-thorough": "deep",
|
|
498
|
-
"architecture-advisor": "deep",
|
|
499
|
-
"plan-reviewer": "deep",
|
|
500
|
-
"gap-analyzer": "deep",
|
|
501
|
-
research: "deep",
|
|
502
|
-
"research-web": "deep",
|
|
503
|
-
"research-local": "deep",
|
|
504
|
-
"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
|
-
build: "mid-execute",
|
|
511
|
-
"qa-reviewer": "mid-execute",
|
|
512
|
-
"docs-maintainer": "mid",
|
|
513
|
-
"lib-reader": "mid",
|
|
514
|
-
"agents-md-writer": "mid",
|
|
515
|
-
"code-searcher": "fast"
|
|
516
|
-
};
|
|
517
|
-
var PILOT_SCOPER_PERMISSIONS = {
|
|
517
|
+
var DEBRIEFER_PERMISSIONS = {
|
|
518
518
|
edit: "deny",
|
|
519
519
|
bash: {
|
|
520
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
521
|
"git log *": "allow",
|
|
531
522
|
"git diff *": "allow",
|
|
532
523
|
"git show *": "allow",
|
|
524
|
+
"git status *": "allow",
|
|
525
|
+
"git rev-parse *": "allow",
|
|
533
526
|
"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
527
|
"cat *": "allow",
|
|
555
528
|
"head *": "allow",
|
|
556
529
|
"tail *": "allow",
|
|
557
|
-
"
|
|
558
|
-
"
|
|
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"
|
|
530
|
+
"ls *": "allow",
|
|
531
|
+
"wc *": "allow"
|
|
567
532
|
},
|
|
568
533
|
webfetch: "deny",
|
|
569
|
-
ast_grep: "
|
|
534
|
+
ast_grep: "deny",
|
|
570
535
|
tsc_check: "deny",
|
|
571
536
|
eslint_check: "deny",
|
|
572
|
-
todo_scan: "
|
|
573
|
-
comment_check: "
|
|
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",
|
|
537
|
+
todo_scan: "deny",
|
|
538
|
+
comment_check: "deny",
|
|
604
539
|
question: "deny",
|
|
605
|
-
serena: "
|
|
540
|
+
serena: "deny",
|
|
606
541
|
memory: "deny",
|
|
607
542
|
git: "allow",
|
|
608
543
|
playwright: "deny",
|
|
609
544
|
linear: "deny"
|
|
610
545
|
};
|
|
611
|
-
var
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
memory: "deny",
|
|
633
|
-
git: "allow",
|
|
634
|
-
playwright: "allow",
|
|
635
|
-
linear: "deny"
|
|
546
|
+
var AGENT_TIERS = {
|
|
547
|
+
prime: "deep",
|
|
548
|
+
scoper: "deep",
|
|
549
|
+
"autopilot-prime": "deep",
|
|
550
|
+
plan: "deep",
|
|
551
|
+
"architecture-advisor": "deep",
|
|
552
|
+
"plan-reviewer": "deep",
|
|
553
|
+
"gap-analyzer": "deep",
|
|
554
|
+
research: "deep",
|
|
555
|
+
"research-web": "deep",
|
|
556
|
+
"research-local": "deep",
|
|
557
|
+
"research-auto": "deep",
|
|
558
|
+
build: "mid-execute",
|
|
559
|
+
"spec-reviewer": "mid-execute",
|
|
560
|
+
"code-reviewer": "mid-execute",
|
|
561
|
+
"code-reviewer-thorough": "deep",
|
|
562
|
+
"docs-maintainer": "mid",
|
|
563
|
+
"lib-reader": "mid",
|
|
564
|
+
"agents-md-writer": "mid",
|
|
565
|
+
debriefer: "mid",
|
|
566
|
+
"code-searcher": "fast"
|
|
636
567
|
};
|
|
637
568
|
function createAgents() {
|
|
638
569
|
return {
|
|
@@ -644,11 +575,31 @@ function createAgents() {
|
|
|
644
575
|
temperature: 0.2,
|
|
645
576
|
permission: PRIME_PERMISSIONS
|
|
646
577
|
}),
|
|
578
|
+
scoper: agentFromPrompt(scoperPrompt, {
|
|
579
|
+
description: "Interactive scoping agent. Runs an inquirer-driven wizard loop \u2014 asks short questions via assistant text, collects answers via inquirer, then writes scope.md. Use at the start of a new feature to align on intent, constraints, and acceptance criteria before planning.",
|
|
580
|
+
mode: "primary",
|
|
581
|
+
model: "anthropic/claude-opus-4-7",
|
|
582
|
+
temperature: 0.3,
|
|
583
|
+
permission: SCOPER_PERMISSIONS,
|
|
584
|
+
tools: SCOPER_DISABLED_TOOLS
|
|
585
|
+
}),
|
|
586
|
+
"autopilot-prime": agentFromPrompt(primePrompt, {
|
|
587
|
+
description: "PRIME for unattended autopilot sessions. Identical to `prime` except the `question` tool is disabled \u2014 autopilot has no user to answer interactive prompts, and a blocking question deadlocks the session. Not user-selectable; invoked by the Ralph loop.",
|
|
588
|
+
mode: "subagent",
|
|
589
|
+
model: "anthropic/claude-opus-4-7",
|
|
590
|
+
temperature: 0.2,
|
|
591
|
+
permission: PRIME_PERMISSIONS,
|
|
592
|
+
tools: AUTOPILOT_PRIME_DISABLED_TOOLS
|
|
593
|
+
}),
|
|
647
594
|
plan: agentFromPrompt(planPrompt, {
|
|
648
|
-
description: "Interactive planner. Orchestrates gap analysis and adversarial review. Produces a written plan in the repo-shared plan directory (
|
|
595
|
+
description: "Interactive planner. Orchestrates gap analysis and adversarial review. Produces a written plan in the repo-shared plan directory (`~/.glorious/opencode/<repo-folder>/plans/`, resolved inline via `git rev-parse --git-common-dir`).",
|
|
649
596
|
mode: "all",
|
|
650
597
|
model: "anthropic/claude-opus-4-7",
|
|
651
598
|
temperature: 0.3,
|
|
599
|
+
// @plan dispatches @gap-analyzer, @code-searcher, and @plan-reviewer
|
|
600
|
+
// as subagents. OpenCode strips the `task` tool from subagent contexts
|
|
601
|
+
// by default; explicit opt-in re-enables it.
|
|
602
|
+
tools: { task: true },
|
|
652
603
|
permission: PLAN_PERMISSIONS
|
|
653
604
|
}),
|
|
654
605
|
build: agentFromPrompt(buildPrompt, {
|
|
@@ -661,11 +612,14 @@ function createAgents() {
|
|
|
661
612
|
// Subagents — model/mode/description from frontmatter, permissions
|
|
662
613
|
// via overrides (see permission blocks above). docs-maintainer has no
|
|
663
614
|
// frontmatter permission declaration and keeps that behavior.
|
|
664
|
-
"
|
|
665
|
-
permission:
|
|
615
|
+
"spec-reviewer": agentFromPrompt(specReviewerPrompt, {
|
|
616
|
+
permission: SPEC_REVIEWER_PERMISSIONS
|
|
666
617
|
}),
|
|
667
|
-
"
|
|
668
|
-
permission:
|
|
618
|
+
"code-reviewer": agentFromPrompt(codeReviewerPrompt, {
|
|
619
|
+
permission: CODE_REVIEWER_PERMISSIONS
|
|
620
|
+
}),
|
|
621
|
+
"code-reviewer-thorough": agentFromPrompt(codeReviewerThoroughPrompt, {
|
|
622
|
+
permission: CODE_REVIEWER_THOROUGH_PERMISSIONS
|
|
669
623
|
}),
|
|
670
624
|
"plan-reviewer": agentFromPrompt(planReviewerPrompt, {
|
|
671
625
|
permission: PLAN_REVIEWER_PERMISSIONS
|
|
@@ -692,58 +646,42 @@ function createAgents() {
|
|
|
692
646
|
mode: "all",
|
|
693
647
|
model: "anthropic/claude-opus-4-7",
|
|
694
648
|
temperature: 0.3,
|
|
649
|
+
// @research dispatches @research-web, @research-local, @research-auto.
|
|
650
|
+
tools: { task: true },
|
|
695
651
|
permission: RESEARCH_PERMISSIONS
|
|
696
652
|
}),
|
|
697
|
-
// Research subagents — thin shims that load the bundled skills
|
|
653
|
+
// Research subagents — thin shims that load the bundled skills.
|
|
654
|
+
// mode: "subagent" — these are internal implementation details of
|
|
655
|
+
// @research's orchestration; users should invoke @research (mode:all)
|
|
656
|
+
// as the primary entry point, not these directly.
|
|
698
657
|
"research-web": agentFromPrompt(researchWebPrompt, {
|
|
699
658
|
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: "
|
|
659
|
+
mode: "subagent",
|
|
701
660
|
model: "anthropic/claude-opus-4-7",
|
|
702
661
|
temperature: 0.3,
|
|
662
|
+
// @research-web dispatches its own parallel workstream agents.
|
|
663
|
+
tools: { task: true },
|
|
703
664
|
permission: RESEARCH_PERMISSIONS
|
|
704
665
|
}),
|
|
705
666
|
"research-local": agentFromPrompt(researchLocalPrompt, {
|
|
706
667
|
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: "
|
|
668
|
+
mode: "subagent",
|
|
708
669
|
model: "anthropic/claude-opus-4-7",
|
|
709
670
|
temperature: 0.3,
|
|
671
|
+
// @research-local dispatches parallel Explore subagents.
|
|
672
|
+
tools: { task: true },
|
|
710
673
|
permission: RESEARCH_PERMISSIONS
|
|
711
674
|
}),
|
|
712
675
|
"research-auto": agentFromPrompt(researchAutoPrompt, {
|
|
713
676
|
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: "
|
|
677
|
+
mode: "subagent",
|
|
715
678
|
model: "anthropic/claude-opus-4-7",
|
|
716
679
|
temperature: 0.3,
|
|
717
680
|
permission: RESEARCH_PERMISSIONS
|
|
718
681
|
}),
|
|
719
|
-
//
|
|
720
|
-
|
|
721
|
-
|
|
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
|
|
682
|
+
// Debriefer — post-run summary agent for the autopilot CLI
|
|
683
|
+
debriefer: agentFromPrompt(debrieferPrompt, {
|
|
684
|
+
permission: DEBRIEFER_PERMISSIONS
|
|
747
685
|
})
|
|
748
686
|
};
|
|
749
687
|
}
|
|
@@ -770,7 +708,6 @@ function readPrompt2(name) {
|
|
|
770
708
|
}
|
|
771
709
|
throw new Error(`Could not find command prompt: ${name}`);
|
|
772
710
|
}
|
|
773
|
-
var autopilotPrompt = readPrompt2("autopilot.md");
|
|
774
711
|
var shipPrompt = readPrompt2("ship.md");
|
|
775
712
|
var reviewPrompt = readPrompt2("review.md");
|
|
776
713
|
var initDeepPrompt = readPrompt2("init-deep.md");
|
|
@@ -779,10 +716,6 @@ var freshPrompt = readPrompt2("fresh.md");
|
|
|
779
716
|
var costsPrompt = readPrompt2("costs.md");
|
|
780
717
|
function createCommands() {
|
|
781
718
|
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
719
|
ship: {
|
|
787
720
|
template: shipPrompt,
|
|
788
721
|
description: "Finalize, commit, push, and open a PR/MR. Human-gated at each step."
|
|
@@ -927,7 +860,7 @@ function resolveHarnessModels(agents, config, pluginOptions) {
|
|
|
927
860
|
}
|
|
928
861
|
}
|
|
929
862
|
if (midExecuteConfigured) {
|
|
930
|
-
const EXECUTOR_AGENTS = ["build", "
|
|
863
|
+
const EXECUTOR_AGENTS = ["build", "spec-reviewer", "code-reviewer"];
|
|
931
864
|
for (const agentName of EXECUTOR_AGENTS) {
|
|
932
865
|
const agentCfg = agents[agentName];
|
|
933
866
|
if (!agentCfg) continue;
|
|
@@ -1492,311 +1425,8 @@ function loadDotenv(directory) {
|
|
|
1492
1425
|
return { filesLoaded, varsSet };
|
|
1493
1426
|
}
|
|
1494
1427
|
|
|
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
1428
|
// src/plugins/notify.ts
|
|
1799
|
-
var
|
|
1429
|
+
var plugin = async ({ $, client }) => {
|
|
1800
1430
|
async function notify(title, message) {
|
|
1801
1431
|
if (process.platform === "darwin") {
|
|
1802
1432
|
const esc = (s) => s.replace(/"/g, '\\"');
|
|
@@ -1819,11 +1449,11 @@ var plugin2 = async ({ $, client }) => {
|
|
|
1819
1449
|
}
|
|
1820
1450
|
};
|
|
1821
1451
|
};
|
|
1822
|
-
var notify_default =
|
|
1452
|
+
var notify_default = plugin;
|
|
1823
1453
|
|
|
1824
1454
|
// src/plugins/cost-tracker.ts
|
|
1825
|
-
import * as
|
|
1826
|
-
import * as
|
|
1455
|
+
import * as fs3 from "fs/promises";
|
|
1456
|
+
import * as path3 from "path";
|
|
1827
1457
|
import * as os2 from "os";
|
|
1828
1458
|
var MAX_LINE_BYTES = 2048;
|
|
1829
1459
|
var ROLLUP_DEBOUNCE_MS = 5e3;
|
|
@@ -1831,11 +1461,11 @@ function resolveDataDir() {
|
|
|
1831
1461
|
const override = process.env.GLORIOUS_COST_TRACKER_DIR;
|
|
1832
1462
|
if (override) {
|
|
1833
1463
|
if (override.startsWith("~")) {
|
|
1834
|
-
return
|
|
1464
|
+
return path3.join(os2.homedir(), override.slice(1));
|
|
1835
1465
|
}
|
|
1836
1466
|
return override;
|
|
1837
1467
|
}
|
|
1838
|
-
return
|
|
1468
|
+
return path3.join(os2.homedir(), ".glorious", "opencode");
|
|
1839
1469
|
}
|
|
1840
1470
|
function zeroTokens() {
|
|
1841
1471
|
return {
|
|
@@ -1902,13 +1532,13 @@ function emptyRollup() {
|
|
|
1902
1532
|
byProvider: {}
|
|
1903
1533
|
};
|
|
1904
1534
|
}
|
|
1905
|
-
var
|
|
1535
|
+
var plugin2 = async () => {
|
|
1906
1536
|
if (process.env.GLORIOUS_COST_TRACKER === "0") {
|
|
1907
1537
|
return {};
|
|
1908
1538
|
}
|
|
1909
1539
|
const dataDir = resolveDataDir();
|
|
1910
|
-
const jsonlPath =
|
|
1911
|
-
const rollupPath =
|
|
1540
|
+
const jsonlPath = path3.join(dataDir, "costs.jsonl");
|
|
1541
|
+
const rollupPath = path3.join(dataDir, "costs.json");
|
|
1912
1542
|
const lastSeen = /* @__PURE__ */ new Map();
|
|
1913
1543
|
const messageMeta = /* @__PURE__ */ new Map();
|
|
1914
1544
|
const rollup = emptyRollup();
|
|
@@ -1924,7 +1554,7 @@ var plugin3 = async () => {
|
|
|
1924
1554
|
async function ensureDir() {
|
|
1925
1555
|
if (disabled) return false;
|
|
1926
1556
|
try {
|
|
1927
|
-
await
|
|
1557
|
+
await fs3.mkdir(dataDir, { recursive: true });
|
|
1928
1558
|
return true;
|
|
1929
1559
|
} catch (err) {
|
|
1930
1560
|
warnOnce("mkdir", err);
|
|
@@ -1973,13 +1603,13 @@ var plugin3 = async () => {
|
|
|
1973
1603
|
if (!await ensureDir()) return;
|
|
1974
1604
|
const tmp = `${rollupPath}.tmp.${process.pid}.${Math.random().toString(36).slice(2, 10)}`;
|
|
1975
1605
|
try {
|
|
1976
|
-
await
|
|
1977
|
-
await
|
|
1606
|
+
await fs3.writeFile(tmp, JSON.stringify(rollup, null, 2) + "\n", "utf8");
|
|
1607
|
+
await fs3.rename(tmp, rollupPath);
|
|
1978
1608
|
lastRollupWriteAt = now;
|
|
1979
1609
|
} catch (err) {
|
|
1980
1610
|
warnOnce("rollup-write", err);
|
|
1981
1611
|
try {
|
|
1982
|
-
await
|
|
1612
|
+
await fs3.unlink(tmp);
|
|
1983
1613
|
} catch {
|
|
1984
1614
|
}
|
|
1985
1615
|
}
|
|
@@ -1999,14 +1629,14 @@ var plugin3 = async () => {
|
|
|
1999
1629
|
return;
|
|
2000
1630
|
}
|
|
2001
1631
|
try {
|
|
2002
|
-
await
|
|
1632
|
+
await fs3.appendFile(jsonlPath, text, "utf8");
|
|
2003
1633
|
} catch (err) {
|
|
2004
1634
|
warnOnce("jsonl-append", err);
|
|
2005
1635
|
}
|
|
2006
1636
|
}
|
|
2007
1637
|
async function warmUp() {
|
|
2008
1638
|
try {
|
|
2009
|
-
const raw = await
|
|
1639
|
+
const raw = await fs3.readFile(jsonlPath, "utf8");
|
|
2010
1640
|
const byMsg = /* @__PURE__ */ new Map();
|
|
2011
1641
|
for (const rawLine of raw.split("\n")) {
|
|
2012
1642
|
if (!rawLine) continue;
|
|
@@ -2140,76 +1770,16 @@ var plugin3 = async () => {
|
|
|
2140
1770
|
}
|
|
2141
1771
|
};
|
|
2142
1772
|
};
|
|
2143
|
-
var cost_tracker_default =
|
|
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;
|
|
1773
|
+
var cost_tracker_default = plugin2;
|
|
2204
1774
|
|
|
2205
1775
|
// src/plugins/tool-hooks.ts
|
|
2206
1776
|
import * as crypto from "crypto";
|
|
2207
|
-
import * as
|
|
2208
|
-
import * as
|
|
1777
|
+
import * as fs4 from "fs";
|
|
1778
|
+
import * as path4 from "path";
|
|
2209
1779
|
import * as os3 from "os";
|
|
2210
|
-
import { execFile as
|
|
2211
|
-
import { promisify as
|
|
2212
|
-
var exec6 =
|
|
1780
|
+
import { execFile as execFileCb } from "child_process";
|
|
1781
|
+
import { promisify as promisify6 } from "util";
|
|
1782
|
+
var exec6 = promisify6(execFileCb);
|
|
2213
1783
|
var EDIT_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "patch", "multiedit"]);
|
|
2214
1784
|
var TS_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
2215
1785
|
var DEFAULT_BACKPRESSURE_THRESHOLD = 6e3;
|
|
@@ -2292,8 +1862,8 @@ function resolveConfig(config, pluginOptions) {
|
|
|
2292
1862
|
};
|
|
2293
1863
|
}
|
|
2294
1864
|
function getToolOutputDir() {
|
|
2295
|
-
const stateHome = process.env["XDG_STATE_HOME"] ||
|
|
2296
|
-
return
|
|
1865
|
+
const stateHome = process.env["XDG_STATE_HOME"] || path4.join(os3.homedir(), ".local", "state");
|
|
1866
|
+
return path4.join(stateHome, "harness-opencode", "tool-output");
|
|
2297
1867
|
}
|
|
2298
1868
|
function hashContent(content) {
|
|
2299
1869
|
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
@@ -2326,9 +1896,9 @@ async function resolveSessionDir(client, sess, sessionID) {
|
|
|
2326
1896
|
}
|
|
2327
1897
|
function isUnderToolOutputDir(filePath) {
|
|
2328
1898
|
try {
|
|
2329
|
-
const abs =
|
|
2330
|
-
const spillDir =
|
|
2331
|
-
return abs === spillDir || abs.startsWith(spillDir +
|
|
1899
|
+
const abs = path4.resolve(filePath);
|
|
1900
|
+
const spillDir = path4.resolve(getToolOutputDir());
|
|
1901
|
+
return abs === spillDir || abs.startsWith(spillDir + path4.sep);
|
|
2332
1902
|
} catch {
|
|
2333
1903
|
return false;
|
|
2334
1904
|
}
|
|
@@ -2362,9 +1932,9 @@ function applyBackpressure(cfg, toolName, callID, output, args) {
|
|
|
2362
1932
|
let diskPath = null;
|
|
2363
1933
|
try {
|
|
2364
1934
|
const dir = getToolOutputDir();
|
|
2365
|
-
|
|
2366
|
-
diskPath =
|
|
2367
|
-
|
|
1935
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
1936
|
+
diskPath = path4.join(dir, `${callID}.txt`);
|
|
1937
|
+
fs4.writeFileSync(diskPath, text);
|
|
2368
1938
|
} catch {
|
|
2369
1939
|
}
|
|
2370
1940
|
const pathNote = diskPath ? ` Full output saved to: ${diskPath}` : "";
|
|
@@ -2410,7 +1980,7 @@ ${tail}`;
|
|
|
2410
1980
|
}
|
|
2411
1981
|
async function runPostEditVerify(cfg, client, sess, sessionID, filePath, output) {
|
|
2412
1982
|
if (!cfg.enabled) return;
|
|
2413
|
-
const ext =
|
|
1983
|
+
const ext = path4.extname(filePath).toLowerCase();
|
|
2414
1984
|
if (!TS_EXTENSIONS.has(ext)) return;
|
|
2415
1985
|
const now = Date.now();
|
|
2416
1986
|
if (now - sess.lastVerifyTs < 2e3) return;
|
|
@@ -2443,17 +2013,17 @@ ${String(stderr)}`;
|
|
|
2443
2013
|
}
|
|
2444
2014
|
if (!raw.trim()) return;
|
|
2445
2015
|
const errors = parseTscOutput(raw);
|
|
2446
|
-
const normPath =
|
|
2016
|
+
const normPath = path4.resolve(cwd, filePath);
|
|
2447
2017
|
const fileErrors = errors.filter((e) => {
|
|
2448
|
-
const errPath =
|
|
2449
|
-
return
|
|
2018
|
+
const errPath = path4.isAbsolute(e.file) ? e.file : path4.resolve(cwd, e.file);
|
|
2019
|
+
return path4.normalize(errPath) === path4.normalize(normPath);
|
|
2450
2020
|
});
|
|
2451
2021
|
if (fileErrors.length === 0) return;
|
|
2452
2022
|
const { rows } = dedupeAndCap(fileErrors, VERIFY_MAX_ERRORS);
|
|
2453
2023
|
const lines = rows.map(formatRow);
|
|
2454
2024
|
output.output += `
|
|
2455
2025
|
|
|
2456
|
-
--- POST-EDIT DIAGNOSTICS (${fileErrors.length} error${fileErrors.length !== 1 ? "s" : ""} in ${
|
|
2026
|
+
--- POST-EDIT DIAGNOSTICS (${fileErrors.length} error${fileErrors.length !== 1 ? "s" : ""} in ${path4.basename(filePath)}) ---
|
|
2457
2027
|
` + lines.join("\n") + `
|
|
2458
2028
|
--- Fix these before proceeding ---`;
|
|
2459
2029
|
} catch {
|
|
@@ -2467,7 +2037,7 @@ function checkEditLoop(cfg, sess, filePath, output) {
|
|
|
2467
2037
|
output.output += `
|
|
2468
2038
|
|
|
2469
2039
|
--- LOOP WARNING ---
|
|
2470
|
-
You've edited ${
|
|
2040
|
+
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
2041
|
---`;
|
|
2472
2042
|
}
|
|
2473
2043
|
}
|
|
@@ -2485,7 +2055,7 @@ function checkReadDedup(cfg, sess, filePath, output) {
|
|
|
2485
2055
|
}
|
|
2486
2056
|
var pluginConfig = null;
|
|
2487
2057
|
var storedPluginOptions;
|
|
2488
|
-
var
|
|
2058
|
+
var plugin3 = async ({ client }, options) => {
|
|
2489
2059
|
storedPluginOptions = options;
|
|
2490
2060
|
return {
|
|
2491
2061
|
config: async (config) => {
|
|
@@ -2518,7 +2088,7 @@ var plugin4 = async ({ client }, options) => {
|
|
|
2518
2088
|
}
|
|
2519
2089
|
};
|
|
2520
2090
|
};
|
|
2521
|
-
var tool_hooks_default =
|
|
2091
|
+
var tool_hooks_default = plugin3;
|
|
2522
2092
|
|
|
2523
2093
|
// src/plugins/telemetry.ts
|
|
2524
2094
|
import { extname as extname2 } from "path";
|
|
@@ -2527,16 +2097,16 @@ import { extname as extname2 } from "path";
|
|
|
2527
2097
|
import { createHash as createHash2, randomUUID } from "crypto";
|
|
2528
2098
|
import { homedir as homedir4 } from "os";
|
|
2529
2099
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync } from "fs";
|
|
2530
|
-
import { join as
|
|
2100
|
+
import { join as join9 } from "path";
|
|
2531
2101
|
var APP_KEY = "A-US-3617699429";
|
|
2532
2102
|
var ENDPOINT = "https://us.aptabase.com/api/v0/event";
|
|
2533
2103
|
var PKG_NAME = "@glrs-dev/harness-plugin-opencode";
|
|
2534
|
-
var PKG_VERSION = true ? "2.
|
|
2104
|
+
var PKG_VERSION = true ? "2.3.0" : "dev";
|
|
2535
2105
|
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
2106
|
var SESSION_ID = randomUUID();
|
|
2537
2107
|
function getInstallId() {
|
|
2538
|
-
const dir =
|
|
2539
|
-
const file =
|
|
2108
|
+
const dir = join9(homedir4(), ".config", "harness-opencode");
|
|
2109
|
+
const file = join9(dir, "install-id");
|
|
2540
2110
|
try {
|
|
2541
2111
|
if (existsSync(file)) return readFileSync5(file, "utf8").trim();
|
|
2542
2112
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -2603,7 +2173,7 @@ function track(eventName, props = {}) {
|
|
|
2603
2173
|
}
|
|
2604
2174
|
|
|
2605
2175
|
// src/plugins/telemetry.ts
|
|
2606
|
-
var
|
|
2176
|
+
var plugin4 = async () => {
|
|
2607
2177
|
if (DISABLED) {
|
|
2608
2178
|
return {};
|
|
2609
2179
|
}
|
|
@@ -2665,7 +2235,7 @@ var plugin5 = async () => {
|
|
|
2665
2235
|
}
|
|
2666
2236
|
};
|
|
2667
2237
|
};
|
|
2668
|
-
var telemetry_default =
|
|
2238
|
+
var telemetry_default = plugin4;
|
|
2669
2239
|
|
|
2670
2240
|
// src/index.ts
|
|
2671
2241
|
var BUNDLED_VERSION = readOurPackageVersion(import.meta.url);
|
|
@@ -2710,22 +2280,19 @@ async function checkForUpdate(client) {
|
|
|
2710
2280
|
} catch {
|
|
2711
2281
|
}
|
|
2712
2282
|
}
|
|
2713
|
-
var
|
|
2283
|
+
var plugin5 = async (input, options) => {
|
|
2714
2284
|
const pluginOptions = options ?? {};
|
|
2715
2285
|
loadDotenv(input.directory);
|
|
2716
2286
|
checkForUpdate(input.client).catch(() => {
|
|
2717
2287
|
});
|
|
2718
|
-
const autopilotHooks = await autopilot_default(input);
|
|
2719
2288
|
const notifyHooks = await notify_default(input);
|
|
2720
2289
|
const costTrackerHooks = await cost_tracker_default(input);
|
|
2721
|
-
const pilotHooks = await pilot_plugin_default(input);
|
|
2722
2290
|
const toolHooks = await tool_hooks_default(input, pluginOptions);
|
|
2723
2291
|
const telemetryHooks = await telemetry_default(input);
|
|
2724
2292
|
const hooks = {
|
|
2725
2293
|
// Config hook: register agents, commands, MCPs, skills
|
|
2726
2294
|
config: async (config) => {
|
|
2727
2295
|
applyConfig(config, pluginOptions);
|
|
2728
|
-
if (autopilotHooks.config) await autopilotHooks.config(config);
|
|
2729
2296
|
if (notifyHooks.config) await notifyHooks.config(config);
|
|
2730
2297
|
if (costTrackerHooks.config) await costTrackerHooks.config(config);
|
|
2731
2298
|
if (toolHooks.config) await toolHooks.config(config);
|
|
@@ -2734,27 +2301,15 @@ var plugin6 = async (input, options) => {
|
|
|
2734
2301
|
tool: createTools(),
|
|
2735
2302
|
// Event handlers from sub-plugins
|
|
2736
2303
|
event: async (input2) => {
|
|
2737
|
-
if (autopilotHooks.event) await autopilotHooks.event(input2);
|
|
2738
2304
|
if (notifyHooks.event) await notifyHooks.event(input2);
|
|
2739
2305
|
if (costTrackerHooks.event) await costTrackerHooks.event(input2);
|
|
2740
2306
|
if (telemetryHooks.event) await telemetryHooks.event(input2);
|
|
2741
2307
|
}
|
|
2742
2308
|
};
|
|
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
2309
|
const hasTelemetryBefore = telemetryHooks["tool.execute.before"] !== void 0;
|
|
2753
|
-
|
|
2754
|
-
if (hasTelemetryBefore || hasPilotBefore) {
|
|
2310
|
+
if (hasTelemetryBefore) {
|
|
2755
2311
|
hooks["tool.execute.before"] = async (input2, output) => {
|
|
2756
2312
|
if (hasTelemetryBefore) await telemetryHooks["tool.execute.before"](input2, output);
|
|
2757
|
-
if (hasPilotBefore) await pilotHooks["tool.execute.before"](input2, output);
|
|
2758
2313
|
};
|
|
2759
2314
|
}
|
|
2760
2315
|
const hasToolHooksAfter = toolHooks["tool.execute.after"] !== void 0;
|
|
@@ -2767,7 +2322,7 @@ var plugin6 = async (input, options) => {
|
|
|
2767
2322
|
}
|
|
2768
2323
|
return hooks;
|
|
2769
2324
|
};
|
|
2770
|
-
var src_default =
|
|
2325
|
+
var src_default = plugin5;
|
|
2771
2326
|
export {
|
|
2772
2327
|
src_default as default
|
|
2773
2328
|
};
|