@use-the-fork/spindle 0.0.2 → 0.2.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 (82) hide show
  1. package/build/Assets/Blueprints/Catalog.js +19 -9
  2. package/build/Assets/Blueprints/agents/sdd-implementer.agent.md +6 -6
  3. package/build/Assets/Blueprints/agents/sdd-orchestrator.agent.md +4 -7
  4. package/build/Assets/Blueprints/skills/author-agent/SKILL.md +9 -8
  5. package/build/Assets/Blueprints/skills/author-instruction/SKILL.md +9 -8
  6. package/build/Assets/Blueprints/skills/author-skill/SKILL.md +9 -8
  7. package/build/Assets/Blueprints/skills/grill/SKILL.md +3 -3
  8. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/SKILL.md +16 -12
  9. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/implementer-prompt.md +2 -2
  10. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/corrective-rounds.md +1 -1
  11. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/example-workflow.md +14 -12
  12. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/full-spec.md +43 -23
  13. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/review-inputs.md +7 -7
  14. package/build/Assets/Blueprints/skills/int-testing-agent-guidance/SKILL.md +2 -2
  15. package/build/Assets/Blueprints/skills/int-writing-skills/SKILL.md +2 -2
  16. package/build/Assets/Blueprints/skills/int-writing-skills/references/testing-skills.md +2 -2
  17. package/build/Assets/Blueprints/skills/{asd-ste100 → ref-asd-ste100}/SKILL.md +1 -1
  18. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/SKILL.md +38 -0
  19. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/concurrency-and-pools.md +73 -0
  20. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/connectors.md +99 -0
  21. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/data-transfer-objects.md +104 -0
  22. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/handling-failures.md +95 -0
  23. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/requests.md +111 -0
  24. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/responses.md +56 -0
  25. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/sending-requests.md +42 -0
  26. package/build/Assets/Blueprints/skills/ref-php-laravel-saloon-api-integrations/references/testing.md +119 -0
  27. package/build/Assets/Blueprints/skills/{author-design → sdd-author-design}/SKILL.md +12 -4
  28. package/build/Assets/Blueprints/skills/{grill-design → sdd-grill-design}/SKILL.md +1 -1
  29. package/build/Assets/Blueprints/skills/{implement-spec → sdd-implement-spec}/SKILL.md +6 -8
  30. package/build/Assets/Blueprints/skills/{to-spec → sdd-to-spec}/SKILL.md +3 -3
  31. package/build/Assets/Blueprints/skills/{to-tickets → sdd-to-tickets}/SKILL.md +3 -3
  32. package/build/Assets/Blueprints/skills/{setup-project → spindle-project-setup}/SKILL.md +4 -4
  33. package/build/Assets/Blueprints/skills/{update-tooling → spindle-tooling-update}/SKILL.md +5 -5
  34. package/build/Assets/Templates/project/copilot-instructions.md +3 -9
  35. package/build/Assets/Templates/project/ticket-tracker.md +14 -6
  36. package/build/BlueprintManagement/Commands/Prompts.js +1 -1
  37. package/build/SubagentDrivenDevelopment/Commands/ChecksRecordCommand.js +27 -5
  38. package/build/SubagentDrivenDevelopment/Commands/ChecksRequireCommand.js +31 -7
  39. package/build/SubagentDrivenDevelopment/Commands/CorrectCommand.js +0 -1
  40. package/build/SubagentDrivenDevelopment/Commands/FinishCommand.js +2 -1
  41. package/build/SubagentDrivenDevelopment/Commands/ImplementCommand.js +2 -0
  42. package/build/SubagentDrivenDevelopment/Commands/{ClaimCommand.js → IntegrateCommand.js} +8 -7
  43. package/build/SubagentDrivenDevelopment/Commands/ReviewCommand.js +9 -9
  44. package/build/SubagentDrivenDevelopment/Commands/StartCommand.js +23 -0
  45. package/build/SubagentDrivenDevelopment/Commands/StatusCommand.js +5 -0
  46. package/build/SubagentDrivenDevelopment/Commands/groups.js +3 -2
  47. package/build/SubagentDrivenDevelopment/Evidence/GitEvidence.js +188 -37
  48. package/build/SubagentDrivenDevelopment/Models/Workflow.js +0 -2
  49. package/build/SubagentDrivenDevelopment/Persistence/AssignmentSchema.js +4 -0
  50. package/build/SubagentDrivenDevelopment/Persistence/CheckSchema.js +4 -13
  51. package/build/SubagentDrivenDevelopment/Persistence/LedgerRepository.js +66 -5
  52. package/build/SubagentDrivenDevelopment/Persistence/ProgressSchema.js +54 -4
  53. package/build/SubagentDrivenDevelopment/Persistence/ReviewSchema.js +4 -0
  54. package/build/SubagentDrivenDevelopment/Policies/AssignmentPolicy.js +0 -3
  55. package/build/SubagentDrivenDevelopment/Policies/CheckPolicy.js +6 -3
  56. package/build/SubagentDrivenDevelopment/Policies/ReadinessPolicy.js +16 -6
  57. package/build/SubagentDrivenDevelopment/Policies/ReviewPolicy.js +16 -2
  58. package/build/SubagentDrivenDevelopment/Policies/WorkflowPolicy.js +8 -8
  59. package/build/SubagentDrivenDevelopment/Services/AssignmentService.js +73 -51
  60. package/build/SubagentDrivenDevelopment/Services/ChecksService.js +376 -21
  61. package/build/SubagentDrivenDevelopment/Services/CorrectionService.js +83 -14
  62. package/build/SubagentDrivenDevelopment/Services/DeliveryCorrectionService.js +3 -7
  63. package/build/SubagentDrivenDevelopment/Services/DeliveryService.js +43 -38
  64. package/build/SubagentDrivenDevelopment/Services/FeatureCreationService.js +1 -1
  65. package/build/SubagentDrivenDevelopment/Services/FeatureFinalizationService.js +1202 -0
  66. package/build/SubagentDrivenDevelopment/Services/FeatureInspectionService.js +41 -49
  67. package/build/SubagentDrivenDevelopment/Services/FeatureWorktreeService.js +544 -0
  68. package/build/SubagentDrivenDevelopment/Services/ReadinessService.js +2 -2
  69. package/build/SubagentDrivenDevelopment/Services/ReviewService.js +39 -3
  70. package/build/SubagentDrivenDevelopment/Services/SubmissionService.js +4 -1
  71. package/build/SubagentDrivenDevelopment/Services/TicketIntegrationService.js +621 -0
  72. package/build/SubagentDrivenDevelopment/Services/TicketService.js +3 -0
  73. package/build/SubagentDrivenDevelopment/Services/TicketWorktreeService.js +317 -0
  74. package/build/SubagentDrivenDevelopment/Services/WorkflowRecordsCommitter.js +336 -0
  75. package/build/SubagentDrivenDevelopment/SubagentDrivenDevelopmentServiceProvider.js +18 -8
  76. package/build/TemplateRendering/Computed/ComputedVariableProviders.js +2 -0
  77. package/build/TemplateRendering/Computed/Providers/AuthoringFlowchartProvider.js +26 -0
  78. package/package.json +2 -2
  79. package/build/SubagentDrivenDevelopment/Services/IntegrationService.js +0 -258
  80. /package/build/Assets/Blueprints/skills/{asd-ste100 → ref-asd-ste100}/CREDITS.MD +0 -0
  81. /package/build/Assets/Blueprints/skills/{asd-ste100 → ref-asd-ste100}/examples/before-after.md +0 -0
  82. /package/build/Assets/Blueprints/skills/{asd-ste100 → ref-asd-ste100}/references/writing-rules.md +0 -0
