guardlink 1.2.0 → 1.4.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 (166) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +50 -2
  3. package/dist/agents/config.d.ts +11 -0
  4. package/dist/agents/config.d.ts.map +1 -1
  5. package/dist/agents/config.js +11 -0
  6. package/dist/agents/config.js.map +1 -1
  7. package/dist/agents/index.d.ts +3 -0
  8. package/dist/agents/index.d.ts.map +1 -1
  9. package/dist/agents/index.js +3 -0
  10. package/dist/agents/index.js.map +1 -1
  11. package/dist/agents/launcher.d.ts +11 -8
  12. package/dist/agents/launcher.d.ts.map +1 -1
  13. package/dist/agents/launcher.js +11 -8
  14. package/dist/agents/launcher.js.map +1 -1
  15. package/dist/agents/prompts.d.ts +9 -0
  16. package/dist/agents/prompts.d.ts.map +1 -1
  17. package/dist/agents/prompts.js +9 -0
  18. package/dist/agents/prompts.js.map +1 -1
  19. package/dist/analyze/index.d.ts +10 -7
  20. package/dist/analyze/index.d.ts.map +1 -1
  21. package/dist/analyze/index.js +10 -7
  22. package/dist/analyze/index.js.map +1 -1
  23. package/dist/analyze/llm.d.ts +11 -10
  24. package/dist/analyze/llm.d.ts.map +1 -1
  25. package/dist/analyze/llm.js +11 -10
  26. package/dist/analyze/llm.js.map +1 -1
  27. package/dist/analyze/prompts.d.ts +3 -0
  28. package/dist/analyze/prompts.d.ts.map +1 -1
  29. package/dist/analyze/prompts.js +3 -0
  30. package/dist/analyze/prompts.js.map +1 -1
  31. package/dist/analyze/tools.d.ts +10 -4
  32. package/dist/analyze/tools.d.ts.map +1 -1
  33. package/dist/analyze/tools.js +10 -4
  34. package/dist/analyze/tools.js.map +1 -1
  35. package/dist/analyzer/index.d.ts +3 -0
  36. package/dist/analyzer/index.d.ts.map +1 -1
  37. package/dist/analyzer/index.js +3 -0
  38. package/dist/analyzer/index.js.map +1 -1
  39. package/dist/analyzer/sarif.d.ts +5 -6
  40. package/dist/analyzer/sarif.d.ts.map +1 -1
  41. package/dist/analyzer/sarif.js +5 -6
  42. package/dist/analyzer/sarif.js.map +1 -1
  43. package/dist/cli/index.d.ts +14 -9
  44. package/dist/cli/index.d.ts.map +1 -1
  45. package/dist/cli/index.js +479 -26
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/dashboard/generate.d.ts +8 -5
  48. package/dist/dashboard/generate.d.ts.map +1 -1
  49. package/dist/dashboard/generate.js +30 -7
  50. package/dist/dashboard/generate.js.map +1 -1
  51. package/dist/dashboard/index.d.ts +5 -0
  52. package/dist/dashboard/index.d.ts.map +1 -1
  53. package/dist/dashboard/index.js +5 -0
  54. package/dist/dashboard/index.js.map +1 -1
  55. package/dist/diff/git.d.ts +10 -7
  56. package/dist/diff/git.d.ts.map +1 -1
  57. package/dist/diff/git.js +10 -7
  58. package/dist/diff/git.js.map +1 -1
  59. package/dist/diff/index.d.ts +4 -0
  60. package/dist/diff/index.d.ts.map +1 -1
  61. package/dist/diff/index.js +4 -0
  62. package/dist/diff/index.js.map +1 -1
  63. package/dist/index.d.ts +2 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +1 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/init/detect.d.ts +5 -0
  68. package/dist/init/detect.d.ts.map +1 -1
  69. package/dist/init/detect.js +5 -0
  70. package/dist/init/detect.js.map +1 -1
  71. package/dist/init/index.d.ts +26 -6
  72. package/dist/init/index.d.ts.map +1 -1
  73. package/dist/init/index.js +91 -11
  74. package/dist/init/index.js.map +1 -1
  75. package/dist/init/picker.d.ts.map +1 -1
  76. package/dist/init/picker.js +17 -6
  77. package/dist/init/picker.js.map +1 -1
  78. package/dist/init/templates.d.ts +20 -0
  79. package/dist/init/templates.d.ts.map +1 -1
  80. package/dist/init/templates.js +132 -21
  81. package/dist/init/templates.js.map +1 -1
  82. package/dist/mcp/index.d.ts +5 -0
  83. package/dist/mcp/index.d.ts.map +1 -1
  84. package/dist/mcp/index.js +5 -0
  85. package/dist/mcp/index.js.map +1 -1
  86. package/dist/mcp/lookup.d.ts +5 -0
  87. package/dist/mcp/lookup.d.ts.map +1 -1
  88. package/dist/mcp/lookup.js +5 -0
  89. package/dist/mcp/lookup.js.map +1 -1
  90. package/dist/mcp/server.d.ts +17 -13
  91. package/dist/mcp/server.d.ts.map +1 -1
  92. package/dist/mcp/server.js +171 -15
  93. package/dist/mcp/server.js.map +1 -1
  94. package/dist/mcp/suggest.d.ts +8 -6
  95. package/dist/mcp/suggest.d.ts.map +1 -1
  96. package/dist/mcp/suggest.js +8 -6
  97. package/dist/mcp/suggest.js.map +1 -1
  98. package/dist/parser/clear.d.ts +36 -0
  99. package/dist/parser/clear.d.ts.map +1 -0
  100. package/dist/parser/clear.js +148 -0
  101. package/dist/parser/clear.js.map +1 -0
  102. package/dist/parser/index.d.ts +2 -0
  103. package/dist/parser/index.d.ts.map +1 -1
  104. package/dist/parser/index.js +1 -0
  105. package/dist/parser/index.js.map +1 -1
  106. package/dist/parser/parse-file.d.ts +5 -2
  107. package/dist/parser/parse-file.d.ts.map +1 -1
  108. package/dist/parser/parse-file.js +29 -2
  109. package/dist/parser/parse-file.js.map +1 -1
  110. package/dist/parser/parse-line.d.ts +3 -3
  111. package/dist/parser/parse-line.js +3 -3
  112. package/dist/parser/parse-project.d.ts +7 -7
  113. package/dist/parser/parse-project.d.ts.map +1 -1
  114. package/dist/parser/parse-project.js +127 -11
  115. package/dist/parser/parse-project.js.map +1 -1
  116. package/dist/report/index.d.ts +3 -0
  117. package/dist/report/index.d.ts.map +1 -1
  118. package/dist/report/index.js +3 -0
  119. package/dist/report/index.js.map +1 -1
  120. package/dist/report/report.d.ts +4 -7
  121. package/dist/report/report.d.ts.map +1 -1
  122. package/dist/report/report.js +4 -7
  123. package/dist/report/report.js.map +1 -1
  124. package/dist/review/index.d.ts +62 -0
  125. package/dist/review/index.d.ts.map +1 -0
  126. package/dist/review/index.js +226 -0
  127. package/dist/review/index.js.map +1 -0
  128. package/dist/tui/commands.d.ts +23 -0
  129. package/dist/tui/commands.d.ts.map +1 -1
  130. package/dist/tui/commands.js +440 -3
  131. package/dist/tui/commands.js.map +1 -1
  132. package/dist/tui/config.d.ts +6 -0
  133. package/dist/tui/config.d.ts.map +1 -1
  134. package/dist/tui/config.js +6 -0
  135. package/dist/tui/config.js.map +1 -1
  136. package/dist/tui/index.d.ts +8 -8
  137. package/dist/tui/index.d.ts.map +1 -1
  138. package/dist/tui/index.js +45 -9
  139. package/dist/tui/index.js.map +1 -1
  140. package/dist/tui/input.d.ts +6 -0
  141. package/dist/tui/input.d.ts.map +1 -1
  142. package/dist/tui/input.js +6 -0
  143. package/dist/tui/input.js.map +1 -1
  144. package/dist/types/index.d.ts +41 -0
  145. package/dist/types/index.d.ts.map +1 -1
  146. package/dist/workspace/index.d.ts +12 -0
  147. package/dist/workspace/index.d.ts.map +1 -0
  148. package/dist/workspace/index.js +9 -0
  149. package/dist/workspace/index.js.map +1 -0
  150. package/dist/workspace/link.d.ts +91 -0
  151. package/dist/workspace/link.d.ts.map +1 -0
  152. package/dist/workspace/link.js +581 -0
  153. package/dist/workspace/link.js.map +1 -0
  154. package/dist/workspace/merge.d.ts +104 -0
  155. package/dist/workspace/merge.d.ts.map +1 -0
  156. package/dist/workspace/merge.js +752 -0
  157. package/dist/workspace/merge.js.map +1 -0
  158. package/dist/workspace/metadata.d.ts +34 -0
  159. package/dist/workspace/metadata.d.ts.map +1 -0
  160. package/dist/workspace/metadata.js +181 -0
  161. package/dist/workspace/metadata.js.map +1 -0
  162. package/dist/workspace/types.d.ts +134 -0
  163. package/dist/workspace/types.d.ts.map +1 -0
  164. package/dist/workspace/types.js +12 -0
  165. package/dist/workspace/types.js.map +1 -0
  166. package/package.json +1 -1
