@crouton-kit/crouter 0.3.78 → 0.3.80

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 (80) hide show
  1. package/dist/build-root.d.ts +12 -4
  2. package/dist/build-root.js +25 -6
  3. package/dist/builtin-memory/crouter-development/plugins.md +82 -5
  4. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +1228 -12
  5. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +3 -3
  6. package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +2 -787
  7. package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +8 -3
  8. package/dist/clients/attach/__tests__/attach-keybindings.test.d.ts +1 -0
  9. package/dist/clients/attach/__tests__/attach-keybindings.test.js +113 -0
  10. package/dist/clients/attach/__tests__/mermaid-render.test.js +9 -1
  11. package/dist/clients/attach/attach-cmd.d.ts +9 -1
  12. package/dist/clients/attach/attach-cmd.js +847 -801
  13. package/dist/clients/attach/auth-pickers.d.ts +0 -12
  14. package/dist/clients/attach/auth-pickers.js +64 -15
  15. package/dist/clients/attach/chat-view.d.ts +4 -0
  16. package/dist/clients/attach/chat-view.js +10 -0
  17. package/dist/clients/attach/graph-overlay.d.ts +12 -2
  18. package/dist/clients/attach/graph-overlay.js +83 -33
  19. package/dist/clients/attach/input-controller.d.ts +19 -0
  20. package/dist/clients/attach/input-controller.js +55 -11
  21. package/dist/clients/attach/titled-editor.d.ts +21 -0
  22. package/dist/clients/attach/titled-editor.js +101 -0
  23. package/dist/commands/human/queue.js +3 -4
  24. package/dist/commands/pkg/plugin-inspect.js +22 -1
  25. package/dist/commands/pkg/plugin-manage.js +31 -9
  26. package/dist/commands/sys/__tests__/setup-core.test.js +158 -1
  27. package/dist/commands/sys/doctor.js +42 -4
  28. package/dist/commands/sys/setup-core.d.ts +37 -0
  29. package/dist/commands/sys/setup-core.js +138 -1
  30. package/dist/commands/sys/setup.d.ts +88 -0
  31. package/dist/commands/sys/setup.js +915 -171
  32. package/dist/commands/view-pick.d.ts +4 -0
  33. package/dist/commands/view-pick.js +17 -7
  34. package/dist/core/__tests__/canvas-inbox-watcher.test.js +34 -9
  35. package/dist/core/__tests__/command-plugins-surfaces.test.d.ts +1 -0
  36. package/dist/core/__tests__/command-plugins-surfaces.test.js +298 -0
  37. package/dist/core/__tests__/command-plugins.test.d.ts +1 -0
  38. package/dist/core/__tests__/command-plugins.test.js +444 -0
  39. package/dist/core/__tests__/fixtures/fake-engine.d.ts +6 -0
  40. package/dist/core/__tests__/fixtures/fake-engine.js +9 -1
  41. package/dist/core/__tests__/preview-registry-sync.test.js +30 -1
  42. package/dist/core/__tests__/scope-crouter-home-fence.test.d.ts +1 -0
  43. package/dist/core/__tests__/scope-crouter-home-fence.test.js +55 -0
  44. package/dist/core/canvas/browse/app.d.ts +6 -0
  45. package/dist/core/canvas/browse/app.js +71 -41
  46. package/dist/core/command-plugins/adapter.d.ts +15 -0
  47. package/dist/core/command-plugins/adapter.js +145 -0
  48. package/dist/core/command-plugins/compose.d.ts +5 -0
  49. package/dist/core/command-plugins/compose.js +56 -0
  50. package/dist/core/command-plugins/discovery.d.ts +104 -0
  51. package/dist/core/command-plugins/discovery.js +565 -0
  52. package/dist/core/config.d.ts +2 -5
  53. package/dist/core/keybindings/__tests__/bespoke-consumers.test.d.ts +1 -0
  54. package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +40 -0
  55. package/dist/core/keybindings/__tests__/resolve.test.js +2 -2
  56. package/dist/core/keybindings/catalog.d.ts +3 -3
  57. package/dist/core/keybindings/catalog.js +2 -1
  58. package/dist/core/profiles/select.d.ts +6 -0
  59. package/dist/core/profiles/select.js +90 -59
  60. package/dist/core/provider-management.d.ts +12 -0
  61. package/dist/core/provider-management.js +24 -0
  62. package/dist/core/runtime/banner.d.ts +13 -0
  63. package/dist/core/runtime/banner.js +51 -0
  64. package/dist/core/runtime/broker.js +7 -6
  65. package/dist/core/runtime/pi-vendored.d.ts +8 -0
  66. package/dist/core/runtime/pi-vendored.js +14 -0
  67. package/dist/core/runtime/recap.d.ts +1 -1
  68. package/dist/core/runtime/recap.js +50 -25
  69. package/dist/core/runtime/session-list-cache.d.ts +10 -0
  70. package/dist/core/runtime/session-list-cache.js +94 -26
  71. package/dist/core/runtime/spawn.js +5 -17
  72. package/dist/core/runtime/tmux.js +2 -1
  73. package/dist/core/scope.js +27 -4
  74. package/dist/core/subscription-state.d.ts +90 -0
  75. package/dist/core/subscription-state.js +762 -0
  76. package/dist/daemon/crtrd.js +253 -12
  77. package/dist/pi-extensions/canvas-recap.js +43 -17
  78. package/dist/types.d.ts +6 -13
  79. package/dist/types.js +0 -3
  80. package/package.json +7 -3