@@ -0,0 +1,119 @@
1
+ # Testing
2
+
3
+ Keep test runs offline. Use `MockClient` with fake responses or existing fixtures.
4
+ Assert the outgoing request and the application's handling of success and failure responses, including 401, 422, and 500.
5
+
6
+ ## Block network access
7
+
8
+ Block requests without a mock client and prevent automatic recording when a fixture is missing.
9
+ For Pest, add this setup to `tests/Pest.php`.
10
+ For PHPUnit, run it in the base `TestCase::setUp()` after `parent::setUp()`.
11
+
12
+ ```php
13
+ use Saloon\Config;
14
+ use Saloon\MockConfig;
15
+
16
+ Config::preventStrayRequests();
17
+ MockConfig::throwOnMissingFixtures();
18
+ ```
19
+
20
+ `preventStrayRequests()` alone does not stop fixture recording when a mock client is attached.
21
+ `throwOnMissingFixtures()` throws `FixtureMissingException` instead of recording a missing fixture.
22
+
23
+ ## Fake responses
24
+
25
+ `MockResponse::make(body, status, headers)` builds a response. An array body is encoded as JSON.
26
+
27
+ ```php
28
+ use Saloon\Http\Faking\MockClient;
29
+ use Saloon\Http\Faking\MockResponse;
30
+
31
+ $mockClient = new MockClient([
32
+ ListProductsRequest::class => MockResponse::make(['data' => [['id' => 1, 'name' => 'Widget']]], 200),
33
+ CreateProductRequest::class => MockResponse::make(['errors' => ['name' => ['Required']]], 422),
34
+ ]);
35
+ ```
36
+
37
+ Mock keys can also be:
38
+
39
+ - URL patterns with `*` wildcards: `'inventory.example.com/api/v1/products/*' => MockResponse::make(...)`.
40
+ - An unkeyed list, returned in sequence regardless of the request: `[MockResponse::make('first'), MockResponse::make('second')]`.
41
+ - A closure: `fn (PendingRequest $pendingRequest) => MockResponse::make(...)`.
42
+
43
+ ## Attach the mock
44
+
45
+ **Local**: attach the mock to a connector or request you control.
46
+
47
+ ```php
48
+ $connector = new InventoryConnector('https://inventory.example.com/api/v1', 'test-token');
49
+ $connector->withMockClient($mockClient);
50
+ ```
51
+
52
+ **Global**: mock requests sent deep inside application code.
53
+
54
+ ```php
55
+ $mockClient = MockClient::global([
56
+ ListProductsRequest::class => MockResponse::make(['data' => []], 200),
57
+ ]);
58
+ ```
59
+
60
+ Without the Laravel plugin, reset global mocks between tests with `MockClient::destroyGlobal()` in `beforeEach` or `setUp`.
61
+ The Laravel plugin resets them automatically.
62
+
63
+ ## Assertions
64
+
65
+ ```php
66
+ use Saloon\Http\Request;
67
+ use Saloon\Http\Response;
68
+
69
+ $mockClient->assertSent(ListProductsRequest::class);
70
+ $mockClient->assertNotSent(CreateProductRequest::class);
71
+ $mockClient->assertSentCount(1);
72
+ $mockClient->assertSentCount(1, ListProductsRequest::class);
73
+ ```
74
+
75
+ These are separate assertion examples. Use `assertNothingSent()` when no request should leave the application.
76
+ For a connector configured with `test-token`, assert the actual bearer header rather than a masked placeholder:
77
+
78
+ ```php
79
+ $token = 'test-token';
80
+
81
+ $mockClient->assertSent(function (Request $request, Response $response) use ($token) {
82
+ return $request instanceof CreateProductRequest
83
+ && $request->body()->all() === ['name' => 'Widget', 'price_cents' => 999]
84
+ && $response->getPsrRequest()->getHeaderLine('Authorization') === ('Bearer ' . $token);
85
+ });
86
+ ```
87
+
88
+ ## Complete example: a failure path
89
+
90
+ ```php
91
+ it('reports validation errors when the inventory API rejects a product', function () {
92
+ $mockClient = MockClient::global([
93
+ CreateProductRequest::class => MockResponse::make(['errors' => ['name' => ['Required']]], 422),
94
+ ]);
95
+
96
+ $result = app(ProductSync::class)->create(name: '', priceCents: 0);
97
+
98
+ expect($result->errors)->toBe(['name' => ['Required']]);
99
+
100
+ $mockClient->assertSent(fn (Request $request) => $request instanceof CreateProductRequest
101
+ && $request->body()->get('name') === '');
102
+ });
103
+ ```
104
+
105
+ A synchronous 422 returns a response rather than throwing.
106
+ If the code under test calls `throw()` or uses `AlwaysThrowOnErrors`, assert the exception instead.
107
+ See [Handling failures](handling-failures.md).
108
+
109
+ ## Fixtures
110
+
111
+ `MockResponse::fixture('inventory/products')` replays `tests/Fixtures/Saloon/inventory/products.json` when the file exists.
112
+ With the setup above, a missing file fails the test without contacting the API.
113
+ Change the directory with `MockConfig::setFixturePath('tests/fixtures/http')`.
114
+
115
+ Record fixtures only through an explicitly authorized process outside normal test runs and CI.
116
+ That process must omit `throwOnMissingFixtures()` and use credentials restricted to recording.
117
+ Without that guard, a missing fixture triggers a real API call and saves the response.
118
+ Use lowercase fixture paths. Redact secrets before committing fixture files.
119
+ To refresh a fixture, delete only its file in the recording process.
@@ -1,17 +1,25 @@
1
1
  ---
