@bendyline/gilde 0.1.53 → 0.1.55

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 (34) hide show
  1. package/authoring/chat-models/qwen3.5-27b-q4.json +147 -0
  2. package/authoring/gstack/evals/cso.json +21 -18
  3. package/authoring/gstack/evals/investigate.json +25 -22
  4. package/authoring/gstack/evals/plan-ceo-review.json +19 -16
  5. package/authoring/gstack/overlays/retro.json +2 -2
  6. package/authoring/gstack/wave.json +2 -2
  7. package/data/chat-models/index.json +1 -1
  8. package/data/chat-models/qw/qwen3.5-27b-q4/manifest.json +217 -0
  9. package/data/chat-models/qw/qwen3.5-27b-q4/versions/1.0.0/manifest.json +90 -0
  10. package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.7/craftbook.json +620 -0
  11. package/data/craftbook-templates/br/browser-qa-audit/versions/2.0.7/test.json +376 -0
  12. package/data/craftbook-templates/de/design-system-consultation/versions/2.0.7/craftbook.json +616 -0
  13. package/data/craftbook-templates/de/design-system-consultation/versions/2.0.7/test.json +201 -0
  14. package/data/craftbook-templates/en/engineering-retrospective/versions/2.0.7/craftbook.json +566 -0
  15. package/data/craftbook-templates/en/engineering-retrospective/versions/2.0.7/test.json +191 -0
  16. package/data/craftbook-templates/ex/executive-level-review/versions/2.0.7/craftbook.json +595 -0
  17. package/data/craftbook-templates/ex/executive-level-review/versions/2.0.7/test.json +139 -0
  18. package/data/craftbook-templates/id/idea-office-hours/versions/2.0.7/craftbook.json +566 -0
  19. package/data/craftbook-templates/id/idea-office-hours/versions/2.0.7/test.json +141 -0
  20. package/data/craftbook-templates/index.json +1 -1
  21. package/data/craftbook-templates/pl/plan/versions/1.0.2/craftbook.json +222 -0
  22. package/data/craftbook-templates/pl/plan/versions/1.0.2/test.json +91 -0
  23. package/data/craftbook-templates/ro/root-cause-investigation/versions/2.0.7/craftbook.json +595 -0
  24. package/data/craftbook-templates/ro/root-cause-investigation/versions/2.0.7/test.json +157 -0
  25. package/data/craftbook-templates/se/security-architecture-review/versions/2.0.7/craftbook.json +597 -0
  26. package/data/craftbook-templates/se/security-architecture-review/versions/2.0.7/test.json +157 -0
  27. package/data/craftbook-templates/sh/ship/versions/1.1.2/craftbook.json +346 -0
  28. package/data/craftbook-templates/sh/ship/versions/1.1.2/test.json +228 -0
  29. package/data/craftbook-templates/sp/spec-authoring/versions/2.0.7/craftbook.json +599 -0
  30. package/data/craftbook-templates/sp/spec-authoring/versions/2.0.7/test.json +162 -0
  31. package/data/craftbook-templates/te/technical-documentation/versions/2.0.7/craftbook.json +577 -0
  32. package/data/craftbook-templates/te/technical-documentation/versions/2.0.7/test.json +174 -0
  33. package/package.json +1 -1
  34. package/schemas/craftbook-test.schema.json +7 -1