@@ -0,0 +1,226 @@
1
+ /**
2
+ * GuardLink — Review module.
3
+ *
4
+ * Interactive governance workflow for unmitigated exposures.
5
+ * Users walk through the GAL (Governance Acceptance List) and decide:
6
+ * accept — write @accepts + @audit (risk acknowledged, intentional)
7
+ * remediate — write @audit with planned-fix note
8
+ * skip — leave open for now
9
+ *
10
+ * @exposes #cli to #arbitrary-write [medium] cwe:CWE-73 -- "Writes @accepts/@audit annotations into source files"
11
+ * @mitigates #cli against #arbitrary-write using #path-validation -- "Only modifies files already in the parsed project"
12
+ * @audit #cli -- "Review decisions require human justification; no empty accepts allowed"
13
+ * @flows ThreatModel -> #cli via getReviewableExposures -- "Exposure list input"
14
+ * @flows #cli -> SourceFiles via writeFile -- "Annotation insertion output"
15
+ * @handles internal on #cli -- "Processes exposure metadata and user justification text"
16
+ */
17
+ import { readFile, writeFile } from 'node:fs/promises';
18
+ import { resolve } from 'node:path';
19
+ import { stripCommentPrefix } from '../parser/comment-strip.js';
20
+ import { findUnmitigatedExposures } from '../parser/validate.js';
21
+ // ─── Severity ordering ──────────────────────────────────────────────
22
+ const SEVERITY_ORDER = {
23
+ critical: 0, high: 1, medium: 2, low: 3,
24
+ };
25
+ // ─── Core logic ─────────────────────────────────────────────────────
26
+ /**
27
+ * Get all unmitigated exposures eligible for review, sorted by severity.
28
+ * Excludes test fixtures and files outside the src/ tree.
29
+ */
30
+ export function getReviewableExposures(model) {
31
+ const unmitigated = findUnmitigatedExposures(model);
32
+ // Filter out test fixtures and non-source files
33
+ const filtered = unmitigated.filter(e => {
34
+ const f = e.location.file;
35
+ return !f.startsWith('tests/') && !f.startsWith('test/') && !f.includes('__tests__/') && !f.includes('fixtures/');
36
+ });
37
+ // Sort: critical → high → medium → low, then by file
38
+ filtered.sort((a, b) => {
39
+ const sa = SEVERITY_ORDER[a.severity || 'low'] ?? 3;
40
+ const sb = SEVERITY_ORDER[b.severity || 'low'] ?? 3;
41
+ if (sa !== sb)
42
+ return sa - sb;
43
+ return a.location.file.localeCompare(b.location.file);
44
+ });
45
+ return filtered.map((exposure, i) => ({
46
+ index: i + 1,
47
+ exposure,
48
+ id: `${exposure.location.file}:${exposure.location.line}`,
49
+ }));
50
+ }
51
+ /**
52
+ * Format a severity tag with color hint for display.
53
+ */
54
+ export function severityLabel(s) {
55
+ if (!s)
56
+ return '[?]';
57
+ return `[${s}]`;
58
+ }
59
+ /**
60
+ * Detect the comment style and indentation from the @exposes source line.
61
+ * Supports JSDoc ( * @...), single-line (// @...), and hash (# @...) styles.
62
+ */
63
+ function detectCommentStyle(rawLine) {
64
+ const indent = rawLine.match(/^(\s*)/)?.[1] || '';
65
+ const trimmed = rawLine.trimStart();
66
+ if (trimmed.startsWith('* @') || trimmed.startsWith('* @')) {
67
+ return { prefix: '* ', indent };
68
+ }
69
+ if (trimmed.startsWith('// @')) {
70
+ return { prefix: '// ', indent };
71
+ }
72
+ if (trimmed.startsWith('# @')) {
73
+ return { prefix: '# ', indent };
74
+ }
75
+ if (trimmed.startsWith('-- @')) {
76
+ return { prefix: '-- ', indent };
77
+ }
78
+ // Fallback: single-line JS style
79
+ return { prefix: '// ', indent };
80
+ }
81
+ /**
82
+ * Check if a source line is a GuardLink annotation (used to walk past coupled blocks).
83
+ */
84
+ function isAnnotationLine(line) {
85
+ const inner = stripCommentPrefix(line);
86
+ if (inner === null)
87
+ return false;
88
+ const trimmed = inner.trim();
89
+ // Annotation line: starts with @verb
90
+ if (trimmed.startsWith('@'))
91
+ return true;
92
+ // Continuation line: -- "..."
93
+ if (/^--\s*"/.test(trimmed))
94
+ return true;
95
+ return false;
96
+ }
97
+ /**
98
+ * Find the insertion point after the coupled annotation block that contains
99
+ * the @exposes line at `exposureLine` (1-indexed).
100
+ *
101
+ * Walks forward from the exposure line past consecutive annotation lines
102
+ * to find the end of the block, then returns the 0-indexed line to insert after.
103
+ */
104
+ function findInsertionIndex(lines, exposureLine) {
105
+ // exposureLine is 1-indexed, convert to 0-indexed
106
+ let idx = exposureLine - 1;
107
+ // Walk forward past consecutive annotation lines
108
+ while (idx + 1 < lines.length && isAnnotationLine(lines[idx + 1])) {
109
+ idx++;
110
+ }
111
+ // Insert after the last annotation line in the block
112
+ return idx + 1;
113
+ }
114
+ // ─── Annotation builders ────────────────────────────────────────────
115
+ function todayISO() {
116
+ return new Date().toISOString().slice(0, 10);
117
+ }
118
+ /**
119
+ * Build the annotation lines to insert for an "accept" decision.
120
+ * Returns lines WITHOUT trailing newline.
121
+ */
122
+ function buildAcceptLines(style, exposure, justification) {
123
+ const { prefix, indent } = style;
124
+ const date = todayISO();
125
+ return [
126
+ `${indent}${prefix}@accepts ${exposure.threat} on ${exposure.asset} -- "${escapeDesc(justification)}"`,
127
+ `${indent}${prefix}@audit ${exposure.asset} -- "Accepted via guardlink review on ${date}"`,
128
+ ];
129
+ }
130
+ /**
131
+ * Build the annotation line to insert for a "remediate" decision.
132
+ */
133
+ function buildRemediateLines(style, exposure, note) {
134
+ const { prefix, indent } = style;
135
+ const date = todayISO();
136
+ return [
137
+ `${indent}${prefix}@audit ${exposure.asset} -- "Planned remediation: ${escapeDesc(note)} — flagged via guardlink review on ${date}"`,
138
+ ];
139
+ }
140
+ /** Escape double quotes in description strings */
141
+ function escapeDesc(s) {
142
+ return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
143
+ }
144
+ // ─── File modification ──────────────────────────────────────────────
145
+ /**
146
+ * Insert annotation lines into a source file after the coupled block
147
+ * containing the given @exposes annotation.
148
+ *
149
+ * Returns the number of lines inserted.
150
+ */
151
+ async function insertAnnotations(root, exposure, newLines) {
152
+ const filePath = resolve(root, exposure.location.file);
153
+ const content = await readFile(filePath, 'utf-8');
154
+ const lines = content.split('\n');
155
+ // Validate that the exposure line exists and looks right
156
+ const exposureIdx = exposure.location.line - 1; // 0-indexed
157
+ if (exposureIdx < 0 || exposureIdx >= lines.length) {
158
+ throw new Error(`Line ${exposure.location.line} out of range in ${exposure.location.file}`);
159
+ }
160
+ const insertIdx = findInsertionIndex(lines, exposure.location.line);
161
+ // Splice in the new lines
162
+ lines.splice(insertIdx, 0, ...newLines);
163
+ await writeFile(filePath, lines.join('\n'));
164
+ return newLines.length;
165
+ }
166
+ // ─── Public API ─────────────────────────────────────────────────────
167
+ /**
168
+ * Apply a review decision to an exposure.
169
+ * For 'accept': inserts @accepts + @audit after the coupled block.
170
+ * For 'remediate': inserts @audit with planned-fix note.
171
+ * For 'skip': does nothing.
172
+ *
173
+ * Returns the result including lines inserted.
174
+ */
175
+ export async function applyReviewAction(root, reviewable, action) {
176
+ if (action.decision === 'skip') {
177
+ return { exposure: reviewable, action, linesInserted: 0 };
178
+ }
179
+ const { exposure } = reviewable;
180
+ const filePath = resolve(root, exposure.location.file);
181
+ const content = await readFile(filePath, 'utf-8');
182
+ const lines = content.split('\n');
183
+ // Detect comment style from the @exposes line
184
+ const exposureIdx = exposure.location.line - 1;
185
+ const style = detectCommentStyle(lines[exposureIdx]);
186
+ let newLines;
187
+ if (action.decision === 'accept') {
188
+ newLines = buildAcceptLines(style, exposure, action.justification);
189
+ }
190
+ else {
191
+ newLines = buildRemediateLines(style, exposure, action.justification);
192
+ }
193
+ const linesInserted = await insertAnnotations(root, exposure, newLines);
194
+ return { exposure: reviewable, action, linesInserted };
195
+ }
196
+ /**
197
+ * Format an exposure for display in CLI/TUI review UI.
198
+ */
199
+ export function formatExposureForReview(r, total) {
200
+ const e = r.exposure;
201
+ const sev = e.severity || 'unknown';
202
+ const desc = e.description || '(no description)';
203
+ return [
204
+ `[${r.index}/${total}] ${e.asset} → ${e.threat} [${sev}]`,
205
+ ` File: ${e.location.file}:${e.location.line}`,
206
+ ` Exposure: "${desc}"`,
207
+ ].join('\n');
208
+ }
209
+ /**
210
+ * Summarize review session results.
211
+ */
212
+ export function summarizeReview(results) {
213
+ const accepted = results.filter(r => r.action.decision === 'accept').length;
214
+ const remediated = results.filter(r => r.action.decision === 'remediate').length;
215
+ const skipped = results.filter(r => r.action.decision === 'skip').length;
216
+ const totalLines = results.reduce((sum, r) => sum + r.linesInserted, 0);
217
+ const parts = [];
218
+ if (accepted > 0)
219
+ parts.push(`${accepted} accepted`);
220
+ if (remediated > 0)
221
+ parts.push(`${remediated} marked for remediation`);
222
+ if (skipped > 0)
223
+ parts.push(`${skipped} skipped`);
224
+ return `Review complete: ${parts.join(', ')}. ${totalLines} annotation line(s) written.`;
225
+ }
226
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/review/index.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,22 @@
3
3
  *
4
4
  * Each command function takes (args, ctx) and prints output directly.
5
5
  * Returns void. Throws on fatal errors.
6
+ *
7
+ * @exposes #tui to #path-traversal [high] cwe:CWE-22 -- "File paths from user args in /view, /sarif -o"
8
+ * @mitigates #tui against #path-traversal using #path-validation -- "resolve() with ctx.root constrains file access"
9
+ * @exposes #tui to #arbitrary-write [high] cwe:CWE-73 -- "/report, /sarif, /dashboard write files"
10
+ * @mitigates #tui against #arbitrary-write using #path-validation -- "Output paths resolved relative to project root"
11
+ * @exposes #tui to #cmd-injection [high] cwe:CWE-78 -- "/annotate and /threat-report spawn child processes"
12
+ * @audit #tui -- "Child process spawning delegated to agents/launcher.ts"
13
+ * @exposes #tui to #api-key-exposure [high] cwe:CWE-798 -- "/model handles API key input and storage"
14
+ * @mitigates #tui against #api-key-exposure using #key-redaction -- "API keys masked in /model show output"
15
+ * @exposes #tui to #prompt-injection [medium] cwe:CWE-77 -- "Freeform chat sends user text to LLM"
16
+ * @audit #tui -- "User freeform text passed to LLM via cmdChat; model context is read-only"
17
+ * @flows UserArgs -> #tui via args -- "Command argument input"
18
+ * @flows #tui -> FileSystem via writeFile -- "Report/config output"
19
+ * @flows #tui -> #agent-launcher via launchAgent -- "Agent spawn path"
20
+ * @flows #tui -> #llm-client via chatCompletion -- "LLM API call path"
21
+ * @handles secrets on #tui -- "Processes and stores API keys via /model"
6
22
  */
7
23
  import type { ThreatModel, ThreatModelExposure } from '../types/index.js';
8
24
  export interface TuiContext {
@@ -37,6 +53,13 @@ export declare function cmdThreatReport(args: string, ctx: TuiContext): Promise<
37
53
  export declare function cmdThreatReports(ctx: TuiContext): void;
38
54
  export declare function cmdAnnotate(args: string, ctx: TuiContext): Promise<void>;
39
55
  export declare function cmdChat(text: string, ctx: TuiContext): Promise<void>;
56
+ export declare function cmdClear(args: string, ctx: TuiContext): Promise<void>;
57
+ export declare function cmdSync(ctx: TuiContext): Promise<void>;
58
+ export declare function cmdUnannotated(ctx: TuiContext): void;
59
+ export declare function cmdReview(args: string, ctx: TuiContext): Promise<void>;
40
60
  export declare function cmdReport(ctx: TuiContext): Promise<void>;
41
61
  export declare function cmdDashboard(ctx: TuiContext): Promise<void>;
62
+ export declare function cmdWorkspace(ctx: TuiContext): void;
63
+ export declare function cmdLink(args: string, ctx: TuiContext): Promise<void>;
64
+ export declare function cmdMerge(args: string, ctx: TuiContext): Promise<void>;
42
65
  //# sourceMappingURL=commands.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/tui/commands.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAmB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAuB3F,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,EAAE,EAAE,OAAO,eAAe,EAAE,SAAS,CAAC;IACtC,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qEAAqE;IACrE,aAAa,EAAE,mBAAmB,EAAE,CAAC;CACtC;AAED,8CAA8C;AAC9C,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAGjE;AAoBD,wBAAgB,OAAO,IAAI,IAAI,CA0C9B;AAID,wBAAgB,MAAM,IAAI,IAAI,CAoJ7B;AAID,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CA4D/C;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CA8DhE;AAID,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAyB3D;AAID,wBAAgB,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CA0B7C;AAID,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CA8C/C;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CA6E9C;AAID,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,IAAI,CAuH3D;AAID,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC1E;AAID,wBAAsB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B7D;AAID,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkEhE;AAID,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B1E;AAID,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC3E;AA6GD,wBAAsB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkI7D;AAkFD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAwIlF;AAID,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAsBtD;AAID,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D9E;AAID,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA8E1E;AAID,wBAAsB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9D;AAID,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBjE"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/tui/commands.ts"],"names":[],"mappings":"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"}