2
- name: author-design
2
+ name: sdd-author-design
3
3
  description: "Use when a user asks to author a design for a feature, workflow, or behavior that has important product decisions to settle."
4
4
  disable-model-invocation: true
5
5
  user-invocable: true
6
6
  metadata:
7
7
  spindle:
8
- version: 1.1.1
8
+ version: 1.1.2
9
9
  ---
10
10
 
11
11
  # Authoring a Design
12
12
 
13
13
  Help the user clarify what they want before turning an idea into a design. A design is optional; when one is created, it is authored and approved before its spec, and tickets follow the spec. Use this for product and project decisions, not as a gate for a clear, bounded task or a user who wants a spec without a design.
14
14
 
15
+ ## Required skills
16
+
17
+ Before drafting or editing, read:
18
+
19
+ - **REQUIRED:** `ref-asd-ste100`
20
+
21
+ Apply the clarity rules from the `ref-asd-ste100` skill. Include a before/after table only when the user requests one.
22
+
15
23
  ## Process
16
24
 
17
25
  1. **Check the brief.** Identify the user's goal, why it matters, what success means, and which important decisions remain open. In an existing project, inspect relevant code and docs first; do not ask for facts the project already answers. If the user asks for a design and the request is specific with no consequential decision open, proceed to the design without unnecessary questioning. **Complete when** the brief is actionable or a concrete unresolved decision is identified.
@@ -21,7 +29,7 @@ Help the user clarify what they want before turning an idea into a design. A des
21
29
  3. **Compare approaches.** Present two or three viable approaches grounded in the project and clarified goal, explain their main trade-offs, recommend one, and ask the user to choose. If only one approach fits, explain why alternatives do not. Wait for the choice before drafting. **Complete when** the user has selected an approach or delegated the choice.
22
30
 
23
31
  4. **Create or select the SDD feature workspace.**
24
- - For a new feature, choose a concise title and author identity, then run `spindle sdd create --title "<feature title>" --author "<author>" --with-design`. Use the returned workspace and spec paths; `design.md` is beside `spec.md`. The command creates both template files, but fill and approve the design before filling the spec.
32
+ - For a new feature, choose a concise title and author identity, then run `{{ computed.spindle_package_manager }} spindle sdd create --title "<feature title>" --author "<author>" --with-design`. Use the returned workspace and spec paths; `design.md` is beside `spec.md`. The command creates both template files, but fill and approve the design before filling the spec.
25
33
  - For an existing numbered SDD feature workspace, reuse it. If `design.md` already exists, preserve it and edit it only as requested. If it is missing, first confirm `spec.md` is still the untouched template; then copy the design template from the Spindle installation's `build/Assets/Templates/sdd/design.md` into that workspace without overwriting existing files. In a source checkout, use `src/Assets/Templates/sdd/design.md`.
26
34
  - If the existing spec has substantive content, stop before adding or revising a design: that would put design after spec. Explain the conflict and ask whether the user wants to continue as an explicit exception or keep the feature spec-only.
27
35
  - Do not create a dated feature directory or a second SDD workspace for the same feature.
@@ -30,7 +38,7 @@ Help the user clarify what they want before turning an idea into a design. A des
30
38
 
31
39
  5. **Write the design.** Use the existing `design.md` scaffold, replacing its `[PLACEHOLDER]` fields with the selected intent, success criteria, scope and constraints, considered approaches and trade-offs, chosen direction, and assumptions or open decisions. Write success criteria as observable outcomes that show the design achieves its intent; include measurable targets where practical without inventing precision. Leave detailed requirements and acceptance scenarios to the subsequent spec. Preserve unresolved decisions explicitly. **Complete when** the design represents the conversation, states observable success outcomes, and distinguishes user decisions from recommendations.
32
40
 
33
- 6. **Get approval.** Share the design path and its content for user approval or correction. Do not begin spec drafting until the user approves the design. If the user opts out of brainstorming or asks for a spec without design, respect that choice; do not create a design as a gate. After approval, ask the user to invoke `/to-spec` to create the spec in the same feature workspace; do not invoke it automatically. **Complete when** the design is approved, corrected for another review, or the user has chosen the spec-only path.
41
+ 6. **Get approval.** Share the design path and its content for user approval or correction. Do not begin spec drafting until the user approves the design. If the user opts out of brainstorming or asks for a spec without design, respect that choice; do not create a design as a gate. After approval, ask the user to invoke `/sdd-to-spec` to create the spec in the same feature workspace; do not invoke it automatically. **Complete when** the design is approved, corrected for another review, or the user has chosen the spec-only path.
34
42
 
35
43
  ## Keep the conversation useful
36
44
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: grill-design
2
+ name: sdd-grill-design
3
3
  description: "Challenge and refine an existing design through an interview, updating the design and relevant domain documentation."
4
4
  argument-hint: "[design.md path or feature directory]"
5
5
  disable-model-invocation: true
@@ -1,16 +1,14 @@
1
1
  ---
2
- name: implement-spec
3
- description: "Implement the result of /to-spec and /to-tickets in code."
2
+ name: sdd-implement-spec
3
+ description: "Implement the result of /sdd-to-spec and /sdd-to-tickets in code."
4
4
  disable-model-invocation: true
5
5
  metadata:
6
6
  spindle:
7
- version: 1.0.0
7
+ version: 1.2.0
8
8
  ---
9
9
 
10
10
  # Implement a Spec
11
11
 
12
- Deliver the supplied spec and all associated tickets in the existing checkout. Require configured tracker guidance; if absent, request `/setup-project`.
13
-
14
12
  ## Required Skills
15
13
 
16
14
  Before acting, read and follow each required skill:
@@ -19,15 +17,15 @@ Before acting, read and follow each required skill:
19
17
 