@@ -1,10 +1,131 @@
1
1
  import { spawnSync } from 'node:child_process';
2
2
  import { chmod, mkdir, writeFile } from 'node:fs/promises';
3
+ import { readFileSync } from 'node:fs';
3
4
  import { homedir } from 'node:os';
4
5
  import { basename, dirname, join, resolve } from 'node:path';
6
+ import { isDeepStrictEqual } from 'node:util';
7
+ import { BINDING_CATALOG, normalizeGesture, resolveKeybindings, } from '../../core/keybindings/index.js';
5
8
  import { builtinPiPackageDir } from '../../core/scope.js';
6
9
  import { readJsonIfExists } from '../../core/fs-utils.js';
7
10
  import { resolveBundledPiCliPath } from '../../core/runtime/pi-cli.js';
11
+ function isKeybindingsObject(value) {
12
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
13
+ }
14
+ function cloneKeybindings(value) {
15
+ if (!isKeybindingsObject(value))
16
+ return {};
17
+ return Object.fromEntries(Object.entries(value).map(([id, gestures]) => [
18
+ id,
19
+ Array.isArray(gestures) ? [...gestures] : gestures,
20
+ ]));
21
+ }
22
+ /** Transactional sparse keybinding draft used by the full-screen setup tab. */
23
+ export class SetupKeybindingsDraft {
24
+ expected;
25
+ baseline;
26
+ current;
27
+ baselineInvalidRoot;
28
+ invalidRoot;
29
+ constructor(rawKeybindings) {
30
+ this.expected = rawKeybindings;
31
+ this.baseline = cloneKeybindings(rawKeybindings);
32
+ this.current = cloneKeybindings(rawKeybindings);
33
+ this.baselineInvalidRoot = rawKeybindings !== undefined && !isKeybindingsObject(rawKeybindings) ? rawKeybindings : undefined;
34
+ this.invalidRoot = this.baselineInvalidRoot;
35
+ }
36
+ get dirty() {
37
+ return !isDeepStrictEqual(this.current, this.baseline)
38
+ || !isDeepStrictEqual(this.invalidRoot, this.baselineInvalidRoot);
39
+ }
40
+ overrides() {
41
+ return cloneKeybindings(this.current);
42
+ }
43
+ expectedKeybindings() {
44
+ return this.expected;
45
+ }
46
+ resolution() {
47
+ return resolveKeybindings(this.invalidRoot === undefined ? this.current : this.invalidRoot);
48
+ }
49
+ /** True while the persisted `keybindings` root is a non-object (e.g. a string):
50
+ * edits cannot be layered onto an invalid root, so the tab must reset-all first. */
51
+ hasInvalidRoot() {
52
+ return this.invalidRoot !== undefined;
53
+ }
54
+ expression(id) {
55
+ return this.resolution().gestures(id).join(', ');
56
+ }
57
+ edit(id, expression) {
58
+ if (this.invalidRoot !== undefined) {
59
+ return {
60
+ ok: false,
61
+ diagnostics: [{
62
+ severity: 'error',
63
+ code: 'invalid-keybindings',
64
+ offendingValue: this.invalidRoot,
65
+ message: 'Reset all before editing: the saved keybindings root is invalid.',
66
+ }],
67
+ };
68
+ }
69
+ const definition = BINDING_CATALOG.find((candidate) => candidate.id === id);
70
+ let gestures;
71
+ try {
72
+ gestures = expression.trim() === ''
73
+ ? []
74
+ : expression.split(',').map((gesture) => normalizeGesture(gesture.trim(), definition));
75
+ }
76
+ catch (error) {
77
+ return {
78
+ ok: false,
79
+ diagnostics: [{
80
+ severity: 'error',
81
+ code: 'invalid-override',
82
+ bindingId: id,
83
+ offendingValue: expression,
84
+ message: error instanceof Error ? error.message : String(error),
85
+ }],
86
+ };
87
+ }
88
+ const deduped = [...new Set(gestures)];
89
+ // Sparse invariant: a member is stored only when it changes the effective
90
+ // resolution. If the committed gestures equal the catalog default for this
91
+ // id, drop the member instead of recording a redundant override — otherwise
92
+ // committing an unchanged default flips the row to a spurious user/unsaved
93
+ // state that persistence would then strip anyway.
94
+ const withoutId = { ...this.current };
95
+ delete withoutId[id];
96
+ const defaultGestures = [...resolveKeybindings(withoutId).gestures(id)];
97
+ const prospective = isDeepStrictEqual(deduped, defaultGestures)
98
+ ? withoutId
99
+ : { ...this.current, [id]: deduped };
100
+ const resolution = resolveKeybindings(prospective);
101
+ const relevant = resolution.diagnostics.filter((diagnostic) => diagnostic.bindingId === id || diagnostic.relatedBindingIds?.includes(id));
102
+ if (relevant.length > 0)
103
+ return { ok: false, diagnostics: relevant };
104
+ this.current = prospective;
105
+ return { ok: true, diagnostics: resolution.diagnostics };
106
+ }
107
+ unbind(id) {
108
+ return this.edit(id, '');
109
+ }
110
+ resetRow(id) {
111
+ delete this.current[id];
112
+ }
113
+ resetAll() {
114
+ this.current = {};
115
+ this.invalidRoot = undefined;
116
+ }
117
+ discard() {
118
+ this.current = cloneKeybindings(this.baseline);
119
+ this.invalidRoot = this.baselineInvalidRoot;
120
+ }
121
+ markSaved(overrides) {
122
+ this.expected = Object.keys(overrides).length === 0 ? undefined : cloneKeybindings(overrides);
123
+ this.baseline = cloneKeybindings(overrides);
124
+ this.current = cloneKeybindings(overrides);
125
+ this.baselineInvalidRoot = undefined;
126
+ this.invalidRoot = undefined;
127
+ }
128
+ }
8
129
  const PACKAGE_COPY = {
9
130
  'crtr-extensions': {
10
131
  name: 'pi-crtr-extensions',
@@ -234,6 +355,22 @@ export function resolveExaKeyPath(homeDir = homedir()) {
234
355
  export function resolveComposioKeyPath(homeDir = homedir()) {
235
356
  return join(homeDir, '.crouter', 'composio.key');
236
357
  }
358
+ function detectApiKey(envVar, keyPath) {
359
+ if ((process.env[envVar] ?? '').trim() !== '')
360
+ return { present: true, source: 'env' };
361
+ try {
362
+ if (readFileSync(keyPath, 'utf8').trim() !== '')
363
+ return { present: true, source: 'file' };
364
+ }
365
+ catch { /* absent/unreadable → not present */ }
366
+ return { present: false };
367
+ }
368
+ export function detectExaKey(homeDir = homedir()) {
369
+ return detectApiKey('EXA_API_KEY', resolveExaKeyPath(homeDir));
370
+ }
371
+ export function detectComposioKey(homeDir = homedir()) {
372
+ return detectApiKey('COMPOSIO_API_KEY', resolveComposioKeyPath(homeDir));
373
+ }
237
374
  export function buildSetupInitialState(opts = {}) {
238
375
  const homeDir = opts.homeDir ?? homedir();
239
376
  const settingsPath = opts.settingsPath ?? resolveSettingsPath(homeDir);
@@ -275,7 +412,7 @@ export function renderSetupStaticInstructions(state) {
275
412
  return [
276
413
  instructions.headline,
277
414
  '',
278
- 'Provider login: open the wizard in a TTY and use the Login tab (same flow as /login) to authenticate a model provider.',
415
+ 'Provider login: open the wizard in a TTY and use the Providers tab (same flow as /login) to authenticate a model provider.',
279
416
  '',
280
417
  'Packages:',
281
418
  ...instructions.packageLines,
@@ -1,2 +1,90 @@
1
1
  import type { LeafDef } from '../../core/command.js';
2
+ import { TUI, type Component, type Focusable } from '@earendil-works/pi-tui';
3
+ import { type BindingId, type BindingResolution } from '../../core/keybindings/index.js';
4
+ import { type SetupPackageId, type SetupPackageManifestEntry, type SetupSubmission, type SetupSystemToolState } from './setup-core.js';
5
+ export declare class SetupWizard implements Component, Focusable {
6
+ private readonly manifest;
7
+ private readonly installedPackageIds;
8
+ private readonly systemTools;
9
+ private readonly exaInput;
10
+ private readonly composioInput;
11
+ private readonly keyInput;
12
+ private readonly openingBindings;
13
+ private readonly keyDraft;
14
+ private readonly terminalRows;
15
+ private readonly selectedPackageIds;
16
+ private readonly selectedSystemTools;
17
+ private readonly providers;
18
+ private activeTab;
19
+ private pluginIndex;
20
+ private systemIndex;
21
+ private expandedPluginId;
22
+ private confirming;
23
+ private keyIndex;
24
+ private keyScroll;
25
+ private keyFilter;
26
+ private filteringKeys;
27
+ private editingKey;
28
+ private keyEditError;
29
+ private keyDiagnostics;
30
+ private keyConfirm;
31
+ private keyNotice;
32
+ private cachedWidth;
33
+ private cachedLines;
34
+ private _focused;
35
+ onSubmit?: (submission: SetupSubmission) => void;
36
+ onCancel?: () => void;
37
+ constructor(manifest: SetupPackageManifestEntry[], installedPackageIds: Set<SetupPackageId>, systemTools: SetupSystemToolState[], tui: TUI, agentDir: string, openingBindings: BindingResolution<BindingId>, rawKeybindings: unknown, terminalRows: () => number);
38
+ set focused(value: boolean);
39
+ get focused(): boolean;
40
+ invalidate(): void;
41
+ private setTab;
42
+ private moveTab;
43
+ private cancel;
44
+ dispose(): void;
45
+ private matches;
46
+ /** Human hint label for an action, derived from the opening snapshot so footers
47
+ * reflect the effective (possibly remapped) gestures the wizard actually honors. */
48
+ private label;
49
+ /** Like `label`, but drops gestures a focused pi text Input consumes as data
50
+ * (single printable chars and the arrow keys), so the Exa/Composio footers do
51
+ * not claim keys that never reach the wizard while a field owns focus. */
52
+ private fieldSafeLabel;
53
+ private handleGlobalTabSwitch;
54
+ private selectedPackage;
55
+ private selectedSystem;
56
+ private movePlugin;
57
+ private moveSystem;
58
+ private togglePackage;
59
+ private toggleSystem;
60
+ private toggleDetails;
61
+ private hasPendingInstalls;
62
+ private buildSubmission;
63
+ private finalize;
64
+ private filteredKeybindings;
65
+ private selectedKeybinding;
66
+ private moveKey;
67
+ private keyViewportLines;
68
+ private keyPageSize;
69
+ private beginKeyEdit;
70
+ private commitKeyEdit;
71
+ private cancelKeyEdit;
72
+ private saveKeybindings;
73
+ private refreshTmuxBindingsAfterSave;
74
+ private confirmKeyAction;
75
+ private handleKeybindingsInput;
76
+ handleInput(data: string): void;
77
+ private renderHeader;
78
+ private renderFooter;
79
+ private renderProviders;
80
+ private renderPlugins;
81
+ private renderSystems;
82
+ private renderExa;
83
+ private renderComposio;
84
+ private renderConfirm;
85
+ private keyRowHasMessage;
86
+ private keyLineCost;
87
+ private renderKeybindings;
88
+ render(width: number): string[];
89
+ }
2
90
  export declare const sysSetupLeaf: LeafDef;