opencode-orchestrator 1.5.4 → 1.6.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.
package/dist/index.js CHANGED
@@ -1,5 +1,15 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
2
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
3
13
  var __esm = (fn, res, err) => function __init() {
4
14
  if (err) throw err[0];
5
15
  try {
@@ -8,10 +18,33 @@ var __esm = (fn, res, err) => function __init() {
8
18
  throw err = [e], e;
9
19
  }
10
20
  };
21
+ var __commonJS = (cb, mod) => function __require2() {
22
+ try {
23
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
24
+ } catch (e) {
25
+ throw mod = 0, e;
26
+ }
27
+ };
11
28
  var __export = (target, all) => {
12
29
  for (var name in all)
13
30
  __defProp(target, name, { get: all[name], enumerable: true });
14
31
  };
32
+ var __copyProps = (to, from, except, desc) => {
33
+ if (from && typeof from === "object" || typeof from === "function") {
34
+ for (let key of __getOwnPropNames(from))
35
+ if (!__hasOwnProp.call(to, key) && key !== except)
36
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
37
+ }
38
+ return to;
39
+ };
40
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
41
+ // If the importer is in node compatibility mode or this is not an ESM
42
+ // file that has been converted to a CommonJS file using a Babel-
43
+ // compatible transform (i.e. "__esModule" has not been set), then set
44
+ // "default" to the CommonJS "module.exports" for node compatibility.
45
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
46
+ mod
47
+ ));
15
48
 
16
49
  // src/shared/agent/types.ts
