agent-trellis 0.6.3 → 0.8.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 (107) hide show
  1. package/README.md +97 -38
  2. package/dist/adapters/claude-code.js +3 -2
  3. package/dist/adapters/codex.js +3 -2
  4. package/dist/adapters/jsonMcp.d.ts +3 -1
  5. package/dist/adapters/jsonMcp.js +18 -4
  6. package/dist/adapters/kimi-code.d.ts +21 -0
  7. package/dist/adapters/kimi-code.js +107 -0
  8. package/dist/adapters/kiro.js +3 -2
  9. package/dist/adapters/mcpPlan.d.ts +26 -2
  10. package/dist/adapters/mcpPlan.js +135 -15
  11. package/dist/adapters/pi.js +22 -3
  12. package/dist/adapters/symlinkPlan.d.ts +7 -0
  13. package/dist/adapters/symlinkPlan.js +16 -7
  14. package/dist/cli.js +129 -20
  15. package/dist/commands/doctor.d.ts +7 -2
  16. package/dist/commands/doctor.js +38 -2
  17. package/dist/commands/init.d.ts +4 -2
  18. package/dist/commands/init.js +26 -13
  19. package/dist/commands/kimi.d.ts +16 -0
  20. package/dist/commands/kimi.js +64 -0
  21. package/dist/commands/manage.d.ts +39 -0
  22. package/dist/commands/manage.js +126 -0
  23. package/dist/commands/mcp.d.ts +22 -1
  24. package/dist/commands/mcp.js +65 -2
  25. package/dist/commands/mcpGateway.d.ts +6 -0
  26. package/dist/commands/mcpGateway.js +34 -14
  27. package/dist/commands/mcpImport.d.ts +27 -0
  28. package/dist/commands/mcpImport.js +336 -0
  29. package/dist/commands/memory.d.ts +5 -3
  30. package/dist/commands/memory.js +12 -8
  31. package/dist/commands/migrate.d.ts +37 -7
  32. package/dist/commands/migrate.js +253 -27
  33. package/dist/commands/onboard.d.ts +74 -2
  34. package/dist/commands/onboard.js +463 -72
  35. package/dist/commands/onboardVerdict.js +20 -7
  36. package/dist/commands/rollback.js +4 -1
  37. package/dist/commands/secretsAudit.d.ts +21 -12
  38. package/dist/commands/secretsAudit.js +39 -10
  39. package/dist/commands/skill.d.ts +17 -0
  40. package/dist/commands/skill.js +47 -2
  41. package/dist/commands/sync.js +2 -0
  42. package/dist/core/canonical.d.ts +58 -4
  43. package/dist/core/canonical.js +183 -11
  44. package/dist/core/capabilitySelection.d.ts +45 -0
  45. package/dist/core/capabilitySelection.js +124 -0
  46. package/dist/core/types.d.ts +25 -2
  47. package/dist/core/types.js +7 -0
  48. package/dist/lib/backup.d.ts +2 -0
  49. package/dist/lib/backup.js +4 -0
  50. package/dist/lib/builtinSkills.d.ts +2 -0
  51. package/dist/lib/builtinSkills.js +4 -0
  52. package/dist/lib/cliMetadata.d.ts +1 -0
  53. package/dist/lib/cliMetadata.js +14 -0
  54. package/dist/lib/gatewayBackend.d.ts +28 -0
  55. package/dist/lib/gatewayBackend.js +72 -1
  56. package/dist/lib/installAgent.d.ts +7 -5
  57. package/dist/lib/installAgent.js +4 -3
  58. package/dist/lib/mcpConnect.js +5 -1
  59. package/dist/lib/mcpMigrateRead.d.ts +1 -0
  60. package/dist/lib/mcpMigrateRead.js +3 -0
  61. package/dist/lib/mcpRuntime.d.ts +46 -0
  62. package/dist/lib/mcpRuntime.js +185 -0
  63. package/dist/lib/mcpStatusProvider.d.ts +10 -0
  64. package/dist/lib/mcpStatusProvider.js +25 -0
  65. package/dist/lib/mcpToolRegistry.d.ts +18 -0
  66. package/dist/lib/mcpToolRegistry.js +107 -14
  67. package/dist/lib/memoryGraph.d.ts +1 -1
  68. package/dist/lib/memoryGraph.js +9 -3
  69. package/dist/lib/memoryProvider.d.ts +58 -0
  70. package/dist/lib/memoryProvider.js +175 -0
  71. package/dist/lib/memoryStatus.d.ts +17 -0
  72. package/dist/lib/memoryStatus.js +88 -0
  73. package/dist/lib/nativeMemory.d.ts +19 -0
  74. package/dist/lib/nativeMemory.js +129 -0
  75. package/dist/lib/runtimeControlProvider.d.ts +16 -0
  76. package/dist/lib/runtimeControlProvider.js +168 -0
  77. package/dist/lib/secretEnv.d.ts +17 -0
  78. package/dist/lib/secretEnv.js +31 -1
  79. package/dist/lib/skillProvider.d.ts +13 -0
  80. package/dist/lib/skillProvider.js +210 -0
  81. package/dist/lib/taskProvider.d.ts +7 -0
  82. package/dist/lib/taskProvider.js +43 -0
  83. package/dist/lib/taskStore.d.ts +46 -0
  84. package/dist/lib/taskStore.js +156 -0
  85. package/dist/lib/terminalPicker.d.ts +23 -28
  86. package/dist/lib/terminalPicker.js +54 -164
  87. package/dist/pi-bridge/bundle.js +493 -51
  88. package/dist/pi-bridge/index.js +42 -21
  89. package/dist/pi-bridge/schemaTranslate.d.ts +4 -8
  90. package/dist/pi-bridge/schemaTranslate.js +4 -8
  91. package/dist/probes/kimi-code.d.ts +12 -0
  92. package/dist/probes/kimi-code.js +55 -0
  93. package/dist/sdk.d.ts +1 -1
  94. package/docs/architecture.md +224 -26
  95. package/docs/assets/agent-trellis-architecture-horizontal.svg +80 -0
  96. package/docs/assets/agent-trellis-architecture-vertical.svg +82 -0
  97. package/docs/assets/trellis-mark.svg +12 -0
  98. package/docs/getting-started.md +403 -35
  99. package/docs/overview.md +131 -0
  100. package/docs/overview.zh-CN.md +100 -0
  101. package/docs/research.md +59 -0
  102. package/docs/roadmap.md +10 -5
  103. package/package.json +5 -3
  104. package/schema/builtin-skills/trellis-runtime/SKILL.md +117 -0
  105. package/schema/capability-selection.example.yaml +23 -0
  106. package/schema/scope.example.yaml +1 -1
  107. package/schema/servers.example.yaml +15 -1