20
18
  ## Steps
21
19
 
22
- 1. **Bind the whole-spec assignment.** Locate the full spec, every ticket and its comments, and tracker guidance. Supply accessible context pointers rather than duplicating their contents. Record the existing checkout, starting revision, existing work and permissions.
20
+ 1. **Bind the whole-spec assignment.** Locate the full spec, every ticket and its comments, and tracker guidance. Supply accessible context pointers rather than duplicating their contents. Record the original branch, existing work, permissions, and the allowed feature worktree location; obtain an allowed location for each ticket at dispatch.
23
21
 
24
22
  **Complete when:** the complete graph and delivery inputs are available to one controller, or missing requirements are reported for triage.
25
23
 
26
- 2. **Execute the complete graph.** Follow [int-subagent-driven-dev](../int-subagent-driven-dev/SKILL.md) once with the entire graph and explicit ownership of frontier selection, sequential ticket delivery, aggregate review, and retrospective. Do not call it as a separate standalone delivery for every ticket. Its dependency validation, shared-checkout workflow, resume handling, review budgets, and completion criteria are authoritative. Accepted work does not unblock dependents until integrated and verified in the existing checkout.
24
+ 2. **Execute the complete graph.** Follow the `int-subagent-driven-dev` skill once with the entire graph and explicit ownership of frontier selection, ticket delivery, aggregate review, and retrospective. Accepted work does not unblock dependents until integrated and verified in the feature worktree.
27
25
 
28
26
  If the tracker calls for a PR, or the user requests one, open an authorized draft during execution after the first authorized commit is available; retain it as draft while delivery is incomplete.
29
27
 
30
- **Complete when:** its final report reconciles every ticket and requirement, one aggregate review, fresh verification and one retrospective for the spec, or explicitly identifies unfinished work and blockers.
28
+ **Complete when:** its final report reconciles every ticket and requirement, one aggregate review, fresh verification, and any retrospective required by policy or requested by the user, or explicitly identifies unfinished work and blockers.
31
29
 
32
30
  3. **Apply authorized publication transitions.** Mark an authorized draft ready only after the full delivery's review and checks pass. Apply closing references and ticket closure only with the user's authorization.
33
31
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: to-spec
2
+ name: sdd-to-spec
3
3
  description: "Turn an agreed feature request or approved design into a spec in its SDD feature workspace, then publish it to the configured ticket tracker."
4
4
  argument-hint: "[design file path]"
5
5
  disable-model-invocation: true
@@ -30,7 +30,7 @@ An optional design file path may be supplied. Read the entire file before drafti
30
30
 
31
31
  2. **Select or create the SDD feature workspace.**
32
32
  - Reuse the existing numbered `.scratch/<feature-id>-<slug>/` workspace when the selected design or spec belongs to one. Use its `spec.md`; do not create a second workspace for the same feature.
33
- - Otherwise, derive a concise feature title from the agreed request and choose an author identity for this run. Run `spindle sdd create --title "<feature title>" --author "<author>"`; add `--with-design` when the selected design must be retained in the new workspace. If using a design outside `.scratch`, copy that approved source into the newly created `design.md`, replacing only the fresh template. Save the returned `spec` path and continue in that workspace.
33
+ - Otherwise, derive a concise feature title from the agreed request and choose an author identity for this run. Run `{{ computed.spindle_package_manager }} spindle sdd create --title "<feature title>" --author "<author>"`; add `--with-design` when the selected design must be retained in the new workspace. If using a design outside `.scratch`, copy that approved source into the newly created `design.md`, replacing only the fresh template. Save the returned `spec` path and continue in that workspace.
34
34
  - When the workspace has `design.md`, read it fully and use it as the requirements source. If it still contains `[PLACEHOLDER]` markers or has not been approved, pause and ask the user to finish or approve the design before drafting the spec.
35
35
  - The selected SDD workspace's pre-created `spec.md` is the output. Replace its template content with the completed spec; do not create a dated folder or a second spec.
36
36
 
@@ -48,6 +48,6 @@ An optional design file path may be supplied. Read the entire file before drafti
48
48
  - Give each important user story a concise, observable acceptance outcome or example scenario focused on user-visible behavior. Leave implementation-slice completion criteria to tickets; no fixed scenario format is required.
49
49
  - Use domain glossary terms. Do not include file paths or code snippets unless a prototype captures a decision more clearly than prose.
50
50
  - Publish the completed spec according to the configured ticket-tracker guidance. Ask before publishing if the destination or status is unclear.
51
- - Once the spec is published, ask the user to invoke `/to-tickets` for planning. Do not invoke it automatically or start implementation here.
51
+ - Once the spec is published, ask the user to invoke `/sdd-to-tickets` for planning. Do not invoke it automatically or start implementation here.
52
52
 
53
53
  **Complete when:** the spec is published at the feature workspace's `spec.md` path, tracker publication is resolved, and no blocking ambiguity is hidden.
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: to-tickets
2
+ name: sdd-to-tickets
3
3
  description: "Break an approved feature spec into tracer-bullet tickets with explicit blockers, then publish them to the configured ticket tracker."
4
4
  argument-hint: "[spec path or tracker reference]"
5
5
  disable-model-invocation: true
@@ -20,7 +20,7 @@ An optional argument is one spec path or tracker reference. Read the full spec a
20
20
  - Use the spec's existing feature workspace. In Spindle's local tracker, this is a numbered `.scratch/<feature-id>-<slug>/` directory containing `spec.md`, `sdd.json`, and `tickets/`. Never create a dated folder or a second workspace for the same feature.
21
21
  - If `design.md` exists in the feature workspace, read it and confirm it was completed and approved before the spec. If the spec is not approved or a present design is unfinished, stop and resolve that before ticket planning.
22
22
  - A design is optional. Do not require or create one when the approved spec was intentionally written without a design.
23
- - For local SDD tracker work, use the feature's `spec.md` path with `spindle sdd` ticket commands. Otherwise follow the configured tracker's documented conventions.
23
+ - For local SDD tracker work, use the feature's `spec.md` path with `{{ computed.spindle_package_manager }} spindle sdd` ticket commands. Otherwise follow the configured tracker's documented conventions.
24
24
 
25
25
  **Complete when:** one approved spec and its tracker destination are identified; any existing design precedes it and is approved.
26
26
 
