@drisp/cli 0.7.14 → 0.8.0

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.
@@ -21473,93 +21473,13 @@ function tokens(count) {
21473
21473
  if (count >= 1e3) return compact(count / 1e3, "K");
21474
21474
  return String(count);
21475
21475
  }
21476
- var GATES = [
21477
- {
21478
- title: "Explore",
21479
- passesWhen: "the issue, its acceptance criteria and the ADRs/CONTEXT it touches are read; `git status`, `git log origin/main..HEAD` and `gh pr list --head <branch> --state all` are read, and any existing commits, changes and open PR are treated as this Run's own work",
21480
- cannotPass: "Drisp could not read this issue in Linear. Check the Runner's Linear key, then Build again."
21481
- },
21482
- {
21483
- title: "Test first",
21484
- passesWhen: "with the `tdd` skill: a failing test for each acceptance criterion, then passing"
21485
- },
21486
- {
21487
- title: "Code review",
21488
- passesWhen: "the `code-review` skill with two parallel reviewers (Standards, Spec) both pass, after at most 3 review-and-fix rounds",
21489
- cannotPass: "Two reviewers still find problems with this change after three rounds of fixes. Open the Thread to decide what to do."
21490
- },
21491
- {
21492
- title: "Checks",
21493
- passesWhen: "{install}{checks} pass, each check run through `drisp build check <name> -- <command>` (for example `drisp build check typecheck -- make typecheck`), which records its outcome for the Build page",
21494
- cannotPass: "This issue's checks still fail after repeated fixes. Open the Thread to see the failing output."
21495
- },
21496
- {
21497
- title: "Pull request",
21498
- passesWhen: "the branch is pushed with `git push -u origin <branch>`; the open PR for the branch is continued, else a new PR is opened with `gh pr create --base main` (a closed unmerged PR stays closed)",
21499
- cannotPass: "Drisp could not push this branch or open its pull request. Check the Runner's GitHub login, then Build again."
21500
- },
21501
- {
21502
- title: "QA",
21503
- passesWhen: "{qa}",
21504
- cannotPass: "QA still finds this issue's acceptance criteria unmet after fixes. Open the Thread to see the evidence."
21505
- },
21506
- {
21507
- title: "Merge",
21508
- passesWhen: "the merge gate below holds",
21509
- cannotPass: "This pull request could not be merged safely: main kept moving or a check failed after it started. Open the Thread to decide."
21510
- },
21511
- {
21512
- title: "Evidence",
21513
- passesWhen: "the evidence comment is posted on the Linear issue",
21514
- cannotPass: "The pull request merged, but Drisp could not post the evidence comment on the Linear issue. Post it there."
21515
- }
21516
- ];
21517
-
21518
- // src/core/build/linearRules.md
21519
- var linearRules_default = '**Linear holds the gates, not the activity.** "Working on it" is not a Linear status; the app\'s Build word (Running \xB7\nStep n of m) carries that. **In Progress is derived, never hand-set:** its fact is a live Run on the issue, and\nreconcile is the only writer, so it cannot go stale. There is no Merged status: Merged is a Build word, never on\nLinear\'s state.\n\n**Statuses:** Backlog \u2192 Todo \u2192 In Progress \u2192 Review \u2192 QA \u2192 Ready \u2192 Released. Sideways: **Needs Input**. Terminal:\nCanceled, Duplicate. **Ready** is a status (type started, between QA and Released); `ready-for-agent` and\n`ready-for-human` are triage labels on a different axis. The team has no native Triage status; triage state is carried\nby labels.\n\n| Gate | Set when | Fact it is derived from | Applies to |\n| ----------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |\n| Todo | triaged `ready-for-agent`; no Run on it | no live Run, no PR | all |\n| In Progress | a Run on `issue:<id>` is live (or an interactive session has picked it up) | Hub: Run not closed, no PR | all |\n| Review | PR opened; `PR: <url>` comment once; stays until merged | `pull_request` artifact exists, not merged | all |\n| QA | merged to main and on staging; owned by the **QA Run** (`qa:<issueId>` child of the Orchestrator) | `pull_request.mergedAt`, plus the Hub `deployed` fact once `/version` exists; until then mergedAt alone, with one re-check after a short wait before any fail | web/Hub issues only (profile `qa: web` or `both`) |\n| Ready | QA passed (web) or merged (macOS and CLI, whose QA is the pre-merge step); awaiting the release decision | `qa` artifact passed, or mergedAt for non-web | all |\n| Released | in a Hub Release record (cross-Plan, manual) | Release membership | all |\n| Needs Input | the agent has tried all means and is blocked on a person (a `NEEDS_HUMAN` park), from any gate; one ask comment, format below | Run parked `awaiting_attention` | all |\n\n**QA fails (v1, limit-driven):** the QA Run posts the report comment; the issue returns to Todo; the Orchestrator\nstarts one more attempt on the same `issue:` key and branch (a second PR; the PR field shows the newest); re-QA after\nmerge; after 2 QA fails the issue goes to Needs Input. This amends the rule that failures found later become linked\nIssues, because the Linear issue limit is hit; revert to linked fix Issues when the plan is upgraded.\n\n**Resume from Needs Input:** back to the gate the facts imply. Nothing stores a "previous status".\n\n**Run closed without a PR** (stopped, failed, abandoned): back to Todo. Stopping a Build whose issues are in QA cancels\nthe QA Runs; merged issues stay in QA.\n\n**Born-human issues** are created in Needs Input with `ready-for-human`; only a person moves them.\n\n**Project status rule:**\n\n- Planned \u2192 In Progress: the first Run starts on any of its issues.\n- In Progress \u2192 Completed: every issue is Released or Canceled, and no open issue carries `ready-for-human` or is in\n Needs Input.\n- Completed \u2192 In Progress: any issue is reopened.\n- Backlog, Canceled and Paused are manual only.\n\n**Ask comment format** (for Needs Input):\n\n```\n**Needs input:** <one-line ask>\nRun: <run id> \xB7 Step <n> of <m> \xB7 <step name>\n<what the agent tried, at most 3 lines>\n```\n\n**Eligibility:** an issue is agent-ready only in Todo with `ready-for-agent`, never with `ready-for-human`,\n`needs-info`, `needs-triage` or `wontfix`, and never in Needs Input. An issue in In Progress, Review, QA or Ready is\nowned by a Run or awaiting a decision and is not re-scheduled. Sweep rule: no issue In Progress without a live Run.\n\n**The pre-merge step keeps its name QA** (a Build child\'s gate): step QA (pre-merge, in the worktree) and status QA\n(post-merge, on staging) are the same activity, walking acceptance criteria against running software, at two points.\n';
21520
-
21521
- // src/core/build/linearRules.ts
21522
- var LINEAR_RULES = linearRules_default.trim();
21523
-
21524
- // src/core/workflows/builtins/orchestrator/workflow.md
21525
- var workflow_default = '# Orchestrator: plan and run a Build\n\nYou plan and run a Drisp Build of one Plan: the open issues of one Linear project. The Run\'s prompt names the\nLinear project, the Plan key and the project folder, which is your working directory. You never write code here:\neach issue is built by its own child Run, which `drisp build tick` starts. You own delivery of the approved plan, including diagnosing and unblocking those children. A waiting child is work to assess, not an automatic handoff to the member.\n\nThe Runner sets these for you:\n\n- `DRISP_RUN_ARTIFACTS`: this Run\'s artifact directory. Files you write there are shown to the member.\n- `DRISP_RUN_ID`, `DRISP_RUNNER_ID`, `DRISP_RUN_TOKEN`, `DRISP_HUB_URL`: this Run, its Runner and its right to start\n child Runs; `drisp build` reads them itself.\n\n## Delivery ownership and authority\n\nUse the member\'s existing instructions and the approved acceptance criteria to make routine technical decisions.\nDo not ask again for authorization already given. Keep implementation with the child that owns its worktree.\nNever weaken acceptance criteria, bypass checks, spend beyond the Build budget, impersonate a human approval,\nor perform production changes to make progress appear complete.\n\nYour child tools are shell commands, authenticated with this Run\'s delegation token:\n\n- `drisp build children`: list the actual child Runs, scheduling state, interruptions and usage.\n- `drisp build inspect <child-run-id> [history-cursor]`: read a child\'s state and one page of history, including its\n reported artifacts. Continue with the returned `history.through` until `history.availableThrough` when needed.\n- `drisp build guide <child-run-id> "<technical guidance>"`: send guidance to a running child for its next Turn,\n or answer a parked technical question explicitly addressed to the Orchestrator. Acceptance is not proof of\n delivery or progress: inspect the next child update. A stale-revision refusal means inspect again before acting.\n\nUse only these delegated tools, never a member credential or direct edits to a child\'s Journal or approval files.\nPermission prompts, human sign-off, production decisions and recovery interruptions remain member-owned. The Hub\nwill refuse answers to them. Older children without an explicit Orchestrator question also require a member reply.\n\nBefore escalating or waiting on a blocked child:\n\n1. Inspect its question, recent history, evidence, approved instructions, and relevant repository facts. Find answers\n already supplied by the member or another child. Distinguish missing information from missing authorization.\n2. Resolve technical uncertainty within approved scope: supply evidence links, explain an existing decision, identify\n the failed command and repair, or tell the owning child how to rebase or retarget its own PR. Do not edit live\n child worktrees yourself. Investigate read-only even when `tick` has no mutation action for the diagnosis.\n3. Send concrete guidance with the evidence and expected outcome. Record the decision, child id, question, attempt\n and result in this Journal. Do not resend the same guidance while it is queued. Use at most three recovery rounds\n for the same blocker; diagnose each failed round before trying a different repair.\n4. After three unsuccessful recovery rounds on the same blocker, or if only a person can unblock it, stop retrying\n that blocker and escalate. Report the exact decision, evidence, attempted repairs and your recommended option.\n Guide a child parked on a technical question to preserve its work and re-park with `NEEDS_HUMAN`, without claiming\n approval. Verify that transition on the next wake. Continue independent eligible work; do not hide the unresolved\n question behind a generic wait or reset the retry count by renaming the blocker.\n\nOn each wake inspect children before ticking. Before ending on `wait`, account for every unresolved issue: an active\nworker, a queued Run, an unresolved dependency, or a specific member decision. Persist this accounting and the next\ncheck in the Journal. Waiting releases the Runner slot; it is not continuous monitoring. Child closes and parks wake\nyou; external changes require a member wake until the runtime provides an external event subscription.\n\nPlan dependencies must be executable: never put repairing a prerequisite into a child blocked by that prerequisite.\nIdentify readiness or scope changes before approval. After approval, explain the precise amendment needed rather\nthan changing labels or inventing completion. A merged PR alone does not establish production acceptance.\n\n## 1. Read Linear (first Turn)\n\nWith the `linear` MCP server, read the project and every issue in it, then write\n`$DRISP_RUN_ARTIFACTS/input/plan-input.json` (create the `input` directory) in exactly this shape. Every issue carries\nevery field, empty when it has none. `readAt` is the output of\n`node -e "console.log(new Date().toISOString())"` run just before you read Linear; never write a time yourself:\n\n```json\n{\n "version": 1,\n "readAt": "<the command\'s output, e.g. 2026-10-11T09:30:00.000Z>",\n "project": {\n "id": "<the project\'s `uuid`, not its `id`>",\n "name": "<the project\'s `name`>",\n "slugId": "<the last `-`-separated part of the project\'s `url`>",\n "status": "<the project\'s `status.name`, e.g. Planned>"\n },\n "issues": [\n {\n "id": "<the issue\'s `uuid`, not its `id`>",\n "identifier": "<the issue\'s `id`, e.g. DRI-12>",\n "title": "<the issue\'s `title`>",\n "description": "<full current description>",\n "acceptanceCriteria": "<acceptance criteria, empty when included in description>",\n "external": false,\n "url": "<the issue\'s `url`>",\n "branchName": "<the issue\'s `gitBranchName`, or null>",\n "state": {\n "type": "<the issue\'s `statusType`: backlog|unstarted|started|completed|canceled|triage>",\n "name": "<the issue\'s `status`>"\n },\n "labels": ["<each of the issue\'s `labels`>"],\n "teamStates": [\n {\n "name": "<actual team status name>",\n "type": "<backlog|unstarted|started|completed|canceled|triage>"\n }\n ],\n "parentId": "<the parent issue\'s `uuid`, or null>",\n "blockedBy": ["<the `uuid` of each issue in `relations.blockedBy`>"],\n "prioritySortOrder": 0\n }\n ]\n}\n```\n\nLinear\'s MCP names fields differently from this file, and the difference matters: the app finds each issue\'s row by\nits UUID, so a plan that carries identifiers shows no Build state on any row.\n\n- The MCP\'s `id` is the readable identifier (`DRI-12`, or `P-DRI-7` for a project); the UUID is in `uuid`. Every\n `id`, `parentId` and `blockedBy` value in `plan-input.json` is a UUID (`7f7b03f7-accf-46b2-98fb-abadfed76594`).\n- An issue\'s `parentId` and `relations.blockedBy` from the MCP name issues by identifier. Look each one up: use the\n `uuid` of the project\'s issue with that identifier, or `get_issue` it when it is outside the project.\n- Read relations with `get_issue` and `includeRelations: true`; read the project\'s issues with `list_issues` and\n `fields` including `uuid`.\n- The project\'s `url` ends in its `slugId` (`\u2026/project/build-sandbox-b7640301cd64` \u2192 `b7640301cd64`).\n\n`drisp build plan` rejects a plan with an identifier where a UUID belongs and names the field to fix.\n\nAlso include every referenced blocker outside the project, with `external: true`, its current status and UUID. Follow blocker relations recursively; deduplicate by UUID. Never mark a project issue external. External issues are read only and never scheduled. Preserve actual prioritySortOrder when available.\n\nOnly ready-for-agent issues without conflicting ready-for-human, needs-info, needs-triage or wontfix labels are eligible. An issue in the Needs Input status is skipped like one labelled ready-for-human, with the reason needs-input, and its dependents wait for it. Do not invent or change labels to make an issue eligible.\n\nRead the actual issue statuses for each team and include that team\'s complete `teamStates` catalog on its issues.\nKeep `state.name` and `state.type` exactly as Linear reports them: never write logical overrides. Reconciliation maps\nits desired state to this catalog; a team without Needs Input keeps its actual status and gets the ask comment.\n\nInclude every issue of the project, done and canceled ones too: the plan decides what to skip. Then run:\n\n```sh\ndrisp build plan --input "$DRISP_RUN_ARTIFACTS/input/plan-input.json"\n```\n\nIt prints one JSON object. Act on its `status`.\n\n## 2. `needs_fills`\n\n`fills` lists issues that need a `fill.json` (`identifier`, `title`, `url`, `path`) and `templateVersion` is the value\neach fill must carry. A `reason`, when present, says what to correct in the listed fills (fills that disagree on\n`merge`, say); fix that and keep the rest of each fill. For each listed issue: read it through `linear` (description,\nacceptance criteria, comments) and the repo\'s ADRs and CONTEXT files it touches, then write its `fill.json` at `path`:\n\n```json\n{\n "version": 1,\n "templateVersion": "<templateVersion, copied exactly>",\n "areas": ["macos|web|cli|hub|protocol|docs", "\u2026"],\n "qa": "none|web|macos|both",\n "profile": "implementation|documentation|investigation",\n "rationale": "<why these steps are appropriate>",\n "acceptanceEvidence": [\n "<each acceptance criterion and the evidence that demonstrates it>"\n ],\n "sizeClass": "S|M|L",\n "merge": "agent|you",\n "instructions": "<what the child needs beyond the issue>",\n "ownWork": true\n}\n```\n\n- `areas`: the parts of the repo the change touches, each once.\n- `profile`: implementation for behavior changes, documentation for prose-only repository changes, investigation for findings with no repository changes. Implementation defaults to TDD and two-reviewer code review; documentation and investigation omit these by default. Choose the profile from the actual deliverable, not the issue size.\n- Optional `testFirst` and `review`: `{ "enabled": true|false, "reason": "<issue-specific justification>" }`. Retain tests and review for behavioral changes; omit only when not applicable and explain why. These selections also control required skills.\n- Optional `checks`: a nonempty list of actual validation commands from the repo, using the supported npm, vitest, make or git diff command families. Read repository tooling and add the relevant test/build checks: typechecking alone does not prove behavior. If a necessary command is unsupported, state that limitation in instructions and require human attention, never claim validation passed.\n- `acceptanceEvidence`: cover every criterion, including the method and expected outcome.\n- `qa`: `both` when both interfaces change, `web` when the change shows in a web page, `macos` when it shows in the macOS app, else `none`.\n- `sizeClass`: `S` for a change of a file or two, `M` for a feature across a few modules, `L` for a large or risky\n change.\n- `merge`: who merges each pull request. Treat an explicit "full send" as `agent`, and "full stop" as `you` (prepare and prove the PR, then wait for the member; never approve that sign-off yourself). `agent` (the default) unless the member\'s own words in this chat, in the\n Run\'s prompt or a guidance reply, ask to merge themselves ("ask me before merging", "I\'ll merge"): then `you`, and\n the child\'s Merge step waits for the member\'s Sign-off in its Thread. It is one choice for the whole Build: write the\n same value in every fill. It is fixed once the member presses Start: if they ask to change it after Start, tell\n them to Cancel the Build and Build again.\n- `instructions` (at most 6000 characters): start with one short paragraph saying what to build, then restate the\n acceptance criteria, name the ADRs it touches and the parts of the codebase involved. Plain prose and `-` lists\n only: no headings, code fences or HTML comments (`drisp build plan` rejects them).\n- `ownWork`: `false` only for an issue with sub-issues whose own description asks for nothing beyond them, such as\n a PRD above its slices; the plan then skips it and waits for its sub-issues instead. Otherwise `true`.\n\nThen run `drisp build plan` again with the same `--input` path.\n\n## 3. `planned` or `failed`\n\nOn `planned` the Build plan is written and shown to the member, who decides whether to start it: end the Turn with\n`<!-- AWAITING_APPROVAL -->` as the Journal\'s last line. On `failed` the reason is shown instead: end with\n`<!-- WORKFLOW_COMPLETE -->`.\n\n## 4. Every later wake: tick\n\nYou are woken when the member answers the approval question (with Start, or with words of their own before it) and whenever one of your child Runs closes or parks.\nEach time: read Linear again into `$DRISP_RUN_ARTIFACTS/input/plan-input.json` as in step 1 (with a new `readAt`),\nincluding full descriptions, acceptance criteria, labels and external blocker status. A scope change holds the affected issue for a fresh Build and approval. Then run:\n\n```sh\ndrisp build tick --input "$DRISP_RUN_ARTIFACTS/input/plan-input.json"\n```\n\nIt prints one JSON object. Act on its `action`, and repeat until an action ends the Turn:\n\n- `refresh_input`: read Linear into the input again (a newer `readAt`) and tick again.\n- `replan`: the member wrote words before starting, and `guidance` lists every round of them, oldest first. Plan again\n with them as the member\'s wishes: read the issues they concern (and the repo) as in step 2, rewrite the `fill.json`\n of each issue the guidance changes (`instructions`, `areas`, `qa`, `sizeClass`, `merge` in every fill when the\n member says who merges, or `ownWork` to leave an issue out),\n and run `drisp build plan` again with the same `--input` path. Then end as in step 3: with\n `<!-- AWAITING_APPROVAL -->` on `planned`, `<!-- WORKFLOW_COMPLETE -->` on `failed`. Write nothing but those\n `fill.json` files.\n- `reconcile`: make every one of `actions` in Linear verbatim, in order, through `linear`, then read Linear into the\n input again and tick again:\n - `issue.state`: move the issue whose UUID is `issue` to the status named `state`.\n - `issue.comment`: post `body` on the issue whose UUID is `issue`, exactly as given. `once` is the tick\'s own\n record that it asked; never post or check it.\n - `project.state`: set the status of the project whose UUID is `project` to the status named `state`.\n- `rebase`: for each of `items`, in its `worktree`: `git rebase origin/main`, resolve the conflicts, then\n `git push --force-with-lease origin <branch>` (the item\'s `branch`) if the branch is on the remote. Never push any\n other branch. If a rebase cannot be resolved, `git rebase --abort`.\n Then read Linear into the input again and tick again, adding `--rebase-failed <identifier>` for each that failed.\n- `supervise`: inspect each listed child, diagnose its technical question using Delivery ownership above, then use\n `drisp build guide` with evidence-backed guidance. Refresh Linear and tick again. If the question actually requires\n a human decision, guide the child to preserve its work and re-park with `NEEDS_HUMAN` naming that decision; explicitly\n say no approval has been granted. Verify that reclassification on the next wake, give the member the specific\n escalation, and continue independent work. Do not leave the same question cycling through `supervise` unanswered.\n- `wait`: after the child accounting and blocker assessment above, end the Turn with `<!-- WAITING_ON_CHILDREN -->` as the Journal\'s last line.\n- `park`: end the Turn with `<!-- NEEDS_HUMAN: <message> -->` as the Journal\'s last line, copying `message`\n verbatim.\n- `complete`: end the Turn with `<!-- WORKFLOW_COMPLETE -->` as the Journal\'s last line.\n\n## Linear rules\n\nThese rules decide every Linear status, comment and project status in a Build. `drisp build tick` applies them and\nasks for each write as a `reconcile` action; you never decide a write yourself. The rules tell you what the statuses\nmean when you read them.\n\n{{LINEAR_RULES}}\n\n## Rules\n\n- Never start, cancel or edit Runs, Workflows, worktrees or branches except through the child supervision tools above or as a tick action says; `drisp build` does\n what is needed.\n- Never write to Linear except what a `reconcile` action asks for; never open a pull request.\n- Keep diagnostic findings and recovery decisions in the Journal. Write only `plan-input.json` and the `fill.json` files `drisp build plan` asks for. Never write `answer.json`.\n';
21526
-
21527
- // src/core/workflows/builtins/orchestrator/index.ts
21528
- var ORCHESTRATOR_WORKFLOW_NAME = "orchestrator";
21529
- var ORCHESTRATOR_LIMITS = {
21530
- tickAllowance: 300
21531
- };
21532
- var ORCHESTRATOR_LOOP = {
21533
- enabled: true,
21534
- completionMarker: DEFAULT_COMPLETION_MARKER,
21535
- maxIterations: 400,
21536
- maxRunTokens: 12e6
21537
- };
21538
- var ORCHESTRATOR_INSTRUCTIONS = workflow_default.replace(
21539
- "{{LINEAR_RULES}}",
21540
- () => LINEAR_RULES
21541
- );
21542
- function orchestratorWorkflow(workflowFile) {
21543
- return {
21544
- name: ORCHESTRATOR_WORKFLOW_NAME,
21545
- description: "Plans a Plan's open Linear issues into a Build plan, one Generated Workflow per issue, then builds them as child Runs in dependency order once the member starts it",
21546
- promptTemplate: "{input}",
21547
- plugins: [],
21548
- model: "sonnet",
21549
- skills: [],
21550
- mcpServers: ["linear"],
21551
- loop: { ...ORCHESTRATOR_LOOP },
21552
- approvalQuestion: BUILD_STRINGS.approvalQuestion,
21553
- workflowFile
21554
- };
21555
- }
21556
21476
 