@@ -1,193 +1,83 @@
1
1
  /**
2
- * Minimal, dependency-free arrow-key/checkbox terminal picker
3
- * (trellis-onboard-interactive-picker design.md D1) — the interaction
4
- * surface `trellis onboard`'s two prompts need (at most four rows, no
5
- * search, no pagination) doesn't need a full prompt library; this
6
- * hand-rolls just enough raw-mode key handling and ANSI rendering for
7
- * that bounded case, matching the project's existing narrow-dependency
8
- * precedent (src/lib/envVarNames.ts, src/lib/secretEnv.ts).
2
+ * Styled interactive prompts used by `trellis onboard`.
9
3
  *
10
- * `input`/`output` are injectable (never a CLI flag) purely so tests can
11
- * drive the real key-parsing/render loop against a plain stream instead
12
- * of a real TTY — same seam pattern (`homeDir`, etc.) used everywhere
13
- * else in this project.
4
+ * The onboarding orchestration depends on semantic values (an index or a set
5
+ * of indices), not on a particular terminal renderer. Clack owns raw-mode
6
+ * handling, color, wrapping, cursor cleanup, and cancellation; the injected
7
+ * streams keep the prompt loop testable without a real terminal.
14
8
  */
9
+ import { CANCEL_SYMBOL, autocompleteMultiselect, isCancel, multiselect, select } from "@clack/prompts";
15
10
  function defaultStreams() {
16
- return { input: process.stdin, output: process.stdout };
11
+ return { input: process.stdin, output: process.stderr };
17
12
  }
18
13
  /**
19
- * True only when both streams are real, raw-mode-capable terminals — the
20
- * exact gate deciding picker vs. the pre-existing numbered-typing prompt
21
- * (design.md D2). A stream lacking `setRawMode` (piped input, some
22
- * minimal TTYs) always falls back, never hangs or guesses.
14
+ * Clack is only started for a real interactive terminal. Piped input keeps
15
+ * the existing numbered fallback in onboard instead of hanging in raw mode.
23
16
  */