@@ -41,7 +41,7 @@ An optional argument is one spec path or tracker reference. Read the full spec a
41
41
  **Complete when:** the user approves the ticket breakdown and blocker relationships.
42
42
 
43
43
  5. **Publish the tickets.**
44
- - For a local Spindle SDD tracker, create each ticket in dependency order with `spindle sdd ticket create --spec <absolute-spec-path>`. Supply its title, reporter, category (`bug` or `enhancement`), and author. Fill the generated ticket's Requirements and Acceptance Criteria using the tracker guidance. After creation, use `spindle sdd ticket update --spec <absolute-spec-path> --ticket <id> --blocked-by <blocker-ids...> --author <author>` to record each dependency; omit `--blocked-by` when there are no blockers. Keep the approved spec and feature ledger authoritative.
44
+ - For a local Spindle SDD tracker, create each ticket in dependency order with `{{ computed.spindle_package_manager }} spindle sdd ticket create --spec <absolute-spec-path>`. Supply its title, reporter, category (`bug` or `enhancement`), and author. Fill the generated ticket's Requirements and Acceptance Criteria using the tracker guidance. After creation, use `{{ computed.spindle_package_manager }} spindle sdd ticket update --spec <absolute-spec-path> --ticket <id> --blocked-by <blocker-ids...> --author <author>` to record each dependency; omit `--blocked-by` when there are no blockers. Keep the approved spec and feature ledger authoritative.
45
45
  - For an external ticket tracker, create one ticket per approved ticket in dependency order and use native blocking relationships when available; otherwise record blockers in each ticket. If the source was an existing ticket, create sub-tickets as required by the tracker.
46
46
  - Apply a status only when the project documents it or the user requests it. Do not close or modify a parent ticket.
47
47
  - Publishing ends here. Tell the user that delivery begins through the project's documented implementation workflow; do not start implementation.
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: setup-project
3
- description: "Use after spindle init to document project tooling and establish domain glossaries."
2
+ name: spindle-project-setup
3
+ description: "Use after {{ computed.spindle_package_manager }} spindle init to document project tooling and establish domain glossaries."
4
4
  disable-model-invocation: false
5
5
  user-invocable: true
6
6
  metadata:
@@ -14,7 +14,7 @@ Curate the commands agents should use and establish project domain documentation
14
14
 
15
15
  ## Prerequisite
16
16
 
17
- The user must have completed `spindle init` before running this skill. This skill
17
+ The user must have completed `{{ computed.spindle_package_manager }} spindle init` before running this skill. This skill
18
18
  does not initialize the project. If the required project guidance or tooling
19
19
  registry is missing, report the prerequisite and stop.
20
20
 
@@ -41,7 +41,7 @@ Also inspect the source to determine whether this is an existing project: it con
41
41
 
42
42
  ### C. Update and verify tooling
43
43
 
44
- Load and follow the `update-tooling` skill. Supply the verified candidate commands and relevant configuration paths found in B as explicit context, and request a full registry comparison for initial setup. That skill owns the proposal, explicit approval, revision loop, `spindle tool` registry mutations, and generated-guide verification; do not duplicate or bypass its approval gate.
44
+ Load and follow the `spindle-tooling-update` skill. Supply the verified candidate commands and relevant configuration paths found in B as explicit context, and request a full registry comparison for initial setup. That skill owns the proposal, explicit approval, revision loop, `{{ computed.spindle_package_manager }} spindle tool` registry mutations, and generated-guide verification; do not duplicate or bypass its approval gate.
45
45
 
46
46
  **Complete when:** the delegated workflow has returned with the registry and guide verified, selecting G. If approval is pending, wait; if it reports failures or discrepancies, report the blocker and stop rather than claiming setup is complete.
47
47
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: update-tooling
2
+ name: spindle-tooling-update
3
3
  description: "Use when tooling commands are added, changed, or removed, or when refreshing the tooling registry and generated guide."
4
4
  argument-hint: "[change description or tooling paths]"
5
5
  disable-model-invocation: false
@@ -34,7 +34,7 @@ flowchart TD
34
34
 
35
35
  ### A. Inspect tooling and registry
36
36
 
37
- Read project guidance and run `spindle tool list` from the target Git working tree. Inspect package manifests, task runner configuration, and test/build configuration for the supplied target, or the whole project when no target is supplied. Verify command names, argument forms, and working-directory requirements against configuration. Preserve unrelated registry entries; absence from a targeted inspection is not evidence that an entry is obsolete.
37
+ Read project guidance and run `{{ computed.spindle_package_manager }} spindle tool list` from the target Git working tree. Inspect package manifests, task runner configuration, and test/build configuration for the supplied target, or the whole project when no target is supplied. Verify command names, argument forms, and working-directory requirements against configuration. Preserve unrelated registry entries; absence from a targeted inspection is not evidence that an entry is obsolete.
38
38
 
39
39
  Do not execute project commands merely to document them if execution could install dependencies, mutate data, or have side effects without authorization. If the registry is missing or invalid, report the prerequisite and stop; do not run initialization or silently repair it.
40
40
 
@@ -59,14 +59,14 @@ Ask for explicit approval of the complete change set and wait. Approval applies
59
59
  Apply only approved changes through Spindle, not by directly editing the registry or generated Markdown. Add one entry per approved command:
60
60
 
61
61
  ```sh
62
- spindle tool add \
62
+ {{ computed.spindle_package_manager }} spindle tool add \
63
63
  --key test-unit \
64
64
  --section Testing \
65
65
  --command "pnpm test -- --run" \
66
66
  --description "Run the focused unit tests."
67
67
  ```
68
68
 
69
- Use `spindle tool update <key>` with the approved `--section`, `--command`, or `--description` fields; `--clear-description` explicitly removes a description. Use `spindle tool remove <key>` for approved removals. Each successful mutation regenerates the guide, grouped by section with empty sections omitted.
69
+ Use `{{ computed.spindle_package_manager }} spindle tool update <key>` with the approved `--section`, `--command`, or `--description` fields; `--clear-description` explicitly removes a description. Use `{{ computed.spindle_package_manager }} spindle tool remove <key>` for approved removals. Each successful mutation regenerates the guide, grouped by section with empty sections omitted.
70
70
  Run project scripts with `{{ computed.spindle_package_manager }} <script>`, such as `{{ computed.spindle_package_manager }} lint`.