@@ -0,0 +1,157 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "title": "Security Architecture Review — admin export surface",
4
+ "objective": "Exercise the Security Architecture Review craftbook against a self-contained service slice and require a prioritized, evidence-linked report that includes both confirmed vulnerabilities and working controls.",
5
+ "tags": [
6
+ "workflow",
7
+ "security",
8
+ "architecture-review",
9
+ "typescript"
10
+ ],
11
+ "prompt": "Use the Security Architecture Review craftbook to review the seeded service slice. This is report-only: do not modify source files. Model assets, actors, trust boundaries, and data flows; audit authorization, command/SQL construction, secrets handling, and relevant common vulnerability classes. Produce the scope and findings register, then write `tasks/eval/security/security-architecture-review.md`. Every confirmed finding must name severity, confidence, concrete workspace evidence, exploit preconditions, impact, and a specific remediation plus verification. Include working controls and rejected hypotheses. Do not invent CVEs, dependency versions, scans, or tests you did not run, and do not reproduce the example secret value in the report.",
12
+ "setup": {
13
+ "projectName": "Admin export security review",
14
+ "about": "A hermetic source-review fixture. No network or dependency lookup is needed or authorized; conclusions must come from seeded files.",
15
+ "missionObjectives": "Deliver an actionable risk posture that distinguishes confirmed source defects, positive controls, and unverified areas without changing implementation.",
16
+ "managedWorkspaceWritePolicy": "deny",
17
+ "files": [
18
+ {
19
+ "path": "docs/architecture.md",
20
+ "content": "# Service slice\n\nAn authenticated HTTP handler receives an export name and email filter from a browser operated by support staff. The handler calls local process and database adapters. `requireUser` is the shared authentication boundary. Only administrators should reach backup export; ordinary authenticated users may search their own customer records. Deployment injects `SESSION_SECRET` from environment configuration.\n"
21
+ },
22
+ {
23
+ "path": "src/auth.ts",
24
+ "content": "export interface User { id: string; role: 'member' | 'admin' }\n\nexport function requireUser(value: User | undefined): User {\n if (!value) throw new Error('unauthorized');\n return value;\n}\n\nexport function requireAdmin(user: User): void {\n if (user.role !== 'admin') throw new Error('forbidden');\n}\n"
25
+ },
26
+ {
27
+ "path": "src/admin-export.ts",
28
+ "content": "import { exec } from 'node:child_process';\nimport type { User } from './auth.js';\nimport { requireAdmin, requireUser } from './auth.js';\n\nexport function exportBackup(currentUser: User | undefined, requestedName: string): void {\n const user = requireUser(currentUser);\n requireAdmin(user);\n exec(`tar -czf backups/${requestedName}.tgz data/`);\n}\n"
29
+ },
30
+ {
31
+ "path": "src/customer-search.ts",
32
+ "content": "export interface Db { query(sql: string): Promise<unknown[]> }\n\nexport function findCustomerByEmail(db: Db, email: string): Promise<unknown[]> {\n return db.query(`SELECT id, email FROM customers WHERE email = '${email}'`);\n}\n"
33
+ },
34
+ {
35
+ "path": "src/safe-audit-log.ts",
36
+ "content": "export interface AuditSink { write(event: { actorId: string; action: string; target: string }): void }\n\nexport function recordExport(sink: AuditSink, actorId: string, target: string): void {\n sink.write({ actorId, action: 'backup.exported', target });\n}\n"
37
+ },
38
+ {
39
+ "path": "config/example.env",
40
+ "content": "# Example only; deployment replaces this value\nSESSION_SECRET=local-dev-only-not-a-real-secret\n"
41
+ }
42
+ ],
43
+ "craftbookParams": {
44
+ "workPath": "tasks/eval"
45
+ }
46
+ },
47
+ "mocks": [],
48
+ "success": {
49
+ "summary": "The named craftbook produces a source-grounded risk posture with prioritized findings, positive controls, remediation, verification, and terminal task evidence.",
50
+ "deliverables": [
51
+ {
52
+ "path": "tasks/eval/security/security-architecture-review.md",
53
+ "kind": "security-report",
54
+ "artifact": true,
55
+ "minBytes": 1700,
56
+ "checks": [
57
+ {
58
+ "kind": "contains",
59
+ "file": "tasks/eval/security/security-architecture-review.md",
60
+ "pattern": "^#{1,3}\\s+Executive risk posture\\b[\\s\\S]*^#{1,3}\\s+What is working\\b[\\s\\S]*^#{1,3}\\s+Prioritized findings\\b[\\s\\S]*^#{1,3}\\s+Remediation plan\\b[\\s\\S]*^#{1,3}\\s+Verification\\b[\\s\\S]*^#{1,3}\\s+Unverified areas\\b",
61
+ "flags": "im",
62
+ "label": "complete security-review structure"
63
+ },
64
+ {
65
+ "kind": "contains",
66
+ "file": "tasks/eval/security/security-architecture-review.md",
67
+ "pattern": "(command injection|shell injection)[\\s\\S]{0,500}src/admin-export\\.ts[\\s\\S]*(severity)[\\s\\S]*(confidence)",
68
+ "flags": "is",
69
+ "label": "command-injection finding with evidence metadata"
70
+ },
71
+ {
72
+ "kind": "contains",
73
+ "file": "tasks/eval/security/security-architecture-review.md",
74
+ "pattern": "(SQL injection|parameteri[sz]ed quer)[\\s\\S]{0,500}src/customer-search\\.ts",
75
+ "flags": "is",
76
+ "label": "SQL-injection finding and remediation"
77
+ },
78
+ {
79
+ "kind": "contains",
80
+ "file": "tasks/eval/security/security-architecture-review.md",
81
+ "pattern": "(requireUser|requireAdmin)[\\s\\S]{0,300}(working|control|authorization|authentication)[\\s\\S]*(safe-audit-log|audit)",
82
+ "flags": "is",
83
+ "label": "positive auth and audit controls"
84
+ },
85
+ {
86
+ "kind": "citationsResolve",
87
+ "file": "tasks/eval/security/security-architecture-review.md",
88
+ "minCitations": 4
89
+ },
90
+ {
91
+ "kind": "notContains",
92
+ "file": "tasks/eval/security/security-architecture-review.md",
93
+ "pattern": "CVE-\\d{4}-\\d+",
94
+ "label": "no invented CVEs"
95
+ },
96
+ {
97
+ "kind": "notContains",
98
+ "file": "tasks/eval/security/security-architecture-review.md",
99
+ "pattern": "local-dev-only-not-a-real-secret",
100
+ "label": "example secret value is not reproduced"
101
+ }
102
+ ]
103
+ }
104
+ ],
105
+ "taskNotes": {
106
+ "minBytes": 180,
107
+ "checks": [
108
+ {
109
+ "kind": "contains",
110
+ "file": "task-notes.md",
111
+ "pattern": "\\bDONE\\b[\\s\\S]*tasks/eval/security/security-architecture-review\\.md[\\s\\S]*(command|SQL)",
112
+ "flags": "i",
113
+ "label": "terminal note records report and principal risks"
114
+ }
115
+ ],
116
+ "requireCraftbookTask": true
117
+ },
118
+ "taskGraph": {
119
+ "requireCraftbookTask": true,
120
+ "requireTerminalStep": true
121
+ },
122
+ "unchangedFixtures": [
123
+ "docs/architecture.md",
124
+ "src/auth.ts",
125
+ "src/admin-export.ts",
126
+ "src/customer-search.ts",
127
+ "src/safe-audit-log.ts",
128
+ "config/example.env"
129
+ ]
130
+ },
131
+ "rubric": {
132
+ "artifact": {
133
+ "path": "tasks/eval/security/security-architecture-review.md",
134
+ "kind": "markdown"
135
+ },
136
+ "axes": [
137
+ {
138
+ "name": "Threat-model coverage",
139
+ "description": "The report connects assets, actors, trust boundaries, privileges, and data flows to the reviewed attack surface."
140
+ },
141
+ {
142
+ "name": "Finding rigor",
143
+ "description": "Confirmed findings cite exact source evidence, state preconditions and impact, and calibrate severity and confidence without overclaiming."
144
+ },
145
+ {
146
+ "name": "Remediation utility",
147
+ "description": "Recommendations are prioritized, source-specific, verifiable, and preserve or strengthen the controls that already work."
148
+ }
149
+ ],
150
+ "contextNote": "No live dependency or dynamic scan is part of this hermetic source-review scenario; the report should say so."
151
+ },
152
+ "qualityFocus": [
153
+ "Both injection paths are found and tied to exact source",
154
+ "Working authentication, authorization, and audit controls are recognized",
155
+ "Unverified areas and evidence limits are explicit"
156
+ ]
157
+ }
@@ -0,0 +1,346 @@
1
+ {
2
+ "id": "ship",
3
+ "name": "Ship",
4
+ "description": "End-to-end release procedure for an already-published feature branch. Six normal\nsteps + one halt step the branches divert to on failure:\n\n1. **Preflight** — verify branch, clean tree, upstream, and commit scope\n2. **Run tests** — project's primary test command\n3. **Self-review pass** — last walk through the published diff\n4. **Open PR** — create the PR from the published branch\n5. **Wait for CI** — poll until green or failure\n6. **Summary** — final DONE\n7. **Halt** (branched target) — DONE_WITH_CONCERNS on any failure\n\nThe branches are the load-bearing piece. If tests fail, PR creation fails,\nCI fails, or the poll times out, the recipe routes to `halt` rather than\nblasting through. The upstream procedure encoded that safety property in\nimperative if/else; the craftbook schema makes it explicit.\n\nScripts:\n- `run-tests.ts` — wraps `run_package_script` with the right test command\n- `open-pr.ts` — calls `github_pr_create` for the already-published branch\n- `wait-checks.ts` — polls `github_check_status` until settled\n\n## Applicability\n\nThe craftbook declares two manifest-level `requirements` so the launcher\nand command registry only offer it where it can actually run:\n\n- **github** — the project must be connected to a GitHub repo (the\n `open-pr` and `wait-checks` scripts call `github_pr_create` /\n `github_check_status` directly; without a connected repo they cannot\n create or observe the pull request).\n- **non-main-branch** — the project's checkout must be on a branch\n other than `main` / `master`. Preflight re-checks this snapshot, requires\n a clean tree and an existing upstream, and stops instead of inventing a\n push capability when the branch has not yet been published.\n\nRequires the github toolset configured. Both gates evaluate via\n`unmetCraftbookRequirements` in `@bendyline/gezel` and are surfaced\nthrough `/api/projects/:id/craftbooks` so the Commands panel hides the\ncraftbook in projects that do not qualify rather than letting the user\nlaunch it and watch PR creation fail.\n",
5
+ "basedOn": {
6
+ "name": "gstack",
7
+ "url": "https://github.com/garrytan/gstack"
8
+ },
9
+ "entryStepId": "preflight",
10
+ "triggers": [
11
+ "ship this",
12
+ "ship it",
13
+ "open a pr",
14
+ "open the pr",
15
+ "release this"
16
+ ],
17
+ "requirements": [
18
+ {
19
+ "kind": "github"
20
+ },
21
+ {
22
+ "kind": "non-main-branch"
23
+ }
24
+ ],
25
+ "paramSchema": {
26
+ "type": "object",
27
+ "properties": {
28
+ "branch": {
29
+ "type": "string",
30
+ "title": "Published source branch",
31
+ "description": "Exact non-main branch to ship. It must already exist on the connected GitHub remote; preflight verifies the checkout and upstream before any PR is created."
32
+ }
33
+ },
34
+ "required": [
35
+ "branch"
36
+ ]
37
+ },
38
+ "steps": [
39
+ {
40
+ "id": "preflight",
41
+ "name": "Preflight",
42
+ "description": "Confirm the working tree is shippable: the checked-out branch matches the requested branch, has an upstream, is clean, and contains the intended commits.",
43
+ "prompt": "Before creating a pull request, verify the exact state with read-only repository tools:\n\n1. Call `run_git({ subcommand: \"status\", args: [\"--short\", \"--branch\"] })` and confirm the checked-out branch is exactly `{{branch}}`, is not `main`/`master`, and has no uncommitted changes.\n2. Call `run_git({ subcommand: \"rev-parse\", args: [\"--abbrev-ref\", \"--symbolic-full-name\", \"@{upstream}\"] })` to prove the branch is already published. This craftbook creates a PR but does not push.\n3. Call `run_git({ subcommand: \"log\", args: [\"-n\", \"10\", \"--oneline\", \"--decorate\"] })` and confirm the recent commits match the intended scope.\n\nIf the branch is wrong, dirty, on trunk, missing an upstream, or contains unexpected commits, write the exact blocker to task notes and report DONE_WITH_CONCERNS without advancing. Otherwise write the verified branch, upstream, clean status, ahead/behind state, and commit scope to task notes, then advance.",
44
+ "suggestedRole": "developer",
45
+ "next": "run-tests",
46
+ "toolPolicy": {
47
+ "disallowBuiltinToolsets": [
48
+ "ai-apps",
49
+ "archives",
50
+ "artifacts",
51
+ "audio",
52
+ "browser-automation",
53
+ "code-execution",
54
+ "craftbooks",
55
+ "data-tables",
56
+ "entity-intel",
57
+ "image-intel",
58
+ "images",
59
+ "role-delegation",
60
+ "role-delegation-escalation",
61
+ "security-intel",
62
+ "team-management",
63
+ "videos",
64
+ "web",
65
+ "workspace-fs-write"
66
+ ],
67
+ "outputMedium": "task-note"
68
+ }
69
+ },
70
+ {
71
+ "id": "run-tests",
72
+ "name": "Run tests",
73
+ "description": "Run the project's test command. Branches on failure to a triage step; on success advances to the review pass.",
74
+ "prompt": "Advance this step to execute its `run-tests` on-exit script exactly once. The script picks the project's primary test command and returns `{ passed: boolean, summary: string }`; the task routes automatically to self-review on success or to the halt step on failure. Do not call the script manually. If the task routes to halt, report DONE_WITH_CONCERNS with the recorded test failure and let the user fix it before re-running the craftbook.",
75
+ "suggestedRole": "developer",
76
+ "onExit": {
77
+ "name": "run-tests",
78
+ "autoAdvanceWhen": {
79
+ "op": "equals",
80
+ "field": "passed",
81
+ "value": true
82
+ }
83
+ },
84
+ "next": "review-pass",
85
+ "branches": [
86
+ {
87
+ "when": {
88
+ "op": "equals",
89
+ "field": "passed",
90
+ "value": false
91
+ },
92
+ "goto": "halt"
93
+ },
94
+ {
95
+ "when": {
96
+ "op": "exists",
97
+ "field": "passed",
98
+ "negate": true
99
+ },
100
+ "goto": "halt"
101
+ }
102
+ ],
103
+ "toolPolicy": {
104
+ "disallowBuiltinToolsets": [
105
+ "ai-apps",
106
+ "archives",
107
+ "artifacts",
108
+ "audio",
109
+ "browser-automation",
110
+ "craftbooks",
111
+ "data-tables",
112
+ "entity-intel",
113
+ "git",
114
+ "image-intel",
115
+ "images",
116
+ "role-delegation",
117
+ "role-delegation-escalation",
118
+ "security-intel",
119
+ "team-management",
120
+ "videos",
121
+ "web",
122
+ "workspace-fs-write"
123
+ ],
124
+ "outputMedium": "task-note"
125
+ }
126
+ },
127
+ {
128
+ "id": "review-pass",
129
+ "name": "Self-review pass",
130
+ "description": "Walk your own diff before opening the PR. Last chance to catch obvious mistakes.",
131
+ "prompt": "Call `run_git({ subcommand: \"diff\", args: [\"@{upstream}...\"] })` and review the exact change set that will enter the pull request. Look for:\n\n- Debug prints or console logging left in\n- Commented-out code\n- Filenames that do not match the intended rename\n- Tests or migrations missing from the published branch\n- Changes outside the stated scope\n\nIf anything is wrong, write the concrete findings to task notes and report DONE_WITH_CONCERNS without advancing; the user must correct, commit, and publish the branch before rerunning. If the diff is clean, record that verdict in task notes and advance.",
132
+ "suggestedRole": "reviewer",
133
+ "next": "open-pr",
134
+ "toolPolicy": {
135
+ "disallowBuiltinToolsets": [
136
+ "ai-apps",
137
+ "archives",
138
+ "artifacts",
139
+ "audio",
140
+ "browser-automation",
141
+ "code-execution",
142
+ "craftbooks",
143
+ "data-tables",
144
+ "entity-intel",
145
+ "image-intel",
146
+ "images",
147
+ "role-delegation",
148
+ "role-delegation-escalation",
149
+ "security-intel",
150
+ "team-management",
151
+ "videos",
152
+ "web",
153
+ "workspace-fs-write"
154
+ ],
155
+ "outputMedium": "task-note"
156
+ }
157
+ },
158
+ {
159
+ "id": "open-pr",
160
+ "name": "Open PR",
161
+ "description": "Open a pull request for the already-published branch.",
162
+ "prompt": "Advance this step to execute its `open-pr` on-exit script exactly once for the verified `{{branch}}` branch. The script calls `github_pr_create`; it does not push. The task advances only when the script returns a PR URL and otherwise routes to the halt step. Do not call the script manually or retry a failed creation blindly.",
163
+ "suggestedRole": "developer",
164
+ "onExit": {
165
+ "name": "open-pr",
166
+ "inputs": {
167
+ "head": "{{branch}}"
168
+ },
169
+ "autoAdvanceWhen": {
170
+ "op": "exists",
171
+ "field": "url"
172
+ }
173
+ },
174
+ "next": "wait-checks",
175
+ "branches": [
176
+ {
177
+ "when": {
178
+ "op": "exists",
179
+ "field": "url",
180
+ "negate": true
181
+ },
182
+ "goto": "halt"
183
+ }
184
+ ],
185
+ "toolPolicy": {
186
+ "disallowBuiltinToolsets": [
187
+ "ai-apps",
188
+ "archives",
189
+ "artifacts",
190
+ "audio",
191
+ "browser-automation",
192
+ "craftbooks",
193
+ "data-tables",
194
+ "entity-intel",
195
+ "image-intel",
196
+ "images",
197
+ "role-delegation",
198
+ "role-delegation-escalation",
199
+ "security-intel",
200
+ "team-management",
201
+ "videos",
202
+ "web",
203
+ "workspace-fs-write"
204
+ ],
205
+ "outputMedium": "none"
206
+ }
207
+ },
208
+ {
209
+ "id": "wait-checks",
210
+ "name": "Wait for CI",
211
+ "description": "Poll workflow runs / check status until the gate is green or fails.",
212
+ "prompt": "Advance this step to execute its `wait-checks` on-exit script exactly once for `{{branch}}` with the default ten-minute timeout. It polls `github_check_status` until the state settles. Do not call the script manually. The task routes automatically to summary on success and to halt on failure, timeout, or a missing result.",
213
+ "suggestedRole": "developer",
214
+ "onExit": {
215
+ "name": "wait-checks",
216
+ "inputs": {
217
+ "ref": "{{branch}}"
218
+ },
219
+ "autoAdvanceWhen": {
220
+ "op": "equals",
221
+ "field": "state",
222
+ "value": "success"
223
+ }
224
+ },
225
+ "next": "summary",
226
+ "branches": [
227
+ {
228
+ "when": {
229
+ "op": "equals",
230
+ "field": "state",
231
+ "value": "failure"
232
+ },
233
+ "goto": "halt"
234
+ },
235
+ {
236
+ "when": {
237
+ "op": "equals",
238
+ "field": "state",
239
+ "value": "timeout"
240
+ },
241
+ "goto": "halt"
242
+ },
243
+ {
244
+ "when": {
245
+ "op": "exists",
246
+ "field": "state",
247
+ "negate": true
248
+ },
249
+ "goto": "halt"
250
+ }
251
+ ],
252
+ "toolPolicy": {
253
+ "disallowBuiltinToolsets": [
254
+ "ai-apps",
255
+ "archives",
256
+ "artifacts",
257
+ "audio",
258
+ "browser-automation",
259
+ "craftbooks",
260
+ "data-tables",
261
+ "entity-intel",
262
+ "image-intel",
263
+ "images",
264
+ "role-delegation",
265
+ "role-delegation-escalation",
266
+ "security-intel",
267
+ "team-management",
268
+ "videos",
269
+ "web",
270
+ "workspace-fs-write"
271
+ ],
272
+ "outputMedium": "task-note"
273
+ }
274
+ },
275
+ {
276
+ "id": "summary",
277
+ "name": "Summary",
278
+ "description": "Stamp a final summary. PR opened, CI green, ready to merge.",
279
+ "prompt": "Write a one-paragraph DONE summary: PR number, URL, scope (one line), test result, CI verdict. Save to task notes. Report DONE.",
280
+ "suggestedRole": "developer",
281
+ "terminal": true,
282
+ "toolPolicy": {
283
+ "disallowBuiltinToolsets": [
284
+ "ai-apps",
285
+ "archives",
286
+ "artifacts",
287
+ "audio",
288
+ "browser-automation",
289
+ "code-execution",
290
+ "craftbooks",
291
+ "data-tables",
292
+ "entity-intel",
293
+ "image-intel",
294
+ "images",
295
+ "role-delegation",
296
+ "role-delegation-escalation",
297
+ "security-intel",
298
+ "team-management",
299
+ "videos",
300
+ "web",
301
+ "workspace-fs-write"
302
+ ],
303
+ "outputMedium": "none"
304
+ }
305
+ },
306
+ {
307
+ "id": "halt",
308
+ "name": "Halted",
309
+ "description": "Something blocked the ship — tests, CI, or push. Report DONE_WITH_CONCERNS.",
310
+ "prompt": "Report DONE_WITH_CONCERNS with the specific failure surfaced upstream. Do not retry, do not push past — the user needs to see this and decide.",
311
+ "suggestedRole": "developer",
312
+ "terminal": true,
313
+ "toolPolicy": {
314
+ "disallowBuiltinToolsets": [
315
+ "ai-apps",
316
+ "archives",
317
+ "artifacts",
318
+ "audio",
319
+ "browser-automation",
320
+ "code-execution",
321
+ "craftbooks",
322
+ "data-tables",
323
+ "entity-intel",
324
+ "git",
325
+ "image-intel",
326
+ "images",
327
+ "role-delegation",
328
+ "role-delegation-escalation",
329
+ "security-intel",
330
+ "team-management",
331
+ "videos",
332
+ "web",
333
+ "workspace-fs-write"
334
+ ],
335
+ "outputMedium": "none"
336
+ }
337
+ }
338
+ ],
339
+ "scripts": {
340
+ "run-tests": "import { defineScript, gezel } from '@bendyline/gezel-sdk';\n\nexport const meta = defineScript({\n name: 'run-tests',\n description:\n 'Run the project test command via run_package_script. Stamps {passed: boolean, summary: string}.',\n inputs: {\n scriptName: {\n type: 'string',\n description: 'Override the npm script name. Defaults to \"test\".',\n default: 'test',\n },\n },\n outputs: {\n passed: { type: 'boolean', description: 'True iff the test command exited 0.' },\n summary: { type: 'string', description: 'Last ~2KB of stdout/stderr.' },\n },\n requires: ['workspace.read'],\n});\n\ninterface PackageScriptResult {\n exitCode: number;\n stdout?: string;\n stderr?: string;\n}\n\nasync function main(): Promise<void> {\n const input = gezel.input as { scriptName?: string };\n const scriptName = input.scriptName ?? 'test';\n const raw = await gezel.mcp.call('run_package_script', { script: scriptName });\n let parsed: PackageScriptResult | null = null;\n if (typeof raw === 'string') {\n try {\n parsed = JSON.parse(raw) as PackageScriptResult;\n } catch {\n // The MCP tool returns a text blob, not always JSON. We treat\n // \"non-zero exit code\" / \"failed\" / \"FAIL \" markers as failure.\n }\n }\n const text = typeof raw === 'string' ? raw : JSON.stringify(raw);\n const looksFailed =\n parsed?.exitCode !== undefined\n ? parsed.exitCode !== 0\n : /(?:^|\\b)(?:fail|error|exit code [1-9]|✗)\\b/i.test(text);\n const tail = text.length > 2048 ? text.slice(-2048) : text;\n gezel.log(`pnpm ${scriptName}: ${looksFailed ? 'failed' : 'passed'}`);\n gezel.output({ passed: !looksFailed, summary: tail });\n}\n\nawait main();\n",
341
+ "open-pr": "import { defineScript, gezel } from '@bendyline/gezel-sdk';\n\nexport const meta = defineScript({\n name: 'open-pr',\n description:\n 'Open a pull request for the current branch via the GitHub MCP tools. Stamps {number, url} on success.',\n inputs: {\n title: { type: 'string', description: 'PR title. Falls back to a derived placeholder.' },\n body: { type: 'string', description: 'PR body. Markdown.' },\n head: {\n type: 'string',\n description: 'Source branch. Defaults to the current branch (caller must resolve).',\n required: true,\n },\n base: { type: 'string', description: 'Target branch.', default: 'main' },\n draft: { type: 'boolean', description: 'Open as draft.', default: false },\n },\n outputs: {\n number: { type: 'number', description: 'Created PR number.' },\n url: { type: 'string', description: 'PR URL.' },\n },\n requires: ['network'],\n});\n\nasync function main(): Promise<void> {\n const input = gezel.input as {\n title?: string;\n body?: string;\n head: string;\n base?: string;\n draft?: boolean;\n };\n const title = input.title ?? `Ship: ${input.head}`;\n const args: Record<string, unknown> = {\n title,\n head: input.head,\n base: input.base ?? 'main',\n };\n if (input.body) args.body = input.body;\n if (input.draft !== undefined) args.draft = input.draft;\n const raw = await gezel.mcp.call('github_pr_create', args);\n const text = typeof raw === 'string' ? raw : '';\n const m = /Opened PR #(\\d+) — (\\S+)/.exec(text);\n if (!m) {\n throw new Error(`unexpected github_pr_create response: ${text.slice(0, 200)}`);\n }\n gezel.output({ number: Number(m[1]), url: m[2]! });\n}\n\nawait main();\n",
342
+ "wait-checks": "import { defineScript, gezel } from '@bendyline/gezel-sdk';\n\nexport const meta = defineScript({\n name: 'wait-checks',\n description:\n 'Poll github_check_status for a ref until it settles. Returns {state: success|failure|pending|timeout, checks[]}.',\n inputs: {\n ref: { type: 'string', description: 'Branch name or commit sha.', required: true },\n timeoutMs: {\n type: 'number',\n description: 'How long to wait before giving up.',\n default: 600_000,\n integer: true,\n },\n pollIntervalMs: {\n type: 'number',\n description: 'How long between polls.',\n default: 15_000,\n integer: true,\n },\n },\n outputs: {\n state: { type: 'string', description: 'Final state: success / failure / timeout.' },\n checks: { type: 'array', description: 'Per-check breakdown.', itemType: 'object' },\n },\n requires: ['network'],\n});\n\ninterface CheckBlock {\n name: string;\n status: string;\n conclusion: string | null;\n url?: string;\n}\n\nfunction parseChecks(text: string): { state: string; checks: CheckBlock[] } {\n const lines = text.split('\\n');\n const stateLine = lines[0] ?? '';\n const stateMatch = /^State:\\s*(\\w+)/i.exec(stateLine);\n const state = stateMatch?.[1]?.toLowerCase() ?? 'unknown';\n const checks: CheckBlock[] = [];\n for (let i = 1; i < lines.length; i++) {\n const m = /^• (.+?) — (\\S+?)(?:\\s*\\/\\s*(\\S+))?$/.exec(lines[i] ?? '');\n if (!m) continue;\n checks.push({\n name: m[1]!,\n status: m[2]!,\n conclusion: m[3] ?? null,\n });\n }\n return { state, checks };\n}\n\nasync function main(): Promise<void> {\n const input = gezel.input as { ref: string; timeoutMs?: number; pollIntervalMs?: number };\n const deadline = Date.now() + (input.timeoutMs ?? 600_000);\n const poll = input.pollIntervalMs ?? 15_000;\n let lastState = 'unknown';\n let lastChecks: CheckBlock[] = [];\n while (Date.now() < deadline) {\n const raw = await gezel.mcp.call('github_check_status', { ref: input.ref });\n const text = typeof raw === 'string' ? raw : '';\n const parsed = parseChecks(text);\n lastState = parsed.state;\n lastChecks = parsed.checks;\n gezel.log(`checks for ${input.ref}: ${parsed.state} (${parsed.checks.length} check(s))`);\n if (parsed.state === 'success' || parsed.state === 'failure') {\n gezel.output({ state: parsed.state, checks: parsed.checks });\n return;\n }\n await new Promise((r) => setTimeout(r, poll));\n }\n gezel.output({ state: 'timeout', checks: lastChecks });\n}\n\nawait main();\n"
343
+ },
344
+ "version": "1.1.2",
345
+ "releasedAt": "2026-09-04T13:46:25Z"
346
+ }