@lawaty/lacode 0.1.0 → 0.1.2

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
@@ -10,12 +10,13 @@ var CATALOG_TTL_MS = 10 * 60 * 1e3;
10
10
  var STUCK_MIN_AGE_MS = 5 * 60 * 1e3;
11
11
  var STUCK_IDLE_MS = 3 * 60 * 1e3;
12
12
  var HANG_COOLDOWN_MS = 10 * 60 * 1e3;
13
+ var UNAVAILABLE_COOLDOWN_MS = 60 * 1e3;
13
14
  var MAX_WEIGHT = 100;
14
15
  var MAX_SLOTS = 4;
15
16
  var COOLDOWN_BASE_MS = 60 * 1e3;
16
17
  var COOLDOWN_MAX_MS = 15 * 60 * 1e3;
17
18
  var STRIKE_DECAY_MS = 30 * 60 * 1e3;
18
- var BASES = ["explore-fast", "implement-fast", "context-manager"];
19
+ var BASES = ["explore", "implement", "context"];
19
20
  var findPackageRoot = (start) => {
20
21
  let dir = start;
21
22
  for (let up = 0; up < 6; up++) {
@@ -136,6 +137,7 @@ function readWeight(entry, at, model, problems) {
136
137
  }
137
138
  return weight;
138
139
  }
140
+ var UNAVAILABLE_PATTERN = /endpoint\s+is\s+unavailable/i;
139
141
  var LIMIT_PATTERNS = [
140
142
  /rate[\s_-]?limit/i,
141
143
  /usage limit/i,
@@ -143,9 +145,11 @@ var LIMIT_PATTERNS = [
143
145
  /\b429\b/,
144
146
  /quota/i,
145
147
  /freelimiterror/i,
146
- /overloaded/i
148
+ /overloaded/i,
149
+ UNAVAILABLE_PATTERN
147
150
  ];
148
151
  var isLimitText = (text) => LIMIT_PATTERNS.some((re) => re.test(text));
152
+ var isUnavailableText = (text) => UNAVAILABLE_PATTERN.test(text);
149
153
  var statedCooldown = (text) => {
150
154
  const hm = /resets?\s+in\s+(\d+)\s*(?:h|hr|hour)s?\s*(\d+)?\s*(?:m|min|minute)?s?/i.exec(text);
151
155
  if (hm) return (Number(hm[1]) * 60 + (hm[2] ? Number(hm[2]) : 0)) * 60 * 1e3;
@@ -327,6 +331,22 @@ function recordStrike(s, model, reason, stated) {
327
331
  }
328
332
  return strike;
329
333
  }
334
+ function coolUnavailable(s, model) {
335
+ if (!s.dirReady) return;
336
+ const now = Date.now();
337
+ const prior = s.cooling.get(model);
338
+ const until = now + UNAVAILABLE_COOLDOWN_MS;
339
+ if (prior && prior.until > until) return prior;
340
+ const strike = { model, until, strikes: 1, reason: "endpoint-unavailable", last: now };
341
+ s.cooling.set(model, strike);
342
+ const path4 = join(s.dir, limitFile(model));
343
+ try {
344
+ writeFileSync(`${path4}.tmp`, JSON.stringify(strike));
345
+ renameSync(`${path4}.tmp`, path4);
346
+ } catch {
347
+ }
348
+ return strike;
349
+ }
330
350
  function refreshCatalog(s, serverUrl) {
331
351
  if (!serverUrl || Date.now() - s.catalogAt < CATALOG_TTL_MS) return;
332
352
  s.catalogAt = Date.now();
@@ -427,11 +447,10 @@ function coolProvider(s, provider, until, reason) {
427
447
  }
428
448
 
429
449
  // src/agents.ts
430
- var DEEP_TIERS = ["explore-deep", "implement-deep"];
431
- var POOLED_BASES = ["explore-fast", "implement-fast", "context-manager"];
450
+ var POOLED_BASES = ["explore", "implement", "context"];
432
451
  var AGENTS = {
433
452
  "build": {
434
- "description": "Default root agent. Orchestrates rather than investigates: read/glob/grep/list/webfetch/websearch are denied by permission, so every question goes to @explore-fast and every code change to @implement-fast. Keeps edit/write/bash for applying and verifying what comes back.",
453
+ "description": "Default root agent. Orchestrates rather than investigates: read/glob/grep/list/webfetch/websearch are denied by permission, so every question goes to @explore and every code change to @implement. Keeps edit/write/bash for applying and verifying what comes back.",
435
454
  "mode": "primary",
436
455
  "temperature": 0.1,
437
456
  prompt: `# Role
@@ -446,17 +465,15 @@ Every question of the form "what does this file do", "where is X handled", or
446
465
 
447
466
  # Delegation
448
467
 
449
- - **Investigation \u2192 @explore-fast.** Give it specific, focused instructions
468
+ - **Investigation \u2192 @explore.** Give it specific, focused instructions
450
469
  ("read src/auth.ts", "grep for 'migration' in *.py", "list the src/
451
470
  directory"), one batch per question. Ask for the exact lines or
452
471
  file:line references you need, not a survey.
453
- - **Implementation \u2192 @implement-fast**, with a finalized plan: the exact
472
+ - **Implementation \u2192 @implement**, with a finalized plan: the exact
454
473
  steps, the files to touch, and the constraints you already learned from the
455
474
  explorers. It edits, writes, and runs tests.
456
- - Never call @explore-deep or @implement-deep yourself. Each tier escalates on
457
- its own when it is stuck; that ladder belongs to the subagents, not to you.
458
475
 
459
- The agents you spawn are the pooled \`explore-fast\` / \`implement-fast\` bases \u2014
476
+ The agents you spawn are the pooled \`explore\` / \`implement\` bases \u2014
460
477
  spawn the bare name and let the pool route, never a \`-1\`/\`-2\` slot variant.
461
478
 
462
479
  # What stays yours
@@ -467,11 +484,11 @@ build, and git.
467
484
 
468
485
  Do NOT use bash to inspect the codebase. \`cat\`, \`head\`, \`tail\`, \`sed\`, \`awk\`,
469
486
  \`grep\`, \`find\`, \`ls\`, \`tree\` and friends are exploration, and exploration goes
470
- to @explore-fast. Bash is for executing and verifying, not for looking.
487
+ to @explore. Bash is for executing and verifying, not for looking.
471
488
 
472
489
  # Repository context
473
490
 
474
- Before delegating a non-trivial task, tell @explore-fast to check
491
+ Before delegating a non-trivial task, tell @explore to check
475
492
  \`.opencode/context/\` first (\`ls .opencode/context\`, never the \`glob\` tool \u2014 it
476
493
  skips hidden directories) and to read only the file relevant to the task:
477
494
  architecture.md for architectural questions, contexts.md for subsystem
@@ -483,7 +500,7 @@ broadly.
483
500
  Files the user explicitly named always take priority over the context map.
484
501
 
485
502
  Never edit \`.opencode/context/\` \u2014 context maintenance belongs to the
486
- context-manager agent (\`/context-update\` or its automatic post-work runs). If
503
+ context agent (\`/context-update\` or its automatic post-work runs). If
487
504
  your work reveals something that belongs in the map, say so in your final
488
505
  report instead of editing it yourself.
489
506
 
@@ -510,13 +527,13 @@ missing). Never paste context file contents into the report.`,
510
527
  "question": "allow",
511
528
  "task": {
512
529
  "*": "deny",
513
- "explore-fast*": "allow",
514
- "implement-fast*": "allow"
530
+ "explore*": "allow",
531
+ "implement*": "allow"
515
532
  }
516
533
  }
517
534
  },
518
535
  "plan": {
519
- "description": "Read-only planner. Identical to @basic: it cannot read, grep, glob, list or run commands, so all investigation is delegated to @explore-fast. Produce a plan; do not edit.",
536
+ "description": "Read-only planner. Identical to @basic: it cannot read, grep, glob, list or run commands, so all investigation is delegated to @explore. Produce a plan; do not edit.",
520
537
  "mode": "primary",
521
538
  "temperature": 0.1,
522
539
  prompt: `You are a senior software architect. Your ONLY job is analysis and planning.
@@ -525,8 +542,8 @@ You CANNOT read files, grep, glob, list directories, or run commands directly. A
525
542
 
526
543
  When you need to understand the codebase:
527
544
  1. Determine exactly what files or patterns need investigating
528
- 2. Invoke @explore-fast with specific, focused instructions (e.g. "read src/auth.ts", "grep for 'migration' in *.py files", "list the src/ directory")
529
- 3. @explore-fast will return its findings \u2014 you process them and plan accordingly
545
+ 2. Invoke @explore with specific, focused instructions (e.g. "read src/auth.ts", "grep for 'migration' in *.py files", "list the src/ directory")
546
+ 3. @explore will return its findings \u2014 you process them and plan accordingly
530
547
 
531
548
  Repository context: before delegating investigation for a non-trivial task,
532
549
  tell the exploration agent to first check \`.opencode/context/\` in this project
@@ -540,12 +557,12 @@ entry points the map lists rather than exploring broadly.
540
557
  Files the user explicitly mentioned always take priority over the context map.
541
558
 
542
559
  Never edit \`.opencode/context/\` \u2014 context maintenance belongs to the
543
- context-manager agent (\`/context-update\` or its automatic post-work runs). If
560
+ context agent (\`/context-update\` or its automatic post-work runs). If
544
561
  your plan implies the map needs a change, say so in the plan instead.
545
562
 
546
563
  When given a task:
547
564
  1. Think through what codebase context you need
548
- 2. Delegate investigation to @explore-fast in focused batches
565
+ 2. Delegate investigation to @explore in focused batches
549
566
  3. Analyze findings for dependencies, edge cases, and architecture impact
550
567
  4. Produce a structured output:
551
568
  - Summary of the change
@@ -580,13 +597,13 @@ Once the plan is complete, present it clearly so the caller can implement it ste
580
597
  "question": "allow",
581
598
  "task": {
582
599
  "*": "deny",
583
- "explore-fast*": "allow",
584
- "implement-fast*": "allow"
600
+ "explore*": "allow",
601
+ "implement*": "allow"
585
602
  }
586
603
  }
587
604
  },
588
- "explore-fast": {
589
- "description": "Default read-only codebase exploration. Free via Zen. Escalates to @explore-deep when stuck or looping.",
605
+ "explore": {
606
+ "description": "Default read-only codebase exploration. Free via Zen.",
590
607
  "mode": "subagent",
591
608
  "temperature": 0.2,
592
609
  prompt: `# Role
@@ -619,119 +636,26 @@ understand them and find the surrounding code, never as a reason to skip them.
619
636
 
620
637
  If the map conflicts with the source, trust the source, say so in your report,
621
638
  and never repeat the stale claim. Never edit \`.opencode/context/\` files \u2014 the
622
- context-manager agent owns those (\`/context-update\` or its automatic post-work
639
+ context agent owns those (\`/context-update\` or its automatic post-work
623
640
  runs). Report what should be updated there instead.
624
641
 
625
642
  <!-- MERGE POINT: paste any project-specific exploration conventions from
626
643
  your current plan.txt / explore instructions here (e.g. which
627
644
  directories to ignore, naming conventions, where docs live). -->
628
645
 
629
- # Escalation
630
-
631
- If you hit any of the following, STOP and delegate to @explore-deep via the
632
- task tool instead of continuing to search:
633
-
634
- - You've made more than ~8 tool calls (read/glob/grep/bash) without
635
- converging on an answer
636
- - The same search strategy (same query pattern, same directory) has failed
637
- twice in a row
638
- - The code you need to understand involves genuinely complex logic you're
639
- not confident you're reading correctly (e.g. dense concurrency, generated
640
- code, deep inheritance/dependency chains, obscure build tooling)
641
- - You cannot locate a symbol, config value, or file the task clearly
642
- requires, after searching from at least two different angles (e.g. by
643
- name and by usage)
644
-
645
- Do not escalate on the first dead end \u2014 try at least one alternative search
646
- strategy yourself first (different keywords, different tool, broader or
647
- narrower scope).
648
-
649
- When escalating, pass full context to @explore-deep:
650
- - The exact question you were asked to answer
651
- - Every search strategy you already tried and what each one returned
652
- - Your best current hypothesis, even if unconfirmed
653
-
654
- Never guess or fabricate a file path, line number, or code behavior to avoid
655
- escalating. A wrong answer is worse than an escalation.
656
-
657
- # No further escalation beyond deep
658
-
659
- You may only escalate to @explore-deep. Do not attempt to call @implement-fast,
660
- @implement-deep, or any other agent \u2014 exploration agents only explore.`,
661
- permission: {
662
- "read": "allow",
663
- "glob": "allow",
664
- "grep": "allow",
665
- "list": "allow",
666
- "edit": "deny",
667
- "bash": "allow",
668
- "webfetch": "allow",
669
- "websearch": "allow",
670
- "question": "allow",
671
- "task": {
672
- "*": "deny",
673
- "explore-deep": "allow"
674
- }
675
- }
676
- },
677
- "explore-deep": {
678
- "description": "Last-resort read-only exploration for genuinely hard problems @explore-fast fails on. Most expensive explore tier \u2014 use deliberately.",
679
- "mode": "subagent",
680
- "temperature": 0.2,
681
- prompt: `# Role
682
-
683
- You are the last-resort codebase exploration agent, called only when
684
- @explore-fast could not resolve a question. You are read-only: you locate,
685
- read, and summarize code, configuration, and documentation. You never edit or
686
- write files.
687
-
688
- You will typically receive context from @explore-fast including what was
689
- already tried and what failed \u2014 read it carefully before starting. Do not
690
- repeat a search strategy that's already been reported as unproductive; start
691
- from a genuinely different angle (e.g. searching by behavior/output instead of
692
- by name, checking git history or tests for hints, reading adjacent modules for
693
- context).
694
-
695
- # Repository context map
696
-
697
- You will usually receive findings that already include what
698
- \`.opencode/context/\` said about the area. Treat that as a starting point, not
699
- as a finished answer: the code is authoritative, and the map may be stale or
700
- incomplete.
701
-
702
- If you do need to consult the map, list it with \`ls .opencode/context\` \u2014 never
703
- the \`glob\` tool, which skips hidden directories \u2014 then read only the file
704
- relevant to the question \u2014 architecture.md, contexts.md, conventions.md,
705
- workflows.md, decisions.md \u2014 and start from its canonical entry points. Explore
706
- beyond them only when the question genuinely requires it. Do not re-walk the
707
- repository to build a complete picture, and do not repeat searches already
708
- reported as unproductive. Never edit \`.opencode/context/\` files \u2014 the
709
- context-manager agent owns those (\`/context-update\` or its automatic post-work
710
- runs). Report what should be updated there instead.
711
-
712
- <!-- MERGE POINT: paste any project-specific exploration conventions from
713
- your current plan.txt / explore instructions here. -->
714
-
715
- # No further escalation
646
+ # When to report back
716
647
 
717
- You are the last resort \u2014 there is no one above you to hand this off to. If,
718
- after genuinely exhausting reasonable approaches, you still cannot answer the
719
- question:
648
+ There is no deeper tier to hand off to. If after genuinely trying \u2014 one
649
+ alternative search strategy first \u2014 you still cannot answer:
720
650
 
721
- - STOP. Do not keep looping or guessing.
722
- - Report back clearly and specifically: what was asked, what you tried
723
- (including what @explore-fast already tried, if provided), and exactly what
724
- information is missing or ambiguous.
725
- - If relevant, state what additional access, file, or human input would
726
- resolve it (e.g. "this appears to be defined in a private package not in
727
- this repo").
651
+ - STOP. Do not loop or guess.
652
+ - Report the exact question, every search you already tried and what each
653
+ one returned, and your best hypothesis even if unconfirmed.
654
+ - Never guess or fabricate a file path, line number, or code behavior. An
655
+ honest "I couldn't find this, here's why" is the correct output.
728
656
 
729
- Never fabricate a file path, line number, or code behavior to produce an
730
- answer. An honest "I couldn't find this, here's why" is the correct output
731
- when that's the truth.
732
-
733
- You may only explore. Do not attempt to call @implement-fast, @implement-deep,
734
- or any other agent.`,
657
+ You may only explore. Do not attempt to call @implement or any other agent \u2014
658
+ exploration agents only explore.`,
735
659
  permission: {
736
660
  "read": "allow",
737
661
  "glob": "allow",
@@ -747,8 +671,8 @@ or any other agent.`,
747
671
  }
748
672
  }
749
673
  },
750
- "implement-fast": {
751
- "description": "Default agent that executes a finalized plan. Escalates to @implement-deep when stuck or looping.",
674
+ "implement": {
675
+ "description": "Default agent that executes a finalized plan.",
752
676
  "mode": "subagent",
753
677
  "temperature": 0.2,
754
678
  prompt: `# Role
@@ -774,7 +698,7 @@ named by the user or the plan always take priority over the map, and the map
774
698
  never justifies skipping work the plan asked for.
775
699
 
776
700
  Do NOT edit \`.opencode/context/\` \u2014 context maintenance is a separate
777
- responsibility handled by the context-manager agent (\`/context-update\` or its
701
+ responsibility handled by the context agent (\`/context-update\` or its
778
702
  automatic post-work runs). If your work reveals something that belongs in the
779
703
  map (a new boundary, entry point, workflow, convention, or decision), say so in
780
704
  your final report instead of editing it yourself.
@@ -784,115 +708,21 @@ your final report instead of editing it yourself.
784
708
  etc. This section should carry over everything from the original
785
709
  shared implement.txt that both tiers need. -->
786
710
 
787
- # Escalation
788
-
789
- If you hit any of the following, STOP and delegate to @implement-deep via
790
- the task tool instead of continuing to retry:
791
-
792
- - The same error or test failure recurs after 2 different attempted fixes
793
- - You've made more than ~8 tool calls without a concrete, verifiable step of
794
- progress (a passing test, a file that now does what it's supposed to, etc.)
795
- - The task requires reasoning you're not confident in \u2014 complex concurrency,
796
- subtle type/generic errors, ambiguous or conflicting requirements in the
797
- plan, or a fix that would require touching many unrelated files
798
- - You find yourself about to revert and redo the same change a third time
711
+ # When to report back
799
712
 
800
- Do not escalate at the first error \u2014 try at least one different approach
801
- yourself first (different fix, different file, re-reading the relevant code).
713
+ There is no deeper tier to hand off to. If after genuinely trying \u2014 at least
714
+ one different fix, or a re-read of the relevant code \u2014 you still cannot
715
+ complete the step:
802
716
 
803
- When escalating, pass full context to @implement-deep:
804
- - The exact plan step / task you were given
805
- - Every approach you already tried and why each one failed (errors,
806
- diffs, test output)
807
- - The current state of the code (what's already changed vs. untouched)
717
+ - STOP. Do not loop or guess.
718
+ - Leave the code in the most coherent state you can; prefer reverting a
719
+ broken partial change over leaving it half-done.
720
+ - Report the plan step, every approach tried and why each failed, and the
721
+ current state of the code. Never mark a step done if it isn't, and never
722
+ fabricate a passing test.
808
723
 
809
- Do not silently abandon a broken change and start over without escalating \u2014
810
- leaving inconsistent partial edits behind is worse than asking for help.
811
-
812
- # No further escalation beyond deep
813
-
814
- You may only escalate to @implement-deep. Do not attempt to call
815
- @explore-fast, @explore-deep, or any other agent for implementation help \u2014
816
- if you need investigation rather than execution, note that explicitly when
817
- you escalate so @implement-deep can decide whether to explore first.`,
818
- permission: {
819
- "read": "allow",
820
- "glob": "allow",
821
- "grep": "allow",
822
- "list": "allow",
823
- "edit": {
824
- "*": "allow",
825
- "*/.opencode/context/**": "deny",
826
- ".opencode/context/**": "deny"
827
- },
828
- "bash": "allow",
829
- "webfetch": "allow",
830
- "websearch": "allow",
831
- "question": "allow",
832
- "task": {
833
- "*": "deny",
834
- "implement-deep": "allow"
835
- }
836
- }
837
- },
838
- "implement-deep": {
839
- "description": "Last-resort executor for genuinely hard problems @implement-fast fails on. Most expensive implement tier \u2014 use deliberately.",
840
- "mode": "subagent",
841
- "temperature": 0.2,
842
- prompt: `# Role
843
-
844
- You are the last-resort agent for executing a finalized plan, called only
845
- when @implement-fast could not complete a step. You read, edit, write, and
846
- run code/bash to make the plan's changes real.
847
-
848
- You will typically receive context from @implement-fast including what was
849
- already tried, what failed, and the current state of the code \u2014 read it
850
- carefully before touching anything. Don't repeat an approach already reported
851
- as failed. Before making further changes, confirm you understand the current
852
- state of the code (it may be a partial, broken edit left by @implement-fast)
853
- rather than assuming it matches the original plan.
854
-
855
- # Repository context
856
-
857
- If \`.opencode/context/\` exists (\`ls .opencode/context\` \u2014 never the \`glob\`
858
- tool, which skips hidden directories), use it as a navigation aid:
859
- conventions.md
860
- before writing or modifying code, architecture.md and contexts.md for layer
861
- and boundary decisions, workflows.md when the change touches a flow,
862
- decisions.md for architectural constraints that must be respected. Read only
863
- the relevant file. Files named by @implement-fast, the user, or the plan
864
- always take priority, and the map never justifies skipping a step.
865
-
866
- Do NOT edit \`.opencode/context/\` \u2014 that belongs to the context-manager agent
867
- (\`/context-update\` or its automatic post-work runs). If your work reveals
868
- something that belongs in the map, say so in your report instead.
869
-
870
- <!-- MERGE POINT: paste your current implement.txt content here \u2014 the same
871
- execution conventions used by implement-fast should apply here too. -->
872
-
873
- # No further escalation
874
-
875
- You are the last resort \u2014 there is no one above you to hand this off to. If,
876
- after genuinely exhausting reasonable approaches, you still cannot complete
877
- the step:
878
-
879
- - STOP. Do not keep looping, guessing, or making speculative changes.
880
- - Leave the code in the most coherent state you can (prefer reverting a
881
- broken partial change over leaving it half-done, unless partial progress is
882
- clearly salvageable and you say so).
883
- - Report back clearly and specifically: the exact error or blocker, what was
884
- already tried (including @implement-fast's attempts, if provided), and what
885
- you believe is needed to unblock it (missing information, a plan
886
- revision, human judgment call, etc.).
887
-
888
- Never mark a step as done if it isn't, and never fabricate a passing
889
- test/build result. An honest "this is blocked, here's why" is the correct
890
- output when that's the truth.
891
-
892
- You may only implement. Do not attempt to call @explore-fast, @explore-deep,
893
- or any other agent \u2014 if the blocker is a missing understanding of the
894
- codebase rather than an execution problem, report that explicitly instead of
895
- trying to explore yourself.`,
724
+ You may only implement. Do not attempt to call @explore or any other agent \u2014
725
+ if the blocker is understanding rather than execution, report that instead.`,
896
726
  permission: {
897
727
  "read": "allow",
898
728
  "glob": "allow",
@@ -912,7 +742,7 @@ trying to explore yourself.`,
912
742
  }
913
743
  }
914
744
  },
