@levu/snap 0.1.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 (168) hide show
  1. package/.github/workflows/ci.yml +26 -0
  2. package/README.md +49 -0
  3. package/dist/cli/help-command.d.ts +1 -0
  4. package/dist/cli/help-command.js +1 -0
  5. package/dist/cli-entry.d.ts +1 -0
  6. package/dist/cli-entry.js +80 -0
  7. package/dist/core/contracts/action-contract.d.ts +25 -0
  8. package/dist/core/contracts/action-contract.js +1 -0
  9. package/dist/core/contracts/help-contract.d.ts +18 -0
  10. package/dist/core/contracts/help-contract.js +1 -0
  11. package/dist/core/contracts/module-contract.d.ts +6 -0
  12. package/dist/core/contracts/module-contract.js +1 -0
  13. package/dist/core/errors/framework-errors.d.ts +19 -0
  14. package/dist/core/errors/framework-errors.js +26 -0
  15. package/dist/core/registry/action-registry.d.ts +16 -0
  16. package/dist/core/registry/action-registry.js +52 -0
  17. package/dist/help/help-command.d.ts +8 -0
  18. package/dist/help/help-command.js +21 -0
  19. package/dist/help/help-model.d.ts +9 -0
  20. package/dist/help/help-model.js +1 -0
  21. package/dist/help/help-renderer.d.ts +2 -0
  22. package/dist/help/help-renderer.js +16 -0
  23. package/dist/help/hierarchy-resolver.d.ts +3 -0
  24. package/dist/help/hierarchy-resolver.js +43 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.js +8 -0
  27. package/dist/modules/sample-content/module.d.ts +3 -0
  28. package/dist/modules/sample-content/module.js +61 -0
  29. package/dist/modules/sample-system/module.d.ts +3 -0
  30. package/dist/modules/sample-system/module.js +71 -0
  31. package/dist/runtime/dispatch.d.ts +11 -0
  32. package/dist/runtime/dispatch.js +47 -0
  33. package/dist/runtime/engine.d.ts +13 -0
  34. package/dist/runtime/engine.js +44 -0
  35. package/dist/runtime/mode-resolver.d.ts +8 -0
  36. package/dist/runtime/mode-resolver.js +8 -0
  37. package/dist/runtime/resume-store.d.ts +13 -0
  38. package/dist/runtime/resume-store.js +45 -0
  39. package/dist/runtime/runtime-context.d.ts +9 -0
  40. package/dist/runtime/runtime-context.js +1 -0
  41. package/dist/runtime/state-machine.d.ts +32 -0
  42. package/dist/runtime/state-machine.js +50 -0
  43. package/dist/src/cli/help-command.d.ts +1 -0
  44. package/dist/src/cli/help-command.js +1 -0
  45. package/dist/src/cli-entry.d.ts +1 -0
  46. package/dist/src/cli-entry.js +80 -0
  47. package/dist/src/core/contracts/action-contract.d.ts +25 -0
  48. package/dist/src/core/contracts/action-contract.js +1 -0
  49. package/dist/src/core/contracts/help-contract.d.ts +18 -0
  50. package/dist/src/core/contracts/help-contract.js +1 -0
  51. package/dist/src/core/contracts/module-contract.d.ts +6 -0
  52. package/dist/src/core/contracts/module-contract.js +1 -0
  53. package/dist/src/core/errors/framework-errors.d.ts +19 -0
  54. package/dist/src/core/errors/framework-errors.js +26 -0
  55. package/dist/src/core/registry/action-registry.d.ts +16 -0
  56. package/dist/src/core/registry/action-registry.js +52 -0
  57. package/dist/src/help/help-command.d.ts +8 -0
  58. package/dist/src/help/help-command.js +21 -0
  59. package/dist/src/help/help-model.d.ts +9 -0
  60. package/dist/src/help/help-model.js +1 -0
  61. package/dist/src/help/help-renderer.d.ts +2 -0
  62. package/dist/src/help/help-renderer.js +16 -0
  63. package/dist/src/help/hierarchy-resolver.d.ts +3 -0
  64. package/dist/src/help/hierarchy-resolver.js +43 -0
  65. package/dist/src/index.d.ts +3 -0
  66. package/dist/src/index.js +8 -0
  67. package/dist/src/modules/sample-content/module.d.ts +3 -0
  68. package/dist/src/modules/sample-content/module.js +61 -0
  69. package/dist/src/modules/sample-system/module.d.ts +3 -0
  70. package/dist/src/modules/sample-system/module.js +71 -0
  71. package/dist/src/runtime/dispatch.d.ts +11 -0
  72. package/dist/src/runtime/dispatch.js +47 -0
  73. package/dist/src/runtime/engine.d.ts +13 -0
  74. package/dist/src/runtime/engine.js +44 -0
  75. package/dist/src/runtime/mode-resolver.d.ts +8 -0
  76. package/dist/src/runtime/mode-resolver.js +8 -0
  77. package/dist/src/runtime/resume-store.d.ts +13 -0
  78. package/dist/src/runtime/resume-store.js +45 -0
  79. package/dist/src/runtime/runtime-context.d.ts +9 -0
  80. package/dist/src/runtime/runtime-context.js +1 -0
  81. package/dist/src/runtime/state-machine.d.ts +32 -0
  82. package/dist/src/runtime/state-machine.js +50 -0
  83. package/dist/src/tui/accessibility-footer.d.ts +7 -0
  84. package/dist/src/tui/accessibility-footer.js +4 -0
  85. package/dist/src/tui/component-adapters/confirm.d.ts +5 -0
  86. package/dist/src/tui/component-adapters/confirm.js +3 -0
  87. package/dist/src/tui/component-adapters/group.d.ts +5 -0
  88. package/dist/src/tui/component-adapters/group.js +7 -0
  89. package/dist/src/tui/component-adapters/multiselect.d.ts +10 -0
  90. package/dist/src/tui/component-adapters/multiselect.js +9 -0
  91. package/dist/src/tui/component-adapters/select.d.ts +10 -0
  92. package/dist/src/tui/component-adapters/select.js +7 -0
  93. package/dist/src/tui/component-adapters/text.d.ts +6 -0
  94. package/dist/src/tui/component-adapters/text.js +7 -0
  95. package/dist/src/tui/interrupt-handlers.d.ts +7 -0
  96. package/dist/src/tui/interrupt-handlers.js +7 -0
  97. package/dist/tests/e2e/cli-smoke.e2e.test.d.ts +1 -0
  98. package/dist/tests/e2e/cli-smoke.e2e.test.js +16 -0
  99. package/dist/tests/integration/runtime-dispatch.integration.test.d.ts +1 -0
  100. package/dist/tests/integration/runtime-dispatch.integration.test.js +20 -0
  101. package/dist/tests/transcript/help.transcript.test.d.ts +1 -0
  102. package/dist/tests/transcript/help.transcript.test.js +18 -0
  103. package/dist/tests/unit/state-machine.test.d.ts +1 -0
  104. package/dist/tests/unit/state-machine.test.js +20 -0
  105. package/dist/tui/accessibility-footer.d.ts +7 -0
  106. package/dist/tui/accessibility-footer.js +4 -0
  107. package/dist/tui/component-adapters/confirm.d.ts +5 -0
  108. package/dist/tui/component-adapters/confirm.js +3 -0
  109. package/dist/tui/component-adapters/group.d.ts +5 -0
  110. package/dist/tui/component-adapters/group.js +7 -0
  111. package/dist/tui/component-adapters/multiselect.d.ts +10 -0
  112. package/dist/tui/component-adapters/multiselect.js +9 -0
  113. package/dist/tui/component-adapters/select.d.ts +10 -0
  114. package/dist/tui/component-adapters/select.js +7 -0
  115. package/dist/tui/component-adapters/text.d.ts +6 -0
  116. package/dist/tui/component-adapters/text.js +7 -0
  117. package/dist/tui/interrupt-handlers.d.ts +7 -0
  118. package/dist/tui/interrupt-handlers.js +7 -0
  119. package/dist/vitest.config.d.ts +2 -0
  120. package/dist/vitest.config.js +7 -0
  121. package/docs/help-contract-spec.md +29 -0
  122. package/docs/module-authoring-guide.md +52 -0
  123. package/package.json +20 -0
  124. package/plans/260209-1547-hub-dual-runtime-framework/phase-01-foundation-and-contracts.md +71 -0
  125. package/plans/260209-1547-hub-dual-runtime-framework/phase-02-runtime-and-state-machine.md +76 -0
  126. package/plans/260209-1547-hub-dual-runtime-framework/phase-03-tui-components-and-policies.md +71 -0
  127. package/plans/260209-1547-hub-dual-runtime-framework/phase-04-help-system-and-ai-readability.md +69 -0
  128. package/plans/260209-1547-hub-dual-runtime-framework/phase-05-testing-and-quality-gates.md +79 -0
  129. package/plans/260209-1547-hub-dual-runtime-framework/phase-06-sample-modules-and-adoption.md +75 -0
  130. package/plans/260209-1547-hub-dual-runtime-framework/plan.md +105 -0
  131. package/plans/260209-1547-hub-dual-runtime-framework/reports/planner-report.md +27 -0
  132. package/plans/260209-1547-hub-dual-runtime-framework/research/researcher-01-report.md +166 -0
  133. package/plans/260209-1547-hub-dual-runtime-framework/research/researcher-02-report.md +87 -0
  134. package/plans/260209-1547-hub-dual-runtime-framework/scout/scout-01-report.md +24 -0
  135. package/src/cli/help-command.ts +1 -0
  136. package/src/cli-entry.ts +83 -0
  137. package/src/core/contracts/action-contract.ts +30 -0
  138. package/src/core/contracts/help-contract.ts +20 -0
  139. package/src/core/contracts/module-contract.ts +7 -0
  140. package/src/core/errors/framework-errors.ts +26 -0
  141. package/src/core/registry/action-registry.ts +94 -0
  142. package/src/help/help-command.ts +32 -0
  143. package/src/help/help-model.ts +10 -0
  144. package/src/help/help-renderer.ts +21 -0
  145. package/src/help/hierarchy-resolver.ts +54 -0
  146. package/src/index.ts +10 -0
  147. package/src/modules/sample-content/module.ts +66 -0
  148. package/src/modules/sample-system/module.ts +74 -0
  149. package/src/runtime/dispatch.ts +64 -0
  150. package/src/runtime/engine.ts +59 -0
  151. package/src/runtime/mode-resolver.ts +18 -0
  152. package/src/runtime/resume-store.ts +53 -0
  153. package/src/runtime/runtime-context.ts +10 -0
  154. package/src/runtime/state-machine.ts +77 -0
  155. package/src/tui/accessibility-footer.ts +11 -0
  156. package/src/tui/component-adapters/confirm.ts +8 -0
  157. package/src/tui/component-adapters/group.ts +12 -0
  158. package/src/tui/component-adapters/multiselect.ts +22 -0
  159. package/src/tui/component-adapters/select.ts +18 -0
  160. package/src/tui/component-adapters/text.ts +13 -0
  161. package/src/tui/interrupt-handlers.ts +15 -0
  162. package/tests/e2e/cli-smoke.e2e.test.ts +19 -0
  163. package/tests/integration/runtime-dispatch.integration.test.ts +23 -0
  164. package/tests/transcript/help.transcript.test.ts +20 -0
  165. package/tests/unit/state-machine.test.ts +22 -0
  166. package/tsconfig.build.json +9 -0
  167. package/tsconfig.json +17 -0
  168. package/vitest.config.ts +8 -0
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createRegistry } from '../../src/index.js';
3
+ import sampleContentModule from '../../src/modules/sample-content/module.js';
4
+ import sampleSystemModule from '../../src/modules/sample-system/module.js';
5
+ import { dispatchAction } from '../../src/runtime/dispatch.js';
6
+ describe('integration dispatch runtime', () => {
7
+ it('dispatches commandline action with required args', async () => {
8
+ const registry = createRegistry([sampleContentModule, sampleSystemModule]);
9
+ const result = await dispatchAction({
10
+ registry,
11
+ moduleId: 'content',
12
+ actionId: 'slugify',
13
+ args: { text: 'Hello Integration Test' },
14
+ isTTY: true
15
+ });
16
+ expect(result.ok).toBe(true);
17
+ expect(result.mode).toBe('commandline');
18
+ expect(result.data).toBe('hello-integration-test');
19
+ });
20
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { renderHelp } from '../../src/help/help-renderer.js';
3
+ import { resolveHelpHierarchy } from '../../src/help/hierarchy-resolver.js';
4
+ import sampleContentModule from '../../src/modules/sample-content/module.js';
5
+ describe('transcript help output', () => {
6
+ it('renders deterministic action help transcript', () => {
7
+ const views = resolveHelpHierarchy([sampleContentModule], 'content', 'slugify');
8
+ const output = renderHelp(views);
9
+ expect(output).toContain('# HELP');
10
+ expect(output).toContain('MODULE: content');
11
+ expect(output).toContain('ACTION: slugify');
12
+ expect(output).toContain('## SUMMARY');
13
+ expect(output).toContain('## ARGS');
14
+ expect(output).toContain('## EXAMPLES');
15
+ expect(output).toContain('## USE-CASES');
16
+ expect(output).toContain('## KEYBINDINGS');
17
+ });
18
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { StateMachine } from '../../src/runtime/state-machine.js';
3
+ describe('state-machine', () => {
4
+ it('supports next/back/jump/exit transitions', () => {
5
+ const machine = new StateMachine('wf', [
6
+ { id: 'a', label: 'A' },
7
+ { id: 'b', label: 'B' },
8
+ { id: 'c', label: 'C' }
9
+ ]);
10
+ expect(machine.currentNode().id).toBe('a');
11
+ machine.transition({ type: 'next' });
12
+ expect(machine.currentNode().id).toBe('b');
13
+ machine.transition({ type: 'jump', targetNodeId: 'c' });
14
+ expect(machine.currentNode().id).toBe('c');
15
+ machine.transition({ type: 'back' });
16
+ expect(machine.currentNode().id).toBe('b');
17
+ machine.transition({ type: 'exit' });
18
+ expect(machine.snapshot().exited).toBe(true);
19
+ });
20
+ });
@@ -0,0 +1,7 @@
1
+ export interface AccessibilityFooterInput {
2
+ moduleId: string;
3
+ actionId: string;
4
+ nodeId: string;
5
+ keybindings: string[];
6
+ }
7
+ export declare const renderAccessibilityFooter: (input: AccessibilityFooterInput) => string;
@@ -0,0 +1,4 @@
1
+ export const renderAccessibilityFooter = (input) => {
2
+ const keys = input.keybindings.join(' | ');
3
+ return `[ctx module=${input.moduleId} action=${input.actionId} node=${input.nodeId}] [keys ${keys}]`;
4
+ };
@@ -0,0 +1,5 @@
1
+ export interface ConfirmPromptInput {
2
+ message: string;
3
+ initialValue?: boolean;
4
+ }
5
+ export declare const runConfirmPrompt: (input: ConfirmPromptInput) => Promise<boolean>;
@@ -0,0 +1,3 @@
1
+ export const runConfirmPrompt = async (input) => {
2
+ return input.initialValue ?? true;
3
+ };
@@ -0,0 +1,5 @@
1
+ export interface GroupStep<T = unknown> {
2
+ key: string;
3
+ run: () => Promise<T>;
4
+ }
5
+ export declare const runGroupPrompt: <T = unknown>(steps: GroupStep<T>[]) => Promise<Record<string, T>>;
@@ -0,0 +1,7 @@
1
+ export const runGroupPrompt = async (steps) => {
2
+ const result = {};
3
+ for (const step of steps) {
4
+ result[step.key] = await step.run();
5
+ }
6
+ return result;
7
+ };
@@ -0,0 +1,10 @@
1
+ export interface MultiSelectOption {
2
+ value: string;
3
+ label: string;
4
+ }
5
+ export interface MultiSelectPromptInput {
6
+ message: string;
7
+ options: MultiSelectOption[];
8
+ initialValues?: string[];
9
+ }
10
+ export declare const runMultiSelectPrompt: (input: MultiSelectPromptInput) => Promise<string[]>;
@@ -0,0 +1,9 @@
1
+ export const runMultiSelectPrompt = async (input) => {
2
+ if (input.options.length === 0) {
3
+ throw new Error(`No options available for multiselect prompt: ${input.message}`);
4
+ }
5
+ if (input.initialValues && input.initialValues.length > 0) {
6
+ return input.initialValues.filter((value) => input.options.some((option) => option.value === value));
7
+ }
8
+ return [input.options[0].value];
9
+ };
@@ -0,0 +1,10 @@
1
+ export interface SelectOption {
2
+ value: string;
3
+ label: string;
4
+ }
5
+ export interface SelectPromptInput {
6
+ message: string;
7
+ options: SelectOption[];
8
+ initialValue?: string;
9
+ }
10
+ export declare const runSelectPrompt: (input: SelectPromptInput) => Promise<string>;
@@ -0,0 +1,7 @@
1
+ export const runSelectPrompt = async (input) => {
2
+ const selected = input.initialValue ?? input.options[0]?.value;
3
+ if (!selected) {
4
+ throw new Error(`No options available for select prompt: ${input.message}`);
5
+ }
6
+ return selected;
7
+ };
@@ -0,0 +1,6 @@
1
+ export interface TextPromptInput {
2
+ message: string;
3
+ initialValue?: string;
4
+ required?: boolean;
5
+ }
6
+ export declare const runTextPrompt: (input: TextPromptInput) => Promise<string>;
@@ -0,0 +1,7 @@
1
+ export const runTextPrompt = async (input) => {
2
+ const value = input.initialValue ?? '';
3
+ if (input.required && value.trim().length === 0) {
4
+ throw new Error(`Required text value missing: ${input.message}`);
5
+ }
6
+ return value;
7
+ };
@@ -0,0 +1,7 @@
1
+ import { ExitCode } from '../core/errors/framework-errors.js';
2
+ export type InterruptSignal = 'SIGINT' | 'ESC' | 'TIMEOUT';
3
+ export interface InterruptResult {
4
+ exitCode: ExitCode;
5
+ reason: string;
6
+ }
7
+ export declare const handleInterrupt: (signal: InterruptSignal) => InterruptResult;
@@ -0,0 +1,7 @@
1
+ import { ExitCode } from '../core/errors/framework-errors.js';
2
+ export const handleInterrupt = (signal) => {
3
+ if (signal === 'TIMEOUT') {
4
+ return { exitCode: ExitCode.VALIDATION_ERROR, reason: 'Workflow timed out' };
5
+ }
6
+ return { exitCode: ExitCode.INTERRUPTED, reason: `Interrupted by ${signal}` };
7
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: import("vite").UserConfig;
2
+ export default _default;
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ export default defineConfig({
3
+ test: {
4
+ environment: 'node',
5
+ include: ['tests/**/*.test.ts']
6
+ }
7
+ });
@@ -0,0 +1,29 @@
1
+ # Help Contract Spec
2
+
3
+ ## Output Contract
4
+
5
+ Help renderer must produce deterministic text sections in this order:
6
+
7
+ 1. `# HELP`
8
+ 2. `MODULE: <module-id>`
9
+ 3. `ACTION: <action-id|*>`
10
+ 4. Section blocks:
11
+ - `## MODULE`
12
+ - `## ACTIONS`
13
+ - `## SUMMARY`
14
+ - `## ARGS`
15
+ - `## EXAMPLES`
16
+ - `## USE-CASES`
17
+ - `## KEYBINDINGS`
18
+
19
+ Each line item in section body uses `- <content>`.
20
+
21
+ ## CLI Levels
22
+
23
+ - `hub -h` => module overview list.
24
+ - `hub -h <module>` => module scoped list.
25
+ - `hub -h <module> <action>` => action detail.
26
+
27
+ ## Validation
28
+
29
+ Missing target returns non-zero exit code with deterministic error message.
@@ -0,0 +1,52 @@
1
+ # Module Authoring Guide
2
+
3
+ ## Goal
4
+
5
+ Define actions once with full triad contract:
6
+
7
+ - `tui` flow steps
8
+ - `commandline` required/optional args
9
+ - `help` metadata
10
+
11
+ ## Minimal Module Shape
12
+
13
+ ```ts
14
+ import type { ModuleContract } from '../core/contracts/module-contract.js';
15
+ import { ExitCode } from '../core/errors/framework-errors.js';
16
+
17
+ const moduleContract: ModuleContract = {
18
+ moduleId: 'example',
19
+ description: 'Example module',
20
+ actions: [
21
+ {
22
+ actionId: 'run',
23
+ description: 'Run example action',
24
+ tui: { steps: ['collect-input', 'confirm'] },
25
+ commandline: { requiredArgs: ['name'] },
26
+ help: {
27
+ summary: 'Run example with one name argument.',
28
+ args: [{ name: 'name', required: true, description: 'Target name' }],
29
+ examples: ['hub example run --name=alice'],
30
+ useCases: [{ name: 'default', description: 'Basic usage', command: 'hub example run --name=alice' }],
31
+ keybindings: ['Enter confirm', 'Esc cancel']
32
+ },
33
+ run: async (context) => ({
34
+ ok: true,
35
+ mode: context.mode,
36
+ exitCode: ExitCode.SUCCESS,
37
+ data: `hello ${String(context.args.name ?? '')}`
38
+ })
39
+ }
40
+ ]
41
+ };
42
+
43
+ export default moduleContract;
44
+ ```
45
+
46
+ ## Register Module
47
+
48
+ Add module to registry bootstrapping in `/Users/khang/Documents/repo/snap/src/cli-entry.ts`.
49
+
50
+ ## Validation Rules
51
+
52
+ Registration fails if any action misses triad data (`tui`, `commandline`, `help`).
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@levu/snap",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "snap": "./dist/cli-entry.js"
7
+ },
8
+ "scripts": {
9
+ "build": "tsc -p tsconfig.build.json",
10
+ "typecheck": "tsc -p tsconfig.json --noEmit",
11
+ "test": "vitest run",
12
+ "dev": "tsx src/cli-entry.ts"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^22.10.2",
16
+ "tsx": "^4.20.3",
17
+ "typescript": "^5.7.2",
18
+ "vitest": "^2.1.8"
19
+ }
20
+ }
@@ -0,0 +1,71 @@
1
+ # Phase 01 — Foundation and contracts
2
+
3
+ ## Context links
4
+ - Parent plan: `./plan.md`
5
+ - Inputs: `./scout/scout-01-report.md`, `./research/researcher-01-report.md`, `./research/researcher-02-report.md`
6
+ - Planner summary: `./reports/planner-report.md`
7
+
8
+ ## Overview
9
+ - Date: 2026-02-09
10
+ - Description: define core framework contracts and registry model enforcing TUI + CLI + help triad.
11
+ - Priority: P0
12
+ - Implementation status: complete
13
+ - Review status: complete
14
+
15
+ ## Key Insights
16
+ - Contract-first is required to prevent CLI/TUI/help drift.
17
+ - Greenfield repo allows clean architecture without migration baggage.
18
+
19
+ ## Requirements
20
+ - Functional:
21
+ - Define module/action contract types.
22
+ - Enforce triad presence at registration time.
23
+ - Define error taxonomy and exit-code map.
24
+ - Define runtime context and lifecycle hooks.
25
+ - Non-functional:
26
+ - Type-safe API surface.
27
+ - Minimal public API for v1 (KISS).
28
+
29
+ ## Architecture
30
+ <!-- Updated: Validation Session 1 - lock single-package layout for MVP -->
31
+ - Locked MVP packaging: single package layout (`src/*`) with modular folders; no monorepo split in v1.
32
+ - `core/contracts/*` for typed schemas and compile-time helpers.
33
+ - `core/registry/*` for module/action registration and validation.
34
+ - `core/errors/*` for standardized framework errors.
35
+
36
+ ## Related code files
37
+ - Modify: none (greenfield)
38
+ - Create:
39
+ - `src/core/contracts/module-contract.ts`
40
+ - `src/core/contracts/action-contract.ts`
41
+ - `src/core/contracts/help-contract.ts`
42
+ - `src/core/registry/action-registry.ts`
43
+ - `src/core/errors/framework-errors.ts`
44
+ - Delete: none
45
+
46
+ ## Implementation Steps
47
+ 1. Define TypeScript contract interfaces and helper builders.
48
+ 2. Implement registry with startup validation.
49
+ 3. Add triad completeness checks and diagnostic messages.
50
+ 4. Add error codes and exit-code policy map.
51
+
52
+ ## Todo list
53
+ - [x] Core contract interfaces defined
54
+ - [x] Registry implemented
55
+ - [x] Triad enforcement implemented
56
+ - [x] Error taxonomy added
57
+
58
+ ## Success Criteria
59
+ - Registering incomplete action fails deterministically with clear diagnostics.
60
+ - Complete action contract can be registered and discovered.
61
+
62
+ ## Risk Assessment
63
+ - Risk: over-modeling too early.
64
+ - Mitigation: keep v1 contracts minimal and extensible.
65
+
66
+ ## Security Considerations
67
+ - Validate user-defined metadata before rendering/executing.
68
+ - Avoid arbitrary code execution in registration path.
69
+
70
+ ## Next steps
71
+ - Build runtime resolver + state machine in Phase 02.
@@ -0,0 +1,76 @@
1
+ # Phase 02 — Runtime and state machine
2
+
3
+ ## Context links
4
+ - Parent plan: `./plan.md`
5
+ - Depends on: `./phase-01-foundation-and-contracts.md`
6
+ - Research: `./research/researcher-01-report.md`, `./research/researcher-02-report.md`
7
+
8
+ ## Overview
9
+ - Date: 2026-02-09
10
+ - Description: implement shared runtime engine and workflow state machine for TUI-default + auto non-interactive behavior.
11
+ - Priority: P0
12
+ - Implementation status: complete
13
+ - Review status: complete
14
+
15
+ ## Key Insights
16
+ - One execution engine must serve both TUI and command paths.
17
+ - Mode resolution must be deterministic and safe in non-TTY contexts.
18
+
19
+ ## Requirements
20
+ - Functional:
21
+ - Implement runtime resolver: default TUI, auto headless when required args provided.
22
+ - Implement state-machine transitions for flow nodes including `next/back/jump/exit`.
23
+ - Implement persisted resume checkpoints for interrupted multi-step workflows.
24
+ - Implement in-process module loading and action dispatch.
25
+ - Implement unified result envelope and exit semantics.
26
+ - Non-functional:
27
+ - Deterministic behavior for CI/automation.
28
+ - No duplicated business logic across adapters.
29
+
30
+ ## Architecture
31
+ <!-- Updated: Validation Session 1 - include jump + resume in MVP -->
32
+ - `runtime/mode-resolver.ts` decides interactive vs non-interactive.
33
+ - `runtime/engine.ts` executes action handlers with shared context.
34
+ - `runtime/state-machine.ts` handles transitions: next/back/jump/exit.
35
+ - `runtime/resume-store.ts` persists and restores workflow checkpoints.
36
+ - `runtime/dispatch.ts` maps parser result to action contract.
37
+
38
+ ## Related code files
39
+ - Modify: none (greenfield)
40
+ - Create:
41
+ - `src/runtime/mode-resolver.ts`
42
+ - `src/runtime/engine.ts`
43
+ - `src/runtime/state-machine.ts`
44
+ - `src/runtime/resume-store.ts`
45
+ - `src/runtime/dispatch.ts`
46
+ - `src/runtime/runtime-context.ts`
47
+ - Delete: none
48
+
49
+ ## Implementation Steps
50
+ 1. Implement mode resolver with strict decision tree.
51
+ 2. Implement shared runtime executor and result envelope.
52
+ 3. Implement workflow state-machine and transition guards including jump.
53
+ 4. Implement resume checkpoint store and restore path.
54
+ 5. Wire dispatch path from parser to runtime.
55
+
56
+ ## Todo list
57
+ - [x] Mode resolver implemented
58
+ - [x] Runtime engine implemented
59
+ - [x] State machine with jump implemented
60
+ - [x] Resume checkpoint store implemented
61
+ - [x] Dispatch integration complete
62
+
63
+ ## Success Criteria
64
+ - Same action handler runs correctly from both TUI and command invocation.
65
+ - Missing args in non-TTY returns strict help/error output without prompt hang.
66
+
67
+ ## Risk Assessment
68
+ - Risk: mode ambiguity in mixed argument scenarios.
69
+ - Mitigation: explicit precedence rules and diagnostics.
70
+
71
+ ## Security Considerations
72
+ - Validate parsed input before dispatch.
73
+ - Enforce safe defaults for cancellation/timeouts.
74
+
75
+ ## Next steps
76
+ - Build TUI component adapters and edge policies in Phase 03.
@@ -0,0 +1,71 @@
1
+ # Phase 03 — TUI components and policies
2
+
3
+ ## Context links
4
+ - Parent plan: `./plan.md`
5
+ - Depends on: `./phase-02-runtime-and-state-machine.md`
6
+ - Research: `./research/researcher-01-report.md`
7
+
8
+ ## Overview
9
+ - Date: 2026-02-09
10
+ - Description: implement clack-based component adapters, accessibility footer, and policy-driven edge handling.
11
+ - Priority: P1
12
+ - Implementation status: complete
13
+ - Review status: complete
14
+
15
+ ## Key Insights
16
+ - Use clack primitives fully, wrap them in framework contracts.
17
+ - Accessibility line helps both humans and AI snapshots understand current state.
18
+
19
+ ## Requirements
20
+ - Functional:
21
+ - Support clack prompts/core patterns (select, multiselect, confirm, text, groups, task logs/spinners).
22
+ - Implement framework wrapper components with validation hooks.
23
+ - Add accessibility footer with current node, selection, keybind hints.
24
+ - Enforce ESC/Ctrl+C/error/invalid-input policies with configurable actions.
25
+ - Non-functional:
26
+ - Async-safe prompt flows.
27
+ - Non-TTY fallback to runtime resolver path.
28
+
29
+ ## Architecture
30
+ - `tui/component-adapters/*` wraps clack APIs.
31
+ - `tui/accessibility-footer.ts` renders stable context text.
32
+ - `tui/interrupt-handlers.ts` maps cancel signals to policy engine.
33
+
34
+ ## Related code files
35
+ - Modify: none (greenfield)
36
+ - Create:
37
+ - `src/tui/component-adapters/select.ts`
38
+ - `src/tui/component-adapters/multiselect.ts`
39
+ - `src/tui/component-adapters/confirm.ts`
40
+ - `src/tui/component-adapters/text.ts`
41
+ - `src/tui/component-adapters/group.ts`
42
+ - `src/tui/accessibility-footer.ts`
43
+ - `src/tui/interrupt-handlers.ts`
44
+ - Delete: none
45
+
46
+ ## Implementation Steps
47
+ 1. Implement component wrappers and shared adapter interfaces.
48
+ 2. Implement input validation and cancellation normalization.
49
+ 3. Add accessibility footer renderer.
50
+ 4. Integrate policy engine hooks for edge-case handling.
51
+
52
+ ## Todo list
53
+ - [x] Core component wrappers implemented
54
+ - [x] Validation/cancel normalization implemented
55
+ - [x] Accessibility footer implemented
56
+ - [x] Policy hooks integrated
57
+
58
+ ## Success Criteria
59
+ - TUI flows execute with consistent keybinding/interrupt behavior.
60
+ - Accessibility footer appears on each interactive step.
61
+
62
+ ## Risk Assessment
63
+ - Risk: terminal compatibility differences.
64
+ - Mitigation: isolate adapter layer and test across OS.
65
+
66
+ ## Security Considerations
67
+ - Sanitize untrusted text displayed in terminal.
68
+ - Avoid leaking sensitive values in prompts and logs.
69
+
70
+ ## Next steps
71
+ - Implement strict help contract and hierarchy in Phase 04.
@@ -0,0 +1,69 @@
1
+ # Phase 04 — Help system and AI readability
2
+
3
+ ## Context links
4
+ - Parent plan: `./plan.md`
5
+ - Depends on: `./phase-01-foundation-and-contracts.md`, `./phase-02-runtime-and-state-machine.md`
6
+ - Research: `./research/researcher-01-report.md`
7
+
8
+ ## Overview
9
+ - Date: 2026-02-09
10
+ - Description: implement strict hierarchical help outputs for module/action/use-case discovery.
11
+ - Priority: P1
12
+ - Implementation status: complete
13
+ - Review status: complete
14
+
15
+ ## Key Insights
16
+ - Text-only can be AI-safe if sections are fixed and deterministic.
17
+ - Help hierarchy must mirror command hierarchy exactly.
18
+
19
+ ## Requirements
20
+ <!-- Updated: Validation Session 1 - lock text-only strict help contract for MVP -->
21
+ - Functional:
22
+ - Implement `hub -h`, `hub -h <module>`, `hub -h <module> <use-case>`.
23
+ - Render strict text-only sections with stable ordering and markers.
24
+ - Include keybindings/navigation notes for TUI-relevant actions.
25
+ - Enforce every action defines complete help metadata.
26
+ - Non-functional:
27
+ - No prose drift across runs.
28
+ - Human-readable and parser-friendly formatting.
29
+
30
+ ## Architecture
31
+ - `help-registry-view` queries contracts and returns normalized help model.
32
+ - `help-renderer` outputs strict sections and delimiters.
33
+ - `diagnostic-renderer` prints missing args/error guidance in same format family.
34
+
35
+ ## Related code files
36
+ - Modify: none (greenfield)
37
+ - Create:
38
+ - `src/help/help-model.ts`
39
+ - `src/help/help-renderer.ts`
40
+ - `src/help/hierarchy-resolver.ts`
41
+ - `src/cli/help-command.ts`
42
+ - Delete: none
43
+
44
+ ## Implementation Steps
45
+ 1. Define strict help section schema and formatting rules.
46
+ 2. Implement hierarchy resolver for module/action/use-case.
47
+ 3. Implement renderers for normal help and error-help.
48
+ 4. Wire help command to parser/runtime paths.
49
+
50
+ ## Todo list
51
+ - [x] Help schema defined
52
+ - [x] Hierarchy resolver implemented
53
+ - [x] Renderer implemented
54
+ - [x] CLI integration complete
55
+
56
+ ## Success Criteria
57
+ - All help levels print deterministic sections.
58
+ - Agent can discover command usage without interacting with TUI.
59
+
60
+ ## Risk Assessment
61
+ - Risk: over-verbose help harms scanability.
62
+ - Mitigation: concise defaults + expanded use-case mode.
63
+
64
+ ## Security Considerations
65
+ - Ensure help/examples never include secrets.
66
+ - Validate untrusted metadata before rendering.
67
+
68
+ ## Next steps
69
+ - Add test matrix and quality gates in Phase 05.