@lawaty/lacode 0.6.0 → 0.7.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/CHANGELOG.md +34 -1
- package/README.md +47 -54
- package/dist/agents.js +72 -78
- package/dist/commands.js +11 -63
- package/dist/index.js +91 -194
- package/docs/BENCHMARKS.md +7 -9
- package/docs/CONFIGURATION.md +12 -12
- package/docs/CONTEXT.md +39 -26
- package/docs/INSTALL.md +14 -15
- package/docs/OMNIROUTE.md +12 -25
- package/docs/TUNNEL.md +16 -14
- package/docs/USER-STORIES.md +25 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -611,8 +611,9 @@ function coolProvider(s, provider, until, reason) {
|
|
|
611
611
|
return affected;
|
|
612
612
|
}
|
|
613
613
|
|
|
614
|
-
// src/lib/
|
|
615
|
-
var
|
|
614
|
+
// src/lib/agent-instructions.ts
|
|
615
|
+
var AGENT_INSTRUCTIONS_COMMAND = "agent-instructions";
|
|
616
|
+
var AGENT_INSTRUCTIONS_WRITER = "instructions";
|
|
616
617
|
|
|
617
618
|
// src/agents.ts
|
|
618
619
|
var POOLED_BASES = ["explore", "implement", "context"];
|
|
@@ -650,14 +651,28 @@ different number.
|
|
|
650
651
|
|
|
651
652
|
The pooled agents are the ONLY route to investigation and implementation. If the
|
|
652
653
|
pool cannot serve a spawn \u2014 every slot cooling or exhausted, spawns repeatedly
|
|
653
|
-
failing, or a runtime message saying no slot is available \u2014 that is a
|
|
654
|
-
|
|
654
|
+
failing, or a runtime message saying no slot is available \u2014 that is not a reason
|
|
655
|
+
to do the work yourself, and not a reason to stop and ask.
|
|
656
|
+
|
|
657
|
+
**Retry.** A refused or cooling slot is transient and costs you nothing but a
|
|
658
|
+
turn. Spawn the bare base again. Do not escalate a \`-N\` variant when a refusal
|
|
659
|
+
names one \u2014 the refusal means the pool has a routing problem, not that you
|
|
660
|
+
picked the wrong number.
|
|
661
|
+
|
|
662
|
+
Retry is always available and never wrong, which is why it is the default. But
|
|
663
|
+
"never wrong" is not "sufficient": looping silently against a pool with every
|
|
664
|
+
model cooling goes nowhere and burns the slot doing it. So separate the two
|
|
665
|
+
failures. **Transient** \u2014 a cooldown, a rate limit, one slot at its ceiling \u2014
|
|
666
|
+
means retry. **Persistent or structural** \u2014 every slot cooling, the same spawn
|
|
667
|
+
failing repeatedly with the same error, a malformed model id \u2014 means stop
|
|
668
|
+
retrying and *report* it: say what failed (slot, model, error) and continue
|
|
669
|
+
with whatever else the task needs, or ask the user. Surface the failure; do not
|
|
670
|
+
spin on it and do not let it end the whole task.
|
|
655
671
|
|
|
656
672
|
**Never fall back to reading, grepping, exploring or implementing on your own.**
|
|
657
|
-
Do not "just quickly" inspect a file because a spawn failed.
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
subagents. A failed spawn is never permission, and silence is not consent.
|
|
673
|
+
Do not "just quickly" inspect a file because a spawn failed. A failed spawn is
|
|
674
|
+
never permission, and silence is not consent \u2014 that part does not change with
|
|
675
|
+
cooldowns, and no amount of retrying grants it.
|
|
661
676
|
|
|
662
677
|
\`edit\`/\`write\`/\`bash\` stay yours for applying and verifying what a subagent
|
|
663
678
|
returned \u2014 never as a substitute for a spawn that could not run.
|
|
@@ -736,7 +751,12 @@ missing). Never paste context file contents into the report.`,
|
|
|
736
751
|
"edit": {
|
|
737
752
|
"*": "allow",
|
|
738
753
|
"*/.opencode/context/**": "deny",
|
|
739
|
-
".opencode/context/**": "deny"
|
|
754
|
+
".opencode/context/**": "deny",
|
|
755
|
+
// AGENTS.md has exactly one writer, the hidden `instructions` agent.
|
|
756
|
+
// opencode resolves a file permission with findLast over the map's own
|
|
757
|
+
// entry order, so this deny has to come AFTER the broad "*" allow above.
|
|
758
|
+
"AGENTS.md": "deny",
|
|
759
|
+
"*/AGENTS.md": "deny"
|
|
740
760
|
},
|
|
741
761
|
"bash": "allow",
|
|
742
762
|
"webfetch": "deny",
|
|
@@ -979,7 +999,11 @@ if the blocker is understanding rather than execution, report that instead.`,
|
|
|
979
999
|
"edit": {
|
|
980
1000
|
"*": "allow",
|
|
981
1001
|
"*/.opencode/context/**": "deny",
|
|
982
|
-
".opencode/context/**": "deny"
|
|
1002
|
+
".opencode/context/**": "deny",
|
|
1003
|
+
// AGENTS.md is written by the hidden `instructions` agent alone; LAST
|
|
1004
|
+
// match wins, so this deny must sit after the broad allow above.
|
|
1005
|
+
"AGENTS.md": "deny",
|
|
1006
|
+
"*/AGENTS.md": "deny"
|
|
983
1007
|
},
|
|
984
1008
|
"bash": "allow",
|
|
985
1009
|
"webfetch": "allow",
|
|
@@ -1023,29 +1047,14 @@ You own exactly these five files and nothing else:
|
|
|
1023
1047
|
during work that are not already recorded in the project's own decision
|
|
1024
1048
|
log. Concise; variable length.
|
|
1025
1049
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
You never create, edit, rename, or delete it \u2014 not at bootstrap, not in an
|
|
1035
|
-
update, not in a review, and not when a run of your own concludes the work
|
|
1036
|
-
has moved on. The client edits it, or asks a live agent to edit it on
|
|
1037
|
-
their explicit instruction. Either way it is their hand, never yours.
|
|
1038
|
-
|
|
1039
|
-
Read it before you write anything. Its \`## Current\` and \`## Next\`
|
|
1040
|
-
sections tell you what is actually being worked on, and \`## Confirmed\`
|
|
1041
|
-
tells you which of your facts the client has ratified. A fact you are
|
|
1042
|
-
writing that appears under \`## Confirmed\` may be stated plainly, without
|
|
1043
|
-
a confidence marker; anything else follows your normal rules \u2014 infer
|
|
1044
|
-
carefully, mark uncertainty. Never copy its content into the five files.
|
|
1045
|
-
|
|
1046
|
-
A missing or empty section is not an instruction. It means the client has
|
|
1047
|
-
not said, not that you may assume anything \u2014 proceed exactly as you would
|
|
1048
|
-
without the file.
|
|
1050
|
+
# Current-state only
|
|
1051
|
+
|
|
1052
|
+
Every file you write states only the current arrangement and the reason it
|
|
1053
|
+
holds, in the present tense. No "used to", "previously", "before this",
|
|
1054
|
+
migration notes or deprecation narrative \u2014 history belongs in the project's
|
|
1055
|
+
changelog, not in your map. An absence that is true today is a fact worth
|
|
1056
|
+
stating, not a removal worth narrating. When a past state is worth keeping,
|
|
1057
|
+
record it briefly in \`changelog.md\` instead.
|
|
1049
1058
|
|
|
1050
1059
|
Never create, modify, or delete anything outside \`.opencode/context/\`. The
|
|
1051
1060
|
\`edit\` permission enforces this. Do not attempt to work around it with bash.
|
|
@@ -1081,11 +1090,6 @@ Then write the five files. For each significant subsystem, give a short
|
|
|
1081
1090
|
reason. This is the single most valuable thing you produce: where an agent
|
|
1082
1091
|
should open its editor next.
|
|
1083
1092
|
|
|
1084
|
-
manager.md is created for the client by the plugin, not by you; if it is
|
|
1085
|
-
missing anyway, mention once in your final report that they can add it
|
|
1086
|
-
themselves to record what is being worked on, what comes next, and what
|
|
1087
|
-
they have ratified. Never create it.
|
|
1088
|
-
|
|
1089
1093
|
# Incremental update
|
|
1090
1094
|
|
|
1091
1095
|
Trigger: \`.opencode/context/\` exists and work has just been done here.
|
|
@@ -1113,14 +1117,6 @@ that is already stated in another context file \u2014 one fact has one home, and
|
|
|
1113
1117
|
the other files link to it. If nothing material changed, make no edits and
|
|
1114
1118
|
report "no update needed".
|
|
1115
1119
|
|
|
1116
|
-
Before editing, re-read manager.md: its \`## Current\` and \`## Next\`
|
|
1117
|
-
sections tell you what the client is actually working on, and its
|
|
1118
|
-
\`## Confirmed\` section settles which of your facts are ratified. If what
|
|
1119
|
-
you are about to write would place the code somewhere the client never
|
|
1120
|
-
described, trust the code, make the edit the code justifies, and report
|
|
1121
|
-
the gap in your final message \u2014 never reconcile the two sides silently,
|
|
1122
|
-
and never edit manager.md to close it.
|
|
1123
|
-
|
|
1124
1120
|
# Minimal exploration
|
|
1125
1121
|
|
|
1126
1122
|
Default shape:
|
|
@@ -1215,14 +1211,10 @@ Audit the five files for:
|
|
|
1215
1211
|
- duplicated information \u2014 one canonical place per fact
|
|
1216
1212
|
- missing canonical entry points for significant subsystems
|
|
1217
1213
|
- unsupported assumptions \u2014 anything unmarked that you cannot verify
|
|
1218
|
-
- manager.md, if present: is \`## Current\` and \`## Next\` still true of
|
|
1219
|
-
recent work, is every \`## Confirmed\` entry still true of the code, has
|
|
1220
|
-
it outgrown roughly 150 lines \u2014 report findings, but never edit, prune,
|
|
1221
|
-
or reorganize it; that is the client's call
|
|
1222
1214
|
|
|
1223
|
-
Fix problems only in the five files you own
|
|
1224
|
-
|
|
1225
|
-
|
|
1215
|
+
Fix problems only in the five files you own. Never modify source code
|
|
1216
|
+
during a review. Report what you found, what you fixed, and what you
|
|
1217
|
+
could not verify.
|
|
1226
1218
|
|
|
1227
1219
|
# Reporting
|
|
1228
1220
|
|
|
@@ -1240,9 +1232,7 @@ Finish with a short report:
|
|
|
1240
1232
|
"edit": {
|
|
1241
1233
|
"*": "deny",
|
|
1242
1234
|
"*/.opencode/context/**": "allow",
|
|
1243
|
-
".opencode/context/**": "allow"
|
|
1244
|
-
"*/.opencode/context/manager.md": "deny",
|
|
1245
|
-
".opencode/context/manager.md": "deny"
|
|
1235
|
+
".opencode/context/**": "allow"
|
|
1246
1236
|
},
|
|
1247
1237
|
"bash": {
|
|
1248
1238
|
"*": "deny",
|
|
@@ -1290,58 +1280,63 @@ Finish with a short report:
|
|
|
1290
1280
|
}
|
|
1291
1281
|
}
|
|
1292
1282
|
};
|
|
1293
|
-
var
|
|
1294
|
-
description: "
|
|
1283
|
+
var INSTRUCTIONS_AGENT = {
|
|
1284
|
+
description: "Edits the project's AGENTS.md. Run only by the /agent-instructions command; no agent or subagent can spawn it.",
|
|
1295
1285
|
mode: "subagent",
|
|
1296
1286
|
hidden: true,
|
|
1297
1287
|
temperature: 0.1,
|
|
1298
1288
|
prompt: `# Role
|
|
1299
1289
|
|
|
1300
|
-
You maintain one file and nothing else:
|
|
1301
|
-
|
|
1302
|
-
other path.
|
|
1290
|
+
You maintain one file and nothing else: the project's \`AGENTS.md\`. You are not a
|
|
1291
|
+
coding agent and you touch no other path.
|
|
1303
1292
|
|
|
1304
|
-
You are run only by the \`/
|
|
1293
|
+
You are run only by the \`/agent-instructions\` command. The client tells you what
|
|
1305
1294
|
they want recorded or changed in the file; you apply that to the file and report
|
|
1306
1295
|
what you changed. You have no permission to edit anything else, and you need
|
|
1307
1296
|
none.
|
|
1308
1297
|
|
|
1309
1298
|
# The file
|
|
1310
1299
|
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1300
|
+
\`AGENTS.md\` is the project's standing instructions \u2014 the rules every agent and
|
|
1301
|
+
subagent runs under. opencode loads it into every session automatically, so what
|
|
1302
|
+
you write here steers all work in this project. Keep it about how to work:
|
|
1303
|
+
conventions, constraints, priorities, things to always do and never do. It says
|
|
1304
|
+
nothing about where code lives \u2014 the source and the context map are the authority
|
|
1305
|
+
on that.
|
|
1315
1306
|
|
|
1316
1307
|
# How to apply a directive
|
|
1317
1308
|
|
|
1318
|
-
- Do what the client asked
|
|
1319
|
-
|
|
1320
|
-
|
|
1309
|
+
- Do what the client asked: add, rewrite, move or remove exactly what they asked
|
|
1310
|
+
for. A bare sentence goes under the most fitting existing heading, and you
|
|
1311
|
+
create a heading only if none fits.
|
|
1321
1312
|
- Never invent facts, never record your own inference as the client's, and never
|
|
1322
1313
|
tidy, reorder or delete content the client did not ask you to touch.
|
|
1323
|
-
-
|
|
1324
|
-
history.
|
|
1314
|
+
- Prefer current-state wording: state how things are, not how they changed.
|
|
1325
1315
|
- Keep the file concise. If it is growing past roughly 150 lines, say so.
|
|
1316
|
+
- If \`AGENTS.md\` does not exist, create it and record the client's instruction in
|
|
1317
|
+
it \u2014 that instruction is the file's first content.
|
|
1318
|
+
- Do NOT add placeholder comments, empty template headings, or example text;
|
|
1319
|
+
write only what the client asked for.
|
|
1320
|
+
- Say plainly in your report that you created the file.
|
|
1326
1321
|
|
|
1327
1322
|
# Reporting
|
|
1328
1323
|
|
|
1329
1324
|
Report briefly what you changed and where. Do not edit any other file.`,
|
|
1330
1325
|
permission: {
|
|
1331
|
-
// Read is scoped to the one file too: the directive is about
|
|
1326
|
+
// Read is scoped to the one file too: the directive is about AGENTS.md, and
|
|
1332
1327
|
// nothing else is any of this agent's business.
|
|
1333
1328
|
read: {
|
|
1334
1329
|
"*": "deny",
|
|
1335
|
-
".
|
|
1336
|
-
"
|
|
1330
|
+
"AGENTS.md": "allow",
|
|
1331
|
+
"*/AGENTS.md": "allow"
|
|
1337
1332
|
},
|
|
1338
1333
|
glob: "deny",
|
|
1339
1334
|
grep: "deny",
|
|
1340
1335
|
list: "deny",
|
|
1341
1336
|
edit: {
|
|
1342
1337
|
"*": "deny",
|
|
1343
|
-
".
|
|
1344
|
-
"
|
|
1338
|
+
"AGENTS.md": "allow",
|
|
1339
|
+
"*/AGENTS.md": "allow"
|
|
1345
1340
|
},
|
|
1346
1341
|
bash: "deny",
|
|
1347
1342
|
webfetch: "deny",
|
|
@@ -1367,7 +1362,7 @@ function buildAgentSet() {
|
|
|
1367
1362
|
set[`${base}-${slot}`] = variant;
|
|
1368
1363
|
}
|
|
1369
1364
|
}
|
|
1370
|
-
set[
|
|
1365
|
+
set[AGENT_INSTRUCTIONS_WRITER] = INSTRUCTIONS_AGENT;
|
|
1371
1366
|
return set;
|
|
1372
1367
|
}
|
|
1373
1368
|
function applyAgents(cfg, agents = buildAgentSet(), opts = {}) {
|
|
@@ -1407,13 +1402,7 @@ Remember: write conclusions, not inventories. Link to the project's existing
|
|
|
1407
1402
|
documentation instead of duplicating it.
|
|
1408
1403
|
|
|
1409
1404
|
Report what you created or updated, what you deliberately left out, and
|
|
1410
|
-
anything that contradicts the code or existing docs
|
|
1411
|
-
|
|
1412
|
-
If \`.opencode/context/manager.md\` does not exist, mention in your final
|
|
1413
|
-
report that the client can add it themselves \u2014 their own file with
|
|
1414
|
-
\`## Current\`, \`## Next\`, \`## Confirmed\` and \`## Instructions\` \u2014 for what
|
|
1415
|
-
is being worked on, what comes next, what they have ratified, and standing
|
|
1416
|
-
direction. Never create it.`
|
|
1405
|
+
anything that contradicts the code or existing docs.`
|
|
1417
1406
|
},
|
|
1418
1407
|
"context-update": {
|
|
1419
1408
|
description: "Incrementally update .opencode/context/ after recent work via the context agent.",
|
|
@@ -1444,9 +1433,8 @@ timestamp-only edits. If nothing material changed, make no edits and report
|
|
|
1444
1433
|
subtask: true,
|
|
1445
1434
|
template: `Context review.
|
|
1446
1435
|
|
|
1447
|
-
Everything outside the five context files is read-only for this run
|
|
1448
|
-
|
|
1449
|
-
code under any circumstances.
|
|
1436
|
+
Everything outside the five context files is read-only for this run. Do not
|
|
1437
|
+
modify source code under any circumstances.
|
|
1450
1438
|
|
|
1451
1439
|
Audit the five context files for:
|
|
1452
1440
|
|
|
@@ -1459,18 +1447,15 @@ Audit the five context files for:
|
|
|
1459
1447
|
- missing canonical entry points for significant subsystems
|
|
1460
1448
|
- unsupported assumptions \u2014 anything stated as fact that you cannot verify,
|
|
1461
1449
|
or that lacks a confidence marker
|
|
1462
|
-
- \`manager.md\`, if present: is \`## Current\` and \`## Next\` still true of
|
|
1463
|
-
recent work, is every \`## Confirmed\` entry still true of the code, has it
|
|
1464
|
-
outgrown roughly 150 lines \u2014 report findings, but never edit it
|
|
1465
1450
|
|
|
1466
1451
|
Fix what you find in \`.opencode/context/\` only, then report: findings, fixes,
|
|
1467
1452
|
and anything you could not verify.`
|
|
1468
1453
|
},
|
|
1469
|
-
|
|
1470
|
-
description: "Apply a client instruction to .
|
|
1471
|
-
agent:
|
|
1454
|
+
[AGENT_INSTRUCTIONS_COMMAND]: {
|
|
1455
|
+
description: "Apply a client instruction to the project's AGENTS.md. Client-only \u2014 runs the instructions agent, the only writer of that file.",
|
|
1456
|
+
agent: AGENT_INSTRUCTIONS_WRITER,
|
|
1472
1457
|
subtask: true,
|
|
1473
|
-
template: `Apply this instruction to
|
|
1458
|
+
template: `Apply this instruction to the project's \`AGENTS.md\`, and edit only that file:
|
|
1474
1459
|
|
|
1475
1460
|
$ARGUMENTS
|
|
1476
1461
|
|
|
@@ -1552,45 +1537,6 @@ function applyCommands(cfg, commands = COMMANDS) {
|
|
|
1552
1537
|
}
|
|
1553
1538
|
return { added, kept };
|
|
1554
1539
|
}
|
|
1555
|
-
var INSTRUCTION_MARKER = "<!-- lacode:context-map-instruction:v1 -->";
|
|
1556
|
-
var INSTRUCTION_OPT_OUT = "<!-- lacode:context-map-instruction:off -->";
|
|
1557
|
-
var STANDING_INSTRUCTION = `## Repository context map
|
|
1558
|
-
|
|
1559
|
-
This project may keep a navigation map in \`.opencode/context/\`. Before broad
|
|
1560
|
-
exploration, check whether it exists (\`ls .opencode/context\` \u2014 never the \`glob\`
|
|
1561
|
-
tool, which skips hidden directories). If \`manager.md\` exists there, read it
|
|
1562
|
-
first: it is the client's own statement of intent \u2014 what is being worked on,
|
|
1563
|
-
what comes next, \`## Confirmed\` lists what the client has ratified, and
|
|
1564
|
-
\`## Instructions\` holds standing managerial directions. It outranks every
|
|
1565
|
-
other context file and every inference of yours about what matters right now.
|
|
1566
|
-
It says nothing about where code lives, so it cannot contradict the code;
|
|
1567
|
-
treat its \`## Confirmed\` entries as settled decisions, not as a licence to
|
|
1568
|
-
skip reading the code. Any heading in it is direction, so read the whole
|
|
1569
|
-
file rather than only the sections above. The rest of the map remains usable,
|
|
1570
|
-
just unratified where \`## Confirmed\` does not cover it. Then read only the
|
|
1571
|
-
file relevant to the task \u2014 \`architecture.md\`, \`contexts.md\`,
|
|
1572
|
-
\`conventions.md\`, \`workflows.md\`, \`decisions.md\` \u2014 and start from the
|
|
1573
|
-
canonical entry points it lists.
|
|
1574
|
-
|
|
1575
|
-
Source code is authoritative: if the map disagrees with the code,
|
|
1576
|
-
trust the code and say so; never edit source to match it.
|
|
1577
|
-
Never edit the five context files yourself \u2014 the context agent owns them.
|
|
1578
|
-
\`manager.md\` is the client's own file and the context agent is explicitly
|
|
1579
|
-
permission-denied from writing it. You may write it only when the client
|
|
1580
|
-
explicitly asks you to in this conversation, and then only what they asked
|
|
1581
|
-
for; never on your own initiative, and never to "keep it up to date". Say in
|
|
1582
|
-
your final report if your work revealed something that belongs to the map, or
|
|
1583
|
-
if \`manager.md\` and the code disagree.`;
|
|
1584
|
-
function applyInstructions(cfg) {
|
|
1585
|
-
const existing = Array.isArray(cfg.instructions) ? cfg.instructions : [];
|
|
1586
|
-
const texts = existing.filter((e) => typeof e === "string");
|
|
1587
|
-
if (texts.some((e) => e.includes(INSTRUCTION_OPT_OUT))) return { added: false };
|
|
1588
|
-
if (texts.some((e) => e.includes(INSTRUCTION_MARKER))) return { added: false };
|
|
1589
|
-
cfg.instructions = [...existing, `${INSTRUCTION_MARKER}
|
|
1590
|
-
|
|
1591
|
-
${STANDING_INSTRUCTION}`];
|
|
1592
|
-
return { added: true };
|
|
1593
|
-
}
|
|
1594
1540
|
|
|
1595
1541
|
// src/plugins/agent-pool.ts
|
|
1596
1542
|
import { tool } from "@opencode-ai/plugin";
|
|
@@ -1926,7 +1872,7 @@ round robin in slot order, each slot taking as many turns as its weight says, so
|
|
|
1926
1872
|
});
|
|
1927
1873
|
|
|
1928
1874
|
// src/plugins/context-autoupdate.ts
|
|
1929
|
-
import { existsSync as existsSync2, readdirSync as readdirSync2, statSync as statSync2
|
|
1875
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2, statSync as statSync2 } from "node:fs";
|
|
1930
1876
|
import * as path2 from "node:path";
|
|
1931
1877
|
|
|
1932
1878
|
// src/lib/jsonc.ts
|
|
@@ -1981,7 +1927,7 @@ import { readFileSync as readFileSync3 } from "node:fs";
|
|
|
1981
1927
|
import * as path from "node:path";
|
|
1982
1928
|
var CONTEXT_DIR = path.join(".opencode", "context");
|
|
1983
1929
|
var WRITER = "context";
|
|
1984
|
-
var
|
|
1930
|
+
var INSTRUCTIONS_WRITER = AGENT_INSTRUCTIONS_WRITER;
|
|
1985
1931
|
var toPosix = (value) => value.split(path.sep).join("/");
|
|
1986
1932
|
var compilePattern = (pattern) => {
|
|
1987
1933
|
const escaped = toPosix(pattern).replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
@@ -2010,8 +1956,8 @@ var evaluatedForm = (mapDir, projectRoot) => {
|
|
|
2010
1956
|
const absolute = toPosix(path.join(mapDir, "architecture.md"));
|
|
2011
1957
|
return projectRoot ? toPosix(path.relative(projectRoot, absolute)) : absolute;
|
|
2012
1958
|
};
|
|
2013
|
-
var
|
|
2014
|
-
const absolute = toPosix(path.join(mapDir, "
|
|
1959
|
+
var agentsForm = (mapDir, projectRoot) => {
|
|
1960
|
+
const absolute = toPosix(path.join(mapDir, "..", "..", "AGENTS.md"));
|
|
2015
1961
|
return projectRoot ? toPosix(path.relative(projectRoot, absolute)) : absolute;
|
|
2016
1962
|
};
|
|
2017
1963
|
var verifyWriterRule = (configPath, mapDir, projectRoot) => {
|
|
@@ -2045,17 +1991,17 @@ var verifyWriterRule = (configPath, mapDir, projectRoot) => {
|
|
|
2045
1991
|
return `context map has more than one writer: ${offenders.join(", ")} would be granted the map by permission, evaluating "${form}". Only ${WRITER} may write the map. Narrow the grant and put the deny LAST -- opencode takes the LAST matching rule, so "${CONTEXT_DIR}/**": "deny" written after "*": "allow" is what denies it: "*": "allow", "*/${CONTEXT_DIR}/**": "deny", "${CONTEXT_DIR}/**": "deny". Both spellings are required because the evaluated path depends on the project root.`;
|
|
2046
1992
|
}
|
|
2047
1993
|
}
|
|
2048
|
-
const
|
|
1994
|
+
const agentsPath = agentsForm(mapDir, projectRoot);
|
|
2049
1995
|
const agentDefs = readAgents(raw);
|
|
2050
1996
|
if (agentDefs) {
|
|
2051
1997
|
const writers = [];
|
|
2052
1998
|
for (const [name, def] of Object.entries(agentDefs)) {
|
|
2053
|
-
if (name ===
|
|
2054
|
-
const win = winningRule(permissionOf(def),
|
|
1999
|
+
if (name === INSTRUCTIONS_WRITER) continue;
|
|
2000
|
+
const win = winningRule(permissionOf(def), agentsPath);
|
|
2055
2001
|
if (win?.action === "allow") writers.push(`${name} (edit rule "${win.pattern}": "${win.action}")`);
|
|
2056
2002
|
}
|
|
2057
2003
|
if (writers.length > 0) {
|
|
2058
|
-
return
|
|
2004
|
+
return `AGENTS.md is writable by permission: ${writers.join(", ")}. It is the project's own file \u2014 the standing instructions every agent runs under \u2014 and only the \`${INSTRUCTIONS_WRITER}\` agent (run solely by /agent-instructions) may write it. Deny it LAST on every other agent, after any broad allow, because opencode takes the LAST matching rule: "*": "allow", "AGENTS.md": "deny", "*/AGENTS.md": "deny". Declare this on every agent above, including \`${WRITER}\`: an agent you define yourself replaces the shipped one wholesale, permission and all.`;
|
|
2059
2005
|
}
|
|
2060
2006
|
}
|
|
2061
2007
|
return void 0;
|
|
@@ -2084,51 +2030,6 @@ var IGNORED_SEGMENTS = /* @__PURE__ */ new Set([
|
|
|
2084
2030
|
".cache",
|
|
2085
2031
|
".git"
|
|
2086
2032
|
]);
|
|
2087
|
-
var MANAGER_TEMPLATE = `# Managerial directions
|
|
2088
|
-
|
|
2089
|
-
This file is yours. No agent writes it: the context agent is explicitly denied
|
|
2090
|
-
permission to touch this path, and nothing changes it except you, or an agent
|
|
2091
|
-
acting on your explicit instruction in that conversation.
|
|
2092
|
-
|
|
2093
|
-
It records what you want done and how you want it approached \u2014 what is being
|
|
2094
|
-
worked on, what comes next, what you have settled, and what every agent should
|
|
2095
|
-
keep in mind. It deliberately says nothing about where code lives: the source
|
|
2096
|
-
and the five generated context files are the only authority on that, so this
|
|
2097
|
-
file can never contradict the code.
|
|
2098
|
-
|
|
2099
|
-
Add any headings you like. The four below are a convenience, not a schema \u2014
|
|
2100
|
-
every heading in this file is direction.
|
|
2101
|
-
|
|
2102
|
-
## Current
|
|
2103
|
-
|
|
2104
|
-
<!-- What is being worked on right now. Rewrite it; do not append a history. -->
|
|
2105
|
-
|
|
2106
|
-
## Next
|
|
2107
|
-
|
|
2108
|
-
<!-- What comes next, in order. -->
|
|
2109
|
-
|
|
2110
|
-
## Confirmed
|
|
2111
|
-
|
|
2112
|
-
<!-- What you have personally ratified. Nothing enters or leaves this list
|
|
2113
|
-
except by your hand \u2014 no agent promotes, prunes or rewrites it. -->
|
|
2114
|
-
|
|
2115
|
-
## Instructions
|
|
2116
|
-
|
|
2117
|
-
<!-- Standing direction that applies beyond the current task: priorities, things
|
|
2118
|
-
to care about, constraints that are not obvious from the code. -->`;
|
|
2119
|
-
var ensureManagerFile = (root) => {
|
|
2120
|
-
try {
|
|
2121
|
-
const target = path2.join(root, ".opencode", "context", "manager.md");
|
|
2122
|
-
if (existsSync2(target)) return { created: false };
|
|
2123
|
-
mkdirSync2(path2.dirname(target), { recursive: true });
|
|
2124
|
-
writeFileSync2(target, MANAGER_TEMPLATE, { flag: "wx" });
|
|
2125
|
-
return { created: true };
|
|
2126
|
-
} catch (error) {
|
|
2127
|
-
if (error?.code === "EEXIST") return { created: false };
|
|
2128
|
-
console.warn(`[context-autoupdate] ensureManagerFile failed: ${error}`);
|
|
2129
|
-
return { created: false };
|
|
2130
|
-
}
|
|
2131
|
-
};
|
|
2132
2033
|
var toPosix2 = (value) => value.split(path2.sep).join("/");
|
|
2133
2034
|
var findProjectConfig = () => {
|
|
2134
2035
|
let dir = import.meta.dir ?? path2.dirname(new URL(import.meta.url).pathname);
|
|
@@ -2172,7 +2073,6 @@ var contextAutoUpdateHooks = (async ({ client, directory }, options) => {
|
|
|
2172
2073
|
});
|
|
2173
2074
|
const root = path2.resolve(directory);
|
|
2174
2075
|
const contextAbs = path2.join(root, CONTEXT_DIR2);
|
|
2175
|
-
if (ensureManagerFile(root).created) void log("info", `created ${CONTEXT_DIR2}/manager.md`);
|
|
2176
2076
|
const config = findProjectConfig();
|
|
2177
2077
|
const writerProblem = config ? verifyWriterRule(config, contextAbs, root) : void 0;
|
|
2178
2078
|
if (writerProblem) void log("error", writerProblem);
|
|
@@ -3132,7 +3032,7 @@ var omniRouteHooks = async (input, options, deps = {}) => {
|
|
|
3132
3032
|
|
|
3133
3033
|
// src/lib/selfupdate.ts
|
|
3134
3034
|
import { spawn as spawn2 } from "node:child_process";
|
|
3135
|
-
import { closeSync, mkdirSync as
|
|
3035
|
+
import { closeSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2, writeSync } from "node:fs";
|
|
3136
3036
|
import { homedir as homedir2 } from "node:os";
|
|
3137
3037
|
import { dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
|
|
3138
3038
|
var REGISTRY_LATEST = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
@@ -3226,8 +3126,8 @@ function readState(path4 = STATE_PATH) {
|
|
|
3226
3126
|
}
|
|
3227
3127
|
function writeState(state2, path4 = STATE_PATH) {
|
|
3228
3128
|
try {
|
|
3229
|
-
|
|
3230
|
-
|
|
3129
|
+
mkdirSync2(dirname3(path4), { recursive: true });
|
|
3130
|
+
writeFileSync2(path4, JSON.stringify(state2));
|
|
3231
3131
|
} catch {
|
|
3232
3132
|
}
|
|
3233
3133
|
}
|
|
@@ -3253,7 +3153,7 @@ function acquireLock(path4 = LOCK_PATH, now = Date.now()) {
|
|
|
3253
3153
|
};
|
|
3254
3154
|
};
|
|
3255
3155
|
try {
|
|
3256
|
-
|
|
3156
|
+
mkdirSync2(dirname3(path4), { recursive: true });
|
|
3257
3157
|
return claim();
|
|
3258
3158
|
} catch {
|
|
3259
3159
|
let orphaned = false;
|
|
@@ -3441,9 +3341,6 @@ var LaCode = (async (input, options) => {
|
|
|
3441
3341
|
if (cmds.added.length > 0) {
|
|
3442
3342
|
await log("info", `commands: added ${cmds.added.join(", ")}; kept ${cmds.kept.join(", ") || "none"} already defined`);
|
|
3443
3343
|
}
|
|
3444
|
-
if (applyInstructions(cfg).added) {
|
|
3445
|
-
await log("info", "instructions: ensured the standing context-map rule is present");
|
|
3446
|
-
}
|
|
3447
3344
|
await omniroute.config?.(cfg);
|
|
3448
3345
|
await pool.config?.(cfg);
|
|
3449
3346
|
} catch (error) {
|
package/docs/BENCHMARKS.md
CHANGED
|
@@ -88,10 +88,9 @@ never priced at 0 and never priced at a guess. If you name such a model
|
|
|
88
88
|
explicitly with `--model` / `--baseline-model`, the run exits non-zero and tells
|
|
89
89
|
you to refresh or to pass `--allow-unknown`.
|
|
90
90
|
|
|
91
|
-
This is
|
|
92
|
-
|
|
93
|
-
default offline run cannot produce an honest ratio.
|
|
94
|
-
as designed.
|
|
91
|
+
This is why the results table below is empty. The pinned snapshot covers the
|
|
92
|
+
bundled free preset only; the default baseline model is not in it, so the
|
|
93
|
+
default offline run cannot produce an honest ratio.
|
|
95
94
|
|
|
96
95
|
## Results
|
|
97
96
|
|
|
@@ -116,11 +115,10 @@ harness prints `unknown`.
|
|
|
116
115
|
`--out docs/BENCHMARKS.md` and exits 2.
|
|
117
116
|
|
|
118
117
|
That refusal is the point. This file ships inside the npm tarball (`files`
|
|
119
|
-
includes `docs`)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
footer pointing back here — goes to its own gitignored filename.
|
|
118
|
+
includes `docs`) and is the hand-written explainer. A generated table is a
|
|
119
|
+
measurement of one machine on one day, not a claim about the package, so the
|
|
120
|
+
explainer is protected and the generated output — which carries a footer
|
|
121
|
+
pointing back here — goes to its own gitignored filename.
|
|
124
122
|
|
|
125
123
|
```bash
|
|
126
124
|
npm run benchmark -- --out docs/BENCHMARKS.generated.md
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -43,10 +43,10 @@ writes the context map and has no business in a browser.
|
|
|
43
43
|
opencode folds an agent's `tools` into its permission list **at config-load
|
|
44
44
|
time**, while decoding the config — before any plugin runs. A plugin's `config`
|
|
45
45
|
hook mutates the already-decoded config, so the fold never re-runs and anything
|
|
46
|
-
it puts in `agent.tools` is inert.
|
|
47
|
-
|
|
48
|
-
`
|
|
49
|
-
|
|
46
|
+
it puts in `agent.tools` is inert. On opencode 1.18.34/1.18.35, a grant
|
|
47
|
+
written in your own config shows two `playwright_*` entries — `deny` then
|
|
48
|
+
`allow`, last one winning — while the same grant injected by the plugin shows
|
|
49
|
+
only the `deny`. LaCode's other injected
|
|
50
50
|
fields are not affected; `permission`, `prompt`, `model`, `description`,
|
|
51
51
|
`temperature`, `mode` and `hidden` are all read after the plugin hook runs.
|
|
52
52
|
|
|
@@ -78,8 +78,8 @@ process.
|
|
|
78
78
|
**18 agent keys**: the 5 bases `build`, `plan`, `explore`, `implement`,
|
|
79
79
|
`context`, plus one hidden
|
|
80
80
|
`<base>-1`..`-4` pool variant for each of the 3 pooled bases, plus the hidden
|
|
81
|
-
`
|
|
82
|
-
only from the `/
|
|
81
|
+
`instructions` agent — the one writer of the project's root `AGENTS.md`,
|
|
82
|
+
reachable only from the `/agent-instructions` command.
|
|
83
83
|
|
|
84
84
|
`build` and `plan` exist in opencode as built-ins, so on a stock config those
|
|
85
85
|
two keys are already taken and merge-without-clobber keeps the built-in — the
|
|
@@ -92,13 +92,13 @@ duplicate of `plan` apart from a pinned model, and `plan` is injected instead.
|
|
|
92
92
|
description — a package cannot ship someone else's provider, quota or benchmark
|
|
93
93
|
results — though its escalation ladder still resolves, because the two deep
|
|
94
94
|
tiers it escalates to *are* injected. And `explore`, `general` and `implement`
|
|
95
|
-
are only `{ "disable": true }` stubs
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
are only `{ "disable": true }` stubs: turning off opencode's built-in agents
|
|
96
|
+
is a decision about one person's configuration, not a default a package should
|
|
97
|
+
impose on a stranger.
|
|
98
98
|
|
|
99
|
-
One **field** is deliberately not injected
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
One **field** is deliberately not injected: `tools`, for the load-time-folding
|
|
100
|
+
reason explained above. Nothing else the plugin writes into an agent is subject
|
|
101
|
+
to it.
|
|
102
102
|
|
|
103
103
|
**Installation merges, it does not clobber** (US-16). An agent, command or
|
|
104
104
|
instruction is added only when that key is absent from your config. A
|