915
- "context-manager": {
745
+ "context": {
916
746
  "description": "Repository cartographer and memory maintainer. Bootstraps and incrementally maintains .opencode/context/ (architecture, contexts, conventions, workflows, decisions) as a small navigation map for future agents. Runs automatically after sessions that changed files; can also be invoked with /context-init, /context-update, /context-review. Never use it for general coding tasks.",
917
747
  "mode": "subagent",
918
748
  "temperature": 0.1,
@@ -1185,19 +1015,16 @@ function buildAgentSet() {
1185
1015
  }
1186
1016
  return set;
1187
1017
  }
1188
- var DEEP_TIER_SET = new Set(DEEP_TIERS);
1189
1018
  function applyAgents(cfg, agents = buildAgentSet(), opts = {}) {
1190
1019
  const target = cfg.agent ??= {};
1191
1020
  const added = [];
1192
1021
  const kept = [];
1193
- const deepModel = typeof opts.deepModel === "string" ? opts.deepModel.trim() : "";
1194
1022
  for (const [name, def] of Object.entries(agents)) {
1195
1023
  if (target[name] !== void 0) {
1196
1024
  kept.push(name);
1197
1025
  continue;
1198
1026
  }
1199
1027
  const copy = JSON.parse(JSON.stringify(def));
1200
- if (deepModel && DEEP_TIER_SET.has(name) && !copy.model) copy.model = deepModel;
1201
1028
  target[name] = copy;
1202
1029
  added.push(name);
1203
1030
  }
@@ -1207,8 +1034,8 @@ function applyAgents(cfg, agents = buildAgentSet(), opts = {}) {
1207
1034
  // src/commands.ts
1208
1035
  var COMMANDS = {
1209
1036
  "context-init": {
1210
- description: "Bootstrap the repository context map (.opencode/context/) via the context-manager agent.",
1211
- agent: "context-manager",
1037
+ description: "Bootstrap the repository context map (.opencode/context/) via the context agent.",
1038
+ agent: "context",
1212
1039
  subtask: true,
1213
1040
  template: `Bootstrap the repository context map.
1214
1041
 
@@ -1228,8 +1055,8 @@ Report what you created or updated, what you deliberately left out, and
1228
1055
  anything that contradicts the code or existing docs.`
1229
1056
  },
1230
1057
  "context-update": {
1231
- description: "Incrementally update .opencode/context/ after recent work via the context-manager agent.",
1232
- agent: "context-manager",
1058
+ description: "Incrementally update .opencode/context/ after recent work via the context agent.",
1059
+ agent: "context",
1233
1060
  subtask: true,
1234
1061
  template: `Incremental context update.
1235
1062
 
@@ -1252,7 +1079,7 @@ timestamp-only edits. If nothing material changed, make no edits and report
1252
1079
  },
1253
1080
  "context-review": {
1254
1081
  description: "Audit .opencode/context/ for staleness, contradictions, excess size, duplication, and missing entry points.",
1255
- agent: "context-manager",
1082
+ agent: "context",
1256
1083
  subtask: true,
1257
1084
  template: `Context review.
1258
1085
 
@@ -1299,7 +1126,7 @@ decisions.md \u2014 then start from the canonical entry points it lists.
1299
1126
 
1300
1127
  Source code is authoritative: if the map disagrees with the code, trust the code,
1301
1128
  say so, and never edit source to match the map. Never edit \`.opencode/context/\`
1302
- yourself \u2014 the context-manager agent owns it. Say in your final report if your
1129
+ yourself \u2014 the context agent owns it. Say in your final report if your
1303
1130
  work revealed something that belongs in the map.`;
1304
1131
  function applyInstructions(cfg) {
1305
1132
  const existing = cfg.instructions;
@@ -1406,24 +1233,6 @@ var agentPoolHooks = (async ({ client, serverUrl }, options) => {
1406
1233
  await log("info", `whitelisted ${id} on ${provider} (${s.origin} slot ${slot.index})`);
1407
1234
  }
1408
1235
  }
1409
- const deepModel = typeof opts.deepModel === "string" ? opts.deepModel.trim() : "";
1410
- const deepSlash = deepModel.indexOf("/");
1411
- if (deepModel && deepSlash > 0) {
1412
- const provider = deepModel.slice(0, deepSlash);
1413
- const id = deepModel.slice(deepSlash + 1);
1414
- const entry = providers?.[provider];
1415
- if (!entry) {
1416
- await warnOnce(`deepModel ${deepModel} names provider ${provider}, which is not configured in opencode.jsonc; explore-deep and implement-deep cannot resolve it`);
1417
- } else {
1418
- const list = entry.whitelist;
1419
- if (list && !list.includes(id)) {
1420
- list.push(id);
1421
- await log("info", `whitelisted ${id} on ${provider} (deepModel)`);
1422
- }
1423
- }
1424
- } else if (deepModel) {
1425
- await warnOnce(`deepModel ${deepModel} is not in provider/model-id form and was ignored`);
1426
- }
1427
1236
  s.known = known;
1428
1237
  await log(
1429
1238
  "info",
@@ -1467,6 +1276,11 @@ var agentPoolHooks = (async ({ client, serverUrl }, options) => {
1467
1276
  const status = typeof info.error.data?.statusCode === "number" ? info.error.data.statusCode : void 0;
1468
1277
  if (!isLimitText(haystack) && status !== 429) return;
1469
1278
  const model = `${info.providerID ?? "?"}/${info.modelID ?? "?"}`;
1279
+ if (isUnavailableText(haystack)) {
1280
+ const transient = coolUnavailable(s, model);
1281
+ if (transient) await log("warn", `cooling ${model} for ${Math.round((transient.until - Date.now()) / 1e3)}s (${transient.reason})`);
1282
+ return;
1283
+ }
1470
1284
  const stated = statedCooldown(haystack) ?? retryAfterMs(info.error.data?.responseHeaders);
1471
1285
  const reason = haystack.match(/rate[\s_-]?limit|usage limit|too many requests|quota|freelimiterror|overloaded/i)?.[0]?.toLowerCase().replace(/[\s_]/g, "-");
1472
1286
  const strike = recordStrike(s, model, reason ?? "rate-limited", stated);
@@ -1585,7 +1399,7 @@ import * as path2 from "node:path";
1585
1399
  import { readFileSync as readFileSync2 } from "node:fs";
1586
1400
  import * as path from "node:path";
1587
1401
  var CONTEXT_DIR = path.join(".opencode", "context");
1588
- var WRITER = "context-manager";
1402
+ var WRITER = "context";
1589
1403
  var toPosix = (value) => value.split(path.sep).join("/");
1590
1404
  var compilePattern = (pattern) => {
1591
1405
  const escaped = toPosix(pattern).replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
@@ -1815,19 +1629,19 @@ var contextAutoUpdateHooks = (async ({ client, directory }) => {
1815
1629
  init(state2, (m) => void log("warn", m));
1816
1630
  const snap = snapshot(state2);
1817
1631
  const slot = pickSlot(state2, snap);
1818
- const agent = agentFor("context-manager", slot.index);
1632
+ const agent = agentFor("context", slot.index);
1819
1633
  const created = await client.session.create({
1820
- body: { title: `context-manager (auto ${mode})` },
1634
+ body: { title: `context (auto ${mode})` },
1821
1635
  query: { directory }
1822
1636
  });
1823
1637
  const target = created.data?.id;
1824
1638
  if (!target) {
1825
1639
  requeue();
1826
- await log("warn", "could not create context-manager session");
1640
+ await log("warn", "could not create context session");
1827
1641
  return;
1828
1642
  }
1829
1643
  const claimKey2 = claimKey(target, "context-autoupdate");
1830
- acquire(state2, "context-manager", slot, target, claimKey2, target);
1644
+ acquire(state2, "context", slot, target, claimKey2, target);
1831
1645
  await log("info", `borrowed pool slot ${slot.index} (${slot.model}, w${slot.weight}) for auto ${mode}`, {
1832
1646
  slot: slot.index,
1833
1647
  weight: slot.weight,
@@ -1885,7 +1699,7 @@ var INTERNAL_TITLE_PREFIXES = [
1885
1699
  // context-autoupdate spawns the cartographer through the session API, with no
1886
1700
  // parentID, so it looks exactly like a root session going idle. Notifying for
1887
1701
  // it would announce the cartographer's own bookkeeping as a finished task.
1888
- "context-manager (auto"
1702
+ "context (auto"
1889
1703
  ];
1890
1704
  var notifyMessage = (outcome, detail) => {
1891
1705
  if (outcome === "error") return detail ? `Failed \u2014 ${detail}` : "Failed";
@@ -1893,6 +1707,58 @@ var notifyMessage = (outcome, detail) => {
1893
1707
  if (outcome === "permission") return detail ? `Awaiting your permission \u2014 ${detail}` : "Awaiting your permission";
1894
1708
  return "Task finished, waiting for your review";
1895
1709
  };
1710
+ var helperArgv = (helper, title, message, urgency, icon) => {
1711
+ const name = helper.split(/[\\/]/).pop() ?? "";
1712
+ return name === "lacode" || name === "lacode.js" ? ["notify", title, message, urgency, icon] : [title, message, urgency, icon];
1713
+ };
1714
+ var safeStringify = (value) => {
1715
+ try {
1716
+ return JSON.stringify(value) ?? void 0;
1717
+ } catch {
1718
+ return void 0;
1719
+ }
1720
+ };
1721
+ var decodeJsonString = (escaped) => {
1722
+ try {
1723
+ const decoded = JSON.parse(`"${escaped}"`);
1724
+ return typeof decoded === "string" ? decoded : "";
1725
+ } catch {
1726
+ return "";
1727
+ }
1728
+ };
1729
+ var cleanDetail = (raw) => {
1730
+ const clean = raw.replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
1731
+ if (!clean) return void 0;
1732
+ return clean.length > 160 ? `${clean.slice(0, 159)}\u2026` : clean;
1733
+ };
1734
+ var errorDetail = (error) => {
1735
+ const candidates = [
1736
+ error?.data?.message,
1737
+ error?.message,
1738
+ error?.error
1739
+ ];
1740
+ for (const candidate of candidates) {
1741
+ if (typeof candidate !== "string") continue;
1742
+ const detail = cleanDetail(candidate);
1743
+ if (detail) return detail;
1744
+ }
1745
+ const serialized = safeStringify(error);
1746
+ const match = serialized ? /"message"\s*:\s*"((?:[^"\\]|\\.)*)"/.exec(serialized) : void 0;
1747
+ if (match?.[1] !== void 0) {
1748
+ const detail = cleanDetail(decodeJsonString(match[1]));
1749
+ if (detail) return detail;
1750
+ }
1751
+ return void 0;
1752
+ };
1753
+ var isUnrecognizedError = (error) => {
1754
+ if (error == null) return false;
1755
+ const name = error?.name;
1756
+ if (typeof name === "string" && /abort/i.test(name)) return false;
1757
+ const serialized = safeStringify(error) ?? "";
1758
+ if (/MessageAbortedError|aborted/i.test(serialized)) return false;
1759
+ if (isLimitText(serialized)) return false;
1760
+ return true;
1761
+ };
1896
1762
  var safeTitle = (raw, fallback = "session") => {
1897
1763
  if (!raw) return fallback;
1898
1764
  const clean = raw.replace(/[\u0000-\u001f\u007f]/g, " ").replace(/\s+/g, " ").trim();
@@ -2034,7 +1900,7 @@ var notifyHooks = (async ({ client, directory }, _options, deps = {}) => {
2034
1900
  resolve2({ ok: false, detail: "no oc-notify helper found" });
2035
1901
  return;
2036
1902
  }
2037
- const child = spawn(helper, [title, message, urgency, "utilities-terminal"], {
1903
+ const child = spawn(helper, helperArgv(helper, title, message, urgency, "utilities-terminal"), {
2038
1904
  stdio: ["ignore", "ignore", "pipe"],
2039
1905
  detached: true
2040
1906
  });
@@ -2151,7 +2017,12 @@ var notifyHooks = (async ({ client, directory }, _options, deps = {}) => {
2151
2017
  if (sessionID2) {
2152
2018
  pending.delete(sessionID2);
2153
2019
  permissions.delete(sessionID2);
2154
- void announce(sessionID2, "error");
2020
+ const error = event.properties.error;
2021
+ if (isUnrecognizedError(error)) {
2022
+ void announce(sessionID2, "error", errorDetail(error));
2023
+ } else {
2024
+ void log("debug", "suppressed: recognized error", { sessionID: sessionID2 });
2025
+ }
2155
2026
  }
2156
2027
  return;
2157
2028
  }
@@ -2203,7 +2074,7 @@ var LaCode = (async (input, options) => {
2203
2074
  const notifier = await settled("notify", () => notifyHooks(input, options)) ?? inertHooks;
2204
2075
  const config = async (cfg) => {
2205
2076
  try {
2206
- const injected = applyAgents(cfg, agentSet, { deepModel: opts.deepModel });
2077
+ const injected = applyAgents(cfg, agentSet);
2207
2078
  if (injected.added.length > 0) {
2208
2079
  await log("info", `agents: added ${injected.added.length}, kept ${injected.kept.length} already defined by the user`);
2209
2080
  }