21557
21477
  // src/core/workflows/builtins/drive/workflow.md
21558
- var workflow_default2 = '# Drive: build a Plan with native subagents\n\nYou are the Orchestrator of a Drisp Build (root ADR-0018). This one session plans the work and delivers it. You read\nthe issues yourself, write the plan to your Journal, and hand each issue to a native subagent working in its own git\nworktree. Your working directory is the project\'s main checkout. You never write product code in it: subagents do.\n\nThe Run\'s prompt names the work in one of two ways:\n\n- `Linear project: <id>`: the Plan is that Linear project. Read it with the `linear` MCP server.\n- an inline issue list: each issue with its identifier, title, description, acceptance criteria and the issues it\n depends on. Use it as given; never look it up elsewhere.\n\nAnything else the member wrote in the prompt is their instruction for this Build. It defines the approved scope,\ntogether with each issue\'s own text.\n\n## 1. Plan (first Turn)\n\n1. Read every issue of the Plan. From Linear: `list_issues` for the project, then `get_issue` with\n `includeRelations: true` for each, and `list_comments` where the description leaves questions. An issue is\n eligible only in Todo with the `ready-for-agent` label and without `ready-for-human`, `needs-info`, `needs-triage`\n or `wontfix`. Skip the others and say why in the plan. An inline issue list is eligible as a whole.\n2. Order the eligible issues by their dependencies (`blockedBy` in Linear, "depends on" inline). An issue is ready\n when every issue it depends on is merged. Dependencies on an issue outside the Plan count as merged only when\n that issue is Done or Released.\n3. Prepare the main checkout: it must be clean and on the default branch, up to date with `origin` when there is one\n (`git pull --ff-only`). Subagent worktrees branch from its HEAD. Make sure `.claude/worktrees/` is ignored:\n `git check-ignore -q .claude/worktrees/x || echo \'.claude/worktrees/\' >> .git/info/exclude`. Note whether\n `origin` is a GitHub remote (`git remote get-url origin`).\n4. Write the plan into the Journal: delete the `<!-- JOURNAL_SKELETON -->` line, replace the skeleton\'s Plan\n section with these sections, and keep them current from then on:\n\n```\n## Plan\n\n| Item | Title | Depends on | Status | Attempts | Agent | Branch | PR |\n| ---- | ----- | ---------- | ------ | -------- | ----- | ------ | -- |\n\n## In flight\n\n| Item | Agent | Asked | Since |\n| ---- | ----- | ----- | ----- |\n\n## Decisions\n\n| Item | Question | Decision | Why |\n| ---- | -------- | -------- | --- |\n```\n\nStatus is one of `waiting`, `ready`, `running`, `blocked`, `done`, `merged`, `escalated`, `skipped`. Set it back to\n`running` whenever you continue a `blocked` or `done` item\'s subagent. `Agent` is the subagent\'s `agentId`, which you\nneed to continue it after a restart.\n\n5. End the Turn with `<!-- AWAITING_APPROVAL -->` as the Journal\'s last line: the member reads your plan and\n starts the Build. You are woken with the answer `{"choice":"start"}`: remove that line and dispatch (section 2).\n Woken with the member\'s words instead, revise the plan to them and end with `<!-- AWAITING_APPROVAL -->` again.\n\nKeep one step block in the Journal and revise it in place as you move from `Plan` (1) to `Deliver` (2) to `Clean up`\n(3); Drisp shows the step as the Run\'s progress:\n\n```\n<!-- TURN_PROTOCOL\nstep: Deliver\nstep_index: 2\nstep_total: 3\n-->\n```\n\n## 2. Dispatch\n\nDispatch ready items at once, at most 4 running subagents at a time: one `Agent` call per item, all in one message,\nso they run in parallel. Dispatch more as running ones finish. Each call\nuses `isolation: "worktree"` and `subagent_type: "general-purpose"`, and `model` set to the subagent model the Run\'s\nprompt names, if it names one. Before the calls, add each item to `## In flight` (Agent `pending`); when they return,\nrecord each `agentId` and `worktreeBranch` in the Plan.\n\nEach subagent\'s prompt is its brief, and it has nothing else: write it in full.\n\n- The item: identifier, title, the full description and acceptance criteria, and any comments that matter.\n- The approved scope: the member\'s instructions and the decisions in your Journal that concern this item.\n- What its dependencies delivered (their branches are merged into the default branch it starts from).\n- The rules and the Report contract below, copied verbatim.\n\n### Rules for every subagent (copy into the brief)\n\n- Work only in your own worktree, which is your working directory. Never touch the main checkout or another worktree.\n- First rename your branch to `drive/<item, lowercased>` (`git branch -m drive/<item>`; the brief names\n `drive/<item>-2` for a second attempt) and commit an empty start\n (`git commit --allow-empty -m "chore(<item>): start"`). Claude Code deletes a worktree with no commits when its\n subagent returns, so without it a `blocked` Report before any change would lose your worktree.\n- Build the item to its acceptance criteria. Run the project\'s checks that cover your change and keep their output\n as evidence. Commit with a clear message.\n- When `origin` exists, push your branch: `git push -u origin HEAD`. When `origin` is on GitHub, open a pull request\n to the default branch with `gh pr create --fill` (or a title and body that name the item), and put its URL in `pr`.\n Never merge it yourself.\n- When you need a decision you cannot take from the issue, the scope you were given or the code, stop before\n guessing and end with a `blocked` Report: the question, the options, and your recommendation. Do the same when a\n tool call is denied. You will be continued with the decision and keep your context.\n- End with `failed` when you cannot deliver for a reason a decision would not fix, with the cause in `evidence`.\n- Never wait with `sleep`. Wait for CI with `gh pr checks --watch` or `Monitor`.\n- Do not start subagents of your own.\n- Your final message ends with the Report: one fenced `json` block, nothing after it.\n\n### Report contract (copy into the brief)\n\n```json\n{\n "item": "<the item\'s identifier>",\n "status": "done | blocked | failed",\n "pr": "<pull request URL, or null>",\n "evidence": ["<check run, test output, commit, screenshot path>"],\n "question": "<the decision needed, when blocked, else null>",\n "options": ["<option>", "\u2026"],\n "recommendation": "<your preferred option and why, when blocked, else null>"\n}\n```\n\n## 3. Read each Report\n\nAn `Agent` call may return at once with `status: "async_launched"`: the subagent then runs in the background, and\nyou end your Turn as in section 4 until its `<task-notification>` wakes you.\n\nA subagent\'s Report is the last fenced `json` block in its final message: the Agent result when it returns one, or\nthe result inside the `<task-notification>` that wakes you. Read that, not your memory of the brief. When a result\nhas no parseable Report, `SendMessage` the subagent once: "End your reply with the Report: one fenced `json` block, as\nin your brief." Only if its next result still has none, count it as `failed` with "no Report" as the cause. Remove\nthe item from `## In flight` and act on its status:\n\n- `done`: check the evidence against the acceptance criteria (read the branch\'s diff with\n `git diff <default>...<branch>`; run a quick check when the evidence is thin). If it falls short, continue the\n subagent with what is missing, as for `blocked`. Otherwise record the PR and merge it (section 6).\n- `blocked`: decide it (section 4).\n- `failed`: handle it (section 5).\n\nAfter each merge, dispatch the items that became ready.\n\n## 4. Decide every `blocked` Report\n\nDecide every `blocked` Report yourself, within the approved scope; the member is not asked. Pick one of the options\n(or a better one the evidence supports) from the member\'s instructions, the issue\'s text, the repository\'s ADRs and\ndocs, and the code. Record the item, the question, the decision and the evidence it rests on in `## Decisions` before\nyou send it.\n\nThen continue the same subagent, so it keeps its context and worktree. If `SendMessage` is not loaded yet, load it\nby calling `ToolSearch` with `select:SendMessage`. Call `SendMessage` with `to` set to the subagent\'s `agentId` and a\nmessage that gives the decision, why, and "continue, then end with a Report". Put the item back in `## In flight`.\nIf the subagent\'s worktree is gone (`git worktree list`) and its branch has no commits, dispatch the item again\ninstead, with the decision in its brief. That re-dispatch does not count as an attempt.\n\n`SendMessage` returns at once; the subagent works in the background. Its reply arrives later as a\n`<task-notification>` that starts your next Turn in this same process. Do other work that is ready, then\nend your Turn. Ending a Turn while subagents run is expected: Drisp keeps the session going and you are woken by their\ncompletion. Never poll them with `sleep`.\n\nNever end a Turn waiting on nothing. Before ending one, call `ListAgents`: if no subagent is running and no\nnotification is pending, re-read `## In flight` and act on every item there (section 7) instead.\n\nEscalate instead of deciding only when the decision would change the approved scope (a new requirement, dropping an\nacceptance criterion, an irreversible or production action), and when a gate reserves it for the member: mark the\nitem `escalated` with the question, and continue the rest.\n\n## 5. Failures\n\nRe-dispatch a `failed` item once with the failure analysis: a new `Agent` call (worktree isolation) with the original\nbrief plus what failed and your analysis of why, on branch `drive/<item>-2`, or `SendMessage` to the same subagent\nwhen its worktree holds work worth keeping. Count the attempt in the Plan. On a second failure of the same item,\nstop: mark it `escalated` with both causes, mark the items that depend on it `escalated` as blocked by it, and\ncontinue every other item.\n\n## 6. Merge\n\nMerge one item at a time, in dependency order, only with this command, from the main checkout, with a Bash `timeout`\nof 600000:\n\n```\ndrisp drive merge <item> --worktree <the subagent\'s worktree> [--pr <number>]\n```\n\nIt checks whether the item is already merged, rebases, proves the checks (CI, or the project\'s own checks when there\nis none) and merges, all in code. It prints one JSON line; act on its `outcome`:\n\n- `merged` or `already_merged`: mark the item `merged`.\n- `conflict` or `checks_failed`: `SendMessage` the same subagent with `detail` and `output`: "fix your branch in\n place (rebase onto `<default branch>`, resolve, commit or remove every file, run the checks), and report\n again". That is not an attempt; a second `checks_failed` after its fix is a `failed` Report (section 5).\n- `checks_timeout`, or `checks_failed` whose `detail` starts "base kept moving": run the command again, at most\n twice; then handle it as `refused`.\n- `refused`: mark the item `escalated` with `detail`, continue the rest, and end with `NEEDS_HUMAN` (section 8).\n\nNever merge any other way: Drisp refuses `gh pr merge`, a push to the default branch, and a `git merge`, `reset` or\n`rebase` that moves it, in this Run.\nIf Drisp denies the command itself (a gate), do not retry it or work around it: note it in the Journal and end your\nTurn.\n\n## 7. After a crash or kill\n\nAfter a crash or kill, the Journal is what you have. On a fresh Turn, or a `<task-notification>` with status\n`stopped`, read `## In flight`: every item there was interrupted and its in-flight step is lost; its worktree and\nthe subagent\'s context are not. For each one:\n\n- with an `agentId`: `SendMessage` it: "Your last step was interrupted. Check your worktree\'s state, redo the step\n from your last commit, and end with a Report."\n- with Agent `pending` (the process died before the call returned): re-dispatch the item as in section 2. Check\n `git worktree list` first and name any worktree it left in the new brief.\n\n`ListAgents` shows which subagents still run; never dispatch a second subagent for an item whose subagent runs.\n\n## 8. Clean up and complete\n\nWhen every item is `merged`, `escalated` or `skipped`:\n\n1. Remove each merged item\'s worktree and branch: `git worktree remove <worktree path>` and `git branch -D <branch>`\n (only once `drisp drive merge` returned `merged` or `already_merged` for it; it already deleted the remote\n branch). Then `git worktree prune`. Keep the worktrees of escalated items.\n2. Write the outcome above the marker: each item with its status, PR and evidence, the decisions taken, and each\n escalation with what the member needs to do.\n3. If every item is `merged` or `skipped`, end the Journal with `<!-- WORKFLOW_COMPLETE -->` as its last non-empty\n line. If any item is `escalated`, end it with `<!-- NEEDS_HUMAN: <reason> -->` instead, the reason naming the\n escalated items and what the member must decide, so the Run parks for the member.\n\n## Linear (when the Plan is a Linear project)\n\nNever change an issue\'s status: Drisp derives In Progress, Review, Ready and Needs Input from the Run and its pull\nrequests. Write only two comments, through `linear`, each once: `PR: <url>` when an item\'s pull request opens, and,\nwhen an item is escalated, one comment that starts `**Needs input:**` and says what the member must decide. Never\nchange labels, priorities or descriptions.\n\n## Rules\n\n- You plan, decide, merge and clean up. Subagents write the code.\n- Keep the Journal current after every dispatch, Report, decision and merge: it is how a restart knows what was in\n flight.\n- Never claim a check passed, an item is done, or the member approved something without evidence.\n';
21478
+ var workflow_default = '# Drive: build a Plan with native subagents\n\nYou are the Orchestrator of a Drisp Build (root ADR-0018). This one session plans the work and delivers it. You read\nthe issues yourself, write the plan to your Journal, and hand each issue to a native subagent working in its own git\nworktree. Your working directory is the project\'s main checkout. You never write product code in it: subagents do.\n\nThe Run\'s prompt names the work in one of two ways:\n\n- `Linear project: <id>`: the Plan is that Linear project. Read it with the `linear` MCP server.\n- an inline issue list: each issue with its identifier, title, description, acceptance criteria and the issues it\n depends on. Use it as given; never look it up elsewhere.\n\nAnything else the member wrote in the prompt is their instruction for this Build. It defines the approved scope,\ntogether with each issue\'s own text. Drive every issue in that scope to verified completion from its current state.\nTracker statuses and triage labels describe the work; they are not admission gates for this Build.\n\n## 1. Plan (first Turn)\n\n1. Read every issue of the Plan. From Linear: `list_issues` for the project without status or label filters; follow\n pagination until every issue is read. Then `get_issue` with `includeRelations: true` for each, and `list_comments`\n for prior decisions, PRs and evidence. An inline issue list is in scope as a whole. Keep every issue in the plan,\n regardless of status or labels, including Backlog, Todo, In Progress, Review, QA, Ready, Released, Done,\n Needs Input, Canceled and Duplicate. Neither Todo nor `ready-for-agent` is required. Do not ask the member to\n change a status or label or restart the Build before you can proceed.\n2. Inspect the actual work and choose the next action for each issue:\n - Backlog, Todo or triage labels: resolve requirements from the issue, comments, repository and member\'s\n instructions, record your decisions, and dispatch the work. `needs-triage`, `needs-info`, `ready-for-human`\n and `wontfix` are context to investigate, not reasons to silently exclude the issue.\n - In Progress or Review: find the existing branch, worktree and PR, inspect what remains, and continue that work\n through review, checks and merge. Coordinate with any active owner; never start a competing implementation.\n - QA or Ready: verify acceptance criteria and outstanding checks, fix failures, and merge if necessary. A merged\n PR alone does not prove that the remaining QA or release work is complete.\n - Released or Done: verify the delivery and acceptance evidence. Record already delivered work as `merged` only\n when its repository changes are on the default branch and no required work remains; otherwise finish the gaps.\n - Needs Input, Canceled or Duplicate: read the reason and any linked issue, resolve it against the approved scope,\n and reuse delivered work where it satisfies the criteria. Decide what you can within scope; escalate a genuine\n unresolved scope decision under section 4. A status alone neither proves completion nor authorizes skipping.\n\n These are starting points, not a new status gate: evidence determines the next action in every state.\n\n3. Order all remaining work by its dependencies (`blockedBy` in Linear, "depends on" inline). An issue is ready\n when the prerequisite deliverables it needs are verified and their repository changes are on the default branch.\n Read external prerequisites and verify their evidence too; a Done or Released status alone is not proof. Do not\n silently add external work to the approved scope. Resolve dependency problems within scope, continue independent\n work, and escalate any prerequisite that needs a member decision rather than declaring the Plan complete.\n4. Prepare the main checkout: it must be clean and on the default branch, up to date with `origin` when there is one\n (`git pull --ff-only`). Subagent worktrees branch from its HEAD. Make sure `.claude/worktrees/` is ignored:\n `git check-ignore -q .claude/worktrees/x || echo \'.claude/worktrees/\' >> .git/info/exclude`. Note whether\n `origin` is a GitHub remote (`git remote get-url origin`).\n5. Write the plan into the Journal: delete the `<!-- JOURNAL_SKELETON -->` line, replace the skeleton\'s Plan\n section with these sections, and keep them current from then on:\n\n```\n## Plan\n\n| Item | Title | Depends on | Status | Attempts | Agent | Branch | PR |\n| ---- | ----- | ---------- | ------ | -------- | ----- | ------ | -- |\n\n## In flight\n\n| Item | Agent | Asked | Since |\n| ---- | ----- | ----- | ----- |\n\n## Decisions\n\n| Item | Question | Decision | Why |\n| ---- | -------- | -------- | --- |\n```\n\nStatus is one of `waiting`, `ready`, `running`, `blocked`, `done`, `merged`, `escalated`, `skipped`. Set it back to\n`running` whenever you continue a `blocked` or `done` item\'s subagent. `Agent` is the subagent\'s `agentId`, which you\nneed to continue it after a restart.\n`skipped` is reserved for work the member explicitly removed from scope; record that instruction in `## Decisions`.\nNever use it for a status, a triage label, a dependency, a missing PR or a lack of immediately dispatchable work.\nRecord each item\'s current evidence and next action in the Journal, including work already delivered before this Run.\n\n6. End the Turn with `<!-- AWAITING_APPROVAL -->` as the Journal\'s last line: the member reads your plan and\n starts the Build. You are woken with the answer `{"choice":"start"}`: remove that line and dispatch (section 2).\n Woken with the member\'s words instead, revise the plan to them and end with `<!-- AWAITING_APPROVAL -->` again.\n\nKeep one step block in the Journal and revise it in place as you move from `Plan` (1) to `Deliver` (2) to `Clean up`\n(3); Drisp shows the step as the Run\'s progress:\n\n```\n<!-- TURN_PROTOCOL\nstep: Deliver\nstep_index: 2\nstep_total: 3\n-->\n```\n\n## 2. Dispatch\n\nDispatch ready items at once, at most 4 running subagents at a time: one `Agent` call per item, all in one message,\nso they run in parallel. Dispatch more as running ones finish. Each call\nuses `isolation: "worktree"` and `subagent_type: "general-purpose"`, and `model` set to the subagent model the Run\'s\nprompt names, if it names one. Before the calls, add each item to `## In flight` (Agent `pending`); when they return,\nrecord each `agentId` and `worktreeBranch` in the Plan.\n\nEach subagent\'s prompt is its brief, and it has nothing else: write it in full.\n\n- The item: identifier, title, the full description and acceptance criteria, and any comments that matter.\n- The approved scope: the member\'s instructions and the decisions in your Journal that concern this item.\n- What its dependencies delivered (their branches are merged into the default branch it starts from).\n- Its current state, existing branch/PR and evidence, and the remaining work: implementation, review fixes, QA,\n merge preparation or release verification. Reuse existing work; do not rebuild an already delivered issue.\n- The rules and the Report contract below, copied verbatim.\n\n### Rules for every subagent (copy into the brief)\n\n- Work only in your own worktree, which is your working directory. Never touch the main checkout or another worktree.\n- For new implementation, first rename your branch to `drive/<item, lowercased>` (`git branch -m drive/<item>`;\n the brief names `drive/<item>-2` for a second attempt) and commit an empty start\n (`git commit --allow-empty -m "chore(<item>): start"`). Claude Code deletes a worktree with no commits when its\n subagent returns, so without it a `blocked` Report before any change would lose your worktree.\n- For an existing open PR, use its branch in your own worktree and update that PR. Never force a branch out of another\n worktree; report an ownership conflict with the context needed to resolve it. For verification of already merged\n work, start from the current default branch. If a fix is needed, create a fresh branch with a new name and a new\n PR; never add changes to the branch or PR that already merged. This also applies when you are continued after a\n merge in this Run. Keep the earlier PR as delivery evidence and put the new PR URL in your Report.\n- Finish the item\'s remaining acceptance criteria from the state in your brief. Run the project\'s relevant checks\n and keep their output as evidence. Commit changes with a clear message. A verification-only task needs evidence,\n not an empty PR. Respect configured gates for any remaining release or production action.\n- When you have changes and `origin` exists, push your branch: `git push -u origin HEAD`. When `origin` is on GitHub,\n reuse an existing open PR or open one to the default branch with `gh pr create --fill` (or a title and body that name\n the item), and put its URL in `pr`. Never merge it yourself.\n- When you need a decision you cannot take from the issue, the scope you were given or the code, stop before\n guessing and end with a `blocked` Report: the question, the options, and your recommendation. Do the same when a\n tool call is denied. You will be continued with the decision and keep your context.\n- End with `failed` when you cannot deliver for a reason a decision would not fix, with the cause in `evidence`.\n- Never wait with `sleep`. Wait for CI with `gh pr checks --watch` or `Monitor`.\n- Do not start subagents of your own.\n- Your final message ends with the Report: one fenced `json` block, nothing after it.\n\n### Report contract (copy into the brief)\n\n```json\n{\n "item": "<the item\'s identifier>",\n "status": "done | blocked | failed",\n "pr": "<pull request URL, or null>",\n "evidence": ["<check run, test output, commit, screenshot path>"],\n "question": "<the decision needed, when blocked, else null>",\n "options": ["<option>", "\u2026"],\n "recommendation": "<your preferred option and why, when blocked, else null>"\n}\n```\n\n## 3. Read each Report\n\nAn `Agent` call may return at once with `status: "async_launched"`: the subagent then runs in the background, and\nyou end your Turn as in section 4 until its `<task-notification>` wakes you.\n\nA subagent\'s Report is the last fenced `json` block in its final message: the Agent result when it returns one, or\nthe result inside the `<task-notification>` that wakes you. Read that, not your memory of the brief. When a result\nhas no parseable Report, `SendMessage` the subagent once: "End your reply with the Report: one fenced `json` block, as\nin your brief." Only if its next result still has none, count it as `failed` with "no Report" as the cause. Remove\nthe item from `## In flight` and act on its status:\n\n- `done`: check the evidence against the acceptance criteria (for unmerged changes, read the branch\'s diff with\n `git diff <default>...<branch>`; for delivered work, inspect the merged PR or commits and current validation\n evidence; run a quick check when the evidence is thin). If it falls short, continue the\n subagent with what is missing, as for `blocked`. If there are unmerged changes, record the PR and merge it\n (section 6). If this was verification of already delivered work, verify the changes are on the default branch\n and no required QA or release work remains, then record `merged` with that evidence; do not create a duplicate PR.\n- `blocked`: decide it (section 4).\n- `failed`: handle it (section 5).\n\nAfter each merge, dispatch the items that became ready.\n\n## 4. Decide every `blocked` Report\n\nDecide every `blocked` Report yourself, within the approved scope; the member is not asked. Pick one of the options\n(or a better one the evidence supports) from the member\'s instructions, the issue\'s text, the repository\'s ADRs and\ndocs, and the code. Record the item, the question, the decision and the evidence it rests on in `## Decisions` before\nyou send it.\n\nThen continue the same subagent, so it keeps its context and worktree. If `SendMessage` is not loaded yet, load it\nby calling `ToolSearch` with `select:SendMessage`. Call `SendMessage` with `to` set to the subagent\'s `agentId` and a\nmessage that gives the decision, why, and "continue, then end with a Report". Put the item back in `## In flight`.\nIf the subagent\'s worktree is gone (`git worktree list`) and its branch has no commits, dispatch the item again\ninstead, with the decision in its brief. That re-dispatch does not count as an attempt.\n\n`SendMessage` returns at once; the subagent works in the background. Its reply arrives later as a\n`<task-notification>` that starts your next Turn in this same process. Do other work that is ready, then\nend your Turn. Ending a Turn while subagents run is expected: Drisp keeps the session going and you are woken by their\ncompletion. Never poll them with `sleep`.\n\nNever end a Turn waiting on nothing. Before ending one, call `ListAgents`: if no subagent is running and no\nnotification is pending, re-read `## In flight` and act on every item there (section 7) instead.\nAlso inspect every unfinished Plan item, even when `## In flight` is empty. Resolve its next action and dispatch it,\nor record the concrete escalation and continue independent work. No dispatchable items is not completion.\n\nEscalate instead of deciding only when the decision would change the approved scope (a new requirement or dropping\nan acceptance criterion), required information remains unavailable after investigation, or a configured gate\nreserves the action for the member. Mark the item `escalated` with the concrete question and evidence of what you\ntried, and continue the rest. The issue\'s status or labels alone never justify escalation.\n\n## 5. Failures\n\nRe-dispatch a `failed` item once with the failure analysis: a new `Agent` call (worktree isolation) with the original\nbrief plus what failed and your analysis of why, on branch `drive/<item>-2`, or `SendMessage` to the same subagent\nwhen its worktree holds work worth keeping. Count the attempt in the Plan. On a second failure of the same item,\nstop: mark it `escalated` with both causes, mark the items that depend on it `escalated` as blocked by it, and\ncontinue every other item.\n\n## 6. Merge\n\nMerge one item at a time, in dependency order, only with this command, from the main checkout, with a Bash `timeout`\nof 600000:\n\n```\ndrisp drive merge <item> --worktree <the subagent\'s worktree> [--pr <number>]\n```\n\nIt checks whether the item is already merged, rebases, proves the checks (CI, or the project\'s own checks when there\nis none) and merges, all in code. It prints one JSON line; act on its `outcome`:\n\n- `merged` or `already_merged`: record the merge evidence. If required QA, release or other acceptance work remains,\n continue the subagent with that work and explicitly tell it that the previous PR has merged: verify the current\n default branch, and use a fresh branch and PR for any fixes (the subagent rules above). Record the new branch and\n PR in the Plan before merging those fixes; never pass the earlier merged PR to the merge command for new changes.\n Mark the item `merged` only when all remaining work is verified complete.\n- `conflict` or `checks_failed`: `SendMessage` the same subagent with `detail` and `output`: "fix your branch in\n place (rebase onto `<default branch>`, resolve, commit or remove every file, run the checks), and report\n again". That is not an attempt; a second `checks_failed` after its fix is a `failed` Report (section 5).\n- `checks_timeout`, or `checks_failed` whose `detail` starts "base kept moving": run the command again, at most\n twice; then handle it as `refused`.\n- `refused`: mark the item `escalated` with `detail`, continue the rest, and end with `NEEDS_HUMAN` (section 8).\n\nNever merge any other way: Drisp refuses `gh pr merge`, a push to the default branch, and a `git merge`, `reset` or\n`rebase` that moves it, in this Run.\nIf Drisp denies the command itself (a gate), do not retry it or work around it: note it in the Journal and end your\nTurn.\n\n## 7. After a crash or kill\n\nAfter a crash or kill, the Journal is what you have. On a fresh Turn, or a `<task-notification>` with status\n`stopped`, read `## In flight`: every item there was interrupted and its in-flight step is lost; its worktree and\nthe subagent\'s context are not. For each one:\n\n- with an `agentId`: `SendMessage` it: "Your last step was interrupted. Check your worktree\'s state, redo the step\n from your last commit, and end with a Report."\n- with Agent `pending` (the process died before the call returned): re-dispatch the item as in section 2. Check\n `git worktree list` first and name any worktree it left in the new brief.\n\n`ListAgents` shows which subagents still run; never dispatch a second subagent for an item whose subagent runs.\n\n## 8. Clean up and complete\n\nWhen every item is `merged`, `escalated` or `skipped`:\n\n1. Audit the Plan against the original issue list. Every in-scope issue must have completion evidence or a concrete\n escalation; every `skipped` item must cite the member\'s explicit scope removal. Revisit legacy skipped entries\n after a restart. Statuses, labels, a merged PR with outstanding acceptance work, and an empty dispatch list are\n never sufficient completion evidence.\n2. Remove each merged item\'s worktree and branch: `git worktree remove <worktree path>` and `git branch -D <branch>`\n (only once `drisp drive merge` returned `merged` or `already_merged` for it; it already deleted the remote\n branch). Remove verification-only worktrees created by this Run only after checking they contain no unmerged\n changes. Never remove a pre-existing worktree or branch owned by someone else. Then `git worktree prune`.\n Keep the worktrees of escalated items.\n3. Write the outcome above the marker: each item with its status, PR and evidence, the decisions taken, and each\n escalation with what the member needs to do.\n4. Only after that audit, if every in-scope item is verified `merged` and every `skipped` item was explicitly removed\n by the member, end the Journal with `<!-- WORKFLOW_COMPLETE -->` as its last non-empty line. If any item is\n `escalated`, end it with `<!-- NEEDS_HUMAN: <reason> -->` instead, the reason naming the escalated items and what\n the member must decide, so the Run parks for the member. Never write WORKFLOW_COMPLETE while in-scope work remains.\n\n## Linear (when the Plan is a Linear project)\n\nNever change an issue\'s status: Drisp derives In Progress, Review, Ready and Needs Input from the Run and its pull\nrequests. Write only two comments, through `linear`, each once: `PR: <url>` when an item\'s pull request opens, and,\nwhen an item is escalated, one comment that starts `**Needs input:**` and says what the member must decide. Never\nchange labels, priorities or descriptions.\n\n## Rules\n\n- You plan, decide, merge and clean up. Subagents write the code.\n- Keep the Journal current after every dispatch, Report, decision and merge: it is how a restart knows what was in\n flight.\n- Never claim a check passed, an item is done, or the member approved something without evidence.\n';
21559
21479
 
