@sorenllm/opencode-forge 0.11.0 → 0.11.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/README.md +7 -1
- package/dist/index.js +17 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -428,6 +428,12 @@ workspace-local file that the host was not launched on is NOT silently
|
|
|
428
428
|
ignored: `/crew` names it and tells you to relaunch there (or fold the
|
|
429
429
|
agents into the global layer).
|
|
430
430
|
|
|
431
|
+
**Id naming**: use plain role words (`research`, `coder`, …) — the plugin
|
|
432
|
+
materializes every id as `forge-<id>` itself. A `forge-`-prefixed id in the
|
|
433
|
+
file would double up (`forge-coder` → agent `forge-forge-coder`); the loader
|
|
434
|
+
auto-strips the prefix (all repetitions) with a warning so existing files
|
|
435
|
+
keep working, but rename the entries to silence it.
|
|
436
|
+
|
|
431
437
|
```jsonc
|
|
432
438
|
{
|
|
433
439
|
// forge subagents — definitions; see the restart table below for apply timing
|
|
@@ -436,7 +442,7 @@ agents into the global layer).
|
|
|
436
442
|
"research": {
|
|
437
443
|
"model": "zai-coding-plan/glm-5.3", // exact "provider/model" string
|
|
438
444
|
"thoughtLevel": "low", // none/low/medium/high/max or a native level name
|
|
439
|
-
// "prompt": "
|
|
445
|
+
// "prompt": "short role description — explicit prompts fully override the built-ins (only research/review ids have them; any other id without a prompt gets a generic one-liner)",
|
|
440
446
|
// "shape": "write", // default readonly denies write/edit/bash
|
|
441
447
|
// "permission": { "bash": "deny" } // optional override; "task" is ALWAYS denied
|
|
442
448
|
},
|
package/dist/index.js
CHANGED
|
@@ -15358,12 +15358,21 @@ function validateAgentSet(raw) {
|
|
|
15358
15358
|
findings.push({ level: "error", code: "agents-not-object", message: 'forge.json "agents" must be an object mapping agent ids to definitions — the agent set is empty' });
|
|
15359
15359
|
return { agents, findings };
|
|
15360
15360
|
}
|
|
15361
|
-
for (const [
|
|
15362
|
-
|
|
15361
|
+
for (const [rawId, entry] of Object.entries(raw)) {
|
|
15362
|
+
let label = `agents.${rawId}`;
|
|
15363
|
+
let id = rawId;
|
|
15364
|
+
if (rawId.startsWith("forge-")) {
|
|
15365
|
+
id = rawId.replace(/^(forge-)+/, "");
|
|
15366
|
+
findings.push({ level: "warn", code: "agent-id-forge-prefix", message: `${label}: the forge- prefix is added automatically at materialization — stripped to "${id}"; rename the entry to silence this warning` });
|
|
15367
|
+
}
|
|
15363
15368
|
if (!AGENT_ID_RE.test(id)) {
|
|
15364
15369
|
findings.push({ level: "error", code: "agent-id-invalid", message: `${label}: agent id must match [a-z0-9-] — entry skipped` });
|
|
15365
15370
|
continue;
|
|
15366
15371
|
}
|
|
15372
|
+
if (agents[id] !== undefined) {
|
|
15373
|
+
findings.push({ level: "error", code: "agent-id-collision", message: `${label}: normalizes to "${id}" which is already defined — entry skipped (first definition wins)` });
|
|
15374
|
+
continue;
|
|
15375
|
+
}
|
|
15367
15376
|
if (!isRecord(entry)) {
|
|
15368
15377
|
findings.push({ level: "error", code: "agent-not-object", message: `${label}: definition must be an object — entry skipped` });
|
|
15369
15378
|
continue;
|
|
@@ -16491,9 +16500,9 @@ var CREW_INIT_TEMPLATE = [
|
|
|
16491
16500
|
"1. The user configures it themselves: create either layer — MERGED, the project layer overrides the global one per agent id (the project file is the nearest .opencode/forge.json walking up from the workspace root):",
|
|
16492
16501
|
"{paths}",
|
|
16493
16502
|
"",
|
|
16494
|
-
"2. Or, ONLY if the user explicitly asks you to configure it in this conversation, you may write the file yourself through the normal write path. NEVER write forge.json without that explicit go-ahead.",
|
|
16503
|
+
"2. Or, ONLY if the user explicitly asks you to configure it in this conversation, you may write the file yourself through the normal write path. NEVER write forge.json without that explicit go-ahead. When you configure it: name ids as PLAIN role words WITHOUT the `forge-` prefix — the plugin materializes every id as `forge-<id>` automatically (a `forge-`-prefixed id doubles up as `forge-forge-coder` and is auto-stripped with a warning). Give EVERY agent a SHORT prompt derived from the role the user asked for — one or two sentences describing its job (the user trims or extends from there); write a long prompt ONLY when the user explicitly asks for that agent.",
|
|
16495
16504
|
"",
|
|
16496
|
-
"Template (JSONC — comments allowed): `model` + `thoughtLevel` are an ATOMIC PAIR — set BOTH to pin the brain and depth (model = exact provider/model identity; thoughtLevel = none/low/medium/high/max or a native level name), or NEITHER for an Auto worker that inherits the parent session's model; exactly one of the two is rejected.",
|
|
16505
|
+
"Template (JSONC — comments allowed): ids are plain role words (research, coder, ...) — the plugin adds the `forge-` prefix at materialization; `model` + `thoughtLevel` are an ATOMIC PAIR — set BOTH to pin the brain and depth (model = exact provider/model identity; thoughtLevel = none/low/medium/high/max or a native level name), or NEITHER for an Auto worker that inherits the parent session's model; exactly one of the two is rejected. Optional per agent: `prompt` — a short role description; an explicit prompt FULLY overrides the built-in role (only the ids `research` and `review` carry built-ins; any other id without a prompt gets a generic one-liner and will not know its job).",
|
|
16497
16506
|
"{template}",
|
|
16498
16507
|
"",
|
|
16499
16508
|
"After the file is saved: NEW agents require a host restart to appear in the task tool; thoughtLevel edits on existing agents apply without restart. Until then, crew stays unavailable."
|
|
@@ -16545,8 +16554,9 @@ var crewBeginTool = tool({
|
|
|
16545
16554
|
const lines = [
|
|
16546
16555
|
"[forge:crew] CREW IS NOT INITIALIZED on this host: no forge subagents are materialized. Crew orchestration is unavailable until the user sets it up.",
|
|
16547
16556
|
`Two layers, MERGED (the project layer overrides the global one per agent id): ${paths.project} (nearest .opencode/forge.json walking up from the workspace) OR ${paths.global}.`,
|
|
16548
|
-
'Template (JSONC): {"agents": {"research": {"model": "provider/model", "thoughtLevel": "low"}}}',
|
|
16549
|
-
"
|
|
16557
|
+
'Template (JSONC): {"agents": {"research": {"model": "provider/model", "thoughtLevel": "low", "prompt": "short role description"}}}',
|
|
16558
|
+
"Agent ids are plain role words WITHOUT the `forge-` prefix — the plugin materializes each id as `forge-<id>` (a prefixed id is auto-stripped with a warning).",
|
|
16559
|
+
"The user may configure it themselves, or ask you to write the file — only on their explicit go-ahead. When you write it, give every agent a SHORT prompt from the role the user asked for (one or two sentences; long only on explicit request) — without a prompt, custom ids get a generic one-liner and will not know their job. Newly added agents need a host restart; thoughtLevel edits apply without one."
|
|
16550
16560
|
];
|
|
16551
16561
|
if (sessionLoaded && Object.keys(sessionLoaded.agents).length > 0 && sessionProject) {
|
|
16552
16562
|
lines.push(`NOTE: this session's workspace DOES have a forge.json (${sessionProject}) with usable agents — but this host instance was launched from ${hostAnchorDir || "a different directory"}, so they are not in the task vocabulary. Relaunch opencode in that workspace, or add the agents to the global layer.`);
|
|
@@ -17050,7 +17060,7 @@ var server = async (input, options) => {
|
|
|
17050
17060
|
if (!existingCrew || String(existingCrew.template ?? "").startsWith("(forge crew")) {
|
|
17051
17061
|
const agentIds = Object.keys(loaded.agents);
|
|
17052
17062
|
const template = agentIds.length > 0 ? crewOrchestrationTemplate(agentIds) : CREW_INIT_TEMPLATE.replaceAll("{paths}", ` - ${forgeConfigPaths({ projectDir: forgeLoaderDir ?? undefined, homeDir: process.env.FORGE_TEST_FORGE_HOME ?? homedir() }).project}
|
|
17053
|
-
- ${forgeConfigPaths({ projectDir: forgeLoaderDir ?? undefined, homeDir: process.env.FORGE_TEST_FORGE_HOME ?? homedir() }).global}`).replaceAll("{template}", JSON.stringify({ agents: { research: { model: "provider/model", thoughtLevel: "low" } } }, null, 2).split(`
|
|
17063
|
+
- ${forgeConfigPaths({ projectDir: forgeLoaderDir ?? undefined, homeDir: process.env.FORGE_TEST_FORGE_HOME ?? homedir() }).global}`).replaceAll("{template}", JSON.stringify({ agents: { research: { model: "provider/model", thoughtLevel: "low", prompt: "short role description — what this agent does" } } }, null, 2).split(`
|
|
17054
17064
|
`).map((l) => " " + l).join(`
|
|
17055
17065
|
`));
|
|
17056
17066
|
const description = agentIds.length > 0 ? "forge crew orchestration: register a declared subtask plan, execute it in waves of parallel native task calls, close with an evidence-checked report" : "forge crew orchestration — NOT INITIALIZED: no forge subagents configured; invoking it shows the one-time setup guidance";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sorenllm/opencode-forge",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "Single general-purpose forge agent for opencode: static worker subagents defined in forge.json (pinned model + thoughtLevel pair, or an Auto worker inheriting the parent model; dispatched through the native task tool — TUI-visible), a plan harness (file-backed plans with approve/close confirmation gates and a hard draft write-ban), a goal harness (autonomous, host-verified objectives), a /crew orchestration command (declared-plan waves with an evidence-checked close gate), a job supervisor (forge_shell with exit-bound completion, idle/success early return, background jobs with poll/log/kill/handoff), and a builtin-shell hang watchdog.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|