71
71
 
72
72
  If the inspected registry or relevant configuration has changed since approval, stop and return to A, then obtain approval for a refreshed proposal. If a command fails, stop and report the failure and any already-applied changes; do not claim atomicity or completion.
@@ -75,7 +75,7 @@ If the inspected registry or relevant configuration has changed since approval,
75
75
 
76
76
  ### E. Verify registry and guide
77
77
 
78
- Run `spindle tool list` again and inspect `docs/agents/tooling.md`. Confirm entries, sections, commands, descriptions, and limitations agree, approved changes are reflected, and unrelated entries remain unchanged. After a decline or no-op, verify the existing state without mutating it. Report mismatches; any corrective changes require a new proposal and approval rather than direct Markdown edits.
78
+ Run `{{ computed.spindle_package_manager }} spindle tool list` again and inspect `docs/agents/tooling.md`. Confirm entries, sections, commands, descriptions, and limitations agree, approved changes are reflected, and unrelated entries remain unchanged. After a decline or no-op, verify the existing state without mutating it. Report mismatches; any corrective changes require a new proposal and approval rather than direct Markdown edits.
79
79
 
80
80
  **Complete when:** verification results and any discrepancies are known, selecting F.
81
81
 
@@ -1,14 +1,8 @@
1
- ## Agent skills
1
+ ## Issue tracker
2
2
 
3
- ### Issue tracker
3
+ SDD specs and tickets live in numbered `.scratch/<feature-id>-<feature-slug>/` workspaces. See `docs/agents/issue-tracker.md` and `docs/agents/ticket-tracker.md` for their conventions.
4
4
 
5
- Repository triage requests are tracked as local Markdown under `.scratch/YYYY-MM-DD-<feature-slug>/`; SDD specs and tickets live in numbered `.scratch/<feature-id>-<feature-slug>/` workspaces. See `docs/agents/issue-tracker.md` and `docs/agents/ticket-tracker.md` for their conventions.
6
-
7
- ### Triage labels
8
-
9
- Use `Category: bug|enhancement` and the five canonical state values in `Status:`. See `docs/agents/triage-labels.md`.
10
-
11
- ### Domain docs
5
+ ## Domain docs
12
6
 
13
7
  This is a multi-context repo; use `GLOSSARY-MAP.md` to find the relevant context glossary and consult `docs/adr/` for cross-context decisions. See `docs/agents/domain.md`.
14
8
 
@@ -15,19 +15,27 @@ Spindle SDD stores feature work in `.scratch/` workspaces. A workspace contains
15
15
  Create each approved ticket in dependency order:
16
16
 
17
17
  ```sh
18
- spindle sdd ticket create --spec <absolute-spec-path> --title "..." --reporter "..." --category enhancement --author maintainer
18
+ {{ computed.spindle_package_manager }} spindle sdd ticket create --spec <absolute-spec-path> --title "..." --reporter "..." --category enhancement --author maintainer
19
19
  ```
20
20
 
21
21
  The command returns the new ticket ID and path. Complete its template, then set dependencies with `ticket update`:
22
22
 
23
23
  ```sh
24
- spindle sdd ticket update --spec <absolute-spec-path> --ticket T-0002 --blocked-by T-0001 --author maintainer
25
- spindle sdd ticket comment --spec <absolute-spec-path> --ticket T-0001 --details "..." --author maintainer
26
- spindle sdd ready --spec <absolute-spec-path>
24
+ {{ computed.spindle_package_manager }} spindle sdd ticket update --spec <absolute-spec-path> --ticket T-0002 --blocked-by T-0001 --author maintainer
25
+ {{ computed.spindle_package_manager }} spindle sdd ticket comment --spec <absolute-spec-path> --ticket T-0001 --details "..." --author maintainer
26
+ {{ computed.spindle_package_manager }} spindle sdd ready --spec <absolute-spec-path>
27
27
  ```
28
28
 
29
- Use `--clear-blocked-by` to remove dependencies. Use `ticket update --status` to change status. Ticket Markdown remains editable; attributed comments are appended under `## Comments`. Do not add an execution field to the ticket file: execution transitions are recorded in `sdd.json`.
29
+ Use `--clear-blocked-by` to remove dependencies. Ticket Markdown remains editable; attributed comments are appended under `## Comments`. Do not add an execution field to the ticket file: execution transitions are recorded in `sdd.json`.
30
30
 
31
31
  ## Delivery
32
32
 