21560
21480
  // src/core/workflows/builtins/drive/index.ts
21561
21481
  var DRIVE_WORKFLOW_NAME = "drive";
21562
- var DRIVE_INSTRUCTIONS = workflow_default2;
21482
+ var DRIVE_INSTRUCTIONS = workflow_default;
21563
21483
  var DRIVE_LOOP = {
21564
21484
  enabled: true,
21565
21485
  completionMarker: DEFAULT_COMPLETION_MARKER,
@@ -21666,11 +21586,6 @@ function resolveBuiltinWorkflow(name) {
21666
21586
  ensureBuiltinFile(name, "workflow.md", DRIVE_INSTRUCTIONS)
21667
21587
  );
21668
21588
  }
21669
- if (name === ORCHESTRATOR_WORKFLOW_NAME) {
21670
- return orchestratorWorkflow(
21671
- ensureBuiltinFile(name, "workflow.md", ORCHESTRATOR_INSTRUCTIONS)
21672
- );
21673
- }
21674
21589
  if (name !== "default") {
21675
21590
  return void 0;
21676
21591
  }
@@ -21693,493 +21608,7 @@ function resolveBuiltinWorkflow(name) {
21693
21608
  };
21694
21609
  }
21695
21610
  function listBuiltinWorkflows() {
21696
- return ["default", DRIVE_WORKFLOW_NAME, ORCHESTRATOR_WORKFLOW_NAME];
21697
- }
21698
-
21699
- // src/core/workflows/builtins/build-child/template.ts
21700
- var DESCRIPTION_TEMPLATE = "Builds {identifier} end to end: tests, review, checks, pull request, QA, merge and evidence. Generated by drisp build from the build-child template.";
21701
- var QA_SECTIONS = {
21702
- web: "each acceptance criterion is walked in a real browser with the `drisp-browser` MCP server and a screenshot of each is saved under `.athena/evidence/`; the screenshot paths go in the evidence comment",
21703
- macos: "each acceptance criterion is walked in the built app with the repo's AX-driven QA loop through the shell (build, launch, drive it through Accessibility, screenshot); the evidence is the screenshot path and the AX dump path, which go in the evidence comment"
21704
- };
21705
- var WORKFLOW_MD_TEMPLATE = `# Build {identifier}
21706
-
21707
- You build one Linear issue end to end in this worktree, unattended, as one Run of a Drisp Build. The Run's prompt names
21708
- the issue, its Linear URL, its branch, this worktree and the Build. Work only in this worktree and on this branch.
21709
-
21710
- ## Tools
21711
-
21712
- Without asking anyone, this Run may edit files inside this worktree (never under \`.git\`), use the MCP servers this
21713
- Workflow selects, and run these shell commands, each with any arguments after it but no option before its subcommand
21714
- (not \`git -C \u2026\` or \`git -c \u2026\`):
21715
-
21716
- {shellCommands}.
21717
-
21718
- Commands that only read (\`ls\`, \`cat\`, \`grep\`) need no grant; anything else asks a person. Write files with the
21719
- Write and Edit tools, never through shell redirection or a heredoc, and keep \`\${\u2026}\` and \`$(\u2026)\` expansions out of
21720
- shell commands.
21721
-
21722
- A refused tool call is not a gate that cannot pass: never answer one with a gate's "cannot pass" line. Do the work
21723
- another way within these limits; when there is none, end the Turn with
21724
- \`<!-- NEEDS_HUMAN: A tool this Build does not allow was refused. Open the Thread to see which one. -->\` as the
21725
- Journal's last line.
21726
-
21727
- ## What this issue needs
21728
-
21729
- {instructions}
21730
-
21731
- ## Ownership and getting unstuck
21732
-
21733
- Carry the approved issue through proof, review, checks and delivery without asking about routine implementation
21734
- choices. Preserve existing work. Fix meaningful CI and review findings; do not stop merely because the PR is open.
21735
- When review is selected, maintain a finding ledger (id, severity, evidence, fixed or declined with reason). Later
21736
- rounds review changed behavior and unresolved findings. Keep fixes within scope; agreement without evidence and an
21737
- exhausted review budget are not approval. Report the actual reviewers and rounds, never invented provider coverage.
21738
-
21739
- The Build Orchestrator can inspect your history and send technical guidance. When blocked on a technical question,
21740
- missing evidence, a dependency fact or a repair you cannot resolve yourself, first record what failed, what you tried,
21741
- relevant paths/PRs and your recommended next action in the Journal. End with
21742
- \`<!-- NEEDS_ORCHESTRATOR: <specific question and recommendation> -->\` as the last line. Your parent can answer
21743
- this question and resume you. Guidance from the Orchestrator is not a human approval and cannot waive acceptance,
21744
- permissions or a reserved sign-off. Never mark a human decision as a technical question to obtain approval indirectly.
21745
-
21746
- Reserve NEEDS_HUMAN for permission grants, credentials, product decisions that change scope, production changes and
21747
- explicit member sign-off. A technical gate failure goes to the Orchestrator first: use its gate failure text as context
21748
- and include actual failing evidence. Do not repeatedly ask the same question without evaluating the supplied guidance.
21749
- For browser screenshots use \`drisp build evidence-copy <source-image> <unique-name.png>\` in this worktree instead
21750
- of shell cp. It copies a PNG, JPEG or WebP into .athena/evidence without replacing existing evidence.
21751
-
21752
- ## Evidence receipts
21753
-
21754
- Progress is not proof that a step passed. Follow each Finish instruction only after its acceptance condition holds.
21755
- Record actual results, commands, output paths and acceptance criteria, never a generic claim of success.
21756
- Commit repository changes before recording validation evidence. Changes to HEAD or source invalidate validation
21757
- receipts: rerun affected tests, review, checks and QA, including after a rebase, before verifying the Merge step.
21758
- Keep evidence files under .athena/evidence/ and do not commit them after validation, since a new commit invalidates receipts.
21759
-
21760
- ## Gates
21761
-
21762
- Work through the gates in this order. Start each gate by running the command its "Start" line gives, which reports the
21763
- gate to the Build page, then record the gate in the Journal before moving on. Never skip a gate and never reorder
21764
- them. When a gate cannot pass, diagnose it and route the question using Ownership and getting unstuck above.
21765
- The gate's "cannot pass" sentence is context, not a requirement to escalate every technical problem to a person.
21766
-
21767
- {gates}
21768
-
21769
- ## Merge gate
21770
-
21771
- After the last rebase, in this Run: Checks pass; both reviewers pass; QA passes when it is a gate; no remote check
21772
- failed after its job started.
21773
-
21774
- Before merging: \`git fetch origin\`; if \`origin/main\` is not an ancestor of HEAD, \`git rebase origin/main\`, run
21775
- Checks again and \`git push --force-with-lease\` to this branch. Repeat at most 3 times; then the Merge gate cannot
21776
- pass.
21777
-
21778
- Then run \`drisp build checks\` in this worktree. It reads the GitHub runs on HEAD (\`gh run view <id> --json jobs\` for
21779
- each failed one) and prints \`{"ok", "failed", "ignored", "pending"}\`. A failed run whose failed jobs ran zero steps
21780
- is in \`ignored\`: it does not block the merge and its name goes in the evidence comment. While \`pending\` is not
21781
- empty, wait a minute and run it again. When \`failed\` is not empty, fix the change; if it still fails, the Merge gate
21782
- cannot pass. Never judge a check by its timing.
21783
-
21784
- {signOff}Immediately before merging, verify the current revision again: {mergeVerify}. If evidence is stale, rerun the
21785
- selected validation steps and record fresh receipts before continuing.
21786
-
21787
- Merge with \`gh pr merge --squash --delete-branch --match-head-commit <sha>\`, where \`<sha>\` is HEAD after the last
21788
- push. When it exits non-zero, \`gh pr view --json state\` decides: \`MERGED\` means the merge happened (a worktree
21789
- cannot check out main afterwards); anything else means it did not.
21790
-
21791
- After a merge, and only then, run \`drisp build merged <pr url>\` in this worktree: it records the merged pull request as the
21792
- \`pull_request\` run artifact and exits non-zero if the pull request is not merged. Never run it before the merge or
21793
- after a failed one; if it fails only because GitHub has not caught up, wait a few seconds and run it again.
21794
-
21795
- ## Evidence comment
21796
-
21797
- Post exactly this on the Linear issue, filling the angle brackets:
21798
-
21799
- \`\`\`
21800
- Drisp Build <orchRunId> \xB7 Run <runId>
21801
- PR: <url> (merged <short sha>)
21802
- Checks: {checksEvidence}
21803
- Review: Standards \u2713 \xB7 Spec \u2713
21804
- QA: none | web: <screenshot paths> | macOS: <screenshot path>, <AX dump path>
21805
- Ignored checks (no steps ran): <names> | none
21806
- \`\`\`
21807
-
21808
- ## Linear
21809
-
21810
- Your Linear writes are exactly: the evidence comment. The Build's Orchestrator makes every other write the rules below
21811
- describe, statuses and the \`PR: <url>\` comment included, from the facts this Run leaves; so never write a status.
21812
- Never create issues and never edit an issue's title or description. The rules describe what each status means.
21813
-
21814
- ${LINEAR_RULES}
21815
-
21816
- When every gate has passed, end with \`<!-- WORKFLOW_COMPLETE -->\` as the Journal's last line.
21817
- `;
21818
- var MERGE_SIGN_OFF = {
21819
- passesWhen: "the merge gate below holds, with the member\u2019s Sign-off on HEAD",
21820
- section: `Sign-off: this Build's member merges, so the merge waits for their Sign-off on the exact head commit. When
21821
- everything above holds and HEAD is pushed, end the Turn with \`<!-- NEEDS_HUMAN: {signOffText} -->\` as the Journal's
21822
- last line, where \`<sha>\` is the full \`git rev-parse HEAD\`. The member answers in this Thread. When their reply signs
21823
- off on that commit, record it with \`{signOffCommand}\`, which refuses any SHA but HEAD; it is your attestation of
21824
- their reply, so never record one they did not give. Any other reply is guidance: act on it, then ask again. A
21825
- Sign-off names one commit: after a rebase or any new commit, ask again before merging.
21826
- When \`gh pr merge\` fails because the branch is protected, the Merge gate cannot pass.
21827
-
21828
- `
21829
- };
21830
- var STAGE_TEMPLATE = `### {n}. {title}
21831
-
21832
- Start: run \`{stepCommand}\`.
21833
-
21834
- Passes when: {passesWhen}.`;
21835
- var CANNOT_PASS_TEMPLATE = `
21836
-
21837
- Cannot pass: \`<!-- {respondentMarker}: {cannotPass} -->\``;
21838
- var NO_GATE_TEXT_TEMPLATE = `
21839
-
21840
- No gate text: the loop's caps apply.`;
21841
-
21842
- // src/core/workflows/builtins/build-child/render.ts
21843
- var RENDERER_RULES = {
21844
- alwaysSkills: [],
21845
- profiles: ["implementation", "documentation", "investigation"],
21846
- alwaysMcpServers: ["linear"],
21847
- areaSkills: {
21848
- macos: ["swiftui-expert-skill", "apple-docs", "apple-hig-components"]
21849
- },
21850
- qaMcpServers: { web: ["drisp-browser"], both: ["drisp-browser"] },
21851
- npmTestAreas: ["cli", "hub", "protocol"],
21852
- /**
21853
- * The Checks gate's commands, resolved from the fill's areas and the repo's layout at the plan's commit: a repo
21854
- * with a root Makefile runs `make check` and `make typecheck STRICT=1` (and `npm test` for the npm areas); one
21855
- * without (a monorepo such as drisp) runs each area's own commands where its marker file exists.
21856
- */
21857
- checks: {
21858
- rootMakefile: ["make check", "make typecheck STRICT=1"],
21859
- npmTest: "npm test",
21860
- byArea: {
21861
- macos: {
21862
- needs: "apps/macos/Makefile",
21863
- commands: [
21864
- "make -C apps/macos check",
21865
- "make -C apps/macos typecheck STRICT=1"
21866
- ]
21867
- },
21868
- cli: {
21869
- needs: "apps/cli/package.json",
21870
- commands: [
21871
- "npm --prefix apps/cli run typecheck",
21872
- "npm --prefix apps/cli run lint",
21873
- "npm --prefix apps/cli run test"
21874
- ]
21875
- },
21876
- hub: {
21877
- needs: "package.json",
21878
- commands: ["npm run typecheck", "npx vitest run modules/hub"]
21879
- },
21880
- protocol: {
21881
- needs: "package.json",
21882
- commands: [
21883
- "npm run typecheck",
21884
- "npx vitest run tests/scenarios/protocol.test.ts"
21885
- ]
21886
- },
21887
- web: { needs: "package.json", commands: ["npm run typecheck"] }
21888
- },
21889
- otherwise: ["git diff --check origin/main"],
21890
- /** A fresh worktree has no dependencies: installed first where the repo pins them and a check needs them. */
21891
- install: { needs: "package-lock.json", command: "npm ci" }
21892
- },
21893
- sizeClasses: {
21894
- S: { model: "sonnet", maxRunTokens: 3e6, maxIterations: 40 },
21895
- M: { model: "sonnet", maxRunTokens: 6e6, maxIterations: 80 },
21896
- L: { model: "opus", maxRunTokens: 12e6, maxIterations: 120 }
21897
- },
21898
- summaryMaxChars: 280,
21899
- /**
21900
- * The child's fixed permission limits (DRI-167; root ADR-0008 "Permission limits"), in Claude Code's permission
21901
- * rule syntax. Never filled: the renderer writes them, so the byte-equality re-validation covers them. Edits
21902
- * (Edit, Write, NotebookEdit) anywhere under the Run's working directory, which bootstrap re-validation pins to the
21903
- * child's own worktree, except `.git`; the shell commands the stages name, by subcommand, each rendered as
21904
- * `Bash(<command> *)` (every Checks and install command starts with one of them); and one rule per selected MCP
21905
- * server. No bare program: not `gh api` or `gh auth token`, not `git config` or `git -c`, not `npm publish` or
21906
- * `npx <any package>`, not `drisp runner …`, and no `node`. Anything else still asks a person.
21907
- */
21908
- permissions: {
21909
- edit: ["Edit(./**)"],
21910
- shell: [
21911
- "drisp build check",
21912
- "drisp build checks",
21913
- "drisp build step",
21914
- "drisp build merged",
21915
- "drisp build evidence-copy",
21916
- "gh pr checks",
21917
- "gh pr create",
21918
- "gh pr list",
21919
- "gh pr merge",
21920
- "gh pr view",
21921
- "gh run list",
21922
- "gh run view",
21923
- "git add",
21924
- "git commit",
21925
- "git diff",
21926
- "git fetch",
21927
- "git log",
21928
- "git merge-base",
21929
- "git push",
21930
- "git rebase",
21931
- "git restore",
21932
- "git rev-parse",
21933
- "git show",
21934
- "git status",
21935
- "make -C apps/macos",
21936
- "make check",
21937
- "make typecheck",
21938
- "npm --prefix apps/cli run",
21939
- "npm ci",
21940
- "npm run",
21941
- "npm test",
21942
- "npx vitest run",
21943
- "sleep"
21944
- ],
21945
- /** Claude Code asks before a write under `.git`; denying it makes that a refusal nobody can approve. */
21946
- deny: ["Edit(./.git)", "Edit(./.git/**)"]
21947
- }
21948
- };
21949
- var LAYOUT_MARKERS = [
21950
- "Makefile",
21951
- "package.json",
21952
- "package-lock.json",
21953
- "apps/macos/Makefile",
21954
- "apps/cli/package.json"
21955
- ];
21956
- function checkCommands(fill, layout) {
21957
- if (fill.checks) return [...fill.checks];
21958
- const rules = RENDERER_RULES.checks;
21959
- if (fill.profile === "documentation" || fill.profile === "investigation")
21960
- return [...rules.otherwise];
21961
- if (layout.includes("Makefile"))
21962
- return [
21963
- ...rules.rootMakefile,
21964
- ...fill.areas.some((area) => RENDERER_RULES.npmTestAreas.includes(area)) ? [rules.npmTest] : []
21965
- ];
21966
- const commands = [
21967
- ...new Set(
21968
- fill.areas.flatMap((area) => {
21969
- const rule = rules.byArea[area];
21970
- return rule && layout.includes(rule.needs) ? rule.commands : [];
21971
- })
21972
- )
21973
- ];
21974
- return commands.length > 0 ? commands : [...rules.otherwise];
21975
- }
21976
- function installCommand(fill, layout) {
21977
- const { install } = RENDERER_RULES.checks;
21978
- if (!layout.includes(install.needs)) return void 0;
21979
- const needsNode = checkCommands(fill, layout).some(
21980
- (command) => /^np[mx] /.test(command) || layout.includes("Makefile") && RENDERER_RULES.checks.rootMakefile.some(
21981
- (rootCommand) => rootCommand === command
21982
- )
21983
- );
21984
- return needsNode ? install.command : void 0;
21985
- }
21986
- var GENERATED_NAME = /^build--([a-z0-9]+)--([A-Z][A-Z0-9]*-[0-9]+)$/;
21987
- function parseGeneratedWorkflowName(name) {
21988
- const match = GENERATED_NAME.exec(name);
21989
- return match ? { slugId: match[1], identifier: match[2] } : void 0;
21990
- }
21991
- function generatedWorkflowName(slugId, identifier) {
21992
- return `build--${slugId}--${identifier}`;
21993
- }
21994
- function sizeClassLimits(sizeClass) {
21995
- return RENDERER_RULES.sizeClasses[sizeClass];
21996
- }
21997
- function renderedSkills(fill) {
21998
- return [
21999
- .../* @__PURE__ */ new Set([
22000
- ...RENDERER_RULES.alwaysSkills,
22001
- ...usesTestFirst(fill) ? ["tdd"] : [],
22002
- ...usesReview(fill) ? ["code-review"] : [],
22003
- ...fill.areas.flatMap((area) => RENDERER_RULES.areaSkills[area] ?? [])
22004
- ])
22005
- ].sort();
22006
- }
22007
- function renderedMcpServers(fill) {
22008
- return [
22009
- .../* @__PURE__ */ new Set([
22010
- ...RENDERER_RULES.alwaysMcpServers,
22011
- ...RENDERER_RULES.qaMcpServers[fill.qa] ?? []
22012
- ])
22013
- ].sort();
22014
- }
22015
- function shellCommands(fill) {
22016
- const commands = [...RENDERER_RULES.permissions.shell];
22017
- return fill.profile !== "investigation" ? commands : commands.filter(
22018
- (command) => ![
22019
- "drisp build merged",
22020
- "gh pr create",
22021
- "gh pr merge",
22022
- "git add",
22023
- "git commit",
22024
- "git push",
22025
- "git rebase",
22026
- "git restore"
22027
- ].includes(command)
22028
- );
22029
- }
22030
- function renderedPermissions(fill) {
22031
- const { edit, deny } = RENDERER_RULES.permissions;
22032
- const shell = shellCommands(fill);
22033
- return {
22034
- allow: [
22035
- ...edit,
22036
- ...shell.map((command) => `Bash(${command} *)`),
22037
- ...renderedMcpServers(fill).map((server) => `mcp__${server}`)
22038
- ],
22039
- deny: [...deny]
22040
- };
22041
- }
22042
- var usesTestFirst = (fill) => fill.testFirst?.enabled ?? (!fill.profile || fill.profile === "implementation");
22043
- var usesReview = (fill) => fill.review?.enabled ?? (!fill.profile || fill.profile === "implementation");
22044
- function selectedGates(fill) {
22045
- const gates = GATES.filter(
22046
- (gate) => (gate.title !== "QA" || fill.qa !== "none") && (gate.title !== "Test first" || usesTestFirst(fill)) && (gate.title !== "Code review" || usesReview(fill)) && (fill.profile !== "investigation" || !["Pull request", "Merge"].includes(gate.title))
22047
- ).map(
22048
- (gate) => fill.profile === "investigation" && gate.title === "Checks" ? {
22049
- ...gate,
22050
- passesWhen: "{install}{checks} pass, each check run through `drisp build check <name> -- <command>`; each finding is supported by a source or reproducible observation and each acceptance criterion has evidence; unresolved questions are stated explicitly"
22051
- } : fill.profile === "investigation" && gate.title === "Evidence" ? {
22052
- ...gate,
22053
- passesWhen: "findings and evidence for each acceptance criterion are posted on the Linear issue, with unresolved questions explicitly stated"
22054
- } : fill.merge === "you" && gate.title === "Merge" ? { ...gate, passesWhen: MERGE_SIGN_OFF.passesWhen } : gate
22055
- );
22056
- if (!usesTestFirst(fill))
22057
- gates.splice(1, 0, {
22058
- title: fill.profile === "investigation" ? "Investigate" : "Implement",
22059
- passesWhen: fill.profile === "investigation" ? "the question is investigated and findings address every acceptance criterion; no repository changes are made" : "the requested change is implemented and each acceptance criterion is checked"
22060
- });
22061
- return gates;
22062
- }
22063
- function gateTitles(fill) {
22064
- return selectedGates(fill).map((gate) => gate.title);
22065
- }
22066
- function summarizeInstructions(instructions) {
22067
- const paragraph = (instructions.trim().split(/\n\s*\n/)[0] ?? "").replace(/\s+/g, " ").trim();
22068
- const max = RENDERER_RULES.summaryMaxChars;
22069
- if (paragraph.length <= max) return paragraph;
22070
- const head = paragraph.slice(0, max - 1);
22071
- const boundary = head.lastIndexOf(" ");
22072
- return `${(boundary > 0 ? head.slice(0, boundary) : head).trimEnd()}\u2026`;
22073
- }
22074
- function checksText(commands) {
22075
- const quoted = commands.map((command) => `\`${command}\``);
22076
- return quoted.length === 1 ? quoted[0] : `${quoted.slice(0, -1).join(", ")} and ${quoted.at(-1)}`;
22077
- }
22078
- var fillSlots = (template, slots) => template.replace(/\{(\w+)\}/g, (whole, key) => slots[key] ?? whole);
22079
- function selectionFlags(fill) {
22080
- return `${fill.profile ? ` --profile ${fill.profile}` : ""}${fill.testFirst ? ` --test-first ${fill.testFirst.enabled}` : ""}${fill.review ? ` --review ${fill.review.enabled}` : ""}`;
22081
- }
22082
- var mergeFlag = (fill) => fill.merge === "you" ? " --merge you" : "";
22083
- function renderStages(fill, checks, install) {
22084
- const gates = selectedGates(fill);
22085
- return gates.map((gate, index) => {
22086
- const passesWhen = fillSlots(gate.passesWhen, {
22087
- install: install ? `after \`${install}\`, ` : "",
22088
- checks: checksText(checks),
22089
- qa: fill.qa === "none" ? "" : fill.qa === "both" ? `${QA_SECTIONS.web}; also ${QA_SECTIONS.macos}` : QA_SECTIONS[fill.qa]
22090
- });
22091
- const command = `drisp build step ${index + 1} --qa ${fill.qa}${selectionFlags(fill)}`;
22092
- const stage = fillSlots(STAGE_TEMPLATE, {
22093
- n: String(index + 1),
22094
- title: gate.title,
22095
- stepCommand: command,
22096
- passesWhen
22097
- });
22098
- const finish = `${command}${gate.title === "Merge" ? mergeFlag(fill) : ""}`;
22099
- return stage + (["Merge", "Evidence"].includes(gate.title) ? `
22100
-
22101
- Before doing this step: run \`${command} --verify\`. Missing or stale evidence must be refreshed first.` : "") + `
22102
-
22103
- Finish: write the actual result and supporting paths to \`.athena/evidence/step-${index + 1}.md\`, then run \`${finish} --complete --evidence .athena/evidence/step-${index + 1}.md\`. This records an agent attestation, not independent verification.` + (gate.cannotPass ? fillSlots(CANNOT_PASS_TEMPLATE, {
22104
- cannotPass: gate.cannotPass,
22105
- respondentMarker: ["Explore", "Pull request"].includes(gate.title) ? "NEEDS_HUMAN" : "NEEDS_ORCHESTRATOR"
22106
- }) : NO_GATE_TEXT_TEMPLATE);
22107
- }).join("\n\n");
22108
- }
22109
- function render(fill, workflowName, layout) {
22110
- const parsed = parseGeneratedWorkflowName(workflowName);
22111
- if (!parsed)
22112
- throw new Error(`Not a Generated Workflow name: ${workflowName}`);
22113
- const limits = sizeClassLimits(fill.sizeClass);
22114
- const workflow = {
22115
- name: workflowName,
22116
- description: fill.profile === "investigation" ? `Investigates ${parsed.identifier} and delivers findings with acceptance evidence.` : fillSlots(DESCRIPTION_TEMPLATE, {
22117
- identifier: parsed.identifier
22118
- }),
22119
- promptTemplate: "{input}",
22120
- workflowFile: "workflow.md",
22121
- plugins: [],
22122
- model: limits.model,
22123
- skills: renderedSkills(fill),
22124
- mcpServers: renderedMcpServers(fill),
22125
- loop: {
22126
- enabled: true,
22127
- maxIterations: limits.maxIterations,
22128
- maxRunTokens: limits.maxRunTokens
22129
- },
22130
- permissions: renderedPermissions(fill)
22131
- };
22132
- const checks = checkCommands(fill, layout);
22133
- let template = WORKFLOW_MD_TEMPLATE;
22134
- if (!usesReview(fill))
22135
- template = template.replaceAll(
22136
- "both reviewers pass;",
22137
- "review is omitted by the approved plan;"
22138
- ).replaceAll(
22139
- "Review: Standards \u2713 \xB7 Spec \u2713",
22140
- "Review: omitted by the approved plan"
22141
- );
22142
- if (fill.profile === "investigation") {
22143
- template = template.replace(
22144
- /## Merge gate[\s\S]*?## Linear/,
22145
- "## Findings\n\nPost findings and acceptance evidence on the Linear issue. No pull request or merge is required.\n\n## Linear"
22146
- );
22147
- template = template.replace(
22148
- "Your Linear writes are exactly: the evidence comment.",
22149
- "Your Linear writes are exactly: the findings and evidence comment."
22150
- );
22151
- }
22152
- const mergeCommand = `drisp build step ${gateTitles(fill).indexOf("Merge") + 1} --qa ${fill.qa}${selectionFlags(fill)}`;
22153
- const workflowMd = fillSlots(template, {
22154
- identifier: parsed.identifier,
22155
- instructions: [
22156
- fill.instructions.trim(),
22157
- fill.rationale ? `Plan rationale: ${fill.rationale}` : "",
22158
- fill.testFirst ? `Test first: ${fill.testFirst.enabled ? "included" : "omitted"} \u2014 ${fill.testFirst.reason}` : "",
22159
- fill.review ? `Code review: ${fill.review.enabled ? "included" : "omitted"} \u2014 ${fill.review.reason}` : "",
22160
- ...(fill.acceptanceEvidence ?? []).map(
22161
- (item) => `Acceptance evidence: ${item}`
22162
- )
22163
- ].filter(Boolean).join("\n\n"),
22164
- gates: renderStages(fill, checks, installCommand(fill, layout)),
22165
- signOff: fill.merge === "you" ? fillSlots(MERGE_SIGN_OFF.section, {
22166
- signOffText: BUILD_STRINGS.mergeSignOff.replace("{sha}", "<sha>"),
22167
- signOffCommand: `${mergeCommand} --merge you --sign-off <sha>`
22168
- }) : "",
22169
- mergeVerify: `\`${mergeCommand}${mergeFlag(fill)} --verify\``,
22170
- checksEvidence: checks.map((command) => `${command} \u2713`).join(" \xB7 "),
22171
- shellCommands: checksText(shellCommands(fill))
22172
- });
22173
- return { workflowJson: `${JSON.stringify(workflow, null, 2)}
22174
- `, workflowMd };
22175
- }
22176
- function verifyRendered(input2) {
22177
- const expected = render(input2.fill, input2.workflowName, input2.layout);
22178
- if (expected.workflowJson !== input2.workflowJson)
22179
- return { ok: false, file: "workflow.json" };
22180
- if (expected.workflowMd !== input2.workflowMd)
22181
- return { ok: false, file: "workflow.md" };
22182
- return { ok: true };
21611
+ return ["default", DRIVE_WORKFLOW_NAME];
22183
21612
  }
