@aragon-agent/cli 0.6.35 → 0.6.37
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.
- package/CHANGELOG.md +21 -0
- package/README.md +3173 -3071
- package/dist/agent/agent-mode.d.ts +20 -4
- package/dist/agent/agent-mode.js +20 -4
- package/dist/agent/controller.d.ts +38 -3
- package/dist/agent/controller.js +64 -4
- package/dist/agent/headless.js +31 -0
- package/dist/agent/reducer.d.ts +13 -2
- package/dist/agent/reducer.js +1 -0
- package/dist/cli.js +12 -0
- package/dist/commands/agents-command.d.ts +15 -0
- package/dist/commands/agents-command.js +27 -0
- package/dist/commands/builtins.js +131 -4
- package/dist/commands/perf.d.ts +11 -0
- package/dist/commands/perf.js +2 -1
- package/dist/commands/registry.d.ts +14 -0
- package/dist/config/app-paths.d.ts +15 -0
- package/dist/config/app-paths.js +33 -2
- package/dist/config/env.d.ts +4 -1
- package/dist/config/env.js +28 -2
- package/dist/config/load.d.ts +10 -0
- package/dist/config/load.js +8 -1
- package/dist/config/schema.d.ts +68 -0
- package/dist/config/schema.js +39 -0
- package/dist/config/store.js +12 -1
- package/dist/config/ui-state.d.ts +18 -0
- package/dist/config/ui-state.js +9 -0
- package/dist/exec/events.d.ts +25 -0
- package/dist/exec/events.js +4 -0
- package/dist/exec/index.js +16 -1
- package/dist/exec/runner.js +10 -0
- package/dist/proc/limits.d.ts +16 -0
- package/dist/proc/limits.js +16 -0
- package/dist/proc/supervisor.d.ts +20 -1
- package/dist/proc/supervisor.js +42 -14
- package/dist/prompts/command.d.ts +34 -0
- package/dist/prompts/command.js +237 -0
- package/dist/prompts/copy.d.ts +89 -0
- package/dist/prompts/copy.js +131 -0
- package/dist/prompts/fill.d.ts +51 -0
- package/dist/prompts/fill.js +46 -0
- package/dist/prompts/limits.d.ts +53 -0
- package/dist/prompts/limits.js +53 -0
- package/dist/prompts/normalize.d.ts +53 -0
- package/dist/prompts/normalize.js +190 -0
- package/dist/prompts/resolve.d.ts +31 -0
- package/dist/prompts/resolve.js +60 -0
- package/dist/prompts/search.d.ts +58 -0
- package/dist/prompts/search.js +146 -0
- package/dist/prompts/store.d.ts +86 -0
- package/dist/prompts/store.js +453 -0
- package/dist/prompts/types.d.ts +204 -0
- package/dist/prompts/types.js +13 -0
- package/dist/session/checkpoint.d.ts +8 -1
- package/dist/session/checkpoint.js +6 -0
- package/dist/session/persist.d.ts +19 -1
- package/dist/session/persist.js +13 -1
- package/dist/session/startup-session.d.ts +7 -2
- package/dist/session/startup-session.js +5 -2
- package/dist/session/store.js +3 -0
- package/dist/session/validate-session.js +64 -1
- package/dist/team/limits.d.ts +25 -0
- package/dist/team/limits.js +26 -0
- package/dist/team/runtime.js +27 -2
- package/dist/team/settled.d.ts +57 -0
- package/dist/team/settled.js +87 -0
- package/dist/team/subagent.js +48 -2
- package/dist/team/timeline.d.ts +74 -0
- package/dist/team/timeline.js +101 -0
- package/dist/team/types.d.ts +24 -1
- package/dist/todo/acceptance.d.ts +120 -0
- package/dist/todo/acceptance.js +399 -0
- package/dist/todo/follow-through.d.ts +48 -23
- package/dist/todo/follow-through.js +110 -44
- package/dist/todo/limits.d.ts +62 -1
- package/dist/todo/limits.js +62 -1
- package/dist/todo/panel-rows.d.ts +29 -39
- package/dist/todo/panel-rows.js +37 -83
- package/dist/todo/plan-sections.d.ts +60 -0
- package/dist/todo/plan-sections.js +108 -0
- package/dist/todo/prompt.d.ts +17 -12
- package/dist/todo/prompt.js +59 -40
- package/dist/todo/row-window.d.ts +51 -0
- package/dist/todo/row-window.js +107 -0
- package/dist/todo/store.d.ts +139 -31
- package/dist/todo/store.js +271 -73
- package/dist/todo/todo-tool.d.ts +33 -8
- package/dist/todo/todo-tool.js +186 -30
- package/dist/todo/types.d.ts +58 -0
- package/dist/ui/App.js +310 -46
- package/dist/ui/Composer.d.ts +6 -2
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/Header.d.ts +9 -1
- package/dist/ui/Header.js +2 -2
- package/dist/ui/PromptInput.d.ts +21 -1
- package/dist/ui/PromptInput.js +21 -1
- package/dist/ui/ScrollbackShell.d.ts +19 -19
- package/dist/ui/ScrollbackShell.js +8 -1
- package/dist/ui/StatusBar.d.ts +5 -0
- package/dist/ui/StatusBar.js +1 -0
- package/dist/ui/TeamPanel.d.ts +26 -44
- package/dist/ui/TeamPanel.js +46 -135
- package/dist/ui/TodoPanel.d.ts +17 -14
- package/dist/ui/TodoPanel.js +146 -38
- package/dist/ui/Transcript.js +1 -1
- package/dist/ui/composer-input.d.ts +10 -0
- package/dist/ui/composer-input.js +57 -24
- package/dist/ui/entries/TodoCard.d.ts +26 -11
- package/dist/ui/entries/TodoCard.js +56 -15
- package/dist/ui/glyphs.d.ts +19 -0
- package/dist/ui/glyphs.js +4 -0
- package/dist/ui/layout/agents-board.d.ts +102 -0
- package/dist/ui/layout/agents-board.js +389 -0
- package/dist/ui/layout/cells.d.ts +61 -0
- package/dist/ui/layout/cells.js +156 -0
- package/dist/ui/layout/header-hints.d.ts +13 -3
- package/dist/ui/layout/header-hints.js +48 -14
- package/dist/ui/layout/status-detail-layout.js +9 -0
- package/dist/ui/layout/status-layout.d.ts +13 -0
- package/dist/ui/layout/team-row.d.ts +139 -0
- package/dist/ui/layout/team-row.js +246 -0
- package/dist/ui/layout/todo-layout.d.ts +38 -0
- package/dist/ui/layout/todo-layout.js +75 -0
- package/dist/ui/layout/virtual-window.js +23 -3
- package/dist/ui/overlays/AgentsBoardOverlay.d.ts +57 -0
- package/dist/ui/overlays/AgentsBoardOverlay.js +183 -0
- package/dist/ui/overlays/HelpOverlay.js +17 -2
- package/dist/ui/overlays/PromptEditorPage.d.ts +48 -0
- package/dist/ui/overlays/PromptEditorPage.js +227 -0
- package/dist/ui/overlays/PromptLibraryOverlay.d.ts +37 -0
- package/dist/ui/overlays/PromptLibraryOverlay.js +191 -0
- package/dist/ui/overlays/PromptPicker.d.ts +36 -0
- package/dist/ui/overlays/PromptPicker.js +129 -0
- package/dist/ui/overlays/PromptTextArea.d.ts +86 -0
- package/dist/ui/overlays/PromptTextArea.js +141 -0
- package/dist/ui/overlays/prompt-library-state.d.ts +162 -0
- package/dist/ui/overlays/prompt-library-state.js +335 -0
- package/dist/ui/overlays/prompt-picker-state.d.ts +71 -0
- package/dist/ui/overlays/prompt-picker-state.js +98 -0
- package/dist/ui/scrollback/band.js +14 -1
- package/dist/ui/team-status.d.ts +25 -0
- package/dist/ui/team-status.js +31 -3
- package/dist/ui/use-startup-notices.d.ts +35 -1
- package/dist/ui/use-startup-notices.js +29 -2
- package/dist/ui/use-wheel-routing.js +9 -1
- package/package.json +2 -2
package/dist/proc/limits.js
CHANGED
|
@@ -79,6 +79,22 @@ export const PROC_LIMITS = {
|
|
|
79
79
|
outputCoalesceMs: 100,
|
|
80
80
|
/** `SIGTERM` -> `SIGKILL` escalation window for a graceful stop. */
|
|
81
81
|
stopGraceMs: 3000,
|
|
82
|
+
/**
|
|
83
|
+
* How long to KEEP ASKING whether the `SIGKILL` actually landed before
|
|
84
|
+
* declaring the job `stopped`.
|
|
85
|
+
*
|
|
86
|
+
* THIS NUMBER IS NOT A GUESS ABOUT THE PLATFORM. `killTree` spawns `taskkill`,
|
|
87
|
+
* which is a process of its own: a Windows tree kill of a shell plus its node
|
|
88
|
+
* child measures ~0.8 s on the reference machine (while starting `cmd` costs
|
|
89
|
+
* 50 ms), so the fixed 250 ms this used to allow expired first and `stop()`
|
|
90
|
+
* reported `stopped` with the child still running - AC-18 caught exactly that.
|
|
91
|
+
* The wait stays BOUNDED against the opposite failure (a promise that never
|
|
92
|
+
* resolves); at this deadline the record keeps the honest `killIncomplete`
|
|
93
|
+
* flag instead.
|
|
94
|
+
*/
|
|
95
|
+
killVerifyMs: 2000,
|
|
96
|
+
/** Liveness poll interval while waiting for a `SIGKILL` to land. */
|
|
97
|
+
killVerifyPollMs: 50,
|
|
82
98
|
/** Below this many terminal columns the status chip degrades to `[N]`. */
|
|
83
99
|
statusCompactCols: 92,
|
|
84
100
|
// --- long-task-jobs: bounded waiting, progress, notices, log mirror --------
|
|
@@ -82,12 +82,31 @@ export declare class ProcSupervisor implements ProcSupervisorPort {
|
|
|
82
82
|
*
|
|
83
83
|
* `SIGTERM` FIRST, `SIGKILL` AFTER `stopGraceMs` — the graceful ladder, which
|
|
84
84
|
* belongs here rather than in `reapSync` because this path has a live event
|
|
85
|
-
* loop to run it on. It then
|
|
85
|
+
* loop to run it on. It then POLLS `process.kill(pid, 0)` for the kill to land,
|
|
86
|
+
* waiting at most `killVerifyMs` so the promise always settles, and records
|
|
86
87
|
* `killIncomplete` when the pid is still there (P2-6): an honest warning beats
|
|
87
88
|
* a silent leak, and `killTree` cannot know on its own whether it worked.
|
|
88
89
|
*/
|
|
89
90
|
stop(id: string): Promise<ServiceSnapshot[]>;
|
|
90
91
|
private stopOne;
|
|
92
|
+
/**
|
|
93
|
+
* Wait for the `SIGKILL` to LAND before calling the job `stopped` (AC-18).
|
|
94
|
+
*
|
|
95
|
+
* THE WINDOW IS NOT THE PLATFORM'S TO PROMISE. This used to wait a fixed
|
|
96
|
+
* 250 ms and then settle whether or not the pid was still there - but the kill
|
|
97
|
+
* it waits for is a `taskkill` PROCESS, and a Windows tree kill measures
|
|
98
|
+
* ~0.8 s here (while starting `cmd` costs 50 ms). So `stop()` resolved while
|
|
99
|
+
* the child was still running: the card, the model and the snapshot all said
|
|
100
|
+
* `stopped` about a live server, which is the one claim this class exists to
|
|
101
|
+
* make honestly.
|
|
102
|
+
*
|
|
103
|
+
* The poll ASKS THE OS instead of assuming, and stops the moment the pid is
|
|
104
|
+
* gone or the child's own `exit` handler settles first (`finish` clears this
|
|
105
|
+
* timer). It stays BOUNDED anyway, because a promise that never resolves is
|
|
106
|
+
* the failure this feature was written to remove: at `killVerifyMs` we settle
|
|
107
|
+
* regardless and keep `killIncomplete`, the warning `bash_output` renders.
|
|
108
|
+
*/
|
|
109
|
+
private settleAfterKill;
|
|
91
110
|
/**
|
|
92
111
|
* SYNCHRONOUS, TOTAL, IDEMPOTENT. The only entry point a signal hook,
|
|
93
112
|
* `process.on('exit')` or `handleFatal` may call.
|
package/dist/proc/supervisor.js
CHANGED
|
@@ -301,7 +301,8 @@ export class ProcSupervisor {
|
|
|
301
301
|
*
|
|
302
302
|
* `SIGTERM` FIRST, `SIGKILL` AFTER `stopGraceMs` — the graceful ladder, which
|
|
303
303
|
* belongs here rather than in `reapSync` because this path has a live event
|
|
304
|
-
* loop to run it on. It then
|
|
304
|
+
* loop to run it on. It then POLLS `process.kill(pid, 0)` for the kill to land,
|
|
305
|
+
* waiting at most `killVerifyMs` so the promise always settles, and records
|
|
305
306
|
* `killIncomplete` when the pid is still there (P2-6): an honest warning beats
|
|
306
307
|
* a silent leak, and `killTree` cannot know on its own whether it worked.
|
|
307
308
|
*/
|
|
@@ -335,19 +336,7 @@ export class ProcSupervisor {
|
|
|
335
336
|
if (isTerminalStatus(record.status))
|
|
336
337
|
return;
|
|
337
338
|
killTree(record.pid, 'SIGKILL');
|
|
338
|
-
|
|
339
|
-
// settle whether or not `exit` fired: a promise that never resolves is
|
|
340
|
-
// the failure this whole feature exists to remove.
|
|
341
|
-
const settle = setTimeout(() => {
|
|
342
|
-
if (isTerminalStatus(record.status))
|
|
343
|
-
return;
|
|
344
|
-
record.status = 'stopped';
|
|
345
|
-
record.endedAt = Date.now();
|
|
346
|
-
if (isAlive(record.pid))
|
|
347
|
-
record.killIncomplete = true;
|
|
348
|
-
this.finish(entry, 'stopped');
|
|
349
|
-
}, 250);
|
|
350
|
-
settle.unref?.();
|
|
339
|
+
this.settleAfterKill(entry);
|
|
351
340
|
}, PROC_LIMITS.stopGraceMs);
|
|
352
341
|
entry.escalation.unref?.();
|
|
353
342
|
// NO SECOND `'exit'` LISTENER HERE. The one `start()` registered already
|
|
@@ -356,6 +345,45 @@ export class ProcSupervisor {
|
|
|
356
345
|
// reads as the thing deciding the status.
|
|
357
346
|
});
|
|
358
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Wait for the `SIGKILL` to LAND before calling the job `stopped` (AC-18).
|
|
350
|
+
*
|
|
351
|
+
* THE WINDOW IS NOT THE PLATFORM'S TO PROMISE. This used to wait a fixed
|
|
352
|
+
* 250 ms and then settle whether or not the pid was still there - but the kill
|
|
353
|
+
* it waits for is a `taskkill` PROCESS, and a Windows tree kill measures
|
|
354
|
+
* ~0.8 s here (while starting `cmd` costs 50 ms). So `stop()` resolved while
|
|
355
|
+
* the child was still running: the card, the model and the snapshot all said
|
|
356
|
+
* `stopped` about a live server, which is the one claim this class exists to
|
|
357
|
+
* make honestly.
|
|
358
|
+
*
|
|
359
|
+
* The poll ASKS THE OS instead of assuming, and stops the moment the pid is
|
|
360
|
+
* gone or the child's own `exit` handler settles first (`finish` clears this
|
|
361
|
+
* timer). It stays BOUNDED anyway, because a promise that never resolves is
|
|
362
|
+
* the failure this feature was written to remove: at `killVerifyMs` we settle
|
|
363
|
+
* regardless and keep `killIncomplete`, the warning `bash_output` renders.
|
|
364
|
+
*/
|
|
365
|
+
settleAfterKill(entry) {
|
|
366
|
+
const deadline = Date.now() + PROC_LIMITS.killVerifyMs;
|
|
367
|
+
const check = () => {
|
|
368
|
+
const { record } = entry;
|
|
369
|
+
// The child's own `exit` handler won the race and already settled this.
|
|
370
|
+
if (isTerminalStatus(record.status))
|
|
371
|
+
return;
|
|
372
|
+
const isGone = !isAlive(record.pid);
|
|
373
|
+
if (!isGone && Date.now() < deadline) {
|
|
374
|
+
entry.escalation = setTimeout(check, PROC_LIMITS.killVerifyPollMs);
|
|
375
|
+
entry.escalation.unref?.();
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
record.status = 'stopped';
|
|
379
|
+
record.endedAt = Date.now();
|
|
380
|
+
if (!isGone)
|
|
381
|
+
record.killIncomplete = true;
|
|
382
|
+
this.finish(entry, 'stopped');
|
|
383
|
+
};
|
|
384
|
+
entry.escalation = setTimeout(check, PROC_LIMITS.killVerifyPollMs);
|
|
385
|
+
entry.escalation.unref?.();
|
|
386
|
+
}
|
|
359
387
|
// -----------------------------------------------------------------------
|
|
360
388
|
// Exit reaping (G5 / I-9)
|
|
361
389
|
// -----------------------------------------------------------------------
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/prompts` and its subcommands (quick-prompt-library §4.3).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/prompts/**` is inside `glyphs.test.ts::inScope`. Every user-facing
|
|
5
|
+
* sentence comes from `copy.ts`.
|
|
6
|
+
*
|
|
7
|
+
* THE COMMAND DOES NOT REACH THE UI THROUGH A CLOSURE. `registerBuiltinCommands(registry)`
|
|
8
|
+
* receives only the registry, so there is no context in which to build a port (F-33).
|
|
9
|
+
* The capability therefore arrives on `CommandContext.prompts`, an OPTIONAL field -
|
|
10
|
+
* `CommandContext` is constructed by literal in dozens of fixtures, and a required
|
|
11
|
+
* field would break every one of them for a feature none of them is about (F-14).
|
|
12
|
+
*
|
|
13
|
+
* THREE THINGS COME FROM THE PORT, and nothing else does: opening the picker, opening
|
|
14
|
+
* the manager on a page, and resolving a reference against the LIVE snapshot. Every
|
|
15
|
+
* MUTATION goes through `store.ts` directly, because that module is the only write
|
|
16
|
+
* authority (I-6) and routing a write through a UI port would make the overlay a
|
|
17
|
+
* second one.
|
|
18
|
+
*
|
|
19
|
+
* `<n|title>` IS RESOLVED BY `resolvePromptRef`, never by "the first match". Titles may
|
|
20
|
+
* repeat, and `rm` has no recycle bin, so an ambiguous reference is a NAMED failure
|
|
21
|
+
* with candidates rather than a guess (D-22).
|
|
22
|
+
*/
|
|
23
|
+
import type { CommandContext, CommandRegistry } from '../commands/registry.js';
|
|
24
|
+
import type { QuickPrompt } from './types.js';
|
|
25
|
+
export declare function registerPromptCommands(registry: CommandRegistry): void;
|
|
26
|
+
/** `1. title [fav] #tag 12 uses` - no body, ever (D-17). */
|
|
27
|
+
export declare function promptListLine(prompt: QuickPrompt, at: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* The dispatcher.
|
|
30
|
+
*
|
|
31
|
+
* `enabled=false` is answered BEFORE any subcommand, and ANSWERED rather than ignored:
|
|
32
|
+
* the command stays registered precisely so this sentence can exist (D-19 / AC-30).
|
|
33
|
+
*/
|
|
34
|
+
export declare function runPromptCommand(ctx: CommandContext): Promise<void>;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/prompts` and its subcommands (quick-prompt-library §4.3).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY - `src/prompts/**` is inside `glyphs.test.ts::inScope`. Every user-facing
|
|
5
|
+
* sentence comes from `copy.ts`.
|
|
6
|
+
*
|
|
7
|
+
* THE COMMAND DOES NOT REACH THE UI THROUGH A CLOSURE. `registerBuiltinCommands(registry)`
|
|
8
|
+
* receives only the registry, so there is no context in which to build a port (F-33).
|
|
9
|
+
* The capability therefore arrives on `CommandContext.prompts`, an OPTIONAL field -
|
|
10
|
+
* `CommandContext` is constructed by literal in dozens of fixtures, and a required
|
|
11
|
+
* field would break every one of them for a feature none of them is about (F-14).
|
|
12
|
+
*
|
|
13
|
+
* THREE THINGS COME FROM THE PORT, and nothing else does: opening the picker, opening
|
|
14
|
+
* the manager on a page, and resolving a reference against the LIVE snapshot. Every
|
|
15
|
+
* MUTATION goes through `store.ts` directly, because that module is the only write
|
|
16
|
+
* authority (I-6) and routing a write through a UI port would make the overlay a
|
|
17
|
+
* second one.
|
|
18
|
+
*
|
|
19
|
+
* `<n|title>` IS RESOLVED BY `resolvePromptRef`, never by "the first match". Titles may
|
|
20
|
+
* repeat, and `rm` has no recycle bin, so an ambiguous reference is a NAMED failure
|
|
21
|
+
* with candidates rather than a guess (D-22).
|
|
22
|
+
*/
|
|
23
|
+
import { PROMPT_DISABLED_COPY, PROMPT_HISTORY_REMINDER_COPY, PROMPT_LIST_EMPTY_COPY, PROMPT_SHOW_WARNING_COPY, PROMPT_UNKNOWN_SUBCOMMAND_COPY, PROMPT_UNAVAILABLE_COPY, promptAmbiguousCopy, promptDeletedCopy, promptErrorCopy, promptFavoriteCopy, promptInvalidSortCopy, promptListFooterCopy, promptMovedCopy, promptMoveRangeCopy, promptNotFoundCopy, promptRmConfirmCopy, promptSavedCopy, promptSortedCopy, } from './copy.js';
|
|
24
|
+
import { promptIndexOf } from './resolve.js';
|
|
25
|
+
import { createPrompt, deletePrompt, loadPromptLibrary, reorderPrompt, reorderPrompts, setPromptFavorite, sortPromptIds, } from './store.js';
|
|
26
|
+
/**
|
|
27
|
+
* `/prompts sort <key>`.
|
|
28
|
+
*
|
|
29
|
+
* `name` is TITLE order - the word the user typed has to be the order they get - and the
|
|
30
|
+
* other two promote a picker view into the persistent manual order.
|
|
31
|
+
*/
|
|
32
|
+
const SORT_KEYS = {
|
|
33
|
+
name: 'name',
|
|
34
|
+
recent: 'recent',
|
|
35
|
+
favorite: 'favorite',
|
|
36
|
+
};
|
|
37
|
+
export function registerPromptCommands(registry) {
|
|
38
|
+
registry.register({
|
|
39
|
+
name: 'prompts',
|
|
40
|
+
description: 'Quick prompt library: pick, list, add, edit, remove, reorder',
|
|
41
|
+
run: (ctx) => runPromptCommand(ctx),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function report(ctx, result, success) {
|
|
45
|
+
if (result.ok) {
|
|
46
|
+
ctx.notify('info', success);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
ctx.notify('warn', promptErrorCopy(result.code));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* `<n|title>` -> entry, or `null` after reporting why not.
|
|
53
|
+
*
|
|
54
|
+
* THE CANDIDATES ARE PRINTED on an ambiguous reference, indexed, and the command does
|
|
55
|
+
* not proceed: `/prompts rm` cannot be undone, so a refusal that costs one more
|
|
56
|
+
* command is strictly better than a deletion the user cannot identify afterwards.
|
|
57
|
+
*/
|
|
58
|
+
function resolveOrReport(ctx, ref) {
|
|
59
|
+
const resolution = ctx.prompts?.resolve(ref);
|
|
60
|
+
if (!resolution) {
|
|
61
|
+
ctx.notify('warn', PROMPT_UNAVAILABLE_COPY);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (resolution.ok)
|
|
65
|
+
return resolution.prompt;
|
|
66
|
+
if (resolution.code === 'ambiguous') {
|
|
67
|
+
const candidates = resolution.candidates.map((prompt, at) => `${at + 1}) ${prompt.title}`);
|
|
68
|
+
ctx.notify('warn', promptAmbiguousCopy(ref, candidates));
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
ctx.notify('warn', promptNotFoundCopy(ref));
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/** `1. title [fav] #tag 12 uses` - no body, ever (D-17). */
|
|
75
|
+
export function promptListLine(prompt, at) {
|
|
76
|
+
const marks = [
|
|
77
|
+
prompt.favorite === true ? '[fav]' : '',
|
|
78
|
+
(prompt.tags ?? []).map((tag) => `#${tag}`).join(' '),
|
|
79
|
+
`${prompt.useCount} uses`,
|
|
80
|
+
].filter((part) => part.length > 0).join(' ');
|
|
81
|
+
return `${at + 1}. ${prompt.title} ${marks}`;
|
|
82
|
+
}
|
|
83
|
+
function runList(ctx, library) {
|
|
84
|
+
if (library.prompts.length === 0) {
|
|
85
|
+
ctx.notify('info', PROMPT_LIST_EMPTY_COPY);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const lines = library.prompts.map((prompt, at) => promptListLine(prompt, at));
|
|
89
|
+
ctx.notify('info', `${lines.join('\n')}\n${promptListFooterCopy(library.prompts.length)}`);
|
|
90
|
+
}
|
|
91
|
+
function runShow(ctx, ref) {
|
|
92
|
+
const prompt = resolveOrReport(ctx, ref);
|
|
93
|
+
if (!prompt)
|
|
94
|
+
return;
|
|
95
|
+
// THE ONLY PATH THAT PUTS A BODY INTO THE TRANSCRIPT (D-17), and it says so first.
|
|
96
|
+
ctx.notify('info', PROMPT_SHOW_WARNING_COPY);
|
|
97
|
+
const tags = (prompt.tags ?? []).map((tag) => `#${tag}`).join(' ');
|
|
98
|
+
const header = [prompt.title, tags].filter((part) => part.length > 0).join(' ');
|
|
99
|
+
ctx.notify('info', `${header}\n${prompt.content}`);
|
|
100
|
+
}
|
|
101
|
+
/** `add <title> :: <body>`. Reached only when the user typed content on the line. */
|
|
102
|
+
function runAddWithArgs(ctx, rest) {
|
|
103
|
+
const split = rest.split('::');
|
|
104
|
+
if (split.length < 2) {
|
|
105
|
+
// A `::`-less `add <something>` is ambiguous between a title and a body, and
|
|
106
|
+
// guessing wrong would store the wrong field. Point at the editor instead.
|
|
107
|
+
ctx.notify('warn', PROMPT_HISTORY_REMINDER_COPY);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const title = (split[0] ?? '').trim();
|
|
111
|
+
const content = split.slice(1).join('::').trim();
|
|
112
|
+
report(ctx, createPrompt({ title, content }), promptSavedCopy(title));
|
|
113
|
+
}
|
|
114
|
+
function runRemove(ctx, rest, library) {
|
|
115
|
+
const confirmed = /(^|\s)--yes\s*$/.test(rest);
|
|
116
|
+
const ref = rest.replace(/(^|\s)--yes\s*$/, '').trim();
|
|
117
|
+
const prompt = resolveOrReport(ctx, ref);
|
|
118
|
+
if (!prompt)
|
|
119
|
+
return;
|
|
120
|
+
if (!confirmed) {
|
|
121
|
+
ctx.notify('warn', promptRmConfirmCopy(prompt.title, ref));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (promptIndexOf(library, prompt.id) < 0) {
|
|
125
|
+
ctx.notify('warn', promptNotFoundCopy(ref));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
report(ctx, deletePrompt(prompt.id), promptDeletedCopy(prompt.title));
|
|
129
|
+
}
|
|
130
|
+
/** `move <ref> <to>`: `to` is 1-based and must exist; an out-of-range move is refused. */
|
|
131
|
+
function runMove(ctx, rest, library) {
|
|
132
|
+
const parts = rest.split(/\s+/).filter((part) => part.length > 0);
|
|
133
|
+
const prompt = resolveOrReport(ctx, parts[0] ?? '');
|
|
134
|
+
if (!prompt)
|
|
135
|
+
return;
|
|
136
|
+
const to = Number.parseInt(parts[1] ?? '', 10);
|
|
137
|
+
if (!Number.isFinite(to) || to < 1 || to > library.prompts.length) {
|
|
138
|
+
ctx.notify('warn', promptMoveRangeCopy(to, library.prompts.length));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const from = promptIndexOf(library, prompt.id);
|
|
142
|
+
report(ctx, reorderPrompt(from, to - 1), promptMovedCopy(prompt.title, to));
|
|
143
|
+
}
|
|
144
|
+
function runSort(ctx, raw, library) {
|
|
145
|
+
const key = SORT_KEYS[raw.trim().toLowerCase()];
|
|
146
|
+
if (!key) {
|
|
147
|
+
ctx.notify('warn', promptInvalidSortCopy(raw.trim()));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const ids = sortPromptIds(library, key);
|
|
151
|
+
const unchanged = ids.length === library.prompts.length
|
|
152
|
+
&& ids.every((id, at) => id === library.prompts[at]?.id);
|
|
153
|
+
// A NO-OP IS NOT A WRITE. Reporting "sorted" after an unnecessary rewrite would
|
|
154
|
+
// also teach the user that asking twice costs a disk write.
|
|
155
|
+
if (unchanged) {
|
|
156
|
+
ctx.notify('info', promptSortedCopy(key));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
report(ctx, reorderPrompts(ids), promptSortedCopy(key));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The dispatcher.
|
|
163
|
+
*
|
|
164
|
+
* `enabled=false` is answered BEFORE any subcommand, and ANSWERED rather than ignored:
|
|
165
|
+
* the command stays registered precisely so this sentence can exist (D-19 / AC-30).
|
|
166
|
+
*/
|
|
167
|
+
export async function runPromptCommand(ctx) {
|
|
168
|
+
// `=== false`, not `!enabled`: a `CliConfig` built without the section (a fixture, an
|
|
169
|
+
// embedded host) must read as ENABLED, which is the documented default.
|
|
170
|
+
if (ctx.controller.getConfig().prompts?.enabled === false) {
|
|
171
|
+
ctx.notify('info', PROMPT_DISABLED_COPY);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const port = ctx.prompts;
|
|
175
|
+
if (!port) {
|
|
176
|
+
ctx.notify('warn', PROMPT_UNAVAILABLE_COPY);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const args = ctx.args.trim();
|
|
180
|
+
const space = args.search(/\s/);
|
|
181
|
+
const verb = (space === -1 ? args : args.slice(0, space)).toLowerCase();
|
|
182
|
+
const rest = space === -1 ? '' : args.slice(space + 1).trim();
|
|
183
|
+
const library = loadPromptLibrary();
|
|
184
|
+
if (verb.length === 0) {
|
|
185
|
+
port.openPicker();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (verb === 'manage') {
|
|
189
|
+
port.openManager({ kind: 'list' });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (verb === 'list') {
|
|
193
|
+
runList(ctx, library);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (verb === 'show') {
|
|
197
|
+
runShow(ctx, rest);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (verb === 'add') {
|
|
201
|
+
if (rest.length === 0) {
|
|
202
|
+
port.openManager({ kind: 'create' });
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
runAddWithArgs(ctx, rest);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (verb === 'edit') {
|
|
209
|
+
const prompt = resolveOrReport(ctx, rest);
|
|
210
|
+
if (!prompt)
|
|
211
|
+
return;
|
|
212
|
+
const entry = { kind: 'edit', id: prompt.id };
|
|
213
|
+
port.openManager(entry);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (verb === 'rm' || verb === 'remove' || verb === 'delete') {
|
|
217
|
+
runRemove(ctx, rest, library);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (verb === 'favorite' || verb === 'fav') {
|
|
221
|
+
const prompt = resolveOrReport(ctx, rest);
|
|
222
|
+
if (!prompt)
|
|
223
|
+
return;
|
|
224
|
+
const next = prompt.favorite !== true;
|
|
225
|
+
report(ctx, setPromptFavorite(prompt.id, next), promptFavoriteCopy(prompt.title, next));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (verb === 'move') {
|
|
229
|
+
runMove(ctx, rest, library);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (verb === 'sort') {
|
|
233
|
+
runSort(ctx, rest, library);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
ctx.notify('warn', PROMPT_UNKNOWN_SUBCOMMAND_COPY);
|
|
237
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chinese copy for the quick-prompt library (quick-prompt-library section 9.10).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY ON DISK. Every string below is written as `\uXXXX` escapes, the way
|
|
5
|
+
* `ui/interaction-copy.ts` does it, because `src/prompts/**` and `src/ui/**` are
|
|
6
|
+
* both inside `glyphs.test.ts::inScope` and that scanner rejects any raw non-ASCII
|
|
7
|
+
* byte. The escapes are the point: the product speaks English in its chrome
|
|
8
|
+
* (labels, footers, the overlays' own vocabulary) and the sentences that explain a
|
|
9
|
+
* failure to THIS user are here, in one table, where a translator can find them
|
|
10
|
+
* and where the API surfaces that build them cannot drift from each other.
|
|
11
|
+
*
|
|
12
|
+
* WHY ONE TABLE AND NOT STRINGS AT THE CALL SITES: the same failure is reported by
|
|
13
|
+
* a toast, by a `/prompts` subcommand and by the editor's error row. Three copies
|
|
14
|
+
* of one sentence is three wordings waiting to happen.
|
|
15
|
+
*/
|
|
16
|
+
import type { PromptSortKey, PromptWriteError } from './types.js';
|
|
17
|
+
/** `\u5df2\u586b\u5165\u300cx\u300d\uff088 \u884c\uff0c\u53ef\u7ee7\u7eed\u7f16\u8f91\uff09`. */
|
|
18
|
+
export declare function promptFilledCopy(title: string, lines: number): string;
|
|
19
|
+
/** `\u5df2\u63d2\u5165\u5230\u5149\u6807\u5904\uff0c\u539f\u5185\u5bb9\u4fdd\u7559\u3002` */
|
|
20
|
+
export declare const PROMPT_INSERTED_COPY = "\u5DF2\u63D2\u5165\u5230\u5149\u6807\u5904\uFF0C\u539F\u5185\u5BB9\u4FDD\u7559\u3002";
|
|
21
|
+
/** `\u5df2\u4fdd\u5b58\u300cx\u300d` */
|
|
22
|
+
export declare function promptSavedCopy(title: string): string;
|
|
23
|
+
/** `\u5df2\u5220\u9664\u300cx\u300d` */
|
|
24
|
+
export declare function promptDeletedCopy(title: string): string;
|
|
25
|
+
/** `\u5df2\u6536\u85cf\u300cx\u300d` / `\u5df2\u53d6\u6d88\u6536\u85cf\u300cx\u300d` */
|
|
26
|
+
export declare function promptFavoriteCopy(title: string, favorite: boolean): string;
|
|
27
|
+
/** `\u5df2\u628a\u300cx\u300d\u79fb\u52a8\u5230\u7b2c n \u4f4d\u3002` */
|
|
28
|
+
export declare function promptMovedCopy(title: string, to: number): string;
|
|
29
|
+
/** `\u5df2\u6309 name \u91cd\u6392\u5e76\u4fdd\u5b58\u3002` */
|
|
30
|
+
export declare function promptSortedCopy(key: PromptSortKey): string;
|
|
31
|
+
/** The kill switch's honest answer (D-19 / AC-30). */
|
|
32
|
+
export declare const PROMPT_DISABLED_COPY = "\u63D0\u793A\u8BCD\u5E93\u5DF2\u5173\u95ED\uFF08prompts.enabled=false\uFF09\u3002";
|
|
33
|
+
/** The port is absent - a test fixture or a build without the overlay. */
|
|
34
|
+
export declare const PROMPT_UNAVAILABLE_COPY = "Prompt library is not available in this build.";
|
|
35
|
+
/** `\u5e93\u6587\u4ef6\u635f\u574f\u2026\u4ee5\u7a7a\u5e93\u7ee7\u7eed` - the one-shot notice after a `.bak` repair (D-4). */
|
|
36
|
+
export declare const PROMPT_CORRUPT_COPY = "\u5E93\u6587\u4EF6\u635F\u574F\u6216\u683C\u5F0F\u4E0D\u7B26\uFF0C\u5DF2\u5907\u4EFD\u4E3A quick-prompts.json.bak\uFF0C\u672C\u6B21\u4EE5\u7A7A\u5E93\u7EE7\u7EED\u3002";
|
|
37
|
+
/** `\u5df2\u8df3\u8fc7 n \u6761\u65e0\u6cd5\u8bc6\u522b\u7684\u8bb0\u5f55\u3002` */
|
|
38
|
+
export declare function promptSkippedCopy(count: number): string;
|
|
39
|
+
/**
|
|
40
|
+
* `\u5df2\u5e94\u7528\uff0c\u4f46\u5199\u5165\u78c1\u76d8\u5931\u8d25\uff1b\u9000\u51fa\u540e\u53ef\u80fd\u4e22\u5931\u3002` (D-4: never roll back memory).
|
|
41
|
+
*
|
|
42
|
+
* ONE SENTENCE for `write_failed`, and it says BOTH halves: that the change is in effect
|
|
43
|
+
* and that it may not survive the process. A shorter "write failed" would read as
|
|
44
|
+
* "nothing happened", which is the one thing this path does not do.
|
|
45
|
+
*/
|
|
46
|
+
export declare const PROMPT_WRITE_FAILED_COPY = "\u5DF2\u5E94\u7528\uFF0C\u4F46\u5199\u5165\u78C1\u76D8\u5931\u8D25\uFF1B\u9000\u51FA\u540E\u53EF\u80FD\u4E22\u5931\u3002";
|
|
47
|
+
/** `\u627e\u4e0d\u5230\u300cx\u300d\u5bf9\u5e94\u7684\u63d0\u793a\u8bcd\u3002` */
|
|
48
|
+
export declare function promptNotFoundCopy(ref: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* `\u300cx\u300d\u5339\u914d n \u6761\uff0c\u8bf7\u7528\u5e8f\u53f7\uff1a\u2026` (D-22).
|
|
51
|
+
*
|
|
52
|
+
* THE CANDIDATES ARE THE WHOLE POINT of this message: without them the user knows
|
|
53
|
+
* only that their command failed, and the next thing they try is the same command.
|
|
54
|
+
*/
|
|
55
|
+
export declare function promptAmbiguousCopy(ref: string, candidates: readonly string[]): string;
|
|
56
|
+
/** Printed above a body that is about to enter the transcript (D-17). */
|
|
57
|
+
export declare const PROMPT_SHOW_WARNING_COPY = "\u4EE5\u4E0B\u6B63\u6587\u5C06\u8FDB\u5165\u4F1A\u8BDD\u8BB0\u5F55\uFF08/save \u4F1A\u5BFC\u51FA\u5B83\uFF09\u3002";
|
|
58
|
+
/** `\u5c06\u5220\u9664\u300cx\u300d\u2026\u786e\u8ba4\u8bf7\u518d\u6267\u884c\u4e00\u6b21\uff1a/prompts rm x --yes` (D-13). */
|
|
59
|
+
export declare function promptRmConfirmCopy(title: string, ref: string): string;
|
|
60
|
+
/** `\u76ee\u6807\u4f4d\u7f6e n \u8d85\u51fa\u8303\u56f4\uff081-m\uff09\u3002` */
|
|
61
|
+
export declare function promptMoveRangeCopy(to: number, max: number): string;
|
|
62
|
+
/** `\u65e0\u6548\u7684\u6392\u5e8f\u65b9\u5f0f\u300cx\u300d\uff0c\u53ef\u7528 name / recent / favorite\u3002` */
|
|
63
|
+
export declare function promptInvalidSortCopy(raw: string): string;
|
|
64
|
+
/** `\u63d0\u793a\u8bcd\u5e93\u4e3a\u7a7a\uff0c\u7528 /prompts add \u65b0\u5efa\u4e00\u6761\u3002` */
|
|
65
|
+
export declare const PROMPT_LIST_EMPTY_COPY = "\u63D0\u793A\u8BCD\u5E93\u4E3A\u7A7A\uFF0C\u7528 /prompts add \u65B0\u5EFA\u4E00\u6761\u3002";
|
|
66
|
+
/** The reminder that a body typed on a command line lands in `prompt-history`. */
|
|
67
|
+
export declare const PROMPT_HISTORY_REMINDER_COPY = "\u63D0\u793A\uFF1A\u5199\u5728\u547D\u4EE4\u884C\u91CC\u7684\u6B63\u6587\u4F1A\u8FDB\u5165 prompt-history\uFF1B\u63A8\u8350\u7528 /prompts add \u540E\u5728\u7F16\u8F91\u5668\u91CC\u8F93\u5165\u3002";
|
|
68
|
+
/** `\u5df2\u5220\u9664\u300cx\u300d` is reused for the `--yes` path; this is the "nothing happened" half. */
|
|
69
|
+
export declare const PROMPT_UNKNOWN_SUBCOMMAND_COPY = "\u672A\u77E5\u5B50\u547D\u4EE4\u3002\u53EF\u7528\uFF1Alist / show / add / edit / rm / move / favorite / sort / manage\u3002";
|
|
70
|
+
/**
|
|
71
|
+
* The one-shot key-migration notice (D-20 / AC-32).
|
|
72
|
+
*
|
|
73
|
+
* `Ctrl+N` IS SPELLED OUT IN FULL, never `^N` (P1-7): `^N` is already this
|
|
74
|
+
* product's word for "transcript line offset" (the header's scroll chip and the
|
|
75
|
+
* help overlay's `^N` row), so the abbreviation would be a second meaning for the
|
|
76
|
+
* same glyph in the same product.
|
|
77
|
+
*/
|
|
78
|
+
export declare const PROMPT_KEY_NOTICE_COPY = "Ctrl+P \u73B0\u5728\u6253\u5F00\u63D0\u793A\u8BCD\u5E93\uFF1B\u5207\u6362 BUILD/PLAN \u8BF7\u7528 Shift+Tab \u6216 Ctrl+N\uFF08\u6216 /plan\uFF09\u3002";
|
|
79
|
+
/** The library page's empty state (the list page draws this instead of nothing). */
|
|
80
|
+
export declare const PROMPT_EMPTY_TITLE_COPY = "No prompts yet.";
|
|
81
|
+
export declare const PROMPT_EMPTY_BODY_COPY = "Press a to create your first prompt.";
|
|
82
|
+
/** `\uff08\u5171 n \u6761\uff09` suffix for `/prompts list`. */
|
|
83
|
+
export declare function promptListFooterCopy(count: number): string;
|
|
84
|
+
/**
|
|
85
|
+
* One sentence per stable error code (D-12). THE CODE IS THE CONTRACT; this table is
|
|
86
|
+
* the only place it becomes words, so the editor's title row, the list's toast and a
|
|
87
|
+
* command's refusal cannot describe the same failure three different ways.
|
|
88
|
+
*/
|
|
89
|
+
export declare function promptErrorCopy(code: PromptWriteError): string;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chinese copy for the quick-prompt library (quick-prompt-library section 9.10).
|
|
3
|
+
*
|
|
4
|
+
* ASCII ONLY ON DISK. Every string below is written as `\uXXXX` escapes, the way
|
|
5
|
+
* `ui/interaction-copy.ts` does it, because `src/prompts/**` and `src/ui/**` are
|
|
6
|
+
* both inside `glyphs.test.ts::inScope` and that scanner rejects any raw non-ASCII
|
|
7
|
+
* byte. The escapes are the point: the product speaks English in its chrome
|
|
8
|
+
* (labels, footers, the overlays' own vocabulary) and the sentences that explain a
|
|
9
|
+
* failure to THIS user are here, in one table, where a translator can find them
|
|
10
|
+
* and where the API surfaces that build them cannot drift from each other.
|
|
11
|
+
*
|
|
12
|
+
* WHY ONE TABLE AND NOT STRINGS AT THE CALL SITES: the same failure is reported by
|
|
13
|
+
* a toast, by a `/prompts` subcommand and by the editor's error row. Three copies
|
|
14
|
+
* of one sentence is three wordings waiting to happen.
|
|
15
|
+
*/
|
|
16
|
+
/** `\u5df2\u586b\u5165\u300cx\u300d\uff088 \u884c\uff0c\u53ef\u7ee7\u7eed\u7f16\u8f91\uff09`. */
|
|
17
|
+
export function promptFilledCopy(title, lines) {
|
|
18
|
+
return `\u5df2\u586b\u5165\u300c${title}\u300d\uff08${lines} \u884c\uff0c\u53ef\u7ee7\u7eed\u7f16\u8f91\uff09`;
|
|
19
|
+
}
|
|
20
|
+
/** `\u5df2\u63d2\u5165\u5230\u5149\u6807\u5904\uff0c\u539f\u5185\u5bb9\u4fdd\u7559\u3002` */
|
|
21
|
+
export const PROMPT_INSERTED_COPY = '\u5df2\u63d2\u5165\u5230\u5149\u6807\u5904\uff0c\u539f\u5185\u5bb9\u4fdd\u7559\u3002';
|
|
22
|
+
/** `\u5df2\u4fdd\u5b58\u300cx\u300d` */
|
|
23
|
+
export function promptSavedCopy(title) {
|
|
24
|
+
return `\u5df2\u4fdd\u5b58\u300c${title}\u300d`;
|
|
25
|
+
}
|
|
26
|
+
/** `\u5df2\u5220\u9664\u300cx\u300d` */
|
|
27
|
+
export function promptDeletedCopy(title) {
|
|
28
|
+
return `\u5df2\u5220\u9664\u300c${title}\u300d`;
|
|
29
|
+
}
|
|
30
|
+
/** `\u5df2\u6536\u85cf\u300cx\u300d` / `\u5df2\u53d6\u6d88\u6536\u85cf\u300cx\u300d` */
|
|
31
|
+
export function promptFavoriteCopy(title, favorite) {
|
|
32
|
+
return favorite
|
|
33
|
+
? `\u5df2\u6536\u85cf\u300c${title}\u300d`
|
|
34
|
+
: `\u5df2\u53d6\u6d88\u6536\u85cf\u300c${title}\u300d`;
|
|
35
|
+
}
|
|
36
|
+
/** `\u5df2\u628a\u300cx\u300d\u79fb\u52a8\u5230\u7b2c n \u4f4d\u3002` */
|
|
37
|
+
export function promptMovedCopy(title, to) {
|
|
38
|
+
return `\u5df2\u628a\u300c${title}\u300d\u79fb\u52a8\u5230\u7b2c ${to} \u4f4d\u3002`;
|
|
39
|
+
}
|
|
40
|
+
/** `\u5df2\u6309 name \u91cd\u6392\u5e76\u4fdd\u5b58\u3002` */
|
|
41
|
+
export function promptSortedCopy(key) {
|
|
42
|
+
return `\u5df2\u6309 ${key} \u91cd\u6392\u5e76\u4fdd\u5b58\u3002`;
|
|
43
|
+
}
|
|
44
|
+
/** The kill switch's honest answer (D-19 / AC-30). */
|
|
45
|
+
export const PROMPT_DISABLED_COPY = '\u63d0\u793a\u8bcd\u5e93\u5df2\u5173\u95ed\uff08prompts.enabled=false\uff09\u3002';
|
|
46
|
+
/** The port is absent - a test fixture or a build without the overlay. */
|
|
47
|
+
export const PROMPT_UNAVAILABLE_COPY = 'Prompt library is not available in this build.';
|
|
48
|
+
/** `\u5e93\u6587\u4ef6\u635f\u574f\u2026\u4ee5\u7a7a\u5e93\u7ee7\u7eed` - the one-shot notice after a `.bak` repair (D-4). */
|
|
49
|
+
export const PROMPT_CORRUPT_COPY = '\u5e93\u6587\u4ef6\u635f\u574f\u6216\u683c\u5f0f\u4e0d\u7b26\uff0c\u5df2\u5907\u4efd\u4e3a quick-prompts.json.bak\uff0c\u672c\u6b21\u4ee5\u7a7a\u5e93\u7ee7\u7eed\u3002';
|
|
50
|
+
/** `\u5df2\u8df3\u8fc7 n \u6761\u65e0\u6cd5\u8bc6\u522b\u7684\u8bb0\u5f55\u3002` */
|
|
51
|
+
export function promptSkippedCopy(count) {
|
|
52
|
+
return `\u5df2\u8df3\u8fc7 ${count} \u6761\u65e0\u6cd5\u8bc6\u522b\u7684\u8bb0\u5f55\u3002`;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `\u5df2\u5e94\u7528\uff0c\u4f46\u5199\u5165\u78c1\u76d8\u5931\u8d25\uff1b\u9000\u51fa\u540e\u53ef\u80fd\u4e22\u5931\u3002` (D-4: never roll back memory).
|
|
56
|
+
*
|
|
57
|
+
* ONE SENTENCE for `write_failed`, and it says BOTH halves: that the change is in effect
|
|
58
|
+
* and that it may not survive the process. A shorter "write failed" would read as
|
|
59
|
+
* "nothing happened", which is the one thing this path does not do.
|
|
60
|
+
*/
|
|
61
|
+
export const PROMPT_WRITE_FAILED_COPY = '\u5df2\u5e94\u7528\uff0c\u4f46\u5199\u5165\u78c1\u76d8\u5931\u8d25\uff1b\u9000\u51fa\u540e\u53ef\u80fd\u4e22\u5931\u3002';
|
|
62
|
+
/** `\u627e\u4e0d\u5230\u300cx\u300d\u5bf9\u5e94\u7684\u63d0\u793a\u8bcd\u3002` */
|
|
63
|
+
export function promptNotFoundCopy(ref) {
|
|
64
|
+
return `\u627e\u4e0d\u5230\u300c${ref}\u300d\u5bf9\u5e94\u7684\u63d0\u793a\u8bcd\u3002`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* `\u300cx\u300d\u5339\u914d n \u6761\uff0c\u8bf7\u7528\u5e8f\u53f7\uff1a\u2026` (D-22).
|
|
68
|
+
*
|
|
69
|
+
* THE CANDIDATES ARE THE WHOLE POINT of this message: without them the user knows
|
|
70
|
+
* only that their command failed, and the next thing they try is the same command.
|
|
71
|
+
*/
|
|
72
|
+
export function promptAmbiguousCopy(ref, candidates) {
|
|
73
|
+
const list = candidates.join('\u3001');
|
|
74
|
+
return `\u300c${ref}\u300d\u5339\u914d ${candidates.length} \u6761\uff0c\u8bf7\u7528\u5e8f\u53f7\uff1a${list}`;
|
|
75
|
+
}
|
|
76
|
+
/** Printed above a body that is about to enter the transcript (D-17). */
|
|
77
|
+
export const PROMPT_SHOW_WARNING_COPY = '\u4ee5\u4e0b\u6b63\u6587\u5c06\u8fdb\u5165\u4f1a\u8bdd\u8bb0\u5f55\uff08/save \u4f1a\u5bfc\u51fa\u5b83\uff09\u3002';
|
|
78
|
+
/** `\u5c06\u5220\u9664\u300cx\u300d\u2026\u786e\u8ba4\u8bf7\u518d\u6267\u884c\u4e00\u6b21\uff1a/prompts rm x --yes` (D-13). */
|
|
79
|
+
export function promptRmConfirmCopy(title, ref) {
|
|
80
|
+
return `\u5c06\u5220\u9664\u300c${title}\u300d\u3002\u6b64\u64cd\u4f5c\u4e0d\u53ef\u64a4\u9500\uff1b\u786e\u8ba4\u8bf7\u518d\u6267\u884c\u4e00\u6b21\uff1a/prompts rm ${ref} --yes`;
|
|
81
|
+
}
|
|
82
|
+
/** `\u76ee\u6807\u4f4d\u7f6e n \u8d85\u51fa\u8303\u56f4\uff081-m\uff09\u3002` */
|
|
83
|
+
export function promptMoveRangeCopy(to, max) {
|
|
84
|
+
return `\u76ee\u6807\u4f4d\u7f6e ${to} \u8d85\u51fa\u8303\u56f4\uff081-${max}\uff09\u3002`;
|
|
85
|
+
}
|
|
86
|
+
/** `\u65e0\u6548\u7684\u6392\u5e8f\u65b9\u5f0f\u300cx\u300d\uff0c\u53ef\u7528 name / recent / favorite\u3002` */
|
|
87
|
+
export function promptInvalidSortCopy(raw) {
|
|
88
|
+
return `\u65e0\u6548\u7684\u6392\u5e8f\u65b9\u5f0f\u300c${raw}\u300d\uff0c\u53ef\u7528 name / recent / favorite\u3002`;
|
|
89
|
+
}
|
|
90
|
+
/** `\u63d0\u793a\u8bcd\u5e93\u4e3a\u7a7a\uff0c\u7528 /prompts add \u65b0\u5efa\u4e00\u6761\u3002` */
|
|
91
|
+
export const PROMPT_LIST_EMPTY_COPY = '\u63d0\u793a\u8bcd\u5e93\u4e3a\u7a7a\uff0c\u7528 /prompts add \u65b0\u5efa\u4e00\u6761\u3002';
|
|
92
|
+
/** The reminder that a body typed on a command line lands in `prompt-history`. */
|
|
93
|
+
export const PROMPT_HISTORY_REMINDER_COPY = '\u63d0\u793a\uff1a\u5199\u5728\u547d\u4ee4\u884c\u91cc\u7684\u6b63\u6587\u4f1a\u8fdb\u5165 prompt-history\uff1b\u63a8\u8350\u7528 /prompts add \u540e\u5728\u7f16\u8f91\u5668\u91cc\u8f93\u5165\u3002';
|
|
94
|
+
/** `\u5df2\u5220\u9664\u300cx\u300d` is reused for the `--yes` path; this is the "nothing happened" half. */
|
|
95
|
+
export const PROMPT_UNKNOWN_SUBCOMMAND_COPY = '\u672a\u77e5\u5b50\u547d\u4ee4\u3002\u53ef\u7528\uff1alist / show / add / edit / rm / move / favorite / sort / manage\u3002';
|
|
96
|
+
/**
|
|
97
|
+
* The one-shot key-migration notice (D-20 / AC-32).
|
|
98
|
+
*
|
|
99
|
+
* `Ctrl+N` IS SPELLED OUT IN FULL, never `^N` (P1-7): `^N` is already this
|
|
100
|
+
* product's word for "transcript line offset" (the header's scroll chip and the
|
|
101
|
+
* help overlay's `^N` row), so the abbreviation would be a second meaning for the
|
|
102
|
+
* same glyph in the same product.
|
|
103
|
+
*/
|
|
104
|
+
export const PROMPT_KEY_NOTICE_COPY = 'Ctrl+P \u73b0\u5728\u6253\u5f00\u63d0\u793a\u8bcd\u5e93\uff1b\u5207\u6362 BUILD/PLAN \u8bf7\u7528 Shift+Tab \u6216 Ctrl+N\uff08\u6216 /plan\uff09\u3002';
|
|
105
|
+
/** The library page's empty state (the list page draws this instead of nothing). */
|
|
106
|
+
export const PROMPT_EMPTY_TITLE_COPY = 'No prompts yet.';
|
|
107
|
+
export const PROMPT_EMPTY_BODY_COPY = 'Press a to create your first prompt.';
|
|
108
|
+
/** `\uff08\u5171 n \u6761\uff09` suffix for `/prompts list`. */
|
|
109
|
+
export function promptListFooterCopy(count) {
|
|
110
|
+
return `\uff08\u5171 ${count} \u6761\uff09`;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* One sentence per stable error code (D-12). THE CODE IS THE CONTRACT; this table is
|
|
114
|
+
* the only place it becomes words, so the editor's title row, the list's toast and a
|
|
115
|
+
* command's refusal cannot describe the same failure three different ways.
|
|
116
|
+
*/
|
|
117
|
+
export function promptErrorCopy(code) {
|
|
118
|
+
switch (code) {
|
|
119
|
+
case 'title_required': return '\u6807\u9898\u4e0d\u80fd\u4e3a\u7a7a';
|
|
120
|
+
case 'content_required': return '\u6b63\u6587\u4e0d\u80fd\u4e3a\u7a7a';
|
|
121
|
+
case 'title_too_long': return '\u6807\u9898\u8d85\u8fc7 80 \u5b57';
|
|
122
|
+
case 'content_too_long': return '\u6b63\u6587\u8d85\u8fc7 8000 \u5b57';
|
|
123
|
+
case 'description_too_long': return '\u63cf\u8ff0\u8d85\u8fc7 200 \u5b57';
|
|
124
|
+
case 'tag_too_long': return '\u6807\u7b7e\u8d85\u8fc7 24 \u5b57';
|
|
125
|
+
case 'too_many_tags': return '\u6807\u7b7e\u6700\u591a 6 \u4e2a';
|
|
126
|
+
case 'too_many_prompts': return '\u6700\u591a 200 \u6761\uff0c\u8bf7\u5148\u5220\u9664';
|
|
127
|
+
case 'not_found': return '\u627e\u4e0d\u5230\u8be5\u63d0\u793a\u8bcd';
|
|
128
|
+
case 'ambiguous': return '\u5339\u914d\u5230\u591a\u6761\uff0c\u8bf7\u7528\u5e8f\u53f7';
|
|
129
|
+
case 'write_failed': return PROMPT_WRITE_FAILED_COPY;
|
|
130
|
+
}
|
|
131
|
+
}
|