24
17
  export function canUseInteractivePicker(streams = defaultStreams()) {
25
18
  const input = streams.input;
26
19
  const output = streams.output;
27
20
  return Boolean(input.isTTY && output.isTTY && typeof input.setRawMode === "function");
28
21
  }
29
- /** Wrapping index navigation — pure, exported for direct unit testing. */
22
+ /** Wrapping index navigation retained as a small public utility for callers/tests. */
30
23
  export function nextIndex(current, delta, length) {
31
24
  return ((current + delta) % length + length) % length;
32
25
  }
33
- /** Pure single-index toggle — exported for direct unit testing. */
26
+ /** Pure single-index toggle retained for callers/tests. */
34
27
  export function toggled(checked, index) {
35
28
  const next = [...checked];
36
29
  next[index] = !next[index];
37
30
  return next;
38
31
  }
39
- const ESC = "\u001b";
40
- const CTRL_C = "\u0003";
41
- const HIDE_CURSOR = `${ESC}[?25l`;
42
- const SHOW_CURSOR = `${ESC}[?25h`;
43
- /** Parses one raw input chunk into a single logical key — arrow escape
44
- * sequences, j/k, space, enter, or Ctrl+C. Anything else is ignored. */
45
- function parseKey(chunk) {
46
- if (chunk === CTRL_C)
47
- return "cancel";
48
- if (chunk === "\r" || chunk === "\n")
49
- return "confirm";
50
- if (chunk === " ")
51
- return "toggle";
52
- if (chunk === `${ESC}[A` || chunk === "k")
53
- return "up";
54
- if (chunk === `${ESC}[B` || chunk === "j")
55
- return "down";
56
- return null;
57
- }
58
- function withRawMode(streams, body) {
59
- const input = streams.input;
60
- const output = streams.output;
61
- const canSetRawMode = typeof input.setRawMode === "function";
62
- if (canSetRawMode)
63
- input.setRawMode(true);
64
- input.resume();
65
- input.setEncoding("utf-8");
66
- output.write(HIDE_CURSOR);
67
- const restore = () => {
68
- output.write(SHOW_CURSOR);
69
- if (canSetRawMode)
70
- input.setRawMode(false);
71
- input.pause();
72
- };
73
- // Second-layer safety net (design.md D6): a thrown error the caller's
74
- // own try/finally doesn't get a chance to run for (process killed
75
- // externally) must still not leave the terminal in raw mode/cursor
76
- // hidden.
77
- process.once("exit", restore);
78
- return body().finally(() => {
79
- restore();
80
- process.removeListener("exit", restore);
81
- });
82
- }
83
- function moveCursorUp(output, lines) {
84
- if (lines > 0)
85
- output.write(`${ESC}[${lines}A`);
86
- }
87
- function clearLines(output, lines) {
88
- for (let i = 0; i < lines; i++) {
89
- output.write(`${ESC}[2K`);
90
- if (i < lines - 1)
91
- output.write(`${ESC}[1B`);
92
- }
93
- moveCursorUp(output, lines - 1);
94
- }
95
- function renderRows(output, rows, previousRowCount) {
96
- if (previousRowCount > 0) {
97
- clearLines(output, previousRowCount);
98
- }
99
- for (const row of rows) {
100
- output.write(`${row}\n`);
101
- }
102
- }
103
- function highlightRow(text, isHighlighted) {
104
- return isHighlighted ? `> ${ESC}[7m${text}${ESC}[0m` : ` ${text}`;
32
+ function wasCancelled(value) {
33
+ return value === CANCEL_SYMBOL || isCancel(value);
105
34
  }
106
35
  /**
107
- * Single-select: Up/Down/j/k moves the highlight, Enter confirms. Resolves
108
- * the confirmed index, or `null` on Ctrl+C cancel. Caller (onboard.ts)
109
- * must have already confirmed `canUseInteractivePicker()` — this function
110
- * does not re-check, and assumes `streams.input` genuinely supports raw
111
- * mode.
36
+ * Single-select prompt. The returned number is the original item index, so
37
+ * callers do not depend on display labels or prompt-library values.
112
38
  */
113
- export async function runSingleSelectPicker(items, streams = defaultStreams()) {
114
- const { input, output } = streams;
115
- return withRawMode(streams, () => {
116
- return new Promise((resolve) => {
117
- let highlighted = 0;
118
- let rowCount = 0;
119
- const draw = () => {
120
- const rows = items.map((label, i) => highlightRow(label, i === highlighted));
121
- renderRows(output, rows, rowCount);
122
- rowCount = rows.length;
123
- };
124
- draw();
125
- const onData = (chunk) => {
126
- const key = parseKey(chunk.toString("utf-8"));
127
- if (key === "up") {
128
- highlighted = nextIndex(highlighted, -1, items.length);
129
- draw();
130
- }
131
- else if (key === "down") {
132
- highlighted = nextIndex(highlighted, 1, items.length);
133
- draw();
134
- }
135
- else if (key === "confirm") {
136
- input.removeListener("data", onData);
137
- resolve(highlighted);
138
- }
139
- else if (key === "cancel") {
140
- input.removeListener("data", onData);
141
- resolve(null);
142
- }
143
- };
144
- input.on("data", onData);
145
- });
39
+ export async function runSingleSelectPicker(items, streams = defaultStreams(), message = "请选择一个迁移来源") {
40
+ const result = await select({
41
+ message,
42
+ options: items.map((item, value) => ({
43
+ label: typeof item === "string" ? item : item.label,
44
+ value,
45
+ ...(typeof item === "string" || item.disabled === undefined ? {} : { disabled: item.disabled }),
46
+ })),
47
+ input: streams.input,
48
+ output: streams.output,
49
+ showInstructions: true,
146
50
  });
51
+ return wasCancelled(result) ? null : result;
147
52
  }
148
53
  /**
149
- * Multi-select (checkbox): Up/Down/j/k moves the highlight, Space toggles
150
- * the current row, Enter confirms. Resolves the checked indices at
151
- * confirm time, or `null` on Ctrl+C cancel. Same precondition as
152
- * `runSingleSelectPicker`.
54
+ * Checkbox prompt. The returned indices preserve the existing onboard
55
+ * contract, while Clack handles checked state, wrapping, colors, and cleanup.
153
56
  */
154
- export async function runMultiSelectPicker(items, initiallyChecked, streams = defaultStreams()) {
155
- const { input, output } = streams;
156
- return withRawMode(streams, () => {
157
- return new Promise((resolve) => {
158
- let highlighted = 0;
159
- let checked = [...initiallyChecked];
160
- let rowCount = 0;
161
- const draw = () => {
162
- const rows = items.map((label, i) => highlightRow(`[${checked[i] ? "x" : " "}] ${label}`, i === highlighted));
163
- renderRows(output, rows, rowCount);
164
- rowCount = rows.length;
165
- };
166
- draw();
167
- const onData = (chunk) => {
168
- const key = parseKey(chunk.toString("utf-8"));
169
- if (key === "up") {
170
- highlighted = nextIndex(highlighted, -1, items.length);
171
- draw();
172
- }
173
- else if (key === "down") {
174
- highlighted = nextIndex(highlighted, 1, items.length);
175
- draw();
176
- }
177
- else if (key === "toggle") {
178
- checked = toggled(checked, highlighted);
179
- draw();
180
- }
181
- else if (key === "confirm") {
182
- input.removeListener("data", onData);
183
- resolve(checked.flatMap((isChecked, i) => (isChecked ? [i] : [])));
184
- }
185
- else if (key === "cancel") {
186
- input.removeListener("data", onData);
187
- resolve(null);
188
- }
189
- };
190
- input.on("data", onData);
191
- });
57
+ export async function runMultiSelectPicker(items, initiallyChecked, streams = defaultStreams(), message = "请选择要启用的项目") {
58
+ const result = await multiselect({
59
+ message,
60
+ options: items.map((label, value) => ({ label, value })),
61
+ initialValues: items.flatMap((_, index) => (initiallyChecked[index] ? [index] : [])),
62
+ input: streams.input,
63
+ output: streams.output,
64
+ required: false,
65
+ showInstructions: true,
66
+ });
67
+ return wasCancelled(result) ? null : [...result].sort((left, right) => left - right);
68
+ }
69
+ /** Searchable multiselect for large skill/MCP inventories. It returns the
70
+ * selected labels as stable names, preserving the semantic adapter contract
71
+ * while avoiding a wall of dozens of rows in the onboarding terminal. */
72
+ export async function runSearchMultiSelectPicker(items, streams = defaultStreams(), message = "选择要迁移的项目") {
73
+ const result = await autocompleteMultiselect({
74
+ message,
75
+ placeholder: "输入关键词筛选",
76
+ options: items.map((value) => ({ label: value, value })),
77
+ initialValues: [...items],
78
+ input: streams.input,
79
+ output: streams.output,
80
+ required: false,
192
81
  });
82
+ return wasCancelled(result) ? null : result;
193
83
  }