@wemuda/launchrail 1.8.0 → 1.9.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.
package/assets/ralph.workflow.js
CHANGED
|
@@ -3,21 +3,23 @@
|
|
|
3
3
|
//
|
|
4
4
|
// The Ralph loop as a deterministic workflow: the plan, the frontier bookkeeping,
|
|
5
5
|
// and every intermediate report live in script variables — not in any context window —
|
|
6
|
-
// so long or wide runs cannot compact away their own state.
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// so long or wide runs cannot compact away their own state. This is the engine for
|
|
7
|
+
// every multi-ticket run (ADR-0022); the launch-ralph skill carries the same policy
|
|
8
|
+
// block as the supervisor's contract and the declared-exception watchable mode, and
|
|
9
|
+
// a policy change belongs in both places (ADR-0005, field-revised by ADR-0010, ADR-0022).
|
|
9
10
|
export const meta = {
|
|
10
11
|
name: 'ralph',
|
|
11
12
|
description: 'Autonomous Ralph loop: implement ready tickets with fresh-context subagents, verification-gated',
|
|
12
13
|
whenToUse:
|
|
13
|
-
'
|
|
14
|
+
'The engine for any multi-ticket Ralph run. Scope a run via args: { only: [9, 10], width: 2 }, just [9, 10], or { max: 5 } to stop after 5 verified merges ("the next five" — the frontier picks which, in dependency order). Declare the integration target with { target: "spec/44-mvp" } to consolidate the campaign onto that branch (default branch untouched; release later with one PR) — omit it to merge each ticket into the default branch. { canary: true } holds width at 1 until the first verified merge. Args must be JSON — resolve any natural-language scope to ticket numbers, a cap, and a target before launching. For a watchable run (an explicit user ask, or a targeted intervention), use the launch-ralph skill instead — and say why.',
|
|
14
15
|
phases: [
|
|
15
|
-
{ title: 'Preflight', detail: 'read project config,
|
|
16
|
+
{ title: 'Preflight', detail: 'read project config, resolve the integration target, run the verification gate' },
|
|
16
17
|
{ title: 'Graph', detail: 'list ready tickets and their blocking edges, verbatim' },
|
|
17
|
-
{ title: 'Build', detail: 'one fresh-context implementer per ticket,
|
|
18
|
+
{ title: 'Build', detail: 'one fresh-context implementer per ticket, handing off at PR-open' },
|
|
19
|
+
{ title: 'Gate', detail: 'per-ticket merge gate: CI wait, squash-merge, explicit close' },
|
|
18
20
|
{ title: 'Verify', detail: 'remote ground truth for every claimed merge' },
|
|
19
21
|
{ title: 'Park', detail: 'comment failure history, label needs-info' },
|
|
20
|
-
{ title: 'Release', detail: 'final verification gate and
|
|
22
|
+
{ title: 'Release', detail: 'final verification gate and the where-it-lives recap' },
|
|
21
23
|
],
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -52,8 +54,17 @@ const POLICY = {
|
|
|
52
54
|
max: A.max ?? 0,
|
|
53
55
|
// Parallel implementers. Width also caps local build concurrency — several implementers
|
|
54
56
|
// share one machine, and fanning out test runs buys backpressure, not speed. Use 1 until
|
|
55
|
-
// a run has landed tickets cleanly on this project
|
|
57
|
+
// a run has landed tickets cleanly on this project — or pass canary: true, which does it
|
|
58
|
+
// for you. Tickets that add DB migrations collide on the next migration number when run
|
|
59
|
+
// in parallel; the pre-PR sync renumbers, but serializing them is cheaper.
|
|
56
60
|
width: A.width ?? 3,
|
|
61
|
+
// Integration target: '' (trunk) merges each ticket PR into the default branch; a branch
|
|
62
|
+
// name consolidates the whole campaign onto that branch and never touches the default
|
|
63
|
+
// branch — the run ends by offering ONE release PR target -> default (ADR-0022).
|
|
64
|
+
target: A.target ?? '',
|
|
65
|
+
// Canary: hold width at 1 until the run's first verified merge proves the plumbing
|
|
66
|
+
// end to end (branch, PR, CI, merge gate, close). For a project's first campaign.
|
|
67
|
+
canary: A.canary ?? false,
|
|
57
68
|
// Tries per ticket: 1 attempt + 1 retry with a fresh context, then park. Deferrals
|
|
58
69
|
// (a declared blocker had not landed yet) hand their attempt back, capped separately.
|
|
59
70
|
attempts: A.attempts ?? 2,
|
|
@@ -84,12 +95,14 @@ where it left off — do not start over. Never open a second PR for the same tic
|
|
|
84
95
|
const PREFLIGHT_SCHEMA = {
|
|
85
96
|
type: 'object',
|
|
86
97
|
additionalProperties: false,
|
|
87
|
-
required: ['green', 'base', 'trackerAccess', 'verifyCommand', 'localCommands', 'failures'],
|
|
98
|
+
required: ['green', 'base', 'defaultBranch', 'trackerAccess', 'verifyCommand', 'localCommands', 'failures'],
|
|
88
99
|
properties: {
|
|
89
100
|
green: { type: 'boolean', description: 'base is synced and the verification gate passed' },
|
|
90
101
|
headSha: { type: 'string', description: 'commit sha the gate ran against' },
|
|
91
102
|
repo: { type: 'string', description: 'owner/name from the git remote, or empty' },
|
|
92
|
-
base: { type: 'string', description: 'default branch
|
|
103
|
+
base: { type: 'string', description: "the run's integration base: the declared target branch when one is set, else the default branch" },
|
|
104
|
+
defaultBranch: { type: 'string', description: 'the repository default branch name' },
|
|
105
|
+
targetCreated: { type: 'boolean', description: 'true when a declared target branch was missing from the remote and was created from the default branch tip' },
|
|
93
106
|
issueTracker: { type: 'string', description: 'issueTracker from .launchrail.yml (github | linear | none)' },
|
|
94
107
|
trackerAccess: {
|
|
95
108
|
type: 'string',
|
|
@@ -145,7 +158,9 @@ const BUILD_SCHEMA = {
|
|
|
145
158
|
properties: {
|
|
146
159
|
status: {
|
|
147
160
|
type: 'string',
|
|
148
|
-
enum: ['
|
|
161
|
+
enum: ['pr-open', 'merged', 'already-done', 'blocked', 'conflict', 'verify-failed', 'failed'],
|
|
162
|
+
description:
|
|
163
|
+
'"pr-open" is the normal hand-off (the loop owns CI and merge); "merged" only when an adopted PR turned out to be merged already (idempotency)',
|
|
149
164
|
},
|
|
150
165
|
pr: { type: 'integer', description: 'PR number, when one was opened or adopted' },
|
|
151
166
|
mergeCommit: { type: 'string' },
|
|
@@ -162,6 +177,24 @@ const BUILD_SCHEMA = {
|
|
|
162
177
|
},
|
|
163
178
|
}
|
|
164
179
|
|
|
180
|
+
const GATE_SCHEMA = {
|
|
181
|
+
type: 'object',
|
|
182
|
+
additionalProperties: false,
|
|
183
|
+
required: ['status', 'summary'],
|
|
184
|
+
properties: {
|
|
185
|
+
status: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
enum: ['merged', 'ci-failed', 'ci-timeout', 'not-mergeable', 'failed'],
|
|
188
|
+
},
|
|
189
|
+
mergeCommit: { type: 'string' },
|
|
190
|
+
issueClosed: { type: 'boolean' },
|
|
191
|
+
summary: {
|
|
192
|
+
type: 'string',
|
|
193
|
+
description: 'on merged: the API facts; on failure: the failing check or conflicting files, enough for a fresh implementer to act on',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
}
|
|
197
|
+
|
|
165
198
|
const VERIFY_SCHEMA = {
|
|
166
199
|
type: 'object',
|
|
167
200
|
additionalProperties: false,
|
|
@@ -211,24 +244,32 @@ Start clean: delete the failed ralph/${ticket.number}-* branch first, re-sync th
|
|
|
211
244
|
: ''
|
|
212
245
|
return `${preamble(pre)}
|
|
213
246
|
|
|
214
|
-
Implement ticket #${ticket.number} ("${ticket.title}")
|
|
247
|
+
Implement ticket #${ticket.number} ("${ticket.title}") through to an open PR. You own the build alone; assume no knowledge of any other session. Other implementers are working on other tickets against the same base right now, so ${pre.base} will move under you. That is expected.
|
|
215
248
|
${retry}
|
|
216
249
|
Steps, in order:
|
|
217
250
|
1. Dependency gate: before anything else, confirm every ticket on this ticket's "Blocked by" line is CLOSED with its work merged into ${pre.base}. If any blocker is still open, do NOT build on a missing dependency — report status "blocked", name the open blocker in "failure", and stop. That is a deferral, not a failure; the loop retries you after the blocker lands.
|
|
218
|
-
2. Read the ticket and everything it links (spec sections, ADRs, journeys). Report status "already-done" if
|
|
251
|
+
2. Read the ticket and everything it links (spec sections, ADRs, journeys). If the tracker tool truncates the body (long code spans are a known trigger), fetch the full text by another route — the tracker's search API, the spec file in the repo — and never implement from a truncated ticket. Report status "already-done" if the ticket is already closed.
|
|
219
252
|
3. Label the ticket ralph:building so a lost session leaves a trace.
|
|
220
253
|
4. Branch from a fresh sync of ${pre.base}: ralph/${ticket.number}-<short-slug>.
|
|
221
254
|
5. Implement by invoking the launch-ralph-implement skill — it owns the per-ticket contract: TDD, the verification gate, browser smoke for user-facing changes, self-review via /code-review, commit conventions.
|
|
222
|
-
6. Pre-PR sync: merge the latest ${pre.base} into your branch. Conflicts are ordinary work — resolve them with the launch-resolving-merge-conflicts skill
|
|
223
|
-
7. Open a PR titled from the ticket, with "Closes #${ticket.number}" in the body. Never open a second PR if one already exists — adopt it. Opening against an up-to-date base means CI tests the state that will actually land.
|
|
224
|
-
8. Wait for CI if the repository has it, spacing polls with the Monitor tool or a background sleep — never a foreground sleep, never a busy loop; treat ~20 minutes as the budget and report status "ci-timeout" beyond it. Fix what your branch broke and push. If a failure reproduces on ${pre.base} itself, report "ci-red" and stop — that is systemic, not this ticket's problem.
|
|
225
|
-
9. Immediately before merging, re-sync with ${pre.base} once more (retry up to 3 times if the base keeps moving), then squash-merge. Squash-merge does not reliably fire "Closes" — read the issue back, close it explicitly if it is still open, and remove the ralph:building label. Never push to ${pre.base} directly; the PR is the only door.
|
|
255
|
+
6. Pre-PR sync: merge the latest ${pre.base} into your branch. Conflicts are ordinary work — resolve them with the launch-resolving-merge-conflicts skill. If ${pre.base} gained DB migrations since you branched, regenerate yours to follow them with the project's migration tool — never hand-edit the migration journal. Re-run the verification gate if anything changed.
|
|
256
|
+
7. Open a PR against ${pre.base}, titled from the ticket, with "Closes #${ticket.number}" in the body. Never open a second PR if one already exists — adopt it. Opening against an up-to-date base means CI tests the state that will actually land. Then report status "pr-open" with the PR number and STOP: the CI wait, the merge, and the issue close belong to the loop's merge gate, not to you — a subagent cannot wait on CI (a background sleep will not resume you). Never push to ${pre.base} directly; the PR is the only door.
|
|
226
257
|
|
|
227
258
|
${INTEGRITY}
|
|
228
259
|
|
|
229
260
|
${IDEMPOTENCY}
|
|
230
261
|
|
|
231
|
-
Report honestly via the schema: "merged" only
|
|
262
|
+
Report honestly via the schema: "pr-open" once the PR exists against ${pre.base}; "merged" only when an adopted PR turned out to be already merged; "blocked" when a declared blocker had not landed; "verify-failed" when the verification gate would not go green; "conflict" when a conflict was too ambiguous to resolve without losing behavior (say which files and why); "failed" otherwise, with a summary a fresh retry can act on. List deliberately-out-of-scope discoveries in "punted".`
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function gatePrompt(pre, ticket, build) {
|
|
266
|
+
return `You are the merge gate for ticket #${ticket.number}: PR #${build.pr} is open against ${pre.base}.
|
|
267
|
+
Tracker access from this environment: ${pre.trackerAccess}
|
|
268
|
+
You own the CI wait, the squash-merge, and the tracker bookkeeping — and nothing else. You never write code, never push commits, never repair a failing branch; a failing PR is reported, not fixed here.
|
|
269
|
+
1. Wait for CI on the PR, if the repository has it. Space checks with the Monitor tool — NEVER a bare background sleep (it will not resume you) and never a busy loop. Treat ~20 minutes as the budget; beyond it report status "ci-timeout".
|
|
270
|
+
2. CI green (or absent): check mergeability against ${pre.base} — the base may have moved since CI started. Mergeable: squash-merge via the tracker API; if the base moves between check and merge, re-check and retry up to 3 times. A real conflict is status "not-mergeable" — name the conflicting files if the API reports them.
|
|
271
|
+
3. Merged: read issue #${ticket.number} back and close it explicitly if it is still open — "Closes #n" only auto-fires from the default branch${POLICY.target ? ', and this run does not merge there' : ', and squash-merge does not reliably fire it even there'} — then remove the ralph:building label. Report status "merged" with the merge commit sha.
|
|
272
|
+
4. CI failed on the PR: report status "ci-failed" with the failing check and a summary a fresh implementer can act on. Fix nothing.`
|
|
232
273
|
}
|
|
233
274
|
|
|
234
275
|
function verifyPrompt(pre, ticket, build) {
|
|
@@ -308,17 +349,39 @@ async function drive(pre, ticket) {
|
|
|
308
349
|
s.failures.push(`still blocked after ${s.defers} deferrals: ${build.failure ?? build.summary}`)
|
|
309
350
|
return { ticket, ok: false }
|
|
310
351
|
}
|
|
311
|
-
if (build.status !== 'merged') {
|
|
352
|
+
if (build.status !== 'pr-open' && build.status !== 'merged') {
|
|
312
353
|
s.failures.push(`[attempt ${s.attempts}] ${build.status}: ${build.failure ?? build.summary}`)
|
|
313
354
|
return { ticket, ok: false }
|
|
314
355
|
}
|
|
315
356
|
if (!build.pr) {
|
|
316
|
-
s.failures.push(`[attempt ${s.attempts}] reported
|
|
357
|
+
s.failures.push(`[attempt ${s.attempts}] reported ${build.status} but returned no PR number`)
|
|
317
358
|
return { ticket, ok: false }
|
|
318
359
|
}
|
|
360
|
+
let mergeCommit = build.mergeCommit
|
|
361
|
+
if (build.status === 'pr-open') {
|
|
362
|
+
// The loop owns the merge gate (ADR-0022): an implementer cannot wait on CI (a
|
|
363
|
+
// subagent's background sleep never resumes it), and a single gate owner keeps
|
|
364
|
+
// merge ordering sane. A failing gate hands the ticket back as a failed attempt;
|
|
365
|
+
// the fresh retry adopts the PR via the idempotency clause, repairs, hands off again.
|
|
366
|
+
const gate = await agent(gatePrompt(pre, ticket, build), {
|
|
367
|
+
label: `gate:#${ticket.number}`,
|
|
368
|
+
phase: 'Gate',
|
|
369
|
+
schema: GATE_SCHEMA,
|
|
370
|
+
effort: 'low',
|
|
371
|
+
})
|
|
372
|
+
if (!gate) {
|
|
373
|
+
s.failures.push('gate agent died (infrastructure)')
|
|
374
|
+
return { ticket, ok: false, dead: true }
|
|
375
|
+
}
|
|
376
|
+
if (gate.status !== 'merged') {
|
|
377
|
+
s.failures.push(`[attempt ${s.attempts}] PR #${build.pr} ${gate.status}: ${gate.summary}`)
|
|
378
|
+
return { ticket, ok: false }
|
|
379
|
+
}
|
|
380
|
+
mergeCommit = gate.mergeCommit || mergeCommit
|
|
381
|
+
}
|
|
319
382
|
// Nothing is trusted from a report — a claimed merge is checked against the remote
|
|
320
383
|
// by a separate, cheap agent with tracker access only.
|
|
321
|
-
const verdict = await agent(verifyPrompt(pre, ticket, build), {
|
|
384
|
+
const verdict = await agent(verifyPrompt(pre, ticket, { pr: build.pr, mergeCommit }), {
|
|
322
385
|
label: `verify:#${ticket.number}`,
|
|
323
386
|
phase: 'Verify',
|
|
324
387
|
schema: VERIFY_SCHEMA,
|
|
@@ -328,7 +391,7 @@ async function drive(pre, ticket) {
|
|
|
328
391
|
if (verdict?.merged && verdict.issueClosed) {
|
|
329
392
|
s.status = 'merged'
|
|
330
393
|
s.pr = build.pr
|
|
331
|
-
s.mergeCommit = verdict.mergeCommit ||
|
|
394
|
+
s.mergeCommit = verdict.mergeCommit || mergeCommit
|
|
332
395
|
return { ticket, ok: true }
|
|
333
396
|
}
|
|
334
397
|
// Merged-but-issue-open fails verification too: the retry adopts the merged PR (the
|
|
@@ -363,9 +426,13 @@ function frontier(tickets, closedBefore) {
|
|
|
363
426
|
// ---------------------------------------------------------------------------
|
|
364
427
|
phase('Preflight')
|
|
365
428
|
const pre = await agent(
|
|
366
|
-
`Preflight for a Ralph loop run in this repository.
|
|
429
|
+
`Preflight for a Ralph loop run in this repository. Report actual state; fix nothing — the one permitted mutation is creating the declared integration branch in step 2.
|
|
367
430
|
1. Read .launchrail.yml (issueTracker, testing commands, modules) and AGENTS.md (verbatim commands).
|
|
368
|
-
2. Identify the repo (git remote) and
|
|
431
|
+
2. Identify the repo (git remote) and its default branch; report the default branch name as defaultBranch. ${
|
|
432
|
+
POLICY.target
|
|
433
|
+
? `This run consolidates onto the integration branch "${POLICY.target}" — that branch is the base. If it does not exist on the remote, create it from the default branch's tip (no force; the default branch itself is never touched) and report targetCreated: true. A missing DEFAULT branch is still not green — do not guess.`
|
|
434
|
+
: `This run merges into the default branch (trunk) — that branch is the base. If it does not exist on the remote, report not green and say the base is missing — do not guess another branch.`
|
|
435
|
+
} Sync the base fresh (clean tree) and report its name as base.
|
|
369
436
|
3. Determine how the tracker is reachable from THIS environment: check whether the CLI the project docs assume (e.g. gh) is installed; if not, name the concrete substitute available here (e.g. GitHub MCP tools) as an instruction future agents can follow.
|
|
370
437
|
4. Run the project's install command, then the verification gate: npx @wemuda/launchrail verify. Report the actual exit codes, not the reassuring summary line. An empty verification contract failing the gate is a refusal condition, not something to work around.
|
|
371
438
|
green means: base synced AND the verification gate exited 0.`,
|
|
@@ -384,11 +451,14 @@ if ((pre.issueTracker ?? 'none') === 'none') {
|
|
|
384
451
|
phase('Graph')
|
|
385
452
|
log(
|
|
386
453
|
`Base green at ${pre.headSha ?? pre.base} on ${pre.base}. ` +
|
|
454
|
+
(POLICY.target
|
|
455
|
+
? `Consolidating onto ${pre.base}${pre.targetCreated ? ' (created from the default branch tip)' : ''}; ${pre.defaultBranch || 'the default branch'} stays untouched. `
|
|
456
|
+
: `Trunk mode — each ticket merges into ${pre.base}. `) +
|
|
387
457
|
(POLICY.only.length > 0
|
|
388
458
|
? `Scoped to ${POLICY.only.map((n) => `#${n}`).join(', ')}.`
|
|
389
459
|
: 'No scope — building the whole ready frontier.') +
|
|
390
460
|
(POLICY.max > 0 ? ` Stopping after ${POLICY.max} verified merge(s).` : '') +
|
|
391
|
-
` Width ${POLICY.width}, ${POLICY.attempts} attempts per ticket.`,
|
|
461
|
+
` Width ${POLICY.width}${POLICY.canary ? ' (canary: width 1 until the first verified merge)' : ''}, ${POLICY.attempts} attempts per ticket.`,
|
|
392
462
|
)
|
|
393
463
|
let graph = await agent(graphPrompt(pre), { label: 'read-graph', phase: 'Graph', schema: GRAPH_SCHEMA, model: 'haiku', effort: 'low' })
|
|
394
464
|
if (!graph) throw new Error('graph agent died — refusing to start')
|
|
@@ -424,7 +494,10 @@ while (rounds < POLICY.maxRounds) {
|
|
|
424
494
|
const ready = frontier(tickets, closedBefore)
|
|
425
495
|
if (ready.length === 0) break
|
|
426
496
|
rounds += 1
|
|
427
|
-
|
|
497
|
+
// Canary: the first verified merge proves the plumbing end to end (branch, PR, CI,
|
|
498
|
+
// merge gate, explicit close); until it lands, dispatch one ticket at a time.
|
|
499
|
+
const width = POLICY.canary && mergedCount() === 0 ? 1 : POLICY.width
|
|
500
|
+
const batch = ready.slice(0, Math.min(width, capLeft))
|
|
428
501
|
log(`round ${rounds}: dispatching ${batch.map((t) => `#${t.number}`).join(', ')} (${ready.length} unblocked)`)
|
|
429
502
|
const results = await parallel(batch.map((t) => () => drive(pre, t)))
|
|
430
503
|
const landed = results.filter((r) => r?.ok)
|
|
@@ -495,10 +568,18 @@ verified means: the verification gate exited 0${pre.browserTesting && merged.len
|
|
|
495
568
|
{ label: 'release-verification', phase: 'Release', schema: RELEASE_SCHEMA },
|
|
496
569
|
)
|
|
497
570
|
|
|
571
|
+
// The recap is part of the contract (ADR-0022): where the work lives and the one
|
|
572
|
+
// next step, as data — the supervisor relays it, never reconstructs it.
|
|
573
|
+
const mode = POLICY.target ? 'consolidation' : 'trunk'
|
|
498
574
|
return {
|
|
499
575
|
rounds,
|
|
500
576
|
verified: release?.verified ?? false,
|
|
501
577
|
maxReached,
|
|
578
|
+
target: { mode, base: pre.base, defaultBranch: pre.defaultBranch ?? '', headSha: release?.headSha ?? '' },
|
|
579
|
+
nextStep:
|
|
580
|
+
mode === 'consolidation'
|
|
581
|
+
? `All campaign work is on ${pre.base}; ${pre.defaultBranch || 'the default branch'} is untouched. Release it with one PR ${pre.base} -> ${pre.defaultBranch || 'the default branch'} — offer it, and open it only when the user says so.`
|
|
582
|
+
: `Every merged ticket is live on ${pre.base}; nothing is left to integrate.`,
|
|
502
583
|
release,
|
|
503
584
|
merged: merged.map((s) => ({ ticket: s.ticket.number, title: s.ticket.title, pr: s.pr, mergeCommit: s.mergeCommit })),
|
|
504
585
|
parked: parked.map((s) => ({ ticket: s.ticket.number, title: s.ticket.title, failures: s.failures })),
|
|
@@ -18,7 +18,9 @@ From `.launchrail.yml`: `issueTracker` and the `testing` commands. From the argu
|
|
|
18
18
|
- **a count** — "the next 5", "max 5" → the loop with a merge cap. Don't hand-pick which five: the cap is a stop condition, and the frontier decides the order — the loop stops after that many *verified merges* and leaves the rest ready;
|
|
19
19
|
- **a spec, slice, or epic reference** — "spec #2's tickets", "the rest of slice 1" → resolve it to explicit numbers against the live tracker: the open tickets that belong to it (a "Part of: #n" line, the spec issue's ticket list, or a label), plus any open in-set blockers so the scope stays dependency-closed. Combinations compose: "the next 5 of spec #2" → that spec's tickets *and* a cap of 5.
|
|
20
20
|
|
|
21
|
-
**Resolve
|
|
21
|
+
**Resolve the integration target with the scope.** Every loop run merges its per-ticket PRs into exactly one base (ADR-0022): **trunk** — the default branch, each ticket live the moment it merges — unless the user names a consolidation branch ("collect spec #44 on `spec/44-mvp`", "don't touch master yet") or the environment forbids pushing to the default branch (a harness-designated branch: use it, and say that constraint is why). Consolidation means the default branch stays untouched and the run ends by offering one release PR `<target> → <default>`; it is a choice the user should recognize, never a silent fallback.
|
|
22
|
+
|
|
23
|
+
**Resolve prose to data before anything launches.** The loop's inputs are ticket numbers and policy values (`only`, `max`, `width`, `target`) — the workflow takes them as JSON args and refuses a natural-language string by design. Translating the user's words into that scope, against live tracker state, is *your* job, and it ends with an echo before any dispatch: "Scope: #14, #15, #19 — the remaining slice-1 tickets; #19 builds after #14. Cap: none. Target: trunk (`master`). Engine: the `ralph` workflow." A misread scope corrected here costs a sentence; corrected after launch it costs a run.
|
|
22
24
|
|
|
23
25
|
## Step 2 — Repair setup, don't gatekeep
|
|
24
26
|
|
|
@@ -26,13 +28,13 @@ If the loop's materials are missing — `modules.ralph` off in the manifest, or
|
|
|
26
28
|
|
|
27
29
|
## Step 3 — Route by scope
|
|
28
30
|
|
|
29
|
-
**The frontier (or
|
|
31
|
+
**The frontier (or any multi-ticket scope):** the engine is the `ralph` workflow (`.claude/workflows/ralph.js`) — launch it with the resolved scope and target as JSON args, e.g. `{ only: [14, 15, 19], max: 5, target: 'spec/2-checkout' }` (`canary: true` on a project's first run), then supervise it per the `launch-ralph` skill, which owns the policies (width, attempts, cap, deferrals, the merge gate, remote-verified merges) and the supervisor's contract. Orchestrating dispatches by hand under that skill instead is the exception, chosen out loud in the echo: the user asked to watch each dispatch, the Workflow tool is unavailable here, or the run is a targeted intervention (one parked ticket). One engine, one shape — a session that invents its own fan-out is not running the loop.
|
|
30
32
|
|
|
31
|
-
**One ticket:** build it here, watchable, under the same contract a Ralph dispatch carries (kept textually parallel with `launch-ralph` — change one, change both):
|
|
33
|
+
**One ticket:** build it here, watchable, under the same contract a Ralph dispatch carries (kept textually parallel with `launch-ralph` — change one, change both). One deliberate divergence: you are the session, not a subagent, so you also run the merge gate yourself — waiting on CI here is fine:
|
|
32
34
|
|
|
33
35
|
1. **Dependency gate:** every ticket on the `Blocked by:` line is closed with its work merged. An open blocker stops you before any code — name it and offer to build it first.
|
|
34
36
|
2. Read the ticket and everything it links (spec sections, ADRs, journeys), plus `AGENTS.md`/`CLAUDE.md`.
|
|
35
|
-
3. Label the ticket `ralph:building`; branch `ralph/<n>-<short-slug>` from a fresh sync of the base.
|
|
37
|
+
3. Label the ticket `ralph:building`; branch `ralph/<n>-<short-slug>` from a fresh sync of the base (the resolved integration target).
|
|
36
38
|
4. Implement by the **`launch-ralph-implement`** contract — TDD, the `verify` gate, browser smoke for user-facing changes, self-review, commit conventions. Name the skill; don't paraphrase it.
|
|
37
39
|
5. Pre-PR sync: merge the latest base; resolve conflicts with `launch-resolving-merge-conflicts`; re-run the gate if anything changed.
|
|
38
40
|
6. Open a PR titled from the ticket with `Closes #<n>`; adopt an existing `ralph/<n>-*` branch or PR rather than opening a second.
|
|
@@ -44,3 +46,4 @@ If the loop's materials are missing — `modules.ralph` off in the manifest, or
|
|
|
44
46
|
- **Only the user starts this.** Conductors and other skills hand over the command (`/launch-implement`); they never invoke it. The engines behind it inherit the same rule — reaching them through this door *is* the explicit user start.
|
|
45
47
|
- **Nothing is done until `npx @wemuda/launchrail verify` is green** — per ticket, and once more on the final base when a loop run ends. Where `modules.browser-testing` is enabled and the change is user-facing, a `launch-browser-smoke` journey is part of done.
|
|
46
48
|
- **Report evidence, not assertions:** PR numbers, merge commits, issues closed, the verify outcome — and what was parked or punted, with why.
|
|
49
|
+
- **Every loop run ends with the campaign recap** (the `launch-ralph` close-out): where the work lives — target branch and head SHA — the ticket → PR → merge-commit table, parked and stuck tickets, punted follow-ups in one list, and the single next step; in consolidation mode that step is *offering* the one release PR to the default branch, opened only when the user says so.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-ralph
|
|
3
|
-
description:
|
|
3
|
+
description: The Ralph implementation loop's contract — policies, dispatch steps, the loop-owned merge gate, and the supervisor's duties when the loop runs as the ralph workflow (the default engine for any multi-ticket run). Skill-mode orchestration of fresh-context implementers lives here too, as the declared exception. Behind /launch-implement (the user-typed front door) — never invoke it on your own initiative; reach it through that door or an explicit user request to run the loop.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Ralph — the autonomous implementation loop
|
|
@@ -9,13 +9,14 @@ The user starts this loop through `/launch-implement` (or by asking for it in so
|
|
|
9
9
|
|
|
10
10
|
You are the orchestrator. **You do not write code. You do not read diffs. You do not fix failing branches yourself.** You compute what's ready, dispatch, verify, and keep a running log. Tracker state and subagent reports in, decisions out.
|
|
11
11
|
|
|
12
|
-
One agent implementing a whole backlog in a single session degrades — context fills with diffs and half-remembered state, and quality drops with every ticket. This loop inverts that: every ticket gets a fresh-context implementer subagent that owns
|
|
12
|
+
One agent implementing a whole backlog in a single session degrades — context fills with diffs and half-remembered state, and quality drops with every ticket. This loop inverts that: every ticket gets a fresh-context implementer subagent that owns the build through an open PR, the loop's merge gate lands it, and nothing anyone reports is trusted until the remote confirms it.
|
|
13
13
|
|
|
14
|
-
This skill is the
|
|
14
|
+
This skill is the loop's contract and its supervisor. The loop itself runs as the deterministic `ralph` workflow (`.claude/workflows/ralph.js`, installed by init; `launchrail sync` restores it) — **the workflow is the engine for every multi-ticket run**, launched with the resolved scope and integration target as JSON args and then supervised per this skill; its script state cannot be compacted away. Orchestrating dispatches from this session instead is the exception, and it is chosen out loud — name the engine and why before anything dispatches: the user asked to watch each dispatch, the Workflow tool is unavailable in this environment, or this is a targeted intervention (one parked ticket, re-run watchably). A hand-rolled fan-out that is neither is not the loop. The two forms share one policy block: change a policy here, change it in the workflow too (ADR-0005, field-revised by ADR-0010 and ADR-0022).
|
|
15
15
|
|
|
16
16
|
## Policies
|
|
17
17
|
|
|
18
|
-
- **
|
|
18
|
+
- **Integration target: declared, singular, restated.** Every run merges its per-ticket PRs into exactly one base, named before anything dispatches and again in the close-out. **Trunk** (the default): the repository's default branch — each verified merge is immediately on mainline, and when the run ends there is nothing left to integrate. **Consolidation**: one named integration branch (e.g. `spec/44-mvp`) collects the whole campaign and the default branch is never touched; the run ends by *offering* one release PR `<target> → <default>` — opened only when the user says so. Consolidation is chosen, never fallen into: the user names a branch or asks for it, or the environment forbids pushing to the default branch — announce that constraint as the reason. A named target missing from the remote is created from the default branch's tip before preflight verifies it; a missing *default* branch stays a refusal. In consolidation mode `Closes #n` never auto-fires (auto-close only triggers from the default branch), so the explicit post-merge close is load-bearing, not belt-and-suspenders.
|
|
19
|
+
- **Width: 3** implementers at once. Width multiplies conflict rate and shared-machine load, not just throughput — use 1 until a run has landed tickets cleanly on this project (the workflow's `canary: true` encodes exactly that). Cut a batch below width when its tickets would obviously collide (same module, same files); when in doubt, narrow. Tickets that add DB migrations are a known collision: two parallel implementers both claim the next migration number — serialize them, or expect the second to renumber at pre-PR sync.
|
|
19
20
|
- **Cap: none** by default. The user may bound a run ("the next 5"): stop once that many merges have been *verified*, keeping every batch within the remainder so the run cannot overshoot. Failed and deferred dispatches never consume the cap — their slots go to other tickets. Hitting the cap ends the run cleanly: the rest of the frontier stays ready (reported, never parked), and close-out runs as usual.
|
|
20
21
|
- **Attempts: 2** — retry a failed ticket once with a fresh context, then park it.
|
|
21
22
|
- **Deferrals are not attempts.** An implementer that stops at its dependency gate (a declared blocker had not actually landed) hands the attempt back and is retried after the blocker lands — capped at 2 deferrals, then it counts as a real failure.
|
|
@@ -23,14 +24,14 @@ This skill is the watchable, checkpointed frontend of the loop. The same loop ex
|
|
|
23
24
|
- **Checkpoints: none** by default — run to completion, report once. The user may ask for a pause after each round instead.
|
|
24
25
|
- **Review gate:** the implementer's own self-review via `/launch-code-review`, inside `launch-ralph-implement`.
|
|
25
26
|
- **Verification gate:** `npx @wemuda/launchrail verify` — per ticket before the PR, and once more on the final base before the loop may report success.
|
|
26
|
-
- **Merge
|
|
27
|
+
- **Merge ownership: the loop, not the implementer.** Implementers build, open the PR, and hand off at PR-open; the merge gate — CI wait, mergeability re-check, squash-merge, explicit issue close, `ralph:building` removal — belongs to the loop (you in skill mode, a per-ticket gate agent in the workflow). An implementer subagent must never sit in a CI wait: it cannot foreground-sleep, and a background sleep surfaces to its parent without resuming it — tokens burn, nothing advances. Merge ordering stays optimistic and remote-arbitrated (re-check mergeability immediately before merging, up to 3 retries if the base moves; no merge locks), and the single gate owner serializes where it matters — critical-path first, schema-touching tickets one at a time.
|
|
27
28
|
- **Labels:** tickets enter as `ready-for-agent`, are marked `ralph:building` while owned, and leave as closed or `needs-info` (parked).
|
|
28
29
|
|
|
29
30
|
## Preconditions — refuse to start if any fails
|
|
30
31
|
|
|
31
32
|
1. `.launchrail.yml` exists with `issueTracker` not `none`, and the tracker is reachable **from this environment**: check whether the CLI the project docs assume (e.g. `gh`) is installed here; if not, identify the substitute (e.g. GitHub MCP tools) and name it in every dispatch.
|
|
32
33
|
2. Open tickets labeled `ready-for-agent` exist and carry explicit `Blocked by: #n` edges (or the tracker's native blocking relations). No tickets with edges → nothing to orchestrate; point the user at `launch-tickets`. If anything wearing `ready-for-agent` is plainly not an implementable ticket — a published spec, research notes, an epic — stop and have it relabeled (e.g. `spec`) before starting: the frontier is computed from the label alone and cannot tell prose from work.
|
|
33
|
-
3. The
|
|
34
|
+
3. The integration target is resolved (trunk or a named consolidation branch — see Policies) and its branch is green on a fresh checkout: sync it (creating a named consolidation branch from the default branch's tip if the remote lacks it), run the install command, then `npx @wemuda/launchrail verify` — report actual exit codes, not the reassuring summary line; a broken base poisons every implementer after it. A missing *default* branch is a refusal, not a cue to guess another. An **empty verification contract fails `verify` and is a refusal condition**: a run whose completion nothing can verify must not start. Tell the user to configure `testing` commands in `.launchrail.yml` first.
|
|
34
35
|
4. The verbatim local commands are known (from `AGENTS.md` / `.launchrail.yml`), including which checks belong to CI rather than the shared local machine.
|
|
35
36
|
|
|
36
37
|
## The loop
|
|
@@ -43,16 +44,24 @@ Sync → compute frontier → dispatch batch → verify → handle outcomes →
|
|
|
43
44
|
|
|
44
45
|
## The dispatch prompt
|
|
45
46
|
|
|
46
|
-
Each implementer prompt is self-contained — assume it knows nothing about this session or the other implementers. It carries: the ticket number and title, the verbatim commands, how to reach the tracker from this environment, and these
|
|
47
|
+
Each implementer prompt is self-contained — assume it knows nothing about this session or the other implementers. It carries: the ticket number and title, the verbatim commands, how to reach the tracker from this environment, which branch is the base (the integration target), and these seven steps:
|
|
47
48
|
|
|
48
49
|
1. **Dependency gate:** before anything else, confirm every ticket on the `Blocked by` line is closed with its work merged into the base. If any blocker is still open, do not build on a missing dependency — report "blocked" naming the open blocker, and stop. A deferral, not a failure; the loop retries after the blocker lands.
|
|
49
|
-
2. Read the ticket and everything it links (spec sections, ADRs, journeys), plus `AGENTS.md`/`CLAUDE.md`. If the ticket is already closed, report "already-done" and stop.
|
|
50
|
+
2. Read the ticket and everything it links (spec sections, ADRs, journeys), plus `AGENTS.md`/`CLAUDE.md`. If the tracker tool truncates the body (long code spans are a known trigger), fetch the full text by another route — the tracker's search API, the spec file in the repo — and never implement from a truncated ticket. If the ticket is already closed, report "already-done" and stop.
|
|
50
51
|
3. Label the ticket `ralph:building` so a lost session leaves a trace.
|
|
51
52
|
4. Branch from a fresh sync of the base: `ralph/<n>-<short-slug>`.
|
|
52
53
|
5. Implement by invoking the **`launch-ralph-implement`** skill — it owns TDD, the verification gate, browser smoke for user-facing changes, self-review via `/launch-code-review`, and commit conventions. Name the skill; do not paraphrase it.
|
|
53
|
-
6. Pre-PR sync: merge the latest base into the branch; resolve conflicts with the **`launch-resolving-merge-conflicts`** skill; re-run the verification gate if anything changed.
|
|
54
|
-
7. Open a PR titled from the ticket with `Closes #<n>` in the body. Never open a second PR for a ticket — adopt an existing one. Opening against an up-to-date base means CI tests the state that will actually land.
|
|
55
|
-
|
|
54
|
+
6. Pre-PR sync: merge the latest base into the branch; resolve conflicts with the **`launch-resolving-merge-conflicts`** skill; if the base gained DB migrations since branching, regenerate yours to follow them with the project's migration tool — never hand-edit the journal; re-run the verification gate if anything changed.
|
|
55
|
+
7. Open a PR against the base, titled from the ticket, with `Closes #<n>` in the body. Never open a second PR for a ticket — adopt an existing one. Opening against an up-to-date base means CI tests the state that will actually land. Then **report PR-open and stop**: the CI wait, the merge, and the issue close belong to the loop's merge gate, not to you. Never push to the base directly.
|
|
56
|
+
|
|
57
|
+
## The merge gate — owned by the loop
|
|
58
|
+
|
|
59
|
+
In skill mode, you run the gate for every PR the implementers hand off (the workflow runs it as a per-ticket gate agent). Order merges yourself — critical-path first, schema-touching PRs one at a time:
|
|
60
|
+
|
|
61
|
+
1. Wait for the PR's CI from *this* session, spacing checks with your own timers (a background sleep here wakes you — the orchestrator can wait; implementer subagents cannot). ~20 minutes is the budget.
|
|
62
|
+
2. Green → re-check mergeability (the base may have moved since CI started), then squash-merge; if the base moves between check and merge, re-check and retry up to 3 times.
|
|
63
|
+
3. Merged → read the issue back and close it explicitly if still open — in consolidation mode auto-close never fires — and remove `ralph:building`. Then verify as always: the remote's word, not yours.
|
|
64
|
+
4. CI failed on the PR, or a real conflict → the ticket becomes a failed attempt with the failing check or conflicting files as its summary; the fresh retry adopts the PR (idempotency clause), repairs, and hands off again. A failure that reproduces on the base itself is systemic — stop the run, not the ticket.
|
|
56
65
|
|
|
57
66
|
Every dispatch — retries included — also carries these two clauses verbatim:
|
|
58
67
|
|
|
@@ -77,7 +86,7 @@ When the Ralph loop runs as the `ralph` workflow instead of through this skill,
|
|
|
77
86
|
1. **Read the resolved scope back, immediately.** The first `log()` lines state it ("Scoped to #11, #12", "Stopping after 5 verified merge(s)", or "No scope — building the whole ready frontier"). An unscoped run when the user asked for three tickets is the cheapest failure to catch and the most expensive to miss — stop and relaunch if it is wrong. Scan the listed numbers for anything that is not an implementable ticket: a spec or research issue wearing `ready-for-agent` will be built as if it were work (the workflow excludes and logs obvious cases, but the label is the fix — have it corrected).
|
|
78
87
|
2. **Establish ground truth from the remote, never from the run's own reports.** On every check-in read the workflow journal (`journal.jsonl`) *and* the tracker/PRs. A merge is real only when the commit is on the base branch and the issue is closed.
|
|
79
88
|
3. **Arm check-ins across the long waits.** If the session can schedule a self-message, arm one a few minutes out (confirm scope and the first dispatches) and a longer fallback (catch completion or a stall). The workflow's completion notification is the primary signal; the check-ins are the backstop so the run survives an interruption.
|
|
80
|
-
4. **Know the healthy shapes so you don't cry wolf.** A ticket can appear twice in Build — that is the retry policy, or a *deferral* because its dependency had not landed yet (not a failure). A ticket only truly fails after two real attempts, then it parks.
|
|
89
|
+
4. **Know the healthy shapes so you don't cry wolf.** A ticket can appear twice in Build — that is the retry policy, or a *deferral* because its dependency had not landed yet (not a failure). Build ending at PR-open with a separate Gate agent doing the merge is the design, not a stall. A ticket only truly fails after two real attempts, then it parks.
|
|
81
90
|
5. **Intervene by exception, not by reflex.** Parked ticket → dispatch a fresh scoped run for just that one. Stall (an agent stops writing, CI never returns) → diagnose from the journal. Wrong scope or wrong base → stop, fix, relaunch. Otherwise stay out of the way; the loop is built to self-correct.
|
|
82
91
|
6. **Report once at the end, concretely** — PR numbers, merge commits, issues closed, the verification outcome, anything punted — then disarm the check-ins.
|
|
83
92
|
|
|
@@ -87,12 +96,18 @@ When the frontier drains (or max rounds / a stop condition hits):
|
|
|
87
96
|
|
|
88
97
|
1. Sync a fresh base and run `npx @wemuda/launchrail verify`. **The loop may not report success while this fails** — report "unverified" with the failures instead.
|
|
89
98
|
2. If `.launchrail.yml` has `modules.browser-testing: true` and any merged ticket changed user-facing behavior, dispatch one smoke run per the `launch-browser-smoke` skill and reference its evidence bundle (`artifacts/verification/<run-id>/`).
|
|
90
|
-
3. Report the
|
|
99
|
+
3. Report the campaign recap — it must let the user act without scrolling back:
|
|
100
|
+
- **Where the work lives:** the integration target and its head SHA; in consolidation mode, say explicitly that the default branch is untouched.
|
|
101
|
+
- The ticket → PR → merge-commit table; parked tickets with their failure histories; stuck tickets and what blocks them.
|
|
102
|
+
- Follow-ups and operator steps implementers punted, gathered into one list.
|
|
103
|
+
- The verification outcome with its evidence. Evidence over assertion — link what was run, never summarize what wasn't.
|
|
104
|
+
- **The single next step:** trunk — nothing; every merged ticket is live on the default branch. Consolidation — offer the one release PR `<target> → <default>` with this recap as its body, and open it only when the user says so.
|
|
91
105
|
|
|
92
106
|
## Rules
|
|
93
107
|
|
|
94
108
|
- Fresh context per dispatch, per retry. No exceptions.
|
|
95
|
-
-
|
|
109
|
+
- One integration target and one engine per run, both declared before the first dispatch and restated in the recap.
|
|
110
|
+
- Never implement, review, or repair code in the orchestrator session — dispatch instead. Running the merge gate is bookkeeping, not repair.
|
|
96
111
|
- Name the skills (`launch-ralph-implement`, `launch-resolving-merge-conflicts`, `launch-browser-smoke`); never paraphrase their contents into a prompt.
|
|
97
112
|
- Blocking edges are parsed from the verbatim `Blocked by` line, by you — never resolved by a model in between.
|
|
98
113
|
- Nothing counts as merged until the remote says so; nothing counts as done until `verify` is green.
|
package/dist/lib/seeds.js
CHANGED
|
@@ -69,7 +69,8 @@ function claudeGeneratedMd(ctx) {
|
|
|
69
69
|
? `
|
|
70
70
|
## The Ralph loop
|
|
71
71
|
|
|
72
|
-
- Implementation starts with \`/launch-implement\` — all ready tickets, or one with \`/launch-implement <ticket>\`.
|
|
72
|
+
- Implementation starts with \`/launch-implement\` — all ready tickets, or one with \`/launch-implement <ticket>\`. Multi-ticket runs execute as the \`ralph\` workflow (\`.claude/workflows/ralph.js\`), supervised per the \`launch-ralph\` skill; single tickets build in-session. Only ever started explicitly by the user.
|
|
73
|
+
- Every run declares one integration target: the default branch (trunk — the default) or a named consolidation branch via the \`target\` workflow arg, which collects the campaign and ends by offering one release PR to the default branch. The run's recap states where the work lives and the single next step.
|
|
73
74
|
- Tickets enter the loop with the \`ready-for-agent\` label and explicit \`Blocked by: #n\` edges; parked tickets carry \`needs-info\` plus their failure history.
|
|
74
75
|
- A ticket counts done only when its PR is merged on the remote, the issue is closed, and \`npx @wemuda/launchrail verify\` is green — agent reports are claims, not evidence.
|
|
75
76
|
- \`.claude/workflows/ralph.js\` is managed by Launchrail: override policy per run via workflow args (e.g. \`{ width: 1 }\`), never by editing the file.
|
package/dist/lib/seeds.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seeds.js","sourceRoot":"","sources":["../../src/lib/seeds.ts"],"names":[],"mappings":"AASA,SAAS,QAAQ,CAAC,GAAgB;IAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW;QAC3C,CAAC,CAAC,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,OAAO;QACtD,CAAC,CAAC,qEAAqE,CAAC;IAE1E,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC,mBAAmB;QAC5D,CAAC,CAAC;;;;CAIL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,gCAAgC,GAAG,CAAC,WAAW;;;;;;;;;;;;;;;;EAgBtD,QAAQ;EACR,aAAa;;;;;;;;;;;6BAWc,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE;;;;CAIxG,CAAC;AACF,CAAC;AAED,SAAS,QAAQ;IACf,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAgB;IACzC,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAC5D,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK;QACtC,CAAC,CAAC
|
|
1
|
+
{"version":3,"file":"seeds.js","sourceRoot":"","sources":["../../src/lib/seeds.ts"],"names":[],"mappings":"AASA,SAAS,QAAQ,CAAC,GAAgB;IAChC,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC;IACzB,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW;QAC3C,CAAC,CAAC,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,GAAG,OAAO;QACtD,CAAC,CAAC,qEAAqE,CAAC;IAE1E,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC,mBAAmB;QAC5D,CAAC,CAAC;;;;CAIL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,gCAAgC,GAAG,CAAC,WAAW;;;;;;;;;;;;;;;;EAgBtD,QAAQ;EACR,aAAa;;;;;;;;;;;6BAWc,QAAQ,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,EAAE;;;;CAIxG,CAAC;AACF,CAAC;AAED,SAAS,QAAQ;IACf,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAgB;IACzC,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAC5D,CAAC,CAAC;;;;;;;;CAQL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK;QACtC,CAAC,CAAC;;;;;;;;;CASL;QACG,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,+BAA+B,GAAG,CAAC,iBAAiB;;;;;;;;;;EAU3D,cAAc,GAAG,KAAK,EAAE,CAAC;AAC3B,CAAC;AAED,SAAS,WAAW;IAClB,OAAO;;;;;;;;;;;;;;;;;;;CAmBR,CAAC;AACF,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,GAAgB;IAClD,OAAO,EAAE,OAAO,EAAE,iCAAiC,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC/G,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,GAAgB;IACxC,OAAO;QACL,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE;QACrE,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QAClE,EAAE,OAAO,EAAE,2BAA2B,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;QACrF,mBAAmB,CAAC,GAAG,CAAC;KACzB,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED