@snappedly-tools/shipyard 0.5.0 → 0.6.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.
Files changed (58) hide show
  1. package/README.md +56 -8
  2. package/dist/index.js +27 -9
  3. package/dist/index.js.map +1 -1
  4. package/dist/main.js +51 -15
  5. package/dist/main.js.map +1 -1
  6. package/dist/templates/parallel-planner/block-scope.sh +160 -0
  7. package/dist/templates/parallel-planner/conflict-prompt.md +22 -0
  8. package/dist/templates/parallel-planner/handoff.sh +175 -0
  9. package/dist/templates/parallel-planner/implement-prompt.md +10 -56
  10. package/dist/templates/parallel-planner/main.mts +434 -188
  11. package/dist/templates/parallel-planner/merge-prompt.md +9 -21
  12. package/dist/templates/parallel-planner/plan-prompt.md +5 -31
  13. package/dist/templates/parallel-planner/select-issues.mjs +788 -0
  14. package/dist/templates/parallel-planner/setup.sh +51 -0
  15. package/dist/templates/parallel-planner/spec-wave-prompt.md +16 -0
  16. package/dist/templates/parallel-planner/template.json +1 -1
  17. package/dist/templates/parallel-planner/triage-prompt.md +5 -0
  18. package/dist/templates/parallel-planner/verify-triage.sh +19 -0
  19. package/dist/templates/parallel-planner-with-review/block-scope.sh +160 -0
  20. package/dist/templates/parallel-planner-with-review/conflict-prompt.md +22 -0
  21. package/dist/templates/parallel-planner-with-review/handoff.sh +175 -0
  22. package/dist/templates/parallel-planner-with-review/implement-prompt.md +10 -56
  23. package/dist/templates/parallel-planner-with-review/main.mts +473 -205
  24. package/dist/templates/parallel-planner-with-review/merge-prompt.md +9 -21
  25. package/dist/templates/parallel-planner-with-review/plan-prompt.md +5 -31
  26. package/dist/templates/parallel-planner-with-review/review-prompt.md +11 -49
  27. package/dist/templates/parallel-planner-with-review/select-issues.mjs +788 -0
  28. package/dist/templates/parallel-planner-with-review/setup.sh +51 -0
  29. package/dist/templates/parallel-planner-with-review/spec-wave-prompt.md +16 -0
  30. package/dist/templates/parallel-planner-with-review/template.json +1 -1
  31. package/dist/templates/parallel-planner-with-review/triage-prompt.md +5 -0
  32. package/dist/templates/parallel-planner-with-review/verify-triage.sh +19 -0
  33. package/dist/templates/sequential-reviewer/block-scope.sh +160 -0
  34. package/dist/templates/sequential-reviewer/handoff.sh +175 -0
  35. package/dist/templates/sequential-reviewer/implement-prompt.md +12 -46
  36. package/dist/templates/sequential-reviewer/main.mts +199 -103
  37. package/dist/templates/sequential-reviewer/review-prompt.md +11 -49
  38. package/dist/templates/sequential-reviewer/select-issues.mjs +788 -0
  39. package/dist/templates/sequential-reviewer/setup.sh +51 -0
  40. package/dist/templates/sequential-reviewer/template.json +1 -1
  41. package/dist/templates/sequential-reviewer/triage-prompt.md +5 -0
  42. package/dist/templates/sequential-reviewer/verify-triage.sh +19 -0
  43. package/dist/templates/shared/block-scope.sh +160 -0
  44. package/dist/templates/shared/handoff.sh +175 -0
  45. package/dist/templates/shared/select-issues.mjs +788 -0
  46. package/dist/templates/shared/setup.sh +51 -0
  47. package/dist/templates/shared/triage-prompt.md +5 -0
  48. package/dist/templates/shared/verify-triage.sh +19 -0
  49. package/dist/templates/simple-loop/block-scope.sh +160 -0
  50. package/dist/templates/simple-loop/handoff.sh +175 -0
  51. package/dist/templates/simple-loop/main.mts +190 -45
  52. package/dist/templates/simple-loop/prompt.md +12 -46
  53. package/dist/templates/simple-loop/select-issues.mjs +788 -0
  54. package/dist/templates/simple-loop/setup.sh +51 -0
  55. package/dist/templates/simple-loop/template.json +1 -1
  56. package/dist/templates/simple-loop/triage-prompt.md +5 -0
  57. package/dist/templates/simple-loop/verify-triage.sh +19 -0
  58. package/package.json +1 -1
package/README.md CHANGED
@@ -29,6 +29,9 @@ plane around the agent:
29
29
 
