praxis-agent 0.35.0 → 0.37.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 (111) hide show
  1. package/README.md +20 -2
  2. package/dist/application/background-agent-manager.d.ts +16 -6
  3. package/dist/application/background-agent-manager.js +139 -97
  4. package/dist/application/context-engine.d.ts +56 -0
  5. package/dist/application/context-engine.js +129 -0
  6. package/dist/application/durable-follow-up.d.ts +14 -0
  7. package/dist/application/durable-follow-up.js +52 -0
  8. package/dist/application/native-session-transcript.d.ts +72 -0
  9. package/dist/application/native-session-transcript.js +351 -0
  10. package/dist/application/native-sidechain-transcript.d.ts +34 -0
  11. package/dist/application/native-sidechain-transcript.js +156 -0
  12. package/dist/application/session-service.d.ts +23 -4
  13. package/dist/application/session-service.js +1130 -494
  14. package/dist/application/subagent-service.d.ts +5 -1
  15. package/dist/application/subagent-service.js +749 -320
  16. package/dist/application/team-agent-runtime.d.ts +29 -0
  17. package/dist/application/team-agent-runtime.js +169 -0
  18. package/dist/application/team-capability.d.ts +27 -0
  19. package/dist/application/team-capability.js +41 -0
  20. package/dist/application/team-lead-operations.d.ts +38 -0
  21. package/dist/application/team-lead-operations.js +155 -0
  22. package/dist/application/team-mailbox.d.ts +54 -0
  23. package/dist/application/team-mailbox.js +196 -0
  24. package/dist/application/team-manager.d.ts +113 -0
  25. package/dist/application/team-manager.js +681 -0
  26. package/dist/application/team-workspace.d.ts +29 -0
  27. package/dist/application/team-workspace.js +197 -0
  28. package/dist/application/top-level-agent-manager.d.ts +1 -0
  29. package/dist/application/top-level-agent-manager.js +1025 -403
  30. package/dist/application/transcript-projection.d.ts +35 -0
  31. package/dist/application/transcript-projection.js +139 -0
  32. package/dist/application/turn-lifecycle.d.ts +2 -0
  33. package/dist/application/turn-memory-coordinator.d.ts +43 -0
  34. package/dist/application/turn-memory-coordinator.js +98 -0
  35. package/dist/cli/agents-dashboard.js +10 -5
  36. package/dist/cli/interactive.d.ts +7 -0
  37. package/dist/cli/interactive.js +645 -334
  38. package/dist/cli/tui/claude-style.d.ts +8 -25
  39. package/dist/cli/tui/claude-style.js +299 -277
  40. package/dist/cli/tui/decision-surface-model.d.ts +71 -0
  41. package/dist/cli/tui/decision-surface-model.js +131 -0
  42. package/dist/cli/tui/decision-surface.d.ts +7 -0
  43. package/dist/cli/tui/decision-surface.js +41 -0
  44. package/dist/cli/tui/help-surface-model.d.ts +68 -0
  45. package/dist/cli/tui/help-surface-model.js +131 -0
  46. package/dist/cli/tui/mcp-panel.js +1 -2
  47. package/dist/cli/tui/permission-surface-model.d.ts +195 -0
  48. package/dist/cli/tui/permission-surface-model.js +360 -0
  49. package/dist/cli/tui/permission-surface.d.ts +7 -0
  50. package/dist/cli/tui/permission-surface.js +69 -0
  51. package/dist/cli/tui/presentation-environment.d.ts +32 -0
  52. package/dist/cli/tui/presentation-environment.js +149 -0
  53. package/dist/cli/tui/task-panel.js +10 -1
  54. package/dist/cli/tui/theme.d.ts +46 -3
  55. package/dist/cli/tui/theme.js +414 -56
  56. package/dist/cli/tui/tool-permission.js +16 -8
  57. package/dist/cli/tui/transcript-presentation.d.ts +19 -1
  58. package/dist/cli/tui/transcript-presentation.js +26 -6
  59. package/dist/cli/tui/transcript-viewport.d.ts +18 -0
  60. package/dist/cli/tui/transcript-viewport.js +517 -111
  61. package/dist/cli/tui/transcript-window-model.d.ts +108 -0
  62. package/dist/cli/tui/transcript-window-model.js +772 -0
  63. package/dist/cli/tui/tui-interaction-router.d.ts +78 -0
  64. package/dist/cli/tui/tui-interaction-router.js +127 -0
  65. package/dist/cli/tui/tui-screen-model.d.ts +114 -0
  66. package/dist/cli/tui/tui-screen-model.js +210 -0
  67. package/dist/cli/tui/tui-view-model.d.ts +2 -49
  68. package/dist/cli/tui/tui-view-model.js +1 -68
  69. package/dist/cli-runtime.d.ts +4 -2
  70. package/dist/cli-runtime.js +397 -32
  71. package/dist/compatibility/claude/transcript-codec.js +6 -0
  72. package/dist/core/agent-orchestration.d.ts +31 -0
  73. package/dist/core/agent-orchestration.js +235 -0
  74. package/dist/core/permission-policy.d.ts +4 -0
  75. package/dist/core/permission-policy.js +21 -0
  76. package/dist/core/runtime.d.ts +6 -0
  77. package/dist/core/runtime.js +20 -2
  78. package/dist/core/team-mailbox.d.ts +54 -0
  79. package/dist/core/team-mailbox.js +212 -0
  80. package/dist/core/team-ownership.d.ts +84 -0
  81. package/dist/core/team-ownership.js +505 -0
  82. package/dist/core/tool-execution-scheduler.js +6 -1
  83. package/dist/core/transcript-event.d.ts +5 -1
  84. package/dist/core/transcript-event.js +12 -0
  85. package/dist/persistence/claude-job-store.d.ts +58 -0
  86. package/dist/persistence/claude-job-store.js +483 -1
  87. package/dist/persistence/claude-transcript-store.d.ts +2 -1
  88. package/dist/persistence/claude-transcript-store.js +2 -10
  89. package/dist/persistence/native-team-mailbox.d.ts +68 -0
  90. package/dist/persistence/native-team-mailbox.js +542 -0
  91. package/dist/persistence/native-team-store.d.ts +34 -0
  92. package/dist/persistence/native-team-store.js +257 -0
  93. package/dist/persistence/native-transcript-reader.d.ts +53 -0
  94. package/dist/persistence/native-transcript-reader.js +283 -0
  95. package/dist/persistence/native-transcript-store.d.ts +69 -0
  96. package/dist/persistence/native-transcript-store.js +321 -0
  97. package/dist/persistence/subagent-lifecycle-store.d.ts +41 -8
  98. package/dist/persistence/subagent-lifecycle-store.js +373 -146
  99. package/dist/persistence/transcript-file-append.d.ts +2 -0
  100. package/dist/persistence/transcript-file-append.js +10 -0
  101. package/dist/platform/exclusive-file-lease.d.ts +3 -0
  102. package/dist/platform/exclusive-file-lease.js +3 -0
  103. package/dist/tools/claude-capabilities.d.ts +4 -0
  104. package/dist/tools/claude-capabilities.js +18 -2
  105. package/dist/tools/team-lead-tools.d.ts +19 -0
  106. package/dist/tools/team-lead-tools.js +479 -0
  107. package/dist/tools/team-member-tools.d.ts +21 -0
  108. package/dist/tools/team-member-tools.js +259 -0
  109. package/package.json +1 -1
  110. package/dist/cli/tui/fullscreen-renderer.d.ts +0 -14
  111. package/dist/cli/tui/fullscreen-renderer.js +0 -13
