@plainconceptsplatform/agent-harness 2.9.0 → 3.0.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.
@@ -1,47 +1,36 @@
1
1
  {
2
2
  "$schema": "https://opencode.ai/config.json",
3
- "instructions": [
4
- "AGENTS.md"
5
- ],
6
- "plugin": [
7
- "@mohak34/opencode-notifier@0.2.8"
8
- ],
9
3
  "mcp": {
10
- "agent-browser": {
11
- "type": "local",
12
- "command": ["agent-browser", "mcp", "--tools", "core"],
13
- "enabled": true
4
+ "servers": {
5
+ "agent-browser": {
6
+ "type": "local",
7
+ "command": ["agent-browser", "mcp", "--tools", "core"],
8
+ "disabled": false
9
+ }
10
+ },
11
+ "timeout": {
12
+ "catalog": 300000,
13
+ "execution": 300000
14
14
  }
15
15
  },
16
- "experimental": {
17
- "mcp_timeout": 300000
18
- },
19
16
  "compaction": {
20
17
  "auto": true,
21
- "prune": true,
22
- "reserved": 10000
18
+ "buffer": 10000
23
19
  },
24
- "permission": {
25
- "question": "allow",
26
- "todowrite": "allow",
27
- "skill": "allow"
28
- },
29
- "skills": {
30
- "paths": [".agents/skills"]
31
- },
32
- // build and plan are the only primaries, and plan is the default: a session
33
- // starts read-only and you switch to build once you know what to change.
34
- // The pc-subagent-tiers plugin
35
- // regenerates .opencode/agents/{build,plan}.md from fullstack-engineer.md on
36
- // every startup and overrides these two entries with the resolved tier model,
37
- // so what is here is only the floor if the plugin cannot run. Every engineer
38
- // is mode: subagent and reached through task(), never picked by a human.
20
+ "permissions": [
21
+ { "action": "question", "resource": "*", "effect": "allow" },
22
+ { "action": "skill", "resource": "*", "effect": "allow" }
23
+ ],
24
+ "skills": [".agents/skills"],
39
25
  "default_agent": "plan",
40
- "agent": {
26
+ "agents": {
41
27
  "build": { "mode": "primary" },
42
28
  "plan": {
43
29
  "mode": "primary",
44
- "permission": { "edit": "deny", "task": "deny" }
30
+ "permissions": [
31
+ { "action": "edit", "resource": "*", "effect": "deny" },
32
+ { "action": "subagent", "resource": "*", "effect": "deny" }
33
+ ]
45
34
  }
46
35
  }
47
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/agent-harness",
3
- "version": "2.9.0",
3
+ "version": "3.0.2",
4
4
  "description": "Installs the Plain Concepts Platform Harness into any codebase, and keeps it up to date. Wires OpenCode, OpenSpec, codegraph, and agentmemory into a multi-agent workflow that runs on native parallel subagents.",
5
5
  "keywords": [
6
6
  "opencode",
@@ -6,23 +6,28 @@ license: MIT
6
6
 
7
7
  ## Transitive loads (optimization skills)
8
8
 
9
- The marker sections below name the optimization skills this project selected. Load each one before doing any work.
9
+ The marker sections below name the optimization skills this project selected. Load each before doing any work.
10
10
 
11
11
  ## Secrets
12
12
 
13
- - Treat `.env` files as write-only: write to them when configuring, and read credentials at runtime from the environment or the secret store.
14
- - Never put a credential, API key or token in a log line, an output, or a commit in anything but encrypted or template form. Anything printed is in a CI log that outlives the run.
13
+ - Treat `.env` files as write-only: write to them when configuring, read credentials at runtime from the environment or secret store.
14
+ - Never put a credential, API key, or token in a log line, output, or commit in anything but encrypted or template form.
15
15
 
16
16
  ## Code
17
17
 
18
- - Comments are for WHY, not WHAT. Use them only where the code does something non-obvious or the reason cannot be inferred from context. Past a 10% comment ratio in a file, refactor for clarity instead.
19
- - Never add a file that collects unrelated things — `constants.js`, `types.ts`, `config.js`, `utils.ts`. One responsibility per file, split by domain or feature (`user-constants.ts`, `order-types.ts`, `auth-config.ts`). A file importing from many unrelated modules is already the symptom.
18
+ - The default is zero comments. Add one only where the code is genuinely non-obvious. Past 10% comment-to-code ratio, refactor for clarity. Never add comments that restate the code, label variables, TODOs without a linked issue, commented-out code, separator banners, or auto-generated docstrings/JSDoc/XML docs unless explicitly asked.
19
+ - Never add a file that collects unrelated things — `constants.js`, `types.ts`, `utils.ts`. One responsibility per file, split by domain. A file importing from many unrelated modules is already the symptom.
20
20
 
21
21
  ## Temporary files
22
22
 
23
- - Never write outside `$REPO_ROOT`, and never to an operating-system temporary directory: the next step and the next agent cannot see it, and nobody cleans it up. Scratch goes under `$REPO_ROOT/.opencode/.tmp/`, in a task-specific child directory when needed (enforced by pc-system-reminders).
24
- - Never report a path under `.tmp/` as a deliverable. Copy or move the artifact to its required repository path first.
25
- - Never leave scratch files behind at the end of a task, unless they are the evidence for a failure you are reporting.
23
+ - Never write outside `$REPO_ROOT` or an OS temp directory: the next agent cannot see it and nobody cleans it up. Scratch goes under `$REPO_ROOT/.opencode/.tmp/` (enforced by pc-system-reminders).
24
+ - Never report a `.tmp/` path as a deliverable. Copy or move the artifact to its repository path first. Never leave scratch files behind unless they are evidence for a failure you are reporting.
25
+
26
+ ## Tests
27
+
28
+ - Never write more tests than the change requires. A bug fix gets one regression test. A new function gets tests for its public contract, not every internal branch. Never aim for a coverage number.
29
+ - Never test framework or library internals. Test your code's contract, not that EF Core saves a tracked entity.
30
+ - Never generate integration, e2e, or snapshot tests unless explicitly asked. Mock nothing you do not own — use a fake that records state. Never add a test that duplicates a type-check or linter rule.
26
31
 
27
32
  <!-- PC-GUARDRAILS-RTK-START -->
28
33
  <!-- PC-GUARDRAILS-RTK-END -->
@@ -41,7 +46,7 @@ The marker sections below name the optimization skills this project selected. Lo
41
46
 
42
47
  ## Engineer workflow (when spawned)
43
48
 
44
- The lead put your task IDs and their text in your prompt. Two things about that are not up to you:
49
+ The lead puts your task IDs and their text in your prompt. Two things about that are not up to you:
45
50
 
46
51
  - Load every skill under your `## Abilities` before you start, guardrails first, one `skill` call per `@skill-name`. Editing, shell and spawning are blocked until you have (pc-system-reminders).
47
- - Edit only files in your assigned scope, then return a summary: task IDs done, files changed, tests and lint result, decisions made. Then you exit. Never poll for more work, and never claim a task the lead did not give you: the lead spawns with the work in hand, so a worker that waits is a worker that hangs the wave.
52
+ - Edit only files in your assigned scope, then return: task IDs done, files changed, tests and lint result, decisions made. Then exit. Never poll for more work or claim a task the lead did not give you.
@@ -1,59 +1,59 @@
1
- ---
2
- name: pc-make-engineer
3
- description: Create a custom engineer agent via persona-driven interactive design. Invoked by the /make-engineer command.
4
- license: MIT
5
- ---
6
-
7
- Create one file, `.opencode/agents/{persona}-engineer.md`, from the [template](template.md). The research behind it is for choosing the right skills, not for filling the file: expertise notes, architecture, conventions, file maps and workflow steps belong in skills.
8
-
9
- ## Rules
10
-
11
- - Never write the agent file before the user has confirmed the skill set and it is installed. An engineer whose abilities do not exist cannot work.
12
- - Never write `model:` or `color:`. `pc-subagent-tiers` injects both at startup, so a hand-picked colour is overwritten.
13
- - Never create `*.build.md`, `*.fast.md`, `*.plan.md`, `build.md` or `plan.md`. The plugin regenerates all of them every startup and anything written there is lost.
14
- - `mode: subagent`. Engineers are reached through `task()`, and a primary would clutter the two-entry list a human picks from.
15
- - The only `##` heading is `## Abilities`, and the identity paragraph is two or three sentences carrying no project knowledge.
16
- - Every `@skill` under `## Abilities` exists in `.agents/skills/` and in `skills-lock.json`. A name that is not installed is skipped rather than blocking the worker, so a typo costs the agent that ability in silence.
17
- - Project-local installs only: `npx skills add -y ...`, never `-g`.
18
- - At most five form questions, and only where more than one option was detected. A signal with one option is used without asking.
19
-
20
- ## Contracts
21
-
22
- Personas: `frontend`, `layout`, `backend`, `data`, `devops`, `security`, `mobile`, `api`, `qa`. A persona passed as an argument (`/make-engineer frontend`) or typed by the user is taken as given.
23
-
24
- Signals to detect: language, framework, data layer, testing, styling, architecture, i18n, CI/CD, cloud and IaC, monitoring, linting, dependency injection.
25
-
26
- Discovery needs `find-skills`, and has no fallback without it:
27
-
28
- ```bash
29
- npx skills add -y vercel-labs/skills@find-skills
30
- ```
31
-
32
- When `.opencode/agents/{persona}-engineer.md` already exists, ask before touching it:
33
-
34
- ```json
35
- {
36
- "questions": [
37
- {
38
- "header": "Overwrite engineer",
39
- "question": "An engineer named \"{persona}-engineer\" already exists. Overwrite or cancel?",
40
- "options": [
41
- { "label": "Overwrite", "description": "Rewrite the file from the template." },
42
- { "label": "Cancel", "description": "Stop. Do not modify the existing file." }
43
- ]
44
- }
45
- ]
46
- }
47
- ```
48
-
49
- `fullstack-engineer.md` is the body `pc-subagent-tiers` copies into `build.md` and `plan.md`, so every skill listed there reaches both primaries. Merge into it additively: add only skills it does not already list, put them in the category lines that already exist where they fit, and leave its frontmatter, identity paragraph and existing ability lines alone.
50
-
51
- ## Flow
52
-
53
- 1. **Persona.** Ask with the `question` tool unless it arrived as an argument. The answer decides what to detect, what to ask, and which skills to look for.
54
- 2. **Signals.** Read `.opencode/source-roots.json` (if it is missing or empty, ask which directories to scan), then `ARCHITECTURE.md`, `DESIGN.md`, and the manifests (`package.json`, `tsconfig.json`, `*.csproj`, `pyproject.toml`, `go.mod`, `Cargo.toml`). Detect what the persona needs and report the inventory.
55
- 3. **Form.** Present the detected options with the `question` tool, pre-selected and marked `(Recommended)`. For `frontend`, `backend`, `layout` and `api`, one question is architecture and patterns, whose options come from the [signal mapping](signal-mapping.md) tables.
56
- 4. **Skills.** A signal already covered by a skill in `.agents/skills/` or `skills-lock.json` needs no search. Map each remaining signal to a query through the [signal mapping](signal-mapping.md), present the candidates as one multi-select `question` grouped by category (name, one line, `owner/repo`, install count), install what the user confirms, and verify each one landed in both `.agents/skills/` and the lockfile.
57
- 5. **Write** the file from the [template](template.md).
58
- 6. **Merge** the new skills into `fullstack-engineer.md`.
59
- 7. **Report** the file created, the skills installed, the signals with no quality skill, whatever failed, and that opencode has to restart before `pc-subagent-tiers` picks the engineer up.
1
+ ---
2
+ name: pc-make-engineer
3
+ description: Create a custom engineer agent via persona-driven interactive design. Invoked by the /make-engineer command.
4
+ license: MIT
5
+ ---
6
+
7
+ Create one file, `.opencode/agents/{persona}-engineer.md`, from the [template](template.md). The research behind it is for choosing the right skills, not for filling the file: expertise notes, architecture, conventions, file maps and workflow steps belong in skills.
8
+
9
+ ## Rules
10
+
11
+ - Never write the agent file before the user has confirmed the skill set and it is installed. An engineer whose abilities do not exist cannot work.
12
+ - Never write `model:` or `color:`. `pc-subagent-tiers` injects both at startup, so a hand-picked colour is overwritten.
13
+ - Never create `*.build.md`, `*.fast.md`, `*.plan.md`, `build.md` or `plan.md`. The plugin regenerates all of them every startup and anything written there is lost.
14
+ - `mode: subagent`. Engineers are reached through the subagent tool, and a primary would clutter the two-entry list a human picks from.
15
+ - The only `##` heading is `## Abilities`, and the identity paragraph is two or three sentences carrying no project knowledge.
16
+ - Every `@skill` under `## Abilities` exists in `.agents/skills/` and in `skills-lock.json`. A name that is not installed is skipped rather than blocking the worker, so a typo costs the agent that ability in silence.
17
+ - Project-local installs only: `npx skills add -y ...`, never `-g`.
18
+ - At most five form questions, and only where more than one option was detected. A signal with one option is used without asking.
19
+
20
+ ## Contracts
21
+
22
+ Personas: `frontend`, `layout`, `backend`, `data`, `devops`, `security`, `mobile`, `api`, `qa`. A persona passed as an argument (`/make-engineer frontend`) or typed by the user is taken as given.
23
+
24
+ Signals to detect: language, framework, data layer, testing, styling, architecture, i18n, CI/CD, cloud and IaC, monitoring, linting, dependency injection.
25
+
26
+ Discovery needs `find-skills`, and has no fallback without it:
27
+
28
+ ```bash
29
+ npx skills add -y vercel-labs/skills@find-skills
30
+ ```
31
+
32
+ When `.opencode/agents/{persona}-engineer.md` already exists, ask before touching it:
33
+
34
+ ```json
35
+ {
36
+ "questions": [
37
+ {
38
+ "header": "Overwrite engineer",
39
+ "question": "An engineer named \"{persona}-engineer\" already exists. Overwrite or cancel?",
40
+ "options": [
41
+ { "label": "Overwrite", "description": "Rewrite the file from the template." },
42
+ { "label": "Cancel", "description": "Stop. Do not modify the existing file." }
43
+ ]
44
+ }
45
+ ]
46
+ }
47
+ ```
48
+
49
+ `fullstack-engineer.md` is the body `pc-subagent-tiers` copies into `build.md` and `plan.md`, so every skill listed there reaches both primaries. Merge into it additively: add only skills it does not already list, put them in the category lines that already exist where they fit, and leave its frontmatter, identity paragraph and existing ability lines alone.
50
+
51
+ ## Flow
52
+
53
+ 1. **Persona.** Ask with the `question` tool unless it arrived as an argument. The answer decides what to detect, what to ask, and which skills to look for.
54
+ 2. **Signals.** Read `.opencode/source-roots.json` (if it is missing or empty, ask which directories to scan), then `ARCHITECTURE.md`, `DESIGN.md`, and the manifests (`package.json`, `tsconfig.json`, `*.csproj`, `pyproject.toml`, `go.mod`, `Cargo.toml`). Detect what the persona needs and report the inventory.
55
+ 3. **Form.** Present the detected options with the `question` tool, pre-selected and marked `(Recommended)`. For `frontend`, `backend`, `layout` and `api`, one question is architecture and patterns, whose options come from the [signal mapping](signal-mapping.md) tables.
56
+ 4. **Skills.** A signal already covered by a skill in `.agents/skills/` or `skills-lock.json` needs no search. Map each remaining signal to a query through the [signal mapping](signal-mapping.md), present the candidates as one multi-select `question` grouped by category (name, one line, `owner/repo`, install count), install what the user confirms, and verify each one landed in both `.agents/skills/` and the lockfile.
57
+ 5. **Write** the file from the [template](template.md).
58
+ 6. **Merge** the new skills into `fullstack-engineer.md`.
59
+ 7. **Report** the file created, the skills installed, the signals with no quality skill, whatever failed, and that opencode has to restart before `pc-subagent-tiers` picks the engineer up.
@@ -1,42 +1,36 @@
1
- # Agent file template
2
-
3
- The whole file, with nothing else in it:
4
-
5
- ```markdown
6
- ---
7
- description: <one sentence naming the persona + top 3-5 detected technologies>
8
- mode: subagent
9
- permission:
10
- edit: allow
11
- bash: allow
12
- read: allow
13
- glob: allow
14
- grep: allow
15
- ---
16
-
17
- <One paragraph: "You are a {persona} engineer specializing in {top technologies}. You own all work in {scope/files}." Keep it to 2-3 sentences max.>
18
-
19
- ## Abilities
20
- - Guardrails: @pc-guardrails-generic, @pc-guardrails-project
21
- - Development: <@installed-skill-1>, <@installed-skill-2>, ...
22
- - Testing: <@installed-skill-for-testing>, ...
23
- - Infrastructure: <@installed-skill-for-devops>, ...
24
- ```
25
-
26
- Replace every `<...>` placeholder with real values, and drop any category line with no skills in it (Guardrails always stays). Development is language, framework, UI and DI skills; Testing is test, lint and typecheck skills; Infrastructure is DevOps, CI/CD and cloud skills.
27
-
28
- ## Description quality bar
29
-
30
- `description:` is the matching key for `/plan-apply`: the lead compares a task's domain text against it to pick a specialist, so a vague one gets the wrong engineer spawned.
31
-
32
- Bad: `"A frontend engineer for React"`
33
-
34
- Good: `"Frontend engineer for Ink 7 + React 19 TUI, FSD architecture, Inversify DI, design tokens, and i18n"`
35
-
36
- Name the persona, list the three to five technologies actually detected, one sentence, no padding.
37
-
38
- ## Identity paragraph
39
-
40
- Two or three sentences: who the engineer is, and what files or layers it owns. A knowledge dump here is knowledge the lead cannot reuse and the engineer did not ask for.
41
-
42
- Good: `"You are a frontend engineer specializing in terminal UI development with Ink 7 + React 19. You own all work in the FSD layers: src/app/, src/widgets/, src/features/, src/entities/, and src/shared/."`
1
+ # Agent file template
2
+
3
+ The whole file, with nothing else in it:
4
+
5
+ ```markdown
6
+ ---
7
+ description: <one sentence naming the persona + top 3-5 detected technologies>
8
+ mode: subagent
9
+ ---
10
+
11
+ <One paragraph: "You are a {persona} engineer specializing in {top technologies}. You own all work in {scope/files}." Keep it to 2-3 sentences max.>
12
+
13
+ ## Abilities
14
+ - Guardrails: @pc-guardrails-generic, @pc-guardrails-project
15
+ - Development: <@installed-skill-1>, <@installed-skill-2>, ...
16
+ - Testing: <@installed-skill-for-testing>, ...
17
+ - Infrastructure: <@installed-skill-for-devops>, ...
18
+ ```
19
+
20
+ Replace every `<...>` placeholder with real values, and drop any category line with no skills in it (Guardrails always stays). Development is language, framework, UI and DI skills; Testing is test, lint and typecheck skills; Infrastructure is DevOps, CI/CD and cloud skills.
21
+
22
+ ## Description quality bar
23
+
24
+ `description:` is the matching key for `/plan-apply`: the lead compares a task's domain text against it to pick a specialist, so a vague one gets the wrong engineer spawned.
25
+
26
+ Bad: `"A frontend engineer for React"`
27
+
28
+ Good: `"Frontend engineer for Ink 7 + React 19 TUI, FSD architecture, Inversify DI, design tokens, and i18n"`
29
+
30
+ Name the persona, list the three to five technologies actually detected, one sentence, no padding.
31
+
32
+ ## Identity paragraph
33
+
34
+ Two or three sentences: who the engineer is, and what files or layers it owns. A knowledge dump here is knowledge the lead cannot reuse and the engineer did not ask for.
35
+
36
+ Good: `"You are a frontend engineer specializing in terminal UI development with Ink 7 + React 19. You own all work in the FSD layers: src/app/, src/widgets/, src/features/, src/entities/, and src/shared/."`
@@ -20,7 +20,7 @@ Each rule must be:
20
20
  - **Concrete**: "Use `pnpm` not `npm`" not "Use the right package manager".
21
21
  - **Evidence-based**: derived from the files and code graph you analyzed. Never invent a rule the project does not state or demonstrate somewhere.
22
22
  - **Not enforced elsewhere.** Skip anything the formatter, linter, type checker, test suite, CI gate or a harness plugin already fails the build on. A rule restating `biome.json` is read on every load and changes nothing: the build was going to catch it. Write the rules that nothing but a careful reader would catch.
23
- - **Not already in `pc-guardrails-generic`.** That skill loads alongside this one, every request. Secrets, comment discipline, scratch-file location and one-responsibility-per-file are its rules, not this file's.
23
+ - **Not already in `pc-guardrails-generic`.** That skill loads alongside this one, every request. Secrets, zero-comment default, scratch-file location, one-responsibility-per-file, minimal-test discipline, and the engineer workflow are its rules, not this file's.
24
24
 
25
25
  **At most 40 rules, across all categories.** Rank by what a violation costs and cut from the bottom; a category with nothing consequential in it gets no rules at all. This cap is the point of the exercise, not tidiness: compliance falls away as a rule file grows, so the 41st rule does not just cost its own tokens, it dilutes the 40 that matter. If more than 40 survive every bar above, the excess is a sign the project's constraints belong in a linter rule or a CI check instead.
26
26
 
@@ -107,6 +107,6 @@ Re-read the output you are about to write. Then:
107
107
  - CI workflow steps (`app-ci.yml`, `ci.yml`)
108
108
  - GitHub branch protection / required checks. If the build catches it, the rule costs tokens and adds nothing. The only exception is a rule whose enforcement is partial or non-obvious (e.g. architecture tests enforce layering but a developer could still import a namespace through reflection or a transitive dependency — that nuance is worth a rule).
109
109
 
110
- 4. **Strip anything already in `pc-guardrails-generic`.** That skill loads on every request alongside this one. Its rules are: secrets discipline, comment discipline (WHY not WHAT, 10% ceiling), scratch-file location, one-responsibility-per-file, and the engineer workflow. Do not restate any of them here.
110
+ 4. **Strip anything already in `pc-guardrails-generic`.** That skill loads on every request alongside this one. Its rules are: secrets discipline, zero-comment default (WHY not WHAT, 10% ceiling, no auto-generated docstrings), scratch-file location, one-responsibility-per-file, minimal-test discipline (one regression test per bug, no framework/library tests, no integration/e2e/snapshot unless asked, no mock-assertion of third-party calls), and the engineer workflow. Do not restate any of them here.
111
111
 
112
112
  5. **Re-count after cutting.** If you are still over 40, you are writing reference material, not constraints. Cut harder.
@@ -1,30 +1,39 @@
1
- # Branching procedure
2
-
3
- Resolve and record the branch names:
4
-
5
- ```bash
6
- START_BRANCH="$(git branch --show-current)"
7
- DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
8
- [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH="main"
9
- ```
10
-
11
- Stash uncommitted work when needed and record that the goal stash exists:
12
-
13
- ```bash
14
- git stash push -u -m "goal-wip"
15
- ```
16
-
17
- Create the feature branch from the synchronized default branch:
18
-
19
- ```bash
20
- git switch "$DEFAULT_BRANCH"
21
-
22
- if git remote get-url origin >/dev/null 2>&1; then
23
- git pull origin "$DEFAULT_BRANCH"
24
- fi
25
-
26
- git switch -c "feature/{slug}"
27
- BRANCH="$(git branch --show-current)"
28
- ```
29
-
30
- Everything through archive happens on `$BRANCH`.
1
+ # Branching procedure
2
+
3
+ Resolve and record the branch names. If the invoking workflow already placed you on a feature branch (`feature/*`, `fix/*`, etc.), it owns the branch: do not stash, switch, pull, or rename. The sandbox hosting the workflow has no git credentials, so those commands would either corrupt the tree or hang, and the workflow has already cut the branch from the default branch. Treat its result as given.
4
+
5
+ ```bash
6
+ BRANCH="$(git branch --show-current)"
7
+ case "$BRANCH" in
8
+ feature/*|fix/*|chore/*|docs/*|refactor/*)
9
+ START_BRANCH="$BRANCH"
10
+ DEFAULT_BRANCH="$BRANCH"
11
+ GOAL_STASH="none"
12
+ ;;
13
+ *)
14
+ START_BRANCH="$BRANCH"
15
+ DEFAULT_BRANCH="$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')"
16
+ [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH="main"
17
+
18
+ # Stash uncommitted work when needed and record that the goal stash exists.
19
+ git stash push -u -m "goal-wip"
20
+ GOAL_STASH="goal-wip"
21
+
22
+ # Create the feature branch from the synchronized default branch.
23
+ git switch "$DEFAULT_BRANCH"
24
+
25
+ if git remote get-url origin >/dev/null 2>&1; then
26
+ git pull origin "$DEFAULT_BRANCH"
27
+ fi
28
+
29
+ git switch -c "feature/{slug}"
30
+ BRANCH="$(git branch --show-current)"
31
+ ;;
32
+ esac
33
+ ```
34
+
35
+ Record the branch name and that `feature/{slug}` was applied unconditionally, so downstream phases can restore if they move off it.
36
+
37
+ Everything through archive happens on `$BRANCH`.
38
+
39
+ When a later phase renames `$BRANCH` to match the canonical change slug (Phase 3 of `pc-plan-goal`), skip the rename if the workflow already fixed the name. Renaming would call `git branch -m`, which a credentialless sandbox refuses, and the workflow's `create_pull_request` is told to use the branch as named. Detect this by checking that `$BRANCH` already starts with `feature/`; if it does, keep it.
@@ -1,98 +0,0 @@
1
- /** @jsxImportSource @opentui/solid */
2
- import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui"
3
- import { createSignal, For, Show } from "solid-js"
4
- import { readFile } from "node:fs/promises"
5
- import { join } from "node:path"
6
-
7
- const id = "ob.subagents"
8
-
9
- type Row = { id: string; agent: string; model: string; task: string; status: string }
10
-
11
- // Renders a live "Subagents" panel in the session sidebar.
12
- //
13
- // Server plugins (opencode.json) cannot draw UI, only TUI plugins (tui.json)
14
- // can, via the `sidebar_content` slot. This panel is fed by the
15
- // `.opencode/harness-run.json` state file that the `pc-subagent-monitor` server
16
- // plugin maintains, so the two cooperate: server plugin = data producer,
17
- // this TUI plugin = renderer.
18
- const tui: TuiPlugin = async (api) => {
19
- const statePath = join(process.cwd(), ".opencode", "harness-run.json")
20
- const [rows, setRows] = createSignal<Row[]>([])
21
- // Only show live subagents, finished/failed ones are kept in harness-run.json
22
- // for recovery but are not navigable targets the user cares about here.
23
- // Entries marked stale (left "running" by a crashed process) are not live.
24
- const active = () => rows().filter((r) => r.status === "running")
25
-
26
- const refresh = async () => {
27
- try {
28
- const data = JSON.parse(await readFile(statePath, "utf-8"))
29
- const agents = data?.agents ?? {}
30
- setRows(
31
- Object.entries(agents)
32
- .filter(([, a]: [string, any]) => !a?.stale)
33
- .map(([sid, a]: [string, any]) => ({
34
- id: sid,
35
- agent: a?.agent ?? "?",
36
- model: a?.model ?? "",
37
- task: Array.isArray(a?.tasks) && a.tasks.length ? a.tasks.join(",") : (a?.title ?? ""),
38
- status: a?.status ?? "running",
39
- })),
40
- )
41
- } catch (err: any) {
42
- // Missing file = genuinely idle. Anything else (transient read/parse
43
- // hiccup) keeps the last good rows instead of flashing "idle" mid-run.
44
- if (err?.code === "ENOENT") setRows([])
45
- }
46
- }
47
-
48
- await refresh()
49
- // session.updated fires constantly; debounce so we don't re-read the file
50
- // on every keystroke-sized event.
51
- let timer: ReturnType<typeof setTimeout> | null = null
52
- const scheduleRefresh = () => {
53
- if (timer) return
54
- timer = setTimeout(() => {
55
- timer = null
56
- void refresh()
57
- }, 200)
58
- }
59
- for (const evt of ["session.created", "session.idle", "session.updated"]) {
60
- try {
61
- api.event.on(evt as any, scheduleRefresh)
62
- } catch {
63
- /* event type unavailable on this host, ignore */
64
- }
65
- }
66
-
67
- api.slots.register({
68
- order: 50,
69
- slots: {
70
- sidebar_content() {
71
- return (
72
- <box flexDirection="column">
73
- <text>Subagents</text>
74
- <Show when={active().length === 0}>
75
- <text> idle</text>
76
- </Show>
77
- <For each={active()}>
78
- {(r) => (
79
- <box onMouseUp={() => api.route.navigate("session", { sessionID: r.id })}>
80
- <text>
81
- {"▶ "}
82
- {r.agent}
83
- {r.model ? ` · ${r.model}` : ""}
84
- {r.task ? `, ${r.task}` : ""}
85
- </text>
86
- </box>
87
- )}
88
- </For>
89
- </box>
90
- )
91
- },
92
- },
93
- })
94
- }
95
-
96
- const pluginModule: TuiPluginModule & { id: string } = { id, tui }
97
-
98
- export default pluginModule
@@ -1,6 +0,0 @@
1
- {
2
- "$schema": "https://opencode.ai/tui.json",
3
- "plugin": [
4
- "./tui/pc-subagents.tsx"
5
- ]
6
- }