@spekn/cli 1.0.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 (159) hide show
  1. package/dist/__tests__/export-cli.test.d.ts +1 -0
  2. package/dist/__tests__/export-cli.test.js +70 -0
  3. package/dist/__tests__/tui-args-policy.test.d.ts +1 -0
  4. package/dist/__tests__/tui-args-policy.test.js +50 -0
  5. package/dist/acp-S2MHZOAD.mjs +23 -0
  6. package/dist/acp-UCCI44JY.mjs +25 -0
  7. package/dist/auth/credentials-store.d.ts +2 -0
  8. package/dist/auth/credentials-store.js +5 -0
  9. package/dist/auth/device-flow.d.ts +36 -0
  10. package/dist/auth/device-flow.js +189 -0
  11. package/dist/auth/jwt.d.ts +1 -0
  12. package/dist/auth/jwt.js +6 -0
  13. package/dist/auth/session.d.ts +67 -0
  14. package/dist/auth/session.js +86 -0
  15. package/dist/auth-login.d.ts +34 -0
  16. package/dist/auth-login.js +202 -0
  17. package/dist/auth-logout.d.ts +25 -0
  18. package/dist/auth-logout.js +115 -0
  19. package/dist/auth-status.d.ts +24 -0
  20. package/dist/auth-status.js +109 -0
  21. package/dist/backlog-generate.d.ts +11 -0
  22. package/dist/backlog-generate.js +308 -0
  23. package/dist/backlog-health.d.ts +11 -0
  24. package/dist/backlog-health.js +287 -0
  25. package/dist/bridge-login.d.ts +40 -0
  26. package/dist/bridge-login.js +277 -0
  27. package/dist/chunk-3PAYRI4G.mjs +2428 -0
  28. package/dist/chunk-M4CS3A25.mjs +2426 -0
  29. package/dist/commands/auth/login.d.ts +30 -0
  30. package/dist/commands/auth/login.js +164 -0
  31. package/dist/commands/auth/logout.d.ts +25 -0
  32. package/dist/commands/auth/logout.js +115 -0
  33. package/dist/commands/auth/status.d.ts +24 -0
  34. package/dist/commands/auth/status.js +109 -0
  35. package/dist/commands/backlog/generate.d.ts +11 -0
  36. package/dist/commands/backlog/generate.js +308 -0
  37. package/dist/commands/backlog/health.d.ts +11 -0
  38. package/dist/commands/backlog/health.js +287 -0
  39. package/dist/commands/bridge/login.d.ts +36 -0
  40. package/dist/commands/bridge/login.js +258 -0
  41. package/dist/commands/export.d.ts +35 -0
  42. package/dist/commands/export.js +485 -0
  43. package/dist/commands/marketplace-export.d.ts +21 -0
  44. package/dist/commands/marketplace-export.js +214 -0
  45. package/dist/commands/project-clean.d.ts +1 -0
  46. package/dist/commands/project-clean.js +126 -0
  47. package/dist/commands/repo/common.d.ts +105 -0
  48. package/dist/commands/repo/common.js +775 -0
  49. package/dist/commands/repo/detach.d.ts +2 -0
  50. package/dist/commands/repo/detach.js +120 -0
  51. package/dist/commands/repo/register.d.ts +21 -0
  52. package/dist/commands/repo/register.js +175 -0
  53. package/dist/commands/repo/sync.d.ts +22 -0
  54. package/dist/commands/repo/sync.js +873 -0
  55. package/dist/commands/skills-import-local.d.ts +16 -0
  56. package/dist/commands/skills-import-local.js +352 -0
  57. package/dist/commands/spec/drift-check.d.ts +3 -0
  58. package/dist/commands/spec/drift-check.js +186 -0
  59. package/dist/commands/spec/frontmatter.d.ts +11 -0
  60. package/dist/commands/spec/frontmatter.js +219 -0
  61. package/dist/commands/spec/lint.d.ts +11 -0
  62. package/dist/commands/spec/lint.js +499 -0
  63. package/dist/commands/spec/parse.d.ts +11 -0
  64. package/dist/commands/spec/parse.js +162 -0
  65. package/dist/export.d.ts +35 -0
  66. package/dist/export.js +485 -0
  67. package/dist/index.d.ts +11 -0
  68. package/dist/index.js +21 -0
  69. package/dist/main.d.ts +1 -0
  70. package/dist/main.js +115280 -0
  71. package/dist/marketplace-export.d.ts +21 -0
  72. package/dist/marketplace-export.js +214 -0
  73. package/dist/project-clean.d.ts +1 -0
  74. package/dist/project-clean.js +126 -0
  75. package/dist/project-context.d.ts +99 -0
  76. package/dist/project-context.js +376 -0
  77. package/dist/repo-common.d.ts +101 -0
  78. package/dist/repo-common.js +671 -0
  79. package/dist/repo-detach.d.ts +2 -0
  80. package/dist/repo-detach.js +102 -0
  81. package/dist/repo-ingest.d.ts +29 -0
  82. package/dist/repo-ingest.js +305 -0
  83. package/dist/repo-register.d.ts +21 -0
  84. package/dist/repo-register.js +175 -0
  85. package/dist/repo-sync.d.ts +16 -0
  86. package/dist/repo-sync.js +152 -0
  87. package/dist/resources/prompt-loader.d.ts +1 -0
  88. package/dist/resources/prompt-loader.js +62 -0
  89. package/dist/resources/prompts/README.md +21 -0
  90. package/dist/resources/prompts/prompts/repo-analysis.prompt.md +126 -0
  91. package/dist/resources/prompts/repo-analysis.prompt.md +151 -0
  92. package/dist/resources/prompts/repo-sync-analysis.prompt.md +85 -0
  93. package/dist/skills-import-local.d.ts +16 -0
  94. package/dist/skills-import-local.js +352 -0
  95. package/dist/spec-drift-check.d.ts +3 -0
  96. package/dist/spec-drift-check.js +186 -0
  97. package/dist/spec-frontmatter.d.ts +11 -0
  98. package/dist/spec-frontmatter.js +219 -0
  99. package/dist/spec-lint.d.ts +11 -0
  100. package/dist/spec-lint.js +499 -0
  101. package/dist/spec-parse.d.ts +11 -0
  102. package/dist/spec-parse.js +162 -0
  103. package/dist/stubs/dotenv.d.ts +5 -0
  104. package/dist/stubs/dotenv.js +6 -0
  105. package/dist/stubs/typeorm.d.ts +22 -0
  106. package/dist/stubs/typeorm.js +28 -0
  107. package/dist/tui/app.d.ts +7 -0
  108. package/dist/tui/app.js +122 -0
  109. package/dist/tui/args.d.ts +8 -0
  110. package/dist/tui/args.js +57 -0
  111. package/dist/tui/capabilities/policy.d.ts +7 -0
  112. package/dist/tui/capabilities/policy.js +64 -0
  113. package/dist/tui/components/frame.d.ts +8 -0
  114. package/dist/tui/components/frame.js +8 -0
  115. package/dist/tui/components/status-bar.d.ts +8 -0
  116. package/dist/tui/components/status-bar.js +8 -0
  117. package/dist/tui/index.d.ts +2 -0
  118. package/dist/tui/index.js +23 -0
  119. package/dist/tui/index.mjs +7563 -0
  120. package/dist/tui/keymap/use-global-keymap.d.ts +19 -0
  121. package/dist/tui/keymap/use-global-keymap.js +82 -0
  122. package/dist/tui/navigation/nav-items.d.ts +3 -0
  123. package/dist/tui/navigation/nav-items.js +18 -0
  124. package/dist/tui/screens/bridge.d.ts +8 -0
  125. package/dist/tui/screens/bridge.js +19 -0
  126. package/dist/tui/screens/decisions.d.ts +5 -0
  127. package/dist/tui/screens/decisions.js +28 -0
  128. package/dist/tui/screens/export.d.ts +5 -0
  129. package/dist/tui/screens/export.js +16 -0
  130. package/dist/tui/screens/home.d.ts +5 -0
  131. package/dist/tui/screens/home.js +33 -0
  132. package/dist/tui/screens/locked.d.ts +5 -0
  133. package/dist/tui/screens/locked.js +9 -0
  134. package/dist/tui/screens/specs.d.ts +5 -0
  135. package/dist/tui/screens/specs.js +31 -0
  136. package/dist/tui/services/client.d.ts +1 -0
  137. package/dist/tui/services/client.js +18 -0
  138. package/dist/tui/services/context-service.d.ts +19 -0
  139. package/dist/tui/services/context-service.js +246 -0
  140. package/dist/tui/shared-enums.d.ts +16 -0
  141. package/dist/tui/shared-enums.js +19 -0
  142. package/dist/tui/state/use-app-state.d.ts +35 -0
  143. package/dist/tui/state/use-app-state.js +177 -0
  144. package/dist/tui/types.d.ts +77 -0
  145. package/dist/tui/types.js +2 -0
  146. package/dist/tui-bundle.d.ts +1 -0
  147. package/dist/tui-bundle.js +5 -0
  148. package/dist/tui-entry.mjs +1407 -0
  149. package/dist/utils/cli-runtime.d.ts +5 -0
  150. package/dist/utils/cli-runtime.js +22 -0
  151. package/dist/utils/help-error.d.ts +7 -0
  152. package/dist/utils/help-error.js +14 -0
  153. package/dist/utils/interaction.d.ts +19 -0
  154. package/dist/utils/interaction.js +93 -0
  155. package/dist/utils/structured-log.d.ts +7 -0
  156. package/dist/utils/structured-log.js +112 -0
  157. package/dist/utils/trpc-url.d.ts +4 -0
  158. package/dist/utils/trpc-url.js +15 -0
  159. package/package.json +59 -0