33
- Use `spindle sdd status` and `spindle sdd ready` to inspect work. Claim and dispatch ready tickets with `spindle sdd claim` and `spindle sdd implement`, submit the assigned report with `spindle sdd submit`, and close completed tickets with `spindle sdd ticket update --status closed`. Follow the `int-subagent-driven-dev` skill for review, correction, and feature completion.
33
+ Use `{{ computed.spindle_package_manager }} spindle sdd status` and `{{ computed.spindle_package_manager }} spindle sdd ready` to inspect work. Follow the `int-subagent-driven-dev` skill for dispatch, review, correction, integration, and feature completion.
34
+
35
+ Inspect feature records for sensitive content, then start a feature worktree in an existing external directory with `{{ computed.spindle_package_manager }} spindle sdd start --spec <absolute-spec-path> --workspace <absolute-directory> --confirm-records`. Use its returned spec path for subsequent commands.
36
+
37
+ Dispatch each ready ticket to a separate worktree with `{{ computed.spindle_package_manager }} spindle sdd implement --spec <feature-spec-path> --ticket <id> --author <name> --workspace <absolute-directory>`. Inspect changed canonical records and pass `--confirm-records` before automatic record commits. Submit the implementation report and review the committed ticket before merging it with `{{ computed.spindle_package_manager }} spindle sdd integrate`.
38
+
39
+ Declare the complete post-merge check list with `checks require --scope post-merge --ticket <id>`, run the checks, and record each result with `checks record --scope post-merge --ticket <id>`. Passing results close the ticket automatically unless a blocker or dependency prevents closure. Resolve it, then repeat `checks require` with the same complete list; rerun any stale checks. Failed checks block other merges until a reviewed correction passes. Resolve conflicts in the ticket worktree, adopt the rebased baseline with `checks require --rebase-baseline`, and obtain fresh checks and review.
40
+
41
+ After aggregate checks and review pass, inspect records and run `{{ computed.spindle_package_manager }} spindle sdd finish --spec <feature-spec-path> --author <name> --confirm-records` from the feature worktree. Include `--report <absolute-report-path>` when a retrospective is required. In the original checkout, declare the complete list with `checks require --scope final`, run the checks, and record each result with `checks record --scope final --merge <merge-sha> --snapshot <snapshot>`. Repeat `finish` there to preflight and clean up. Final checks cover the merge; a separate ledger-only relocation commit follows. Preserve work and inspect the journal if recovery or cleanup is blocked.
@@ -20,7 +20,7 @@ export async function promptSpindlePackageManager() {
20
20
  message: "Which package-manager command should Spindle use in generated guidance?",
21
21
  options: [
22
22
  { value: "npm run", label: "npm run" },
23
- { value: "pnpm", label: "pnpm" },
23
+ { value: "pnpm exec", label: "pnpm exec" },
24
24
  { value: "yarn", label: "yarn" },
25
25
  { value: "bun", label: "bun" },
26
26
  { value: "other", label: "Other" },
@@ -2,6 +2,7 @@ import { Command } from "../../Commands/Command.js";
2
2
  import { CommandOptions } from "../../Commands/CommandOptions.js";
3
3
  import { group } from "./groups.js";
4
4
  import { ChecksService } from "../Services/ChecksService.js";
5
+ import { FeatureFinalizationService } from "../Services/FeatureFinalizationService.js";
5
6
  export class ChecksRecordCommand extends Command {
6
7
  static register(root, createApp) {
7
8
  group(root, "checks")
@@ -9,7 +10,8 @@ export class ChecksRecordCommand extends Command {
9
10
  .description("Record an externally executed check against a current snapshot.")
10
11
  .requiredOption("--spec <path>", "Feature spec path", CommandOptions.once("--spec"))
11
12
  .option("--ticket <id>", "Ticket ID", CommandOptions.once("--ticket"))
12
- .option("--scope <scope>", "Workflow scope: delivery")
13
+ .option("--scope <scope>", "Workflow scope: delivery, post-merge or final")
14
+ .option("--merge <sha>", "Exact feature merge commit; required for scope final", CommandOptions.once("--merge"))
13
15
  .requiredOption("--snapshot <snapshot>", "CLI-returned content snapshot identity", CommandOptions.once("--snapshot"))
14
16
  .requiredOption("--command <command>", "Exact required command", CommandOptions.once("--command"))
15
17
  .requiredOption("--result <result>", "Check result: passed, failed, unavailable", CommandOptions.once("--result"))
@@ -18,11 +20,12 @@ export class ChecksRecordCommand extends Command {
18
20
  .requiredOption("--author <author>", "Acting controller", CommandOptions.once("--author"))
19
21
  .allowExcessArguments(false)
20
22
  .action(async (options) => {
21
- if (options.scope !== undefined && options.scope !== "delivery") {
22
- throw new Error("--scope must be 'delivery'.");
23
+ if (options.scope !== undefined &&
24
+ !["delivery", "post-merge", "final"].includes(options.scope)) {
25
+ throw new Error("--scope must be 'delivery', 'post-merge' or 'final'.");
23
26
  }
24
- if (Boolean(options.ticket) === (options.scope === "delivery")) {
25
- throw new Error("checks record needs exactly one of --ticket or --scope delivery.");
27
+ if ((options.scope === "delivery" || options.scope === "final") === Boolean(options.ticket)) {
28
+ throw new Error("checks record needs --ticket or --scope delivery/final; scope post-merge also needs --ticket.");
26
29
  }
27
30
  const command = await (await createApp()).make(ChecksRecordCommand);
28
31
  console.log(JSON.stringify(await command.run(options), null, 2));
@@ -30,6 +33,25 @@ export class ChecksRecordCommand extends Command {
30
33
  }
31
34
  async run(options) {
32
35
  this.assertApplicationBooted();
36
+ if (options.scope === "final") {
37
+ if (options.ticket || options.paths || !options.merge)
38
+ throw new Error("Final records require --merge and do not accept ticket/path coverage.");
39
+ const finalization = await this.app.make(FeatureFinalizationService);
40
+ const feature = finalization.recordedFeature(options.spec);
41
+ if (!feature)
42
+ throw new Error("Final records require a recorded feature merge.");
43
+ return finalization.record({
44
+ feature: feature.feature,
45
+ merge: options.merge,
46
+ snapshot: options.snapshot,
47
+ command: options.command,
48
+ result: options.result,
49
+ author: options.author,
50
+ ...(options.details ? { details: options.details } : {}),
51
+ });
52
+ }
53
+ if (options.merge)
54
+ throw new Error("--merge is only valid with --scope final.");
33
55
  return (await this.app.make(ChecksService)).checksRecord(options);
34
56
  }
35
57
  }
@@ -2,6 +2,7 @@ import { Command } from "../../Commands/Command.js";
2
2
  import { CommandOptions } from "../../Commands/CommandOptions.js";
3
3
  import { group } from "./groups.js";
4
4
  import { ChecksService } from "../Services/ChecksService.js";
5
+ import { FeatureFinalizationService } from "../Services/FeatureFinalizationService.js";
5
6
  export class ChecksRequireCommand extends Command {
6
7
  static register(root, createApp) {
7
8
  group(root, "checks")
@@ -9,25 +10,48 @@ export class ChecksRequireCommand extends Command {
9
10
  .description("Add or remove a required external check.")
10
11
  .requiredOption("--spec <path>", "Feature spec path", CommandOptions.once("--spec"))
11
12
  .option("--ticket <id>", "Ticket ID", CommandOptions.once("--ticket"))
12
- .option("--scope <scope>", "Workflow scope: delivery")
13
- .requiredOption("--command <command>", "Exact externally executed command", CommandOptions.once("--command"))
13
+ .option("--scope <scope>", "Workflow scope: delivery, post-merge or final")
14
+ .requiredOption("--command <command>", "Exact externally executed command; repeat for post-merge or final lists", (value, previous = []) => [...previous, value], [])
14
15
  .option("--remove", "Remove the requirement; requires --details rationale")
16
+ .option("--rebase-baseline", "Adopt current feature HEAD after manually rebasing the ticket worktree")
15
17
  .option("--details <details>", "Removal rationale")
16
18
  .requiredOption("--author <author>", "Acting controller", CommandOptions.once("--author"))
17
19
  .allowExcessArguments(false)
18
20
  .action(async (options) => {
19
- if (options.scope !== undefined && options.scope !== "delivery") {
20
- throw new Error("--scope must be 'delivery'.");
21
+ if (options.scope !== undefined &&
22
+ options.scope !== "delivery" &&
23
+ options.scope !== "post-merge" &&
24
+ options.scope !== "final") {
25
+ throw new Error("--scope must be 'delivery', 'post-merge' or 'final'.");
21
26
  }
22
- if (Boolean(options.ticket) === (options.scope === "delivery")) {
23
- throw new Error("checks require needs exactly one of --ticket or --scope delivery.");
27
+ if ((options.scope === "delivery" || options.scope === "final") === Boolean(options.ticket)) {
28
+ throw new Error("checks require needs --ticket or --scope delivery/final; scope post-merge also needs --ticket.");
24
29
  }
30
+ if (options.scope !== "post-merge" &&
31
+ options.scope !== "final" &&
32
+ options.command.length !== 1)
33
+ throw new Error("Exactly one --command is required outside scopes post-merge and final.");
25
34
  const command = await (await createApp()).make(ChecksRequireCommand);
26
- console.log(JSON.stringify(await command.run(options), null, 2));
35
+ console.log(JSON.stringify(await command.run({
36
+ ...options,
37
+ command: options.scope === "post-merge" || options.scope === "final"
38
+ ? options.command
39
+ : options.command[0],
40
+ }), null, 2));
27
41
  });
28
42
  }
29
43
  async run(options) {
30
44
  this.assertApplicationBooted();
45
+ if (options.scope === "final") {
46
+ if (options.ticket || options.remove || options.details || options.rebaseBaseline) {
47
+ throw new Error("Final declarations do not accept ticket, removal, rebase or coverage options.");
48
+ }
49
+ return (await this.app.make(FeatureFinalizationService)).declare({
50
+ spec: options.spec,
51
+ command: Array.isArray(options.command) ? options.command : [options.command],
52
+ author: options.author,
53
+ });
54
+ }
31
55
  return (await this.app.make(ChecksService)).checksRequire(options);
32
56
  }
33
57
  }
@@ -15,7 +15,6 @@ export class CorrectCommand extends Command {
15
15
  .requiredOption("--details <details>", "Correction objective or adjudication rationale", CommandOptions.once("--details"))
16
16
  .option("--decision <decision>", "Continuation decision: continue or pause")
17
17
  .option("--assessment <assessment>", "Recorded progress assessment for the prior attempt")
18
- .option("--assessment-result <result>", "Progress result: productive")
19
18
  .option("--reason <reason>", "Pause reason: no-progress, repeated-failure, recurring-blocker, requirements-disagreement, worker-blocked")
20
19
  .requiredOption("--author <author>", "Controller author", CommandOptions.once("--author"))
21
20
  .allowExcessArguments(false)
@@ -6,10 +6,11 @@ export class FinishCommand extends Command {
6
6
  static register(root, createApp) {
7
7
  group(root)
8
8
  .command("finish")
9
- .description("Complete feature delivery after all tickets are closed and required checks and reviews pass.")
9
+ .description("Merge approved feature delivery, then clean up only after exact final-merge checks pass.")
10
10
  .requiredOption("--spec <path>", "Feature spec path", CommandOptions.once("--spec"))
11
11
  .option("--report <path>", "Optional or policy-required Markdown report inside feature reports/", CommandOptions.once("--report"))
12
12
  .requiredOption("--author <author>", "Controller author", CommandOptions.once("--author"))
13
+ .option("--confirm-records", "Confirm inspected canonical records may be committed")
13
14
  .allowExcessArguments(false)
14
15
  .action(async (options) => {
15
16
  const command = await (await createApp()).make(FinishCommand);
@@ -10,6 +10,8 @@ export class ImplementCommand extends Command {
10
10
  .requiredOption("--spec <path>", "Feature spec path", CommandOptions.once("--spec"))
11
11
  .requiredOption("--ticket <id>", "Ticket ID", CommandOptions.once("--ticket"))
12
12
  .requiredOption("--author <author>", "Controller author", CommandOptions.once("--author"))
13
+ .requiredOption("--workspace <directory>", "Existing absolute external directory for the ticket worktree", CommandOptions.once("--workspace"))
14
+ .option("--confirm-records", "Confirm that current canonical feature records were inspected before batching")
13
15
  .allowExcessArguments(false)
14
16
  .action(async (options) => {
15
17
  const command = await (await createApp()).make(ImplementCommand);
@@ -1,23 +1,24 @@
1
1
  import { Command } from "../../Commands/Command.js";
2
2
  import { CommandOptions } from "../../Commands/CommandOptions.js";
3
3
  import { group } from "./groups.js";
4
- import { AssignmentService } from "../Services/AssignmentService.js";
5
- export class ClaimCommand extends Command {
4
+ import { TicketIntegrationService } from "../Services/TicketIntegrationService.js";
5
+ export class IntegrateCommand extends Command {
6
6
  static register(root, createApp) {
7
7
  group(root)
8
- .command("claim")
9
- .description("Claim a ready ticket from a clean Git checkout.")
10
- .requiredOption("--spec <path>", "Feature spec path", CommandOptions.once("--spec"))
8
+ .command("integrate")
9
+ .description("Merge a currently reviewed ticket commit into the feature branch.")
10
+ .requiredOption("--spec <path>", "Canonical feature spec", CommandOptions.once("--spec"))
11
11
  .requiredOption("--ticket <id>", "Ticket ID", CommandOptions.once("--ticket"))
12
12
  .requiredOption("--author <author>", "Controller author", CommandOptions.once("--author"))
13
+ .option("--confirm-records", "Confirm that current canonical feature records were inspected before batching")
13
14
  .allowExcessArguments(false)
14
15
  .action(async (options) => {
15
- const command = await (await createApp()).make(ClaimCommand);
16
+ const command = await (await createApp()).make(IntegrateCommand);
16
17
  console.log(JSON.stringify(await command.run(options), null, 2));
17
18
  });
18
19
  }
19
20
  async run(options) {
20
21
  this.assertApplicationBooted();
21
- return (await this.app.make(AssignmentService)).claim(options);
22
+ return (await this.app.make(TicketIntegrationService)).integrate(options);
22
23
  }
23
24
  }