17
50
  var init_types = __esm({
@@ -1830,6 +1863,32 @@ var init_shared = __esm({
1830
1863
  }
1831
1864
  });
1832
1865
 
1866
+ // src/agents/prompts/registry.ts
1867
+ function interpolate(template, vars = {}) {
1868
+ return template.replace(
1869
+ /\{\{(\w+)\}\}/g,
1870
+ (match, key) => Object.prototype.hasOwnProperty.call(vars, key) ? String(vars[key]) : match
1871
+ );
1872
+ }
1873
+ function bodyOf(fragment) {
1874
+ return typeof fragment === "string" ? fragment : fragment.body;
1875
+ }
1876
+ function keptUnderProfile(fragment, profile) {
1877
+ if (profile !== "compact") return true;
1878
+ return typeof fragment === "string" ? true : !fragment.verbose;
1879
+ }
1880
+ function composePrompt(fragments, options = {}) {
1881
+ const profile = options.profile ?? "standard";
1882
+ const separator = options.separator ?? "\n\n";
1883
+ const joined = fragments.filter((fragment) => keptUnderProfile(fragment, profile)).map(bodyOf).join(separator);
1884
+ return interpolate(joined, options.vars);
1885
+ }
1886
+ var init_registry = __esm({
1887
+ "src/agents/prompts/registry.ts"() {
1888
+ "use strict";
1889
+ }
1890
+ });
1891
+
1833
1892
  // src/agents/prompts/01_philosophy/execution_assurance.ts
1834
1893
  var EXECUTION_ASSURANCE;
1835
1894
  var init_execution_assurance = __esm({
@@ -4490,8 +4549,9 @@ var init_commander = __esm({
4490
4549
  "src/agents/commander.ts"() {
4491
4550
  "use strict";
4492
4551
  init_agent();
4552
+ init_registry();
4493
4553
  init_prompts();
4494
- systemPrompt = [
4554
+ systemPrompt = composePrompt([
4495
4555
  CORE_PHILOSOPHY,
4496
4556
  COMMANDER_ROLE,
4497
4557
  COMMANDER_IDENTITY,
@@ -4515,7 +4575,7 @@ var init_commander = __esm({
4515
4575
  COMPLETION_CONDITIONS,
4516
4576
  AUTONOMOUS_MANDATE,
4517
4577
  MISSION_STATUS_FORMAT
4518
- ].join("\n\n");
4578
+ ]);
4519
4579
  commander = {
4520
4580
  id: AGENT_NAMES.COMMANDER,
4521
4581
  description: "Commander - orchestrator with parallel execution, loop state, and sync issue handling",
@@ -4526,6 +4586,154 @@ var init_commander = __esm({
4526
4586
  }
4527
4587
  });
4528
4588
 
4589
+ // node_modules/jsonc-parser/lib/umd/main.js
4590
+ var require_main = __commonJS({
4591
+ "node_modules/jsonc-parser/lib/umd/main.js"(exports, module) {
4592
+ (function(factory) {
4593
+ if (typeof module === "object" && typeof module.exports === "object") {
4594
+ var v = factory(__require, exports);
4595
+ if (v !== void 0) module.exports = v;
4596
+ } else if (typeof define === "function" && define.amd) {
4597
+ define(["require", "exports", "./impl/format", "./impl/edit", "./impl/scanner", "./impl/parser"], factory);
4598
+ }
4599
+ })(function(require3, exports2) {
4600
+ "use strict";
4601
+ Object.defineProperty(exports2, "__esModule", { value: true });
4602
+ exports2.applyEdits = exports2.modify = exports2.format = exports2.printParseErrorCode = exports2.ParseErrorCode = exports2.stripComments = exports2.visit = exports2.getNodeValue = exports2.getNodePath = exports2.findNodeAtOffset = exports2.findNodeAtLocation = exports2.parseTree = exports2.parse = exports2.getLocation = exports2.SyntaxKind = exports2.ScanError = exports2.createScanner = void 0;
4603
+ const formatter = require3("./impl/format");
4604
+ const edit = require3("./impl/edit");
4605
+ const scanner = require3("./impl/scanner");
4606
+ const parser = require3("./impl/parser");
4607
+ exports2.createScanner = scanner.createScanner;
4608
+ var ScanError;
4609
+ (function(ScanError2) {
4610
+ ScanError2[ScanError2["None"] = 0] = "None";
4611
+ ScanError2[ScanError2["UnexpectedEndOfComment"] = 1] = "UnexpectedEndOfComment";
4612
+ ScanError2[ScanError2["UnexpectedEndOfString"] = 2] = "UnexpectedEndOfString";
4613
+ ScanError2[ScanError2["UnexpectedEndOfNumber"] = 3] = "UnexpectedEndOfNumber";
4614
+ ScanError2[ScanError2["InvalidUnicode"] = 4] = "InvalidUnicode";
4615
+ ScanError2[ScanError2["InvalidEscapeCharacter"] = 5] = "InvalidEscapeCharacter";
4616
+ ScanError2[ScanError2["InvalidCharacter"] = 6] = "InvalidCharacter";
4617
+ })(ScanError || (exports2.ScanError = ScanError = {}));
4618
+ var SyntaxKind;
4619
+ (function(SyntaxKind2) {
4620
+ SyntaxKind2[SyntaxKind2["OpenBraceToken"] = 1] = "OpenBraceToken";
4621
+ SyntaxKind2[SyntaxKind2["CloseBraceToken"] = 2] = "CloseBraceToken";
4622
+ SyntaxKind2[SyntaxKind2["OpenBracketToken"] = 3] = "OpenBracketToken";
4623
+ SyntaxKind2[SyntaxKind2["CloseBracketToken"] = 4] = "CloseBracketToken";
4624
+ SyntaxKind2[SyntaxKind2["CommaToken"] = 5] = "CommaToken";
4625
+ SyntaxKind2[SyntaxKind2["ColonToken"] = 6] = "ColonToken";
4626
+ SyntaxKind2[SyntaxKind2["NullKeyword"] = 7] = "NullKeyword";
4627
+ SyntaxKind2[SyntaxKind2["TrueKeyword"] = 8] = "TrueKeyword";
4628
+ SyntaxKind2[SyntaxKind2["FalseKeyword"] = 9] = "FalseKeyword";
4629
+ SyntaxKind2[SyntaxKind2["StringLiteral"] = 10] = "StringLiteral";
4630
+ SyntaxKind2[SyntaxKind2["NumericLiteral"] = 11] = "NumericLiteral";
4631
+ SyntaxKind2[SyntaxKind2["LineCommentTrivia"] = 12] = "LineCommentTrivia";
4632
+ SyntaxKind2[SyntaxKind2["BlockCommentTrivia"] = 13] = "BlockCommentTrivia";
4633
+ SyntaxKind2[SyntaxKind2["LineBreakTrivia"] = 14] = "LineBreakTrivia";
4634
+ SyntaxKind2[SyntaxKind2["Trivia"] = 15] = "Trivia";
4635
+ SyntaxKind2[SyntaxKind2["Unknown"] = 16] = "Unknown";
4636
+ SyntaxKind2[SyntaxKind2["EOF"] = 17] = "EOF";
4637
+ })(SyntaxKind || (exports2.SyntaxKind = SyntaxKind = {}));
4638
+ exports2.getLocation = parser.getLocation;
4639
+ exports2.parse = parser.parse;
4640
+ exports2.parseTree = parser.parseTree;
4641
+ exports2.findNodeAtLocation = parser.findNodeAtLocation;
4642
+ exports2.findNodeAtOffset = parser.findNodeAtOffset;
4643
+ exports2.getNodePath = parser.getNodePath;
4644
+ exports2.getNodeValue = parser.getNodeValue;
4645
+ exports2.visit = parser.visit;
4646
+ exports2.stripComments = parser.stripComments;
4647
+ var ParseErrorCode;
4648
+ (function(ParseErrorCode2) {
4649
+ ParseErrorCode2[ParseErrorCode2["InvalidSymbol"] = 1] = "InvalidSymbol";
4650
+ ParseErrorCode2[ParseErrorCode2["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
4651
+ ParseErrorCode2[ParseErrorCode2["PropertyNameExpected"] = 3] = "PropertyNameExpected";
4652
+ ParseErrorCode2[ParseErrorCode2["ValueExpected"] = 4] = "ValueExpected";
4653
+ ParseErrorCode2[ParseErrorCode2["ColonExpected"] = 5] = "ColonExpected";
4654
+ ParseErrorCode2[ParseErrorCode2["CommaExpected"] = 6] = "CommaExpected";
4655
+ ParseErrorCode2[ParseErrorCode2["CloseBraceExpected"] = 7] = "CloseBraceExpected";
4656
+ ParseErrorCode2[ParseErrorCode2["CloseBracketExpected"] = 8] = "CloseBracketExpected";
4657
+ ParseErrorCode2[ParseErrorCode2["EndOfFileExpected"] = 9] = "EndOfFileExpected";
4658
+ ParseErrorCode2[ParseErrorCode2["InvalidCommentToken"] = 10] = "InvalidCommentToken";
4659
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfComment"] = 11] = "UnexpectedEndOfComment";
4660
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfString"] = 12] = "UnexpectedEndOfString";
4661
+ ParseErrorCode2[ParseErrorCode2["UnexpectedEndOfNumber"] = 13] = "UnexpectedEndOfNumber";
4662
+ ParseErrorCode2[ParseErrorCode2["InvalidUnicode"] = 14] = "InvalidUnicode";
4663
+ ParseErrorCode2[ParseErrorCode2["InvalidEscapeCharacter"] = 15] = "InvalidEscapeCharacter";
4664
+ ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
4665
+ })(ParseErrorCode || (exports2.ParseErrorCode = ParseErrorCode = {}));
4666
+ function printParseErrorCode(code) {
4667
+ switch (code) {
4668
+ case 1:
4669
+ return "InvalidSymbol";
4670
+ case 2:
4671
+ return "InvalidNumberFormat";
4672
+ case 3:
4673
+ return "PropertyNameExpected";
4674
+ case 4:
4675
+ return "ValueExpected";
4676
+ case 5:
4677
+ return "ColonExpected";
4678
+ case 6:
4679
+ return "CommaExpected";
4680
+ case 7:
4681
+ return "CloseBraceExpected";
4682
+ case 8:
4683
+ return "CloseBracketExpected";
4684
+ case 9:
4685
+ return "EndOfFileExpected";
4686
+ case 10:
4687
+ return "InvalidCommentToken";
4688
+ case 11:
4689
+ return "UnexpectedEndOfComment";
4690
+ case 12:
4691
+ return "UnexpectedEndOfString";
4692
+ case 13:
4693
+ return "UnexpectedEndOfNumber";
4694
+ case 14:
4695
+ return "InvalidUnicode";
4696
+ case 15:
4697
+ return "InvalidEscapeCharacter";
4698
+ case 16:
4699
+ return "InvalidCharacter";
4700
+ }
4701
+ return "<unknown ParseErrorCode>";
4702
+ }
4703
+ exports2.printParseErrorCode = printParseErrorCode;
4704
+ function format(documentText, range, options) {
4705
+ return formatter.format(documentText, range, options);
4706
+ }
4707
+ exports2.format = format;
4708
+ function modify(text, path11, value, options) {
4709
+ return edit.setProperty(text, path11, value, options);
4710
+ }
4711
+ exports2.modify = modify;
4712
+ function applyEdits(text, edits) {
4713
+ let sortedEdits = edits.slice(0).sort((a, b) => {
4714
+ const diff = a.offset - b.offset;
4715
+ if (diff === 0) {
4716
+ return a.length - b.length;
4717
+ }
4718
+ return diff;
4719
+ });
4720
+ let lastModifiedOffset = text.length;
4721
+ for (let i = sortedEdits.length - 1; i >= 0; i--) {
4722
+ let e = sortedEdits[i];
4723
+ if (e.offset + e.length <= lastModifiedOffset) {
4724
+ text = edit.applyEdit(text, e);
4725
+ } else {
4726
+ throw new Error("Overlapping edit");
4727
+ }
4728
+ lastModifiedOffset = e.offset;
4729
+ }
4730
+ return text;
4731
+ }
4732
+ exports2.applyEdits = applyEdits;
4733
+ });
4734
+ }
4735
+ });
4736
+
4529
4737
  // src/core/session/store.ts
4530
4738
  var store_exports = {};
4531
4739
  __export(store_exports, {
@@ -6268,8 +6476,9 @@ init_commander();
6268
6476
 
6269
6477
  // src/agents/subagents/planner.ts
6270
6478
  init_agent();
6479
+ init_registry();
6271
6480
  init_prompts();
6272
- var systemPrompt2 = [
6481
+ var systemPrompt2 = composePrompt([
6273
6482
  PLANNER_ROLE,
6274
6483
  MODULARITY_ENFORCEMENT,
6275
6484
  HYPER_PARALLEL_ENFORCEMENT,
@@ -6287,7 +6496,7 @@ var systemPrompt2 = [
6287
6496
  SHARED_AST_TOOLS,
6288
6497
  SKILLS_CAPABILITIES,
6289
6498
  SHARED_WORKSPACE
6290
- ].join("\n\n");
6499
+ ]);
6291
6500
  var planner = {
6292
6501
  id: AGENT_NAMES.PLANNER,
6293
6502
  description: "Planner - file-level planning, TODO creation and sync",
@@ -6298,8 +6507,9 @@ var planner = {
6298
6507
 
6299
6508
  // src/agents/subagents/worker.ts
6300
6509
  init_agent();
6510
+ init_registry();
6301
6511
  init_prompts();
6302
- var systemPrompt3 = [
6512
+ var systemPrompt3 = composePrompt([
6303
6513
  WORKER_ROLE,
6304
6514
  MODULARITY_ENFORCEMENT,
6305
6515
  HYPER_PARALLEL_ENFORCEMENT,
@@ -6319,7 +6529,7 @@ var systemPrompt3 = [
6319
6529
  SKILLS_CAPABILITIES,
6320
6530
  VERIFICATION_REQUIREMENTS,
6321
6531
  SHARED_WORKSPACE
6322
- ].join("\n\n");
6532
+ ]);
6323
6533
  var worker = {
6324
6534
  id: AGENT_NAMES.WORKER,
6325
6535
  description: "Worker - TDD file-level implementation, reads .opencode, follows Commander",
@@ -6330,8 +6540,9 @@ var worker = {
6330
6540
 
6331
6541
  // src/agents/subagents/reviewer.ts
6332
6542
  init_agent();
6543
+ init_registry();
6333
6544
  init_prompts();
6334
- var systemPrompt4 = [
6545
+ var systemPrompt4 = composePrompt([
6335
6546
  REVIEWER_ROLE,
6336
6547
  MODULARITY_ENFORCEMENT,
6337
6548
  HYPER_PARALLEL_ENFORCEMENT,
@@ -6349,7 +6560,7 @@ var systemPrompt4 = [
6349
6560
  SHARED_AST_TOOLS,
6350
6561
  EVIDENCE_FORMAT,
6351
6562
  SHARED_WORKSPACE
6352
- ].join("\n\n");
6563
+ ]);
6353
6564
  var reviewer = {
6354
6565
  id: AGENT_NAMES.REVIEWER,
6355
6566
  description: "Reviewer - async verification, integration testing, sync validation",
@@ -20887,6 +21098,7 @@ function date4(params) {
20887
21098
  config(en_default());
20888
21099
 
20889
21100
  // src/core/agents/agent-registry.ts
21101
+ var import_jsonc_parser = __toESM(require_main(), 1);
20890
21102
  var AgentDefinitionSchema = external_exports.object({
20891
21103
  id: external_exports.string(),
20892
21104
  // ID is required inside the definition object
@@ -20946,7 +21158,7 @@ var AgentRegistry = class _AgentRegistry {
20946
21158
  const agentsConfigPath = path2.join(this.directory, PATHS.AGENTS_CONFIG);
20947
21159
  try {
20948
21160
  const content = await fs2.readFile(agentsConfigPath, "utf-8");
20949
- const customAgents = JSON.parse(content);
21161
+ const customAgents = (0, import_jsonc_parser.parse)(content);
20950
21162
  if (typeof customAgents === "object" && customAgents !== null) {
20951
21163
  for (const [name, def] of Object.entries(customAgents)) {
20952
21164
  const result = AgentDefinitionSchema.safeParse(def);
@@ -20968,10 +21180,10 @@ var AgentRegistry = class _AgentRegistry {
20968
21180
 
20969
21181
  // src/core/agents/manager/task-launcher.ts
20970
21182
  var TaskLauncher = class {
20971
- constructor(client, directory, store, concurrency, sessionPool2, onTaskError, startPolling) {
21183
+ constructor(client, directory, store2, concurrency, sessionPool2, onTaskError, startPolling) {
20972
21184
  this.client = client;
20973
21185
  this.directory = directory;
20974
- this.store = store;
21186
+ this.store = store2;
20975
21187
  this.concurrency = concurrency;
20976
21188
  this.sessionPool = sessionPool2;
20977
21189
  this.onTaskError = onTaskError;
@@ -21146,9 +21358,9 @@ ${action.modifyPrompt}`;
21146
21358
  init_shared();
21147
21359
  init_logger();
21148
21360
  var TaskResumer = class {
21149
- constructor(client, store, findBySession, startPolling, notifyParentIfAllComplete) {
21361
+ constructor(client, store2, findBySession, startPolling, notifyParentIfAllComplete) {
21150
21362
  this.client = client;
21151
- this.store = store;
21363
+ this.store = store2;
21152
21364
  this.findBySession = findBySession;
21153
21365
  this.startPolling = startPolling;
21154
21366
  this.notifyParentIfAllComplete = notifyParentIfAllComplete;
@@ -21303,9 +21515,9 @@ var progressNotifier = ProgressNotifier.getInstance();
21303
21515
  // src/core/agents/manager/task-poller.ts
21304
21516
  var TaskPoller = class {
21305
21517
  // 5s when idle
21306
- constructor(client, store, concurrency, notifyParentIfAllComplete, scheduleCleanup, pruneExpiredTasks, onTaskComplete) {
21518
+ constructor(client, store2, concurrency, notifyParentIfAllComplete, scheduleCleanup, pruneExpiredTasks, onTaskComplete) {
21307
21519
  this.client = client;
21308
- this.store = store;
21520
+ this.store = store2;
21309
21521
  this.concurrency = concurrency;
21310
21522
  this.notifyParentIfAllComplete = notifyParentIfAllComplete;
21311
21523
  this.scheduleCleanup = scheduleCleanup;
@@ -21517,9 +21729,9 @@ init_shared();
21517
21729
  init_logger();
21518
21730
  init_store();
21519
21731
  var TaskCleaner = class {
21520
- constructor(client, store, concurrency, sessionPool2) {
21732
+ constructor(client, store2, concurrency, sessionPool2) {
21521
21733
  this.client = client;
21522
- this.store = store;
21734
+ this.store = store2;
21523
21735
  this.concurrency = concurrency;
21524
21736
  this.sessionPool = sessionPool2;
21525
21737
  }
@@ -21632,9 +21844,9 @@ You will be notified when ALL tasks complete. Continue productive work.`;
21632
21844
  init_shared();
21633
21845
  init_logger();
21634
21846
  var EventHandler = class {
21635
- constructor(client, store, concurrency, findBySession, notifyParentIfAllComplete, scheduleCleanup, validateSessionHasOutput2, onTaskComplete) {
21847
+ constructor(client, store2, concurrency, findBySession, notifyParentIfAllComplete, scheduleCleanup, validateSessionHasOutput2, onTaskComplete) {
21636
21848
  this.client = client;
21637
- this.store = store;
21849
+ this.store = store2;
21638
21850
  this.concurrency = concurrency;
21639
21851
  this.findBySession = findBySession;
21640
21852
  this.notifyParentIfAllComplete = notifyParentIfAllComplete;
@@ -22302,7 +22514,7 @@ var ParallelAgentManager = class _ParallelAgentManager {
22302
22514
  this.poller.stop();
22303
22515
  this.store.clear();
22304
22516
  MemoryManager.getInstance().clearTaskMemory();
22305
- Promise.resolve().then(() => (init_store(), store_exports)).then((store) => store.clearAll()).catch(() => {
22517
+ Promise.resolve().then(() => (init_store(), store_exports)).then((store2) => store2.clearAll()).catch(() => {
22306
22518
  });
22307
22519
  }
22308
22520
  /**
@@ -35608,6 +35820,7 @@ init_logger();
35608
35820
  // src/core/loop/mission-loop.ts
35609
35821
  init_logger();
35610
35822
  init_shared();
35823
+ init_constants6();
35611
35824
  import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync4 } from "node:fs";
35612
35825
  import { join as join6 } from "node:path";
35613
35826
 
@@ -35792,6 +36005,35 @@ function parseLedgerLine(line) {
35792
36005
  }
35793
36006
  }
35794
36007
 
36008
+ // src/core/knowledge/retrieval-weights.ts
36009
+ var NEUTRAL_WEIGHTS = { lexical: 1, tag: 1, graph: 1 };
36010
+ var ROLE_WEIGHTS = {
36011
+ // Planner reasons about dependencies/architecture -> favor structure.
36012
+ planner: { lexical: 0.8, tag: 1.1, graph: 1.3 },
36013
+ // Worker implements concrete changes -> favor exact lexical hits.
36014
+ worker: { lexical: 1.3, tag: 1, graph: 0.7 },
36015
+ // Reviewer needs breadth of evidence -> favor tag/topic coverage.
36016
+ reviewer: { lexical: 1, tag: 1.2, graph: 1 },
36017
+ // Commander coordinates -> neutral.
36018
+ commander: { lexical: 1, tag: 1, graph: 1 }
36019
+ };
36020
+ function weightsForRole(role) {
36021
+ if (!role) return NEUTRAL_WEIGHTS;
36022
+ return ROLE_WEIGHTS[role.toLowerCase()] ?? NEUTRAL_WEIGHTS;
36023
+ }
36024
+ function horizonForLevel(level) {
36025
+ switch (level) {
36026
+ case "system":
36027
+ case "project":
36028
+ return "strategic";
36029
+ case "task":
36030
+ return "closure";
36031
+ case "mission":
36032
+ default:
36033
+ return "execution";
36034
+ }
36035
+ }
36036
+
35795
36037
  // src/core/knowledge/mission-memory.ts
35796
36038
  var BRAIN_DIR = join5(PATHS.DOCS, "brain");
35797
36039
  var SCRATCHPAD_FILE = "scratchpad.md";
@@ -35964,6 +36206,7 @@ function buildMemoryNoteContent(state2, entry) {
35964
36206
  `title: "${escapeYaml(`${entry.level} memory ${entry.id}`)}"`,
35965
36207
  "keep: true",
35966
36208
  `level: "${entry.level}"`,
36209
+ `horizon: "${horizonForLevel(entry.level)}"`,
35967
36210
  `importance: ${entry.importance.toFixed(3)}`,
35968
36211
  `session: "${escapeYaml(state2.sessionID)}"`,
35969
36212
  `recorded_at: "${recordedAt}"`,
@@ -36005,6 +36248,7 @@ function capitalize(value) {
36005
36248
 
36006
36249
  // src/core/loop/mission-loop.ts
36007
36250
  var STATE_FILE = MISSION_CONTROL.STATE_FILE;
36251
+ var ESCALATION_STAGNATION_THRESHOLD = 5;
36008
36252
  var DEFAULT_MAX_ITERATIONS = MISSION_CONTROL.DEFAULT_MAX_ITERATIONS;
36009
36253
  var UNKNOWN_STATUS = "unknown";
36010
36254
  function getStateFilePath(directory) {
@@ -36143,7 +36387,28 @@ Next action:
36143
36387
 
36144
36388
  Completion rule:
36145
36389
  Do not declare success while TODO/checklist/sync verification is still failing.
36390
+ Before declaring done, briefly self-account: (1) scope fit vs the objective,
36391
+ (2) what verification ran, (3) any residual risk or follow-on wiring.
36146
36392
  </mission_loop>`;
36393
+ if (context.escalate) {
36394
+ prompt += `
36395
+
36396
+ <escalation reason="repeated_stagnation">
36397
+ Progress has stalled across ${context.stagnation}. Stop blind retries.
36398
+ Follow ${RECOVERY_PRINCIPLE}
36399
+ 1. DECOMPOSE the blocked step into smaller, independently verifiable pieces.
36400
+ 2. RE-PLAN with a different approach if decomposition does not unblock it.
36401
+ 3. If still blocked, summarize the exact blocker and ASK the user for direction.
36402
+ </escalation>`;
36403
+ }
36404
+ if (context.unverifiedChanges > 0) {
36405
+ prompt += `
36406
+
36407
+ <wiring_gate>
36408
+ ${context.unverifiedChanges} changed file(s) this mission have no verification evidence yet.
36409
+ Run the project's tests/build/lint over the changed surface and cite the result before declaring done.
36410
+ </wiring_gate>`;
36411
+ }
36147
36412
  if (state2.iteration > 1) {
36148
36413
  prompt += "\n" + CLEANUP_INSTRUCTION.replace("%ITER%", state2.iteration.toString());
36149
36414
  }
@@ -36152,13 +36417,16 @@ Do not declare success while TODO/checklist/sync verification is still failing.
36152
36417
  function normalizeContinuationContext(state2, input) {
36153
36418
  const verificationSummary = typeof input === "string" ? input : input?.verificationSummary;
36154
36419
  const continuationReason = typeof input === "string" ? void 0 : input?.continuationReason;
36420
+ const unverifiedChanges = typeof input === "string" ? 0 : input?.unverifiedChanges ?? 0;
36155
36421
  const stagnationCount = state2.stagnationCount ?? 0;
36156
36422
  return {
36157
36423
  objective: state2.objective || deriveObjective(state2.prompt),
36158
36424
  progress: state2.lastProgress ?? UNKNOWN_STATUS,
36159
36425
  verification: verificationSummary ?? state2.lastVerificationSummary ?? UNKNOWN_STATUS,
36160
36426
  reason: continuationReason ?? state2.lastContinuationReason ?? "verification_failed",
36161
- stagnation: stagnationCount > 0 ? `${stagnationCount} unchanged check(s)` : "not detected"
36427
+ stagnation: stagnationCount > 0 ? `${stagnationCount} unchanged check(s)` : "not detected",
36428
+ unverifiedChanges,
36429
+ escalate: stagnationCount >= ESCALATION_STAGNATION_THRESHOLD
36162
36430
  };
36163
36431
  }
36164
36432
 
@@ -39709,6 +39977,47 @@ Safely refactor code across files using syntax patterns.`,
39709
39977
 
39710
39978
  // src/tools/web/webfetch.ts
39711
39979
  init_shared();
39980
+
39981
+ // src/utils/parsing/safe-json.ts
39982
+ function stripCodeFence(input) {
39983
+ const trimmed = input.trim();
39984
+ const fence = /^```[a-zA-Z0-9]*\s*\n([\s\S]*?)\n```$/;
39985
+ const match = trimmed.match(fence);
39986
+ return match ? match[1].trim() : trimmed;
39987
+ }
39988
+ function extractBracketed(input) {
39989
+ const firstObj = input.indexOf("{");
39990
+ const firstArr = input.indexOf("[");
39991
+ const candidates = [firstObj, firstArr].filter((i) => i >= 0);
39992
+ if (candidates.length === 0) return null;
39993
+ const start = Math.min(...candidates);
39994
+ const open = input[start];
39995
+ const close = open === "{" ? "}" : "]";
39996
+ const end = input.lastIndexOf(close);
39997
+ if (end <= start) return null;
39998
+ return input.slice(start, end + 1);
39999
+ }
40000
+ function removeTrailingCommas(input) {
40001
+ return input.replace(/,(\s*[}\]])/g, "$1");
40002
+ }
40003
+ function safeJsonParse(input, fallback = null) {
40004
+ if (typeof input !== "string") return fallback;
40005
+ const cleaned = stripCodeFence(input);
40006
+ if (!cleaned) return fallback;
40007
+ const attempts = [cleaned];
40008
+ const bracketed = extractBracketed(cleaned);
40009
+ if (bracketed && bracketed !== cleaned) attempts.push(bracketed);
40010
+ attempts.push(removeTrailingCommas(bracketed ?? cleaned));
40011
+ for (const candidate of attempts) {
40012
+ try {
40013
+ return JSON.parse(candidate);
40014
+ } catch {
40015
+ }
40016
+ }
40017
+ return fallback;
40018
+ }
40019
+
40020
+ // src/tools/web/webfetch.ts
39712
40021
  function htmlToMarkdown(html) {
39713
40022
  return html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<h1[^>]*>(.*?)<\/h1>/gi, "# $1\n\n").replace(/<h2[^>]*>(.*?)<\/h2>/gi, "## $1\n\n").replace(/<h3[^>]*>(.*?)<\/h3>/gi, "### $1\n\n").replace(/<h4[^>]*>(.*?)<\/h4>/gi, "#### $1\n\n").replace(/<h5[^>]*>(.*?)<\/h5>/gi, "##### $1\n\n").replace(/<h6[^>]*>(.*?)<\/h6>/gi, "###### $1\n\n").replace(/<p[^>]*>(.*?)<\/p>/gi, "$1\n\n").replace(/<pre[^>]*><code[^>]*>([\s\S]*?)<\/code><\/pre>/gi, "```\n$1\n```\n\n").replace(/<code[^>]*>(.*?)<\/code>/gi, "`$1`").replace(/<li[^>]*>(.*?)<\/li>/gi, "- $1\n").replace(/<ul[^>]*>/gi, "\n").replace(/<\/ul>/gi, "\n").replace(/<ol[^>]*>/gi, "\n").replace(/<\/ol>/gi, "\n").replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, "[$2]($1)").replace(/<strong[^>]*>(.*?)<\/strong>/gi, "**$1**").replace(/<b[^>]*>(.*?)<\/b>/gi, "**$1**").replace(/<em[^>]*>(.*?)<\/em>/gi, "*$1*").replace(/<i[^>]*>(.*?)<\/i>/gi, "*$1*").replace(/<blockquote[^>]*>([\s\S]*?)<\/blockquote>/gi, "> $1\n\n").replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(/\n{3,}/g, "\n\n").trim();
39714
40023
  }
@@ -39776,7 +40085,8 @@ ${cached3.content}`;
39776
40085
  const contentType = response.headers.get("content-type") || "";
39777
40086
  const html = await response.text();
39778
40087
  if (contentType.includes("application/json")) {
39779
- const content = JSON.stringify(JSON.parse(html), null, 2);
40088
+ const parsed = safeJsonParse(html);
40089
+ const content = parsed !== null ? JSON.stringify(parsed, null, 2) : html;
39780
40090
  if (cache2) {
39781
40091
  const filename = await set3(url3, content, "JSON Response");
39782
40092
  return `${OUTPUT_LABEL.JSON_FETCHED} (cached: ${PATHS.DOCS}/${filename})
@@ -40552,6 +40862,25 @@ function mergeConcurrencyConfig(base, override) {
40552
40862
  };
40553
40863
  }
40554
40864
 
40865
+ // src/core/config/options-schema.ts
40866
+ var D = DEFAULT_MISSION_RUNTIME_OPTIONS;
40867
+ var MissionLoopOptionsSchema = external_exports.object({
40868
+ ledger: external_exports.boolean().catch(D.ledger).default(D.ledger),
40869
+ markdownMemory: external_exports.boolean().catch(D.markdownMemory).default(D.markdownMemory),
40870
+ maxEvidenceEvents: external_exports.number().int().positive().catch(D.maxEvidenceEvents).default(D.maxEvidenceEvents)
40871
+ }).catch({ ...D });
40872
+ var ConcurrencyMap = external_exports.record(external_exports.string(), external_exports.number().int().positive());
40873
+ var OrchestratorOptionsSchema = external_exports.object({
40874
+ agentConcurrency: ConcurrencyMap.optional(),
40875
+ providerConcurrency: ConcurrencyMap.optional(),
40876
+ modelConcurrency: ConcurrencyMap.optional(),
40877
+ defaultConcurrency: external_exports.number().int().positive().optional(),
40878
+ missionLoop: MissionLoopOptionsSchema.optional()
40879
+ }).passthrough();
40880
+ function parseMissionLoopOptions(value) {
40881
+ return MissionLoopOptionsSchema.parse(value);
40882
+ }
40883
+
40555
40884
  // src/core/config/plugin-options.ts
40556
40885
  function parseOrchestratorPluginOptions(options) {
40557
40886
  const source = isRecord4(options) ? options : {};
@@ -40561,21 +40890,7 @@ function parseOrchestratorPluginOptions(options) {
40561
40890
  };
40562
40891
  }
40563
40892
  function readMissionLoopOptions(value) {
40564
- if (!isRecord4(value)) return DEFAULT_MISSION_RUNTIME_OPTIONS;
40565
- return {
40566
- ledger: readBoolean(value.ledger, DEFAULT_MISSION_RUNTIME_OPTIONS.ledger),
40567
- markdownMemory: readBoolean(value.markdownMemory, DEFAULT_MISSION_RUNTIME_OPTIONS.markdownMemory),
40568
- maxEvidenceEvents: readPositiveInteger(
40569
- value.maxEvidenceEvents,
40570
- DEFAULT_MISSION_RUNTIME_OPTIONS.maxEvidenceEvents
40571
- )
40572
- };
40573
- }
40574
- function readBoolean(value, fallback) {
40575
- return typeof value === "boolean" ? value : fallback;
40576
- }
40577
- function readPositiveInteger(value, fallback) {
40578
- return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : fallback;
40893
+ return parseMissionLoopOptions(value);
40579
40894
  }
40580
40895
  function isRecord4(value) {
40581
40896
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -40902,6 +41217,61 @@ function createSessionStateStore() {
40902
41217
  };
40903
41218
  }
40904
41219
 
41220
+ // src/core/loop/evidence.ts
41221
+ var MAX_TRACKED_FILES = 200;
41222
+ var store = /* @__PURE__ */ new Map();
41223
+ var WRITE_TOOLS = /* @__PURE__ */ new Set([
41224
+ "write",
41225
+ "edit",
41226
+ "patch",
41227
+ "multiedit",
41228
+ "multi_patch",
41229
+ "apply_patch",
41230
+ "sed_replace",
41231
+ "ast_replace"
41232
+ ]);
41233
+ var SHELL_TOOLS = /* @__PURE__ */ new Set(["bash", "shell", "run_command", "run_background"]);
41234
+ var VERIFY_HINT = /\b(test|spec|vitest|jest|pytest|build|tsc|typecheck|lint|eslint|clippy|cargo\s+test|npm\s+test|go\s+test|check)\b/i;
41235
+ function ensure(sessionID) {
41236
+ let evidence = store.get(sessionID);
41237
+ if (!evidence) {
41238
+ evidence = { changedFiles: /* @__PURE__ */ new Set(), lastChangeAt: 0, lastVerifyAt: 0 };
41239
+ store.set(sessionID, evidence);
41240
+ }
41241
+ return evidence;
41242
+ }
41243
+ function recordChangedFile(sessionID, filePath, now = Date.now()) {
41244
+ if (!sessionID || !filePath) return;
41245
+ const evidence = ensure(sessionID);
41246
+ if (evidence.changedFiles.size < MAX_TRACKED_FILES) {
41247
+ evidence.changedFiles.add(filePath);
41248
+ }
41249
+ evidence.lastChangeAt = now;
41250
+ }
41251
+ function recordVerification(sessionID, now = Date.now()) {
41252
+ if (!sessionID) return;
41253
+ ensure(sessionID).lastVerifyAt = now;
41254
+ }
41255
+ function recordToolEvidence(sessionID, tool2, args, now = Date.now()) {
41256
+ if (!sessionID || !tool2) return;
41257
+ const name = tool2.toLowerCase();
41258
+ if (WRITE_TOOLS.has(name)) {
41259
+ const candidate = args?.filePath ?? args?.path ?? args?.file;
41260
+ if (typeof candidate === "string") recordChangedFile(sessionID, candidate, now);
41261
+ } else if (SHELL_TOOLS.has(name)) {
41262
+ const command = String(args?.command ?? args?.cmd ?? "");
41263
+ if (VERIFY_HINT.test(command)) recordVerification(sessionID, now);
41264
+ }
41265
+ }
41266
+ function getUnverifiedChangeCount(sessionID) {
41267
+ const evidence = store.get(sessionID);
41268
+ if (!evidence || evidence.changedFiles.size === 0) return 0;
41269
+ return evidence.lastVerifyAt >= evidence.lastChangeAt ? 0 : evidence.changedFiles.size;
41270
+ }
41271
+ function clearEvidence(sessionID) {
41272
+ store.delete(sessionID);
41273
+ }
41274
+
40905
41275
  // src/core/loop/progress-tracker.ts
40906
41276
  init_logger();
40907
41277
  var DEFAULT_STAGNATION_THRESHOLD = 3;
@@ -41264,7 +41634,8 @@ async function injectContinuation2(client, directory, sessionID, loopState, cust
41264
41634
  const continuationReason = customPrompt ? "stagnation_intervention" : loopState.lastContinuationReason;
41265
41635
  let prompt = generateMissionContinuationPrompt(loopState, {
41266
41636
  verificationSummary: summary,
41267
- continuationReason
41637
+ continuationReason,
41638
+ unverifiedChanges: getUnverifiedChangeCount(sessionID)
41268
41639
  });
41269
41640
  if (customPrompt) {
41270
41641
  prompt = `${customPrompt}
@@ -41431,6 +41802,7 @@ function cleanupSession3(sessionID) {
41431
41802
  clearCompactionState(sessionID);
41432
41803
  clearCircuitState(sessionID);
41433
41804
  resetProgress(sessionID);
41805
+ clearEvidence(sessionID);
41434
41806
  }
41435
41807
  function handleSessionCompacted(sessionID) {
41436
41808
  armCompactionGuard(sessionID, Date.now());
@@ -41660,6 +42032,7 @@ function createToolExecuteAfterHandler(ctx) {
41660
42032
  toolOutput
41661
42033
  );
41662
42034
  recordToolCall(toolInput.sessionID, toolInput.tool);
42035
+ recordToolEvidence(toolInput.sessionID, toolInput.tool, toolInput.arguments || {});
41663
42036
  log(`[tool.execute.after] Completed ${toolInput.tool}`, {
41664
42037
  sessionID: toolInput.sessionID,
41665
42038
  step: session.step,
@@ -41907,14 +42280,14 @@ var HybridSearch = class {
41907
42280
  /**
41908
42281
  * Fuse lexical, tag, and graph rankings via RRF to produce a single list.
41909
42282
  */
41910
- search(query, maxResults) {
42283
+ search(query, maxResults, weights) {
41911
42284
  const limit = maxResults ?? DEFAULT_MAX_RESULTS;
41912
42285
  const terms = this.tokenize(query);
41913
42286
  if (terms.length === 0) return [];
41914
42287
  const lexicalRanked = this.lexicalSearch(terms);
41915
42288
  const tagRanked = this.tagSearch(terms);
41916
42289
  const graphRanked = this.graphSearch(terms);
41917
- return this.fuseResults(lexicalRanked, tagRanked, graphRanked, limit);
42290
+ return this.fuseResults(lexicalRanked, tagRanked, graphRanked, limit, weights ?? NEUTRAL_WEIGHTS);
41918
42291
  }
41919
42292
  /**
41920
42293
  * BM25-inspired term-frequency scoring across all indexed documents.
@@ -41986,20 +42359,20 @@ var HybridSearch = class {
41986
42359
  * Reciprocal Rank Fusion: combine three ranked lists into a single ranking.
41987
42360
  * Formula: score(d) = Σ 1/(k + rank_i) for each list where d appears.
41988
42361
  */
41989
- fuseResults(lexical, tags, graph, limit) {
42362
+ fuseResults(lexical, tags, graph, limit, weights) {
41990
42363
  const fused = /* @__PURE__ */ new Map();
41991
- this.addRrfScores(fused, lexical, "lexical");
41992
- this.addRrfScores(fused, tags, "tag");
41993
- this.addRrfScores(fused, graph, "graph");
42364
+ this.addRrfScores(fused, lexical, "lexical", weights.lexical);
42365
+ this.addRrfScores(fused, tags, "tag", weights.tag);
42366
+ this.addRrfScores(fused, graph, "graph", weights.graph);
41994
42367
  return Array.from(fused.entries()).map(([noteName, { score, matchType }]) => ({ noteName, score, matchType })).sort((a, b) => b.score - a.score).slice(0, limit);
41995
42368
  }
41996
42369
  /**
41997
42370
  * Accumulate RRF scores from a single ranked list into the fused map.
41998
42371
  * The matchType is set to the source with the highest individual contribution.
41999
42372
  */
42000
- addRrfScores(fused, ranked, matchType) {
42373
+ addRrfScores(fused, ranked, matchType, weight = 1) {
42001
42374
  for (let i = 0; i < ranked.length; i++) {
42002
- const rrfScore = 1 / (RRF_K + i + 1);
42375
+ const rrfScore = weight * (1 / (RRF_K + i + 1));
42003
42376
  const existing = fused.get(ranked[i]);
42004
42377
  if (existing) {
42005
42378
  existing.score += rrfScore;
@@ -42224,13 +42597,13 @@ var KNOWLEDGE_ROOTS = ["docs", path10.join(".opencode", "docs")];
42224
42597
  var SKIP_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", "bin", ".git", "archive"]);
42225
42598
  var GENERATED_SCRATCHPAD_PATH = path10.join(".opencode", "docs", "brain", "scratchpad.md");
42226
42599
  var KnowledgeContextProvider = class {
42227
- buildPrompt(directory, query) {
42600
+ buildPrompt(directory, query, role) {
42228
42601
  const normalizedQuery = query.trim();
42229
42602
  if (!normalizedQuery) return null;
42230
42603
  const markdownFiles = this.collectMarkdownFiles(directory);
42231
42604
  if (markdownFiles.length === 0) return null;
42232
42605
  const indexed = this.indexKnowledge(directory, markdownFiles);
42233
- const results = indexed.search.search(normalizedQuery, MAX_RESULTS);
42606
+ const results = indexed.search.search(normalizedQuery, MAX_RESULTS, weightsForRole(role));
42234
42607
  if (results.length === 0) return null;
42235
42608
  return this.formatPrompt(normalizedQuery, results, indexed);
42236
42609
  }