22184
21613
 
22185
21614
  // src/core/workflows/sourceMetadata.ts
@@ -22353,10 +21782,7 @@ function copyWorkflowFiles(sourcePath, destDir) {
22353
21782
  ...fs9.existsSync(instructionsPath) ? { instructions: fs9.readFileSync(instructionsPath, "utf-8") } : {}
22354
21783
  });
22355
21784
  copyRelativeAsset(promptAsset);
22356
- if (typeof workflow.name === "string" && parseGeneratedWorkflowName(workflow.name))
22357
- copyRelativeAsset(GENERATED_FILL);
22358
21785
  }
22359
- var GENERATED_FILL = "fill.json";
22360
21786
  function toStoredMetadata(source) {
22361
21787
  if (source.kind === "marketplace-remote") {
22362
21788
  return {
@@ -24790,34 +24216,9 @@ export {
24790
24216
  installWorkflowPlugins,
24791
24217
  resolveWorkflowPlugins,
24792
24218
  external_exports,
24793
- parseWorkflowConfig,
24794
24219
  selectWorkflowCapabilities,
24795
- BUILD_STRINGS,
24796
- GATES,
24797
- ORCHESTRATOR_WORKFLOW_NAME,
24798
- ORCHESTRATOR_LIMITS,
24799
- ORCHESTRATOR_LOOP,
24800
24220
  DRIVE_WORKFLOW_NAME,
24801
24221
  listBuiltinWorkflows,
24802
- DESCRIPTION_TEMPLATE,
24803
- QA_SECTIONS,
24804
- WORKFLOW_MD_TEMPLATE,
24805
- MERGE_SIGN_OFF,
24806
- STAGE_TEMPLATE,
24807
- CANNOT_PASS_TEMPLATE,
24808
- NO_GATE_TEXT_TEMPLATE,
24809
- RENDERER_RULES,
24810
- LAYOUT_MARKERS,
24811
- parseGeneratedWorkflowName,
24812
- generatedWorkflowName,
24813
- sizeClassLimits,
24814
- renderedSkills,
24815
- renderedMcpServers,
24816
- renderedPermissions,
24817
- gateTitles,
24818
- summarizeInstructions,
24819
- render,
24820
- verifyRendered,
24821
24222
  readWorkflowSourceMetadata,
24822
24223
  workflowRegistryDir,
24823
24224
  resolveWorkflow,
@@ -24829,4 +24230,4 @@ export {
24829
24230
  compileWorkflowPlan,
24830
24231
  collectMcpServersWithOptions
24831
24232
  };
24832
- //# sourceMappingURL=chunk-GGAPZULS.js.map
24233
+ //# sourceMappingURL=chunk-5R66YGDF.js.map