@@ -0,0 +1,22 @@
1
+ export declare const Entity: (..._args: any[]) => (target: any) => any;
2
+ export declare const Column: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
3
+ export declare const PrimaryGeneratedColumn: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
4
+ export declare const CreateDateColumn: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
5
+ export declare const UpdateDateColumn: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
6
+ export declare const ManyToOne: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
7
+ export declare const OneToMany: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
8
+ export declare const JoinColumn: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
9
+ export declare const Index: (..._args: any[]) => (_target: any, ..._rest: any[]) => void;
10
+ export declare const Unique: (..._args: any[]) => (target: any) => any;
11
+ export declare class DataSource {
12
+ constructor(_opts: any);
13
+ initialize(): Promise<Awaited<this>>;
14
+ }
15
+ export declare const IsNull: () => {
16
+ _type: string;
17
+ };
18
+ export type MigrationInterface = {
19
+ up(qr: any): Promise<void>;
20
+ down(qr: any): Promise<void>;
21
+ };
22
+ export type QueryRunner = any;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ // No-op stub for typeorm — the CLI never touches the database but @spekn/shared
3
+ // entity files import decorators at the top level. This prevents the
4
+ // "Dynamic require of 'typeorm' is not supported" error in the ESM TUI bundle.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.IsNull = exports.DataSource = exports.Unique = exports.Index = exports.JoinColumn = exports.OneToMany = exports.ManyToOne = exports.UpdateDateColumn = exports.CreateDateColumn = exports.PrimaryGeneratedColumn = exports.Column = exports.Entity = void 0;
7
+ /* eslint-disable @typescript-eslint/no-unused-vars */
8
+ const noop = (..._args) => (_target, ..._rest) => { };
9
+ const noopClass = (..._args) => (target) => target;
10
+ // Decorators
11
+ exports.Entity = noopClass;
12
+ exports.Column = noop;
13
+ exports.PrimaryGeneratedColumn = noop;
14
+ exports.CreateDateColumn = noop;
15
+ exports.UpdateDateColumn = noop;
16
+ exports.ManyToOne = noop;
17
+ exports.OneToMany = noop;
18
+ exports.JoinColumn = noop;
19
+ exports.Index = noop;
20
+ exports.Unique = noopClass;
21
+ // Classes / functions used at runtime in shared
22
+ class DataSource {
23
+ constructor(_opts) { }
24
+ initialize() { return Promise.resolve(this); }
25
+ }
26
+ exports.DataSource = DataSource;
27
+ const IsNull = () => ({ _type: "isNull" });
28
+ exports.IsNull = IsNull;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { TuiScreenId } from './types';
3
+ export declare function TuiApp({ apiUrl, initialScreen, projectId }: {
4
+ apiUrl: string;
5
+ initialScreen: TuiScreenId;
6
+ projectId?: string;
7
+ }): React.JSX.Element;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TuiApp = TuiApp;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ink_1 = require("ink");
6
+ const ui_1 = require("@inkjs/ui");
7
+ const use_app_state_1 = require("./state/use-app-state");
8
+ const use_global_keymap_1 = require("./keymap/use-global-keymap");
9
+ const frame_1 = require("./components/frame");
10
+ const status_bar_1 = require("./components/status-bar");
11
+ const home_1 = require("./screens/home");
12
+ const specs_1 = require("./screens/specs");
13
+ const export_1 = require("./screens/export");
14
+ const decisions_1 = require("./screens/decisions");
15
+ const bridge_1 = require("./screens/bridge");
16
+ const locked_1 = require("./screens/locked");
17
+ /** Brand-aligned theme: Electric Indigo spinner, semantic colors via component defaults */
18
+ const speknTheme = (0, ui_1.extendTheme)(ui_1.defaultTheme, {
19
+ components: {
20
+ Spinner: {
21
+ styles: {
22
+ frame: () => ({ color: '#6366F1' }),
23
+ },
24
+ },
25
+ },
26
+ });
27
+ function renderMainScreen(screen, state) {
28
+ if (screen === 'home')
29
+ return (0, jsx_runtime_1.jsx)(home_1.HomeScreen, { state: state });
30
+ if (screen === 'specs')
31
+ return (0, jsx_runtime_1.jsx)(specs_1.SpecsScreen, { state: state });
32
+ if (screen === 'export')
33
+ return (0, jsx_runtime_1.jsx)(export_1.ExportScreen, { state: state });
34
+ if (screen === 'decisions')
35
+ return (0, jsx_runtime_1.jsx)(decisions_1.DecisionsScreen, { state: state });
36
+ if (screen === 'bridge')
37
+ return (0, jsx_runtime_1.jsx)(bridge_1.BridgeScreen, { state: state });
38
+ const nav = state.navPolicy.find((item) => item.id === screen);
39
+ return (0, jsx_runtime_1.jsx)(locked_1.LockedScreen, { item: nav });
40
+ }
41
+ function TuiApp({ apiUrl, initialScreen, projectId }) {
42
+ const { state, refresh, setScreen, toggleHelp, setSearchQuery, setCommandMode, setExportFormat, previewExport, generateExport, bridgeStart, bridgeStop, appendLog, } = (0, use_app_state_1.useAppState)(apiUrl, initialScreen, projectId);
43
+ (0, use_global_keymap_1.useGlobalKeymap)({
44
+ screen: state.screen,
45
+ navPolicy: state.navPolicy,
46
+ commandMode: state.commandMode,
47
+ showHelp: state.showHelp,
48
+ onNavigate: setScreen,
49
+ onHelpToggle: toggleHelp,
50
+ onSearchToggle: () => setSearchQuery(state.searchQuery ? '' : '*'),
51
+ onSearchClear: () => setSearchQuery(''),
52
+ onCommandModeToggle: setCommandMode,
53
+ onRefresh: () => {
54
+ void refresh();
55
+ },
56
+ onExportPreview: () => {
57
+ void previewExport();
58
+ },
59
+ onExportGenerate: () => {
60
+ void generateExport();
61
+ },
62
+ onBridgeStart: bridgeStart,
63
+ onBridgeStop: () => {
64
+ void bridgeStop();
65
+ },
66
+ });
67
+ const handleCommandSubmit = (command) => {
68
+ const normalized = command.trim().toLowerCase();
69
+ setCommandMode(false);
70
+ if (!normalized)
71
+ return;
72
+ if (normalized === 'help') {
73
+ toggleHelp();
74
+ return;
75
+ }
76
+ if (normalized === 'refresh' || normalized === 'r') {
77
+ void refresh();
78
+ return;
79
+ }
80
+ if (normalized.startsWith('goto ')) {
81
+ const target = normalized.replace('goto ', '').trim();
82
+ setScreen(target);
83
+ appendLog(`[nav] goto ${target}`);
84
+ return;
85
+ }
86
+ if (normalized === 'show specs') {
87
+ setScreen('specs');
88
+ return;
89
+ }
90
+ if (normalized === 'show export') {
91
+ setScreen('export');
92
+ return;
93
+ }
94
+ if (normalized === 'run export') {
95
+ void generateExport();
96
+ return;
97
+ }
98
+ if (normalized === 'format claude') {
99
+ setExportFormat('claude-md');
100
+ appendLog('[export] Format switched to claude-md');
101
+ return;
102
+ }
103
+ if (normalized === 'format cursor') {
104
+ setExportFormat('cursorrules');
105
+ appendLog('[export] Format switched to cursorrules');
106
+ return;
107
+ }
108
+ if (normalized === 'bridge start') {
109
+ bridgeStart();
110
+ return;
111
+ }
112
+ if (normalized === 'bridge stop') {
113
+ void bridgeStop();
114
+ return;
115
+ }
116
+ appendLog(`[command] Unknown: ${command}`);
117
+ };
118
+ const left = `${state.boot?.organizationName ?? '...'} / ${state.boot?.projectName ?? '...'}`;
119
+ const center = state.loading ? 'Loading...' : state.statusLine;
120
+ const right = `${state.screen} | phase:${state.workflow.currentPhase ?? 'n/a'} | role:${state.boot?.role ?? 'n/a'} | tier:${state.boot?.plan ?? 'n/a'}`;
121
+ return ((0, jsx_runtime_1.jsx)(ui_1.ThemeProvider, { theme: speknTheme, children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { bold: true, color: "cyan", children: "Spekn TUI - Technical Cockpit" }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: "Shortcuts: j/k/h/l nav, : commands, ? help, r refresh, Ctrl+C quit" }), state.error ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { marginTop: 1, children: (0, jsx_runtime_1.jsx)(ui_1.Alert, { variant: "error", children: state.error }) })) : null, (0, jsx_runtime_1.jsxs)(ink_1.Box, { marginTop: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Box, { width: "28%", flexDirection: "column", children: (0, jsx_runtime_1.jsx)(frame_1.Frame, { title: "Navigation", children: state.navPolicy.map((item, index) => ((0, jsx_runtime_1.jsxs)(ink_1.Text, { color: state.screen === item.id ? 'green' : item.state === 'locked' ? 'yellow' : item.state === 'disabled' ? 'gray' : undefined, children: [state.screen === item.id ? '>' : ' ', " ", index + 1, ". ", item.label, item.state === 'locked' ? ' (locked)' : item.state === 'disabled' ? ' (disabled)' : ''] }, item.id))) }) }), (0, jsx_runtime_1.jsx)(ink_1.Box, { width: "52%", flexDirection: "column", children: (0, jsx_runtime_1.jsx)(frame_1.Frame, { title: "Context", children: renderMainScreen(state.screen, state) }) }), (0, jsx_runtime_1.jsx)(ink_1.Box, { width: "20%", flexDirection: "column", children: (0, jsx_runtime_1.jsx)(frame_1.Frame, { title: "Event Log", dim: true, children: (state.logs.length === 0 ? ['[system] ready'] : state.logs.slice(0, 7)).map((line, index) => ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: line }, `log-${index}`))) }) })] }), state.showHelp ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { marginTop: 1, children: (0, jsx_runtime_1.jsx)(ui_1.Alert, { variant: "info", children: "Help: j/k/h/l navigate | :help | :goto specs | :run export | format claude/cursor | bridge start/stop" }) })) : null, state.commandMode ? ((0, jsx_runtime_1.jsxs)(ink_1.Box, { marginTop: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "green", children: ":" }), (0, jsx_runtime_1.jsx)(ui_1.TextInput, { placeholder: "command...", onSubmit: handleCommandSubmit })] })) : null, (0, jsx_runtime_1.jsx)(status_bar_1.StatusBar, { left: left, center: center, right: right })] }) }));
122
+ }
@@ -0,0 +1,8 @@
1
+ import type { TuiScreenId } from './types';
2
+ export interface TuiCliOptions {
3
+ projectId?: string;
4
+ apiUrl: string;
5
+ initialView: TuiScreenId;
6
+ noColor: boolean;
7
+ }
8
+ export declare function parseTuiArgs(args: string[]): TuiCliOptions;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTuiArgs = parseTuiArgs;
4
+ const VIEW_ALIASES = {
5
+ home: 'home',
6
+ specs: 'specs',
7
+ export: 'export',
8
+ decisions: 'decisions',
9
+ bridge: 'bridge',
10
+ };
11
+ function parseTuiArgs(args) {
12
+ let projectId;
13
+ let apiUrl = process.env.SPEKN_API_URL ?? 'http://localhost:3000';
14
+ let initialView = 'home';
15
+ let noColor = false;
16
+ for (let i = 0; i < args.length; i++) {
17
+ const arg = args[i];
18
+ if ((arg === '--project-id' || arg === '--project') && args[i + 1]) {
19
+ projectId = args[++i];
20
+ continue;
21
+ }
22
+ if (arg.startsWith('--project-id=')) {
23
+ projectId = arg.slice('--project-id='.length);
24
+ continue;
25
+ }
26
+ if (arg === '--api-url' && args[i + 1]) {
27
+ apiUrl = args[++i];
28
+ continue;
29
+ }
30
+ if (arg.startsWith('--api-url=')) {
31
+ apiUrl = arg.slice('--api-url='.length);
32
+ continue;
33
+ }
34
+ if (arg === '--view' && args[i + 1]) {
35
+ const candidate = VIEW_ALIASES[String(args[++i]).toLowerCase()];
36
+ if (candidate)
37
+ initialView = candidate;
38
+ continue;
39
+ }
40
+ if (arg.startsWith('--view=')) {
41
+ const candidate = VIEW_ALIASES[arg.slice('--view='.length).toLowerCase()];
42
+ if (candidate)
43
+ initialView = candidate;
44
+ continue;
45
+ }
46
+ if (arg === '--no-color') {
47
+ noColor = true;
48
+ continue;
49
+ }
50
+ }
51
+ return {
52
+ projectId,
53
+ apiUrl,
54
+ initialView,
55
+ noColor,
56
+ };
57
+ }
@@ -0,0 +1,7 @@
1
+ import { OrganizationPlan } from '../shared-enums';
2
+ import type { CapabilityContext, NavItemPolicy } from '../types';
3
+ type OrganizationPlanType = (typeof OrganizationPlan)[keyof typeof OrganizationPlan];
4
+ export declare function meetsMinimumTier(current: OrganizationPlanType, required: OrganizationPlanType): boolean;
5
+ export declare function resolveNavPolicy(ctx: CapabilityContext): NavItemPolicy[];
6
+ export declare function isActionAllowed(policy: NavItemPolicy): boolean;
7
+ export {};
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.meetsMinimumTier = meetsMinimumTier;
4
+ exports.resolveNavPolicy = resolveNavPolicy;
5
+ exports.isActionAllowed = isActionAllowed;
6
+ const shared_enums_1 = require("../shared-enums");
7
+ const TIER_ORDER = {
8
+ [shared_enums_1.OrganizationPlan.FREE]: 0,
9
+ [shared_enums_1.OrganizationPlan.PRO]: 1,
10
+ [shared_enums_1.OrganizationPlan.TEAM]: 2,
11
+ [shared_enums_1.OrganizationPlan.ENTERPRISE]: 3,
12
+ };
13
+ const NAV_DEFINITIONS = [
14
+ { id: 'home', label: 'Home', description: 'Next actions and workflow pulse', requiredPlan: shared_enums_1.OrganizationPlan.FREE },
15
+ { id: 'specs', label: 'Specs', description: 'Manage governed specifications', requiredPlan: shared_enums_1.OrganizationPlan.FREE },
16
+ { id: 'export', label: 'Export', description: 'Generate CLAUDE.md / .cursorrules', requiredPlan: shared_enums_1.OrganizationPlan.FREE },
17
+ { id: 'decisions', label: 'Decision Log', description: 'Review decisions and rationale', requiredPlan: shared_enums_1.OrganizationPlan.FREE },
18
+ { id: 'bridge', label: 'Local Bridge', description: 'Bridge status and controls', requiredPlan: shared_enums_1.OrganizationPlan.PRO },
19
+ { id: 'active-runs', label: 'Active Runs', description: 'Realtime orchestration dashboard', requiredPlan: shared_enums_1.OrganizationPlan.TEAM },
20
+ { id: 'phase-gates', label: 'Phase Gates', description: 'Approve and unblock workflow phases', requiredPlan: shared_enums_1.OrganizationPlan.TEAM },
21
+ { id: 'skills-marketplace', label: 'Skills Marketplace', description: 'Manage shared managed skills', requiredPlan: shared_enums_1.OrganizationPlan.TEAM },
22
+ { id: 'org-governance', label: 'Org Governance', description: 'Compliance, policy, deployment gates', requiredPlan: shared_enums_1.OrganizationPlan.ENTERPRISE },
23
+ ];
24
+ const GATE_DISABLED_PHASES = [
25
+ shared_enums_1.WorkflowPhase.SPECIFY,
26
+ shared_enums_1.WorkflowPhase.CLARIFY,
27
+ ];
28
+ function meetsMinimumTier(current, required) {
29
+ return TIER_ORDER[current] >= TIER_ORDER[required];
30
+ }
31
+ function resolveNavPolicy(ctx) {
32
+ return NAV_DEFINITIONS.map((item) => {
33
+ if (!meetsMinimumTier(ctx.plan, item.requiredPlan)) {
34
+ return {
35
+ ...item,
36
+ state: 'locked',
37
+ reason: `Requires ${item.requiredPlan.toUpperCase()} tier`,
38
+ };
39
+ }
40
+ if (item.id === 'phase-gates' && ctx.role === 'viewer') {
41
+ return {
42
+ ...item,
43
+ state: 'disabled',
44
+ reason: 'Viewer role cannot approve gates',
45
+ };
46
+ }
47
+ if (item.id === 'phase-gates' &&
48
+ ctx.workflowPhase &&
49
+ GATE_DISABLED_PHASES.includes(ctx.workflowPhase)) {
50
+ return {
51
+ ...item,
52
+ state: 'disabled',
53
+ reason: `Gate approvals are unavailable in ${ctx.workflowPhase} phase`,
54
+ };
55
+ }
56
+ return {
57
+ ...item,
58
+ state: 'enabled',
59
+ };
60
+ });
61
+ }
62
+ function isActionAllowed(policy) {
63
+ return policy.state === 'enabled';
64
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface FrameProps {
3
+ title: string;
4
+ children: React.ReactNode;
5
+ dim?: boolean;
6
+ }
7
+ export declare function Frame({ title, children, dim }: FrameProps): React.JSX.Element;
8
+ export {};
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Frame = Frame;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ink_1 = require("ink");
6
+ function Frame({ title, children, dim = false }) {
7
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", borderStyle: "round", borderColor: dim ? 'gray' : 'cyan', paddingX: 1, paddingY: 0, marginRight: 1, minHeight: 7, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { bold: true, color: dim ? 'gray' : 'cyan', children: title }), (0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", marginTop: 0, children: children })] }));
8
+ }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ interface StatusBarProps {
3
+ left: string;
4
+ center: string;
5
+ right: string;
6
+ }
7
+ export declare function StatusBar({ left, center, right }: StatusBarProps): React.JSX.Element;
8
+ export {};
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StatusBar = StatusBar;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ink_1 = require("ink");
6
+ function StatusBar({ left, center, right }) {
7
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, justifyContent: "space-between", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: left }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: center }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: right })] }));
8
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export declare function runTuiCli(args: string[]): Promise<number>;
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.runTuiCli = runTuiCli;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const ink_1 = require("ink");
7
+ const args_1 = require("./args");
8
+ const app_1 = require("./app");
9
+ async function runTuiCli(args) {
10
+ try {
11
+ const options = (0, args_1.parseTuiArgs)(args);
12
+ if (options.noColor) {
13
+ process.env.FORCE_COLOR = '0';
14
+ }
15
+ (0, ink_1.render)((0, jsx_runtime_1.jsx)(app_1.TuiApp, { apiUrl: options.apiUrl, initialScreen: options.initialView, projectId: options.projectId }));
16
+ return 0;
17
+ }
18
+ catch (error) {
19
+ const message = error instanceof Error ? error.message : String(error);
20
+ process.stderr.write(`Error: ${message}\n`);
21
+ return 1;
22
+ }
23
+ }