30
30
  ## Install and run
31
31
 
32
+ Before running Shipyard, install the [Snappedly skills](https://github.com/snappedly/skills)
33
+ and run `setup-snapedly-skills` in the target repository.
34
+
32
35
  Requirements: Node.js 20.18.1+, Git, Docker, and credentials for your chosen
33
36
  agent. Run these commands in the repository Shipyard should change:
34
37
 
@@ -61,13 +64,13 @@ the [agent guide](docs/content/docs/agents.mdx) for authentication details.
61
64
 
62
65
  ## Pick the workflow you need
63
66
 
64
- | Template | Best for | Built-in flow |
65
- | ------------------------------ | --------------------- | ------------------------------------------------- |
66
- | `blank` | One custom task | One agent run |
67
- | `simple-loop` | A small issue backlog | Implement issues sequentially |
68
- | `sequential-reviewer` | Safer issue delivery | Implement → review, one issue at a time |
69
- | `parallel-planner` | Independent issues | Plan dependencies → implement in parallel → merge |
70
- | `parallel-planner-with-review` | Maximum autonomy | Plan → implement and review in parallel → merge |
67
+ | Template | Best for | Built-in flow |
68
+ | ------------------------------ | --------------------- | --------------------------------------------- |
69
+ | `blank` | One custom task | One agent run |
70
+ | `simple-loop` | A small issue backlog | Implement issues sequentially → review PRs |
71
+ | `sequential-reviewer` | Safer issue delivery | Implement → review → review PR |
72
+ | `parallel-planner` | Independent issues | Plan → implement in parallel → review PRs |
73
+ | `parallel-planner-with-review` | Maximum autonomy | Plan → implement and review in parallel → PRs |
71
74
 
72
75
  All templates are generated TypeScript. Adjust prompts, models, iteration
73
76
  limits, branch strategy, hooks, and checks in `.shipyard/main.ts` or
@@ -80,12 +83,57 @@ Shipyard controller ready for GitHub Issues. Label an issue `shipyard`; the
80
83
  controller wakes, drains a finite batch of eligible work, coalesces duplicate
81
84
  wake-ups, and stops when it makes no progress. Restarting it recovers work
82
85
  labelled while the host was offline.
86
+ GitHub-backed `shipyard init` provisions `shipyard`, `shipyard:blocked`,
87
+ `shipyard:pending`, `shipyard:complete`, and `shipyard:outstanding-tasks` in the repository.
88
+ It also provisions the `bug`, `enhancement`, and five triage state labels.
89
+ For a connected repository, init reports an error if any label cannot be created.
90
+
91
+ The bundled issue workflows install Snappedly skills and the candidate's
92
+ dependencies in Docker. When Shipyard takes an activated ticket, it runs
93
+ `/triage` first and checks the current GitHub labels. Implementation requires
94
+ both `shipyard` and `ready-for-agent`, with no conflicting triage state. Other
95
+ triage outcomes follow the normal blocked flow: Shipyard adds
96
+ `shipyard:blocked`, removes `shipyard`, and records the reason on the ticket.
97
+ A standalone ready issue then runs through `/implement`. Activating
98
+ a planning spec or a linked executable child resolves the parent and only
99
+ linked tickets labelled `shipyard` into one `/implement-spec` scope. The sequential
100
+ templates deliver selected tickets on one branch; the parallel templates assign
101
+ ready tickets to `/implement` workers, integrate dependency waves, resolve ticket
102
+ merge conflicts on the spec branch, and review the integrated change. One
103
+ non-draft PR per spec awaits human merge. Later selected tickets update that PR.
104
+ Shipyard also recognizes a ticket added to an open verified spec PR's `Source
105
+ issues:` line as belonging to that spec, even without a GitHub sub-issue or
106
+ `## Parent` link. Conflicting links block the selected ticket for correction.
107
+ Selected tickets receive `shipyard:pending` while Shipyard works on them.
108
+ Successful handoff replaces it with `shipyard:complete` and removes `shipyard`.
109
+ The parent spec and PR show `shipyard:blocked` if an unfinished child is blocked,
110
+ `shipyard:outstanding-tasks` if children remain, or `shipyard:complete` when all
111
+ linked tickets are complete. Spec labels report child state; they never prevent
112
+ a reactivated child from running. The issues remain open under the target
113
+ repository's closure policy.
114
+ With no labelled tickets yet, Shipyard marks the parent outstanding and waits
115
+ to create the PR until a ticket is selected.
116
+ If an attempted issue cannot be completed, Shipyard comments with the reason,
117
+ marks the attempted tickets `shipyard:blocked`, clears `shipyard:pending`, and
118
+ removes `shipyard` from the scope. The parent spec and any existing PR show
119
+ `shipyard:blocked` while an unfinished child remains blocked. It does not
120
+ publish a new PR for failed work. Resolve the problem, remove
121
+ `shipyard:blocked` from a ticket, then add `shipyard` to retry that ticket;
122
+ the parent spec's status label needs no manual change. Missing or ambiguous
123
+ relationships block the affected selected issue and record the reason. If GitHub cannot confirm whether a
124
+ PR became ready, Shipyard leaves the issue active for reconciliation. The GitHub token
125
+ needs Contents, Issues, and Pull requests read/write permission plus Metadata
126
+ read permission. Keep the Mac and foreground controller running for wake-ups.
127
+ If GitHub rejects a failure comment, Shipyard keeps a local pending report for
128
+ replay. A fresh `shipyard` activation on an unblocked ticket supersedes that
129
+ report. Spec and PR status label failures are logged without stopping ticket
130
+ work; retained activation lets the next invocation recalculate their labels.
83
131
 
84
132
  Accept runner installation during `init`, or install it later:
85
133
 
86
134
  ```sh
87
135
  npx shipyard runner install
88
- git add .github/workflows/shipyard-wake.yml .shipyard/.gitignore
136
+ git add .shipyard .github/workflows/shipyard-wake.yml
89
137
  git commit -m "Add Shipyard wake workflow"
90
138
  git push
91
139
  npx shipyard runner start
package/dist/index.js CHANGED
@@ -1596,6 +1596,15 @@ var interactive = async (options) => {
1596
1596
  }
1597
1597
  return result3;
1598
1598
  };
1599
+ var runRequiredSandboxHook = (sandbox, command, cwd, sudo) => Effect.flatMap(
1600
+ sandbox.exec(command, { cwd, sudo }),
1601
+ (result3) => result3.exitCode === 0 ? Effect.succeed(result3) : Effect.fail(
1602
+ new Error(
1603
+ `Sandbox setup failed (exit ${result3.exitCode}): ${command}
1604
+ ${result3.stderr}`
1605
+ )
1606
+ )
1607
+ );
1599
1608
  var buildSandboxHandle = (ctx, close) => {
1600
1609
  const {
1601
1610
  branch,
@@ -2004,10 +2013,12 @@ var createSandboxFromWorktree = async (options) => {
2004
2013
  `git config --global --add safe.directory ${shellQuote(sandboxRepoDir)}`
2005
2014
  );
2006
2015
  const sandboxEffects = (sandboxOnReady ?? []).map(
2007
- (hook) => sandbox.exec(hook.command, {
2008
- cwd: sandboxRepoDir,
2009
- sudo: hook.sudo
2010
- })
2016
+ (hook) => runRequiredSandboxHook(
2017
+ sandbox,
2018
+ hook.command,
2019
+ sandboxRepoDir,
2020
+ hook.sudo
2021
+ )
2011
2022
  );
2012
2023
  const allEffects = [...sandboxEffects];
2013
2024
  if (hostOnReady?.length) {
@@ -2016,7 +2027,12 @@ var createSandboxFromWorktree = async (options) => {
2016
2027
  yield* Effect.all(allEffects, {
2017
2028
  concurrency: "unbounded"
2018
2029
  });
2019
- })
2030
+ }).pipe(
2031
+ Effect.onError(
2032
+ () => providerHandle ? Effect.promise(() => providerHandle.close().catch(() => {
2033
+ })) : Effect.void
2034
+ )
2035
+ )
2020
2036
  );
2021
2037
  }
2022
2038
  const applyToHost = isIsolated && providerHandle ? () => syncOut(worktreePath, providerHandle) : () => Effect.void;
@@ -2133,10 +2149,12 @@ var createSandbox = async (options) => {
2133
2149
  `git config --global --add safe.directory ${shellQuote(sandboxRepoDir2)}`
2134
2150
  );
2135
2151
  const sandboxEffects = (sandboxOnReady ?? []).map(
2136
- (hook) => sandbox2.exec(hook.command, {
2137
- cwd: sandboxRepoDir2,
2138
- sudo: hook.sudo
2139
- })
2152
+ (hook) => runRequiredSandboxHook(
2153
+ sandbox2,
2154
+ hook.command,
2155
+ sandboxRepoDir2,
2156
+ hook.sudo
2157
+ )
2140
2158
  );
2141
2159
  const allEffects = [...sandboxEffects];
2142
2160
  if (hostOnReady?.length) {