@@ -0,0 +1,71 @@
1
+ import type { ClaudePlanApprovalRequest, ClaudeQuestion } from '../../tools/claude-interactive-tools.js';
2
+ import type { ClaudePermissionMode } from '../../permissions/claude-permission-resolver.js';
3
+ export type TuiPlanElevatedMode = Extract<ClaudePermissionMode, 'auto' | 'bypassPermissions' | 'acceptEdits'>;
4
+ export interface TuiDecisionSurfaceAction {
5
+ readonly visualLabel?: string;
6
+ readonly screenReaderLabel: string;
7
+ }
8
+ export interface TuiDecisionSurfaceOption {
9
+ readonly index: number;
10
+ readonly label: string;
11
+ readonly description?: string;
12
+ readonly preview?: string;
13
+ readonly selected: boolean;
14
+ }
15
+ export interface TuiDecisionSurfaceCancellation {
16
+ readonly visualLabel: string;
17
+ readonly screenReaderLabel: string;
18
+ }
19
+ export interface TuiDecisionSurfaceRange {
20
+ readonly min: number;
21
+ readonly max: number;
22
+ }
23
+ export type TuiDecisionSurfaceInput = {
24
+ readonly kind: 'plan-approval';
25
+ readonly request: ClaudePlanApprovalRequest;
26
+ readonly selectedIndex: number;
27
+ readonly feedbackMode: boolean;
28
+ readonly feedback: string;
29
+ readonly elevatedMode: TuiPlanElevatedMode;
30
+ } | {
31
+ readonly kind: 'question';
32
+ readonly questions: readonly ClaudeQuestion[];
33
+ readonly questionIndex: number;
34
+ readonly answer: string;
35
+ };
36
+ export interface TuiPlanApprovalSurfaceModel {
37
+ readonly kind: 'plan-approval';
38
+ readonly heading: 'Ready to code?';
39
+ readonly intro: "Here is Praxis's plan:";
40
+ readonly explanation: string;
41
+ readonly planPath: string;
42
+ readonly plan?: string;
43
+ readonly options: readonly TuiDecisionSurfaceOption[];
44
+ readonly selectedIndex: number;
45
+ readonly range: TuiDecisionSurfaceRange;
46
+ readonly feedbackMode: boolean;
47
+ readonly feedback: string;
48
+ readonly feedbackPlaceholder: string;
49
+ readonly actions: readonly TuiDecisionSurfaceAction[];
50
+ readonly cancellation: TuiDecisionSurfaceCancellation;
51
+ }
52
+ export interface TuiQuestionSurfaceModel {
53
+ readonly kind: 'question';
54
+ readonly questionIndex: number;
55
+ readonly questionCount: number;
56
+ readonly progress: string;
57
+ readonly header: string;
58
+ readonly question: string;
59
+ readonly heading: string;
60
+ readonly multiSelect: boolean;
61
+ readonly answer: string;
62
+ readonly options: readonly TuiDecisionSurfaceOption[];
63
+ readonly range: TuiDecisionSurfaceRange;
64
+ readonly guidance?: string;
65
+ readonly actions: readonly TuiDecisionSurfaceAction[];
66
+ readonly cancellation: TuiDecisionSurfaceCancellation;
67
+ readonly emptyState?: string;
68
+ }
69
+ export type TuiDecisionSurfaceModel = TuiPlanApprovalSurfaceModel | TuiQuestionSurfaceModel;
70
+ export declare function projectTuiDecisionSurface(input: TuiDecisionSurfaceInput): TuiDecisionSurfaceModel;
71
+ //# sourceMappingURL=decision-surface-model.d.ts.map
@@ -0,0 +1,131 @@
1
+ function normalizeIndex(value, count, empty = -1) {
2
+ if (count === 0)
3
+ return empty;
4
+ const integer = Number.isFinite(value) ? Math.trunc(value) : 0;
5
+ return Math.max(0, Math.min(count - 1, integer));
6
+ }
7
+ function range(count) {
8
+ return { min: count > 0 ? 1 : 0, max: count };
9
+ }
10
+ const cancellation = {
11
+ visualLabel: 'Esc to cancel',
12
+ screenReaderLabel: 'Escape to cancel',
13
+ };
14
+ const questionCancellation = {
15
+ visualLabel: 'Esc cancels',
16
+ screenReaderLabel: 'Escape cancels',
17
+ };
18
+ function projectedOptions(options, selectedIndex) {
19
+ return options.map((option, index) => ({
20
+ index: index + 1,
21
+ label: option.label,
22
+ ...(option.description === undefined
23
+ ? {}
24
+ : { description: option.description }),
25
+ ...(option.preview === undefined ? {} : { preview: option.preview }),
26
+ selected: index === selectedIndex,
27
+ }));
28
+ }
29
+ function emptyQuestionModel(answer) {
30
+ return {
31
+ kind: 'question',
32
+ questionIndex: -1,
33
+ questionCount: 0,
34
+ progress: 'Question 0 of 0',
35
+ header: '',
36
+ question: '',
37
+ heading: 'Question',
38
+ multiSelect: false,
39
+ answer,
40
+ options: [],
41
+ range: range(0),
42
+ actions: [],
43
+ cancellation: questionCancellation,
44
+ emptyState: 'No questions available.',
45
+ };
46
+ }
47
+ export function projectTuiDecisionSurface(input) {
48
+ if (input.kind === 'plan-approval') {
49
+ const selectedIndex = normalizeIndex(input.selectedIndex, 3);
50
+ const elevatedLabel = input.elevatedMode === 'auto'
51
+ ? 'Yes, and use auto mode'
52
+ : input.elevatedMode === 'bypassPermissions'
53
+ ? 'Yes, and bypass permissions'
54
+ : 'Yes, auto-accept edits';
55
+ const options = projectedOptions([
56
+ { label: elevatedLabel },
57
+ { label: 'Yes, manually approve edits' },
58
+ { label: 'No, keep planning' },
59
+ ], selectedIndex);
60
+ return {
61
+ kind: 'plan-approval',
62
+ heading: 'Ready to code?',
63
+ intro: "Here is Praxis's plan:",
64
+ explanation: 'Praxis has written up a plan and is ready to execute. Would you like to proceed?',
65
+ planPath: input.request.planPath,
66
+ ...(input.request.plan ? { plan: input.request.plan } : {}),
67
+ options,
68
+ selectedIndex,
69
+ range: range(options.length),
70
+ feedbackMode: input.feedbackMode,
71
+ feedback: input.feedback,
72
+ feedbackPlaceholder: selectedIndex === 2
73
+ ? 'Tell Praxis what to change'
74
+ : 'Add feedback for implementation',
75
+ actions: input.feedbackMode
76
+ ? [
77
+ {
78
+ visualLabel: 'Enter to submit',
79
+ screenReaderLabel: 'Enter to submit',
80
+ },
81
+ {
82
+ visualLabel: 'Tab to collapse',
83
+ screenReaderLabel: 'Tab to collapse feedback',
84
+ },
85
+ ]
86
+ : [
87
+ {
88
+ visualLabel: 'Enter to confirm',
89
+ screenReaderLabel: 'Enter selection [1-3]',
90
+ },
91
+ {
92
+ visualLabel: 'Tab to add feedback',
93
+ screenReaderLabel: 'Tab to add feedback',
94
+ },
95
+ { screenReaderLabel: 'Use up/down arrows to change selection' },
96
+ { screenReaderLabel: 'Press 1, 2, or 3 to choose directly' },
97
+ { screenReaderLabel: 'Press y to approve' },
98
+ { screenReaderLabel: 'Press n to keep planning' },
99
+ ],
100
+ cancellation,
101
+ };
102
+ }
103
+ const count = input.questions.length;
104
+ const questionIndex = normalizeIndex(input.questionIndex, count);
105
+ if (count === 0)
106
+ return emptyQuestionModel(input.answer);
107
+ const current = input.questions[questionIndex];
108
+ if (current === undefined)
109
+ return emptyQuestionModel(input.answer);
110
+ const options = projectedOptions(current.options, -1);
111
+ const guidance = current.multiSelect
112
+ ? 'Enter comma-separated option numbers or custom text'
113
+ : 'Enter one option number or custom text';
114
+ return {
115
+ kind: 'question',
116
+ questionIndex,
117
+ questionCount: count,
118
+ progress: `Question ${questionIndex + 1} of ${count}`,
119
+ header: current.header,
120
+ question: current.question,
121
+ heading: `${current.header}: ${current.question}`,
122
+ multiSelect: current.multiSelect,
123
+ answer: input.answer,
124
+ options,
125
+ range: range(options.length),
126
+ guidance,
127
+ actions: [{ visualLabel: guidance, screenReaderLabel: guidance }],
128
+ cancellation: questionCancellation,
129
+ };
130
+ }
131
+ //# sourceMappingURL=decision-surface-model.js.map
@@ -0,0 +1,7 @@
1
+ import type { TuiDecisionSurfaceModel } from './decision-surface-model.js';
2
+ export declare function DecisionSurface({ model, width, screenReader, }: {
3
+ model: TuiDecisionSurfaceModel;
4
+ width: number;
5
+ screenReader: boolean;
6
+ }): import("react").JSX.Element;
7
+ //# sourceMappingURL=decision-surface.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import { DialogFrame } from './claude-style.js';
4
+ import { useTuiTheme } from './theme.js';
5
+ function Footer({ actions, cancellation, screenReader, }) {
6
+ const labels = actions.flatMap((action) => screenReader
7
+ ? [action.screenReaderLabel]
8
+ : action.visualLabel === undefined
9
+ ? []
10
+ : [action.visualLabel]);
11
+ return (_jsx(Text, { dimColor: true, children: labels
12
+ .concat(screenReader
13
+ ? cancellation.screenReaderLabel
14
+ : cancellation.visualLabel)
15
+ .join(' · ') }));
16
+ }
17
+ function Option({ option, screenReader, }) {
18
+ const theme = useTuiTheme();
19
+ const selected = option.selected;
20
+ return (_jsxs(Text, { ...(selected ? theme.text.selectedRow : {}), children: [screenReader || theme.noColor
21
+ ? selected
22
+ ? 'Selected: '
23
+ : ''
24
+ : selected
25
+ ? '❯ '
26
+ : ' ', option.index, ". ", option.label, option.description ? `: ${option.description}` : ''] }));
27
+ }
28
+ function PlanSurface({ model, screenReader, }) {
29
+ return (_jsxs(DialogFrame, { title: model.heading, screenReader: screenReader, children: [_jsx(Text, { children: model.intro }), model.plan ? (_jsx(Box, { borderStyle: screenReader ? undefined : 'classic', borderLeft: false, borderRight: false, paddingX: screenReader ? 0 : 1, marginY: 1, children: _jsx(Text, { children: model.plan }) })) : null, _jsx(Text, { dimColor: true, children: model.explanation }), model.options.map((option) => (_jsx(Option, { option: option, screenReader: screenReader }, option.index))), model.feedbackMode ? (_jsxs(Text, { children: [screenReader ? 'Feedback: ' : '› ', model.feedback || model.feedbackPlaceholder] })) : null, _jsx(Text, { dimColor: true, children: model.planPath }), _jsx(Footer, { ...model, screenReader: screenReader })] }));
30
+ }
31
+ function QuestionSurface({ model, screenReader, }) {
32
+ return (_jsxs(DialogFrame, { title: model.heading, screenReader: screenReader, children: [_jsx(Text, { children: model.progress }), model.emptyState ? _jsx(Text, { dimColor: true, children: model.emptyState }) : null, model.options.map((option) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { children: [option.index, ". ", option.label, option.description ? ` — ${option.description}` : ''] }), option.preview ? _jsx(Text, { dimColor: true, children: option.preview }) : null] }, `${option.index}-${option.label}`))), _jsxs(Text, { children: [screenReader ? 'Current answer: ' : '› ', model.answer || (screenReader ? '(empty)' : '')] }), _jsx(Footer, { ...model, screenReader: screenReader })] }));
33
+ }
34
+ export function DecisionSurface({ model, width, screenReader, }) {
35
+ const content = model.kind === 'plan-approval' ? (_jsx(PlanSurface, { model: model, screenReader: screenReader })) : (_jsx(QuestionSurface, { model: model, screenReader: screenReader }));
36
+ const normalizedWidth = Number.isFinite(width)
37
+ ? Math.min(100, Math.max(1, Math.trunc(width)))
38
+ : 100;
39
+ return screenReader ? content : _jsx(Box, { width: normalizedWidth, children: content });
40
+ }
41
+ //# sourceMappingURL=decision-surface.js.map
@@ -0,0 +1,68 @@
1
+ export type TuiHelpTabId = 'general' | 'commands' | 'custom-commands';
2
+ export interface TuiHelpShortcut {
3
+ readonly id: string;
4
+ readonly key: string;
5
+ readonly description: string;
6
+ }
7
+ export interface TuiHelpShortcutGroup {
8
+ readonly id: string;
9
+ readonly shortcuts: readonly TuiHelpShortcut[];
10
+ }
11
+ export interface TuiHelpCommandInput {
12
+ readonly name: string;
13
+ readonly description: string;
14
+ }
15
+ export interface TuiHelpCommandRow {
16
+ readonly id: string;
17
+ readonly ordinal: number;
18
+ readonly invocation: string;
19
+ readonly description: string;
20
+ }
21
+ export interface TuiHelpDocumentation {
22
+ readonly label: 'Praxis documentation';
23
+ readonly url: 'https://github.com/Forest-Isle/Praxis';
24
+ }
25
+ export interface TuiHelpGeneralContent {
26
+ readonly kind: 'general';
27
+ readonly description: string;
28
+ readonly shortcutGroups: readonly TuiHelpShortcutGroup[];
29
+ }
30
+ export interface TuiHelpCommandContent {
31
+ readonly kind: 'commands' | 'custom-commands';
32
+ readonly heading: string;
33
+ readonly commands: readonly TuiHelpCommandRow[];
34
+ readonly focusedIndex: number | null;
35
+ readonly emptyText: string;
36
+ }
37
+ export type TuiHelpActiveContent = TuiHelpGeneralContent | TuiHelpCommandContent;
38
+ export interface TuiHelpTab {
39
+ readonly id: TuiHelpTabId;
40
+ readonly label: 'General' | 'Commands' | 'Custom commands';
41
+ readonly current: boolean;
42
+ }
43
+ export interface TuiHelpSurfaceInput {
44
+ readonly invocation: '?' | '/help';
45
+ readonly tabIndex: number;
46
+ readonly selectedIndex: number;
47
+ readonly builtinCommands: readonly TuiHelpCommandInput[];
48
+ readonly customCommands: readonly TuiHelpCommandInput[];
49
+ }
50
+ export interface TuiHelpSurfaceModel {
51
+ readonly kind: 'help';
52
+ readonly title: 'Help';
53
+ readonly invocation: '?' | '/help';
54
+ readonly tabs: readonly TuiHelpTab[];
55
+ readonly activeTab: {
56
+ readonly id: TuiHelpTabId;
57
+ readonly label: TuiHelpTab['label'];
58
+ };
59
+ readonly activeContent: TuiHelpActiveContent;
60
+ readonly navigation: {
61
+ readonly switchTabs: 'Left/Right to switch tabs';
62
+ readonly browseCommands?: 'Up/Down to browse commands';
63
+ readonly close: 'Esc to close';
64
+ };
65
+ readonly documentation: TuiHelpDocumentation;
66
+ }
67
+ export declare function projectTuiHelpSurface(input: TuiHelpSurfaceInput): TuiHelpSurfaceModel;
68
+ //# sourceMappingURL=help-surface-model.d.ts.map
@@ -0,0 +1,131 @@
1
+ const TAB_DEFINITIONS = [
2
+ { id: 'general', label: 'General' },
3
+ { id: 'commands', label: 'Commands' },
4
+ { id: 'custom-commands', label: 'Custom commands' },
5
+ ];
6
+ const SHORTCUT_GROUPS = [
7
+ {
8
+ id: 'prompt',
9
+ shortcuts: [
10
+ { id: 'bash-mode', key: '!', description: 'for bash mode' },
11
+ { id: 'commands', key: '/', description: 'for commands' },
12
+ { id: 'file-paths', key: '@', description: 'for file paths' },
13
+ { id: 'background', key: '&', description: 'for background' },
14
+ { id: 'side-question', key: '/btw', description: 'for side question' },
15
+ ],
16
+ },
17
+ {
18
+ id: 'navigation',
19
+ shortcuts: [
20
+ {
21
+ id: 'clear-input',
22
+ key: 'double tap esc',
23
+ description: 'to clear input',
24
+ },
25
+ {
26
+ id: 'auto-accept-edits',
27
+ key: 'shift + tab',
28
+ description: 'to auto-accept edits',
29
+ },
30
+ {
31
+ id: 'verbose-output',
32
+ key: 'ctrl + o',
33
+ description: 'for verbose output',
34
+ },
35
+ { id: 'toggle-tasks', key: 'ctrl + t', description: 'to toggle tasks' },
36
+ {
37
+ id: 'newline',
38
+ key: 'backslash (\\) + return (⏎)',
39
+ description: 'for newline',
40
+ },
41
+ ],
42
+ },
43
+ {
44
+ id: 'editing',
45
+ shortcuts: [
46
+ { id: 'undo', key: 'ctrl + shift + _', description: 'to undo' },
47
+ { id: 'suspend', key: 'ctrl + z', description: 'to suspend' },
48
+ { id: 'paste-images', key: 'ctrl + v', description: 'to paste images' },
49
+ { id: 'switch-model', key: 'opt + p', description: 'to switch model' },
50
+ { id: 'stash-prompt', key: 'ctrl + s', description: 'to stash prompt' },
51
+ {
52
+ id: 'external-editor',
53
+ key: 'ctrl + g',
54
+ description: 'to edit in $EDITOR',
55
+ },
56
+ {
57
+ id: 'customize-keybindings',
58
+ key: '/keybindings',
59
+ description: 'to customize',
60
+ },
61
+ ],
62
+ },
63
+ ];
64
+ const DOCUMENTATION = {
65
+ label: 'Praxis documentation',
66
+ url: 'https://github.com/Forest-Isle/Praxis',
67
+ };
68
+ const GENERAL_DESCRIPTION = 'Praxis understands your codebase, makes edits with your permission, and executes commands from your terminal.';
69
+ function normalizeIndex(value) {
70
+ return Number.isFinite(value) ? Math.trunc(value) : 0;
71
+ }
72
+ function clamp(value, minimum, maximum) {
73
+ const normalized = normalizeIndex(value);
74
+ return Math.max(minimum, Math.min(maximum, normalized));
75
+ }
76
+ function projectCommands(commands, tab, selectedIndex) {
77
+ const rows = commands.map((command, index) => ({
78
+ id: `${tab}:${index}:${command.name}`,
79
+ ordinal: index + 1,
80
+ invocation: `/${command.name}`,
81
+ description: command.description,
82
+ }));
83
+ return {
84
+ kind: tab,
85
+ heading: tab === 'commands'
86
+ ? 'Browse default commands'
87
+ : 'Browse shared commands and skills',
88
+ commands: rows,
89
+ focusedIndex: rows.length === 0 ? null : clamp(selectedIndex, 0, rows.length - 1),
90
+ emptyText: 'No commands found.',
91
+ };
92
+ }
93
+ export function projectTuiHelpSurface(input) {
94
+ const tabIndex = clamp(input.tabIndex, 0, TAB_DEFINITIONS.length - 1);
95
+ const activeTab = tabIndex === 0
96
+ ? TAB_DEFINITIONS[0]
97
+ : tabIndex === 1
98
+ ? TAB_DEFINITIONS[1]
99
+ : TAB_DEFINITIONS[2];
100
+ const tabs = TAB_DEFINITIONS.map((tab) => ({
101
+ ...tab,
102
+ current: tab.id === activeTab.id,
103
+ }));
104
+ const activeContent = activeTab.id === 'general'
105
+ ? {
106
+ kind: 'general',
107
+ description: GENERAL_DESCRIPTION,
108
+ shortcutGroups: SHORTCUT_GROUPS,
109
+ }
110
+ : projectCommands(activeTab.id === 'commands'
111
+ ? input.builtinCommands
112
+ : input.customCommands, activeTab.id, input.selectedIndex);
113
+ return {
114
+ kind: 'help',
115
+ title: 'Help',
116
+ invocation: input.invocation,
117
+ tabs,
118
+ activeTab,
119
+ activeContent,
120
+ navigation: {
121
+ switchTabs: 'Left/Right to switch tabs',
122
+ ...(activeContent.kind === 'general' ||
123
+ activeContent.commands.length === 0
124
+ ? {}
125
+ : { browseCommands: 'Up/Down to browse commands' }),
126
+ close: 'Esc to close',
127
+ },
128
+ documentation: DOCUMENTATION,
129
+ };
130
+ }
131
+ //# sourceMappingURL=help-surface-model.js.map
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Box, Text } from 'ink';
3
- import { useTerminalWidth } from './claude-style.js';
4
3
  import { tuiMcpServerActions, } from './mcp-panel-projector.js';
5
4
  const CLAUDE_EMPTY_MESSAGE = 'No MCP servers configured. Run claude doctor if this is unexpected — it lists MCP config files that failed validation. Otherwise, run claude mcp --help or visit https://code.claude.com/docs/en/mcp to learn more.';
6
5
  const SCOPE_LABELS = {
@@ -75,7 +74,7 @@ function ToolPanel({ server, state, }) {
75
74
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: tool.name }), _jsx(Text, { children: server.name }), _jsxs(Text, { children: ["Tool name: ", ' ' + tool.name] }), _jsxs(Text, { children: ["Full name: ", ' ' + tool.fullName] }), _jsx(Text, { children: "Description:" }), _jsx(Text, { children: tool.description ?? '' }), _jsx(Text, { dimColor: true, children: "Esc to go back" })] }));
76
75
  }
77
76
  export function McpPanel({ model, state, screenReader = false, width, dataPlane = 'claude', }) {
78
- const terminalWidth = useTerminalWidth(width);
77
+ const terminalWidth = width ?? 80;
79
78
  const server = model.servers[state.serverIndex];
80
79
  let content;
81
80
  if (model.servers.length === 0)
@@ -0,0 +1,195 @@
1
+ import type { ComposerEditorState } from './composer-editor.js';
2
+ import type { TuiPermissionBehavior, TuiPermissionRule } from './permission-settings.js';
3
+ import type { RecentlyDeniedAction } from './recently-denied.js';
4
+ import type { TuiToolPermissionModel, TuiToolPermissionOption } from './tool-permission.js';
5
+ export type TuiPermissionSurfaceInput = {
6
+ kind: 'tool-request';
7
+ model: TuiToolPermissionModel;
8
+ selection: number;
9
+ feedbackMode: boolean;
10
+ feedback: string;
11
+ ruleEditor?: ComposerEditorState | null;
12
+ } | {
13
+ kind: 'recovery-request';
14
+ display: string;
15
+ heading?: string;
16
+ selection: number;
17
+ feedbackMode: boolean;
18
+ feedback: string;
19
+ } | {
20
+ kind: 'permission-dashboard';
21
+ tabIndex: number;
22
+ selectedIndex: number;
23
+ query: string;
24
+ rules: readonly TuiPermissionRule[];
25
+ recentDenied: readonly RecentlyDeniedAction[];
26
+ retryingDeniedId?: string | null;
27
+ workspaceDirectories: readonly {
28
+ path: string;
29
+ original: boolean;
30
+ }[];
31
+ } | {
32
+ kind: 'permission-rule-input';
33
+ behavior: TuiPermissionBehavior;
34
+ value: string;
35
+ } | {
36
+ kind: 'permission-scope';
37
+ behavior: TuiPermissionBehavior;
38
+ rule: string;
39
+ selectedIndex: number;
40
+ settingsDirectory: string;
41
+ } | {
42
+ kind: 'permission-delete';
43
+ rule: TuiPermissionRule;
44
+ selectedIndex: number;
45
+ } | {
46
+ kind: 'workspace-directory-input';
47
+ value: string;
48
+ } | {
49
+ kind: 'workspace-directory-delete';
50
+ path: string;
51
+ selectedIndex: number;
52
+ };
53
+ export interface TuiPermissionSurfaceAction {
54
+ readonly label: string;
55
+ readonly key?: string;
56
+ readonly screenReaderLabel?: string;
57
+ readonly usesSelectionRange?: boolean;
58
+ }
59
+ export interface TuiPermissionSurfaceOption {
60
+ readonly index: number;
61
+ readonly label: string;
62
+ readonly description?: string;
63
+ readonly selected: boolean;
64
+ readonly value?: string;
65
+ }
66
+ export interface TuiPermissionSurfaceRow {
67
+ readonly index: number;
68
+ readonly label: string;
69
+ readonly description?: string;
70
+ readonly selected: boolean;
71
+ readonly id?: string;
72
+ readonly status?: 'denied' | 'retrying';
73
+ readonly original?: boolean;
74
+ }
75
+ export interface TuiPermissionDashboardModel {
76
+ readonly kind: 'permission-dashboard';
77
+ readonly heading: 'Permissions';
78
+ readonly tabs: readonly {
79
+ readonly index: number;
80
+ readonly label: string;
81
+ readonly current: boolean;
82
+ }[];
83
+ readonly tabIndex: number;
84
+ readonly description: string;
85
+ readonly query: string;
86
+ readonly rows: readonly TuiPermissionSurfaceRow[];
87
+ readonly emptyState?: string;
88
+ readonly originalWorkspace?: TuiPermissionSurfaceRow;
89
+ readonly range: {
90
+ readonly min: number;
91
+ readonly max: number;
92
+ };
93
+ readonly actions: readonly TuiPermissionSurfaceAction[];
94
+ readonly cancellation: string;
95
+ }
96
+ export interface TuiPermissionToolRequestModel {
97
+ readonly kind: 'tool-request';
98
+ readonly heading: string;
99
+ readonly tool: TuiToolPermissionModel;
100
+ readonly options: readonly TuiToolPermissionOption[];
101
+ readonly selectedIndex: number;
102
+ readonly range: {
103
+ readonly min: number;
104
+ readonly max: number;
105
+ };
106
+ readonly feedbackMode: boolean;
107
+ readonly feedback: string;
108
+ readonly ruleEditor?: ComposerEditorState | null;
109
+ readonly actions: readonly TuiPermissionSurfaceAction[];
110
+ readonly cancellation: string;
111
+ }
112
+ export interface TuiPermissionRecoveryRequestModel {
113
+ readonly kind: 'recovery-request';
114
+ readonly heading: string;
115
+ readonly display: string;
116
+ readonly question: string;
117
+ readonly options: readonly TuiPermissionSurfaceOption[];
118
+ readonly selectedIndex: number;
119
+ readonly range: {
120
+ readonly min: number;
121
+ readonly max: number;
122
+ };
123
+ readonly feedbackMode: boolean;
124
+ readonly feedback: string;
125
+ readonly feedbackPlaceholder: string;
126
+ readonly actions: readonly TuiPermissionSurfaceAction[];
127
+ readonly cancellation: string;
128
+ }
129
+ export interface TuiPermissionRuleInputModel {
130
+ readonly kind: 'permission-rule-input';
131
+ readonly heading: string;
132
+ readonly behavior: TuiPermissionBehavior;
133
+ readonly value: string;
134
+ readonly description: string;
135
+ readonly placeholder: string;
136
+ readonly actions: readonly TuiPermissionSurfaceAction[];
137
+ readonly cancellation: string;
138
+ }
139
+ export interface TuiPermissionScopeModel {
140
+ readonly kind: 'permission-scope';
141
+ readonly heading: string;
142
+ readonly behavior: TuiPermissionBehavior;
143
+ readonly rule: string;
144
+ readonly description: string;
145
+ readonly options: readonly TuiPermissionSurfaceOption[];
146
+ readonly selectedIndex: number;
147
+ readonly range: {
148
+ readonly min: number;
149
+ readonly max: number;
150
+ };
151
+ readonly actions: readonly TuiPermissionSurfaceAction[];
152
+ readonly cancellation: string;
153
+ }
154
+ export interface TuiPermissionDeleteModel {
155
+ readonly kind: 'permission-delete';
156
+ readonly heading: string;
157
+ readonly rule: string;
158
+ readonly description?: string;
159
+ readonly scope: string;
160
+ readonly question: string;
161
+ readonly options: readonly TuiPermissionSurfaceOption[];
162
+ readonly selectedIndex: number;
163
+ readonly range: {
164
+ readonly min: number;
165
+ readonly max: number;
166
+ };
167
+ readonly actions: readonly TuiPermissionSurfaceAction[];
168
+ readonly cancellation: string;
169
+ }
170
+ export interface TuiWorkspaceDirectoryInputModel {
171
+ readonly kind: 'workspace-directory-input';
172
+ readonly heading: string;
173
+ readonly description: string;
174
+ readonly value: string;
175
+ readonly placeholder: string;
176
+ readonly actions: readonly TuiPermissionSurfaceAction[];
177
+ readonly cancellation: string;
178
+ }
179
+ export interface TuiWorkspaceDirectoryDeleteModel {
180
+ readonly kind: 'workspace-directory-delete';
181
+ readonly heading: string;
182
+ readonly path: string;
183
+ readonly description: string;
184
+ readonly options: readonly TuiPermissionSurfaceOption[];
185
+ readonly selectedIndex: number;
186
+ readonly range: {
187
+ readonly min: number;
188
+ readonly max: number;
189
+ };
190
+ readonly actions: readonly TuiPermissionSurfaceAction[];
191
+ readonly cancellation: string;
192
+ }
193
+ export type TuiPermissionSurfaceModel = TuiPermissionToolRequestModel | TuiPermissionRecoveryRequestModel | TuiPermissionDashboardModel | TuiPermissionRuleInputModel | TuiPermissionScopeModel | TuiPermissionDeleteModel | TuiWorkspaceDirectoryInputModel | TuiWorkspaceDirectoryDeleteModel;
194
+ export declare function projectTuiPermissionSurface(input: TuiPermissionSurfaceInput): TuiPermissionSurfaceModel;
195
+ //# sourceMappingURL=permission-surface-model.d.ts.map