agent-trellis 0.7.0 → 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 (104) 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 +6 -1
  10. package/dist/adapters/mcpPlan.js +106 -8
  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 +121 -21
  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 +16 -5
  32. package/dist/commands/migrate.js +90 -17
  33. package/dist/commands/onboard.d.ts +74 -2
  34. package/dist/commands/onboard.js +458 -71
  35. package/dist/commands/rollback.js +4 -1
  36. package/dist/commands/skill.d.ts +17 -0
  37. package/dist/commands/skill.js +47 -2
  38. package/dist/commands/sync.js +2 -0
  39. package/dist/core/canonical.d.ts +15 -7
  40. package/dist/core/canonical.js +101 -13
  41. package/dist/core/capabilitySelection.d.ts +45 -0
  42. package/dist/core/capabilitySelection.js +124 -0
  43. package/dist/core/types.d.ts +25 -2
  44. package/dist/core/types.js +7 -0
  45. package/dist/lib/backup.d.ts +2 -0
  46. package/dist/lib/backup.js +4 -0
  47. package/dist/lib/builtinSkills.d.ts +2 -0
  48. package/dist/lib/builtinSkills.js +4 -0
  49. package/dist/lib/cliMetadata.d.ts +1 -0
  50. package/dist/lib/cliMetadata.js +14 -0
  51. package/dist/lib/gatewayBackend.d.ts +28 -0
  52. package/dist/lib/gatewayBackend.js +72 -1
  53. package/dist/lib/installAgent.d.ts +7 -5
  54. package/dist/lib/installAgent.js +4 -3
  55. package/dist/lib/mcpConnect.js +5 -1
  56. package/dist/lib/mcpMigrateRead.d.ts +1 -0
  57. package/dist/lib/mcpMigrateRead.js +3 -0
  58. package/dist/lib/mcpRuntime.d.ts +46 -0
  59. package/dist/lib/mcpRuntime.js +185 -0
  60. package/dist/lib/mcpStatusProvider.d.ts +10 -0
  61. package/dist/lib/mcpStatusProvider.js +25 -0
  62. package/dist/lib/mcpToolRegistry.d.ts +18 -0
  63. package/dist/lib/mcpToolRegistry.js +107 -14
  64. package/dist/lib/memoryGraph.d.ts +1 -1
  65. package/dist/lib/memoryGraph.js +9 -3
  66. package/dist/lib/memoryProvider.d.ts +58 -0
  67. package/dist/lib/memoryProvider.js +175 -0
  68. package/dist/lib/memoryStatus.d.ts +17 -0
  69. package/dist/lib/memoryStatus.js +88 -0
  70. package/dist/lib/nativeMemory.d.ts +19 -0
  71. package/dist/lib/nativeMemory.js +129 -0
  72. package/dist/lib/runtimeControlProvider.d.ts +16 -0
  73. package/dist/lib/runtimeControlProvider.js +168 -0
  74. package/dist/lib/secretEnv.d.ts +2 -1
  75. package/dist/lib/secretEnv.js +6 -2
  76. package/dist/lib/skillProvider.d.ts +13 -0
  77. package/dist/lib/skillProvider.js +210 -0
  78. package/dist/lib/taskProvider.d.ts +7 -0
  79. package/dist/lib/taskProvider.js +43 -0
  80. package/dist/lib/taskStore.d.ts +46 -0
  81. package/dist/lib/taskStore.js +156 -0
  82. package/dist/lib/terminalPicker.d.ts +23 -49
  83. package/dist/lib/terminalPicker.js +53 -218
  84. package/dist/pi-bridge/bundle.js +475 -37
  85. package/dist/pi-bridge/index.js +42 -21
  86. package/dist/pi-bridge/schemaTranslate.d.ts +4 -8
  87. package/dist/pi-bridge/schemaTranslate.js +4 -8
  88. package/dist/probes/kimi-code.d.ts +12 -0
  89. package/dist/probes/kimi-code.js +55 -0
  90. package/dist/sdk.d.ts +1 -1
  91. package/docs/architecture.md +224 -26
  92. package/docs/assets/agent-trellis-architecture-horizontal.svg +80 -0
  93. package/docs/assets/agent-trellis-architecture-vertical.svg +82 -0
  94. package/docs/assets/trellis-mark.svg +12 -0
  95. package/docs/getting-started.md +328 -35
  96. package/docs/overview.md +131 -0
  97. package/docs/overview.zh-CN.md +100 -0
  98. package/docs/research.md +59 -0
  99. package/docs/roadmap.md +9 -5
  100. package/package.json +3 -2
  101. package/schema/builtin-skills/trellis-runtime/SKILL.md +117 -0
  102. package/schema/capability-selection.example.yaml +23 -0
  103. package/schema/scope.example.yaml +1 -1
  104. package/schema/servers.example.yaml +15 -1
@@ -4,21 +4,23 @@
4
4
  * Pure `collectMigratePlan` / effectful `applyMigratePlan`, same
5
5
  * plan-then-apply split every adapter already uses.
6
6
  */
7
- import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
8
8
  import { homedir } from "node:os";
9
- import { join } from "node:path";
9
+ import { dirname, join } from "node:path";
10
10
  import * as claudeCodeProbe from "../probes/claude-code.js";
11
11
  import * as codexProbe from "../probes/codex.js";
12
12
  import * as kiroProbe from "../probes/kiro.js";
13
13
  import * as piProbe from "../probes/pi.js";
14
+ import * as kimiCodeProbe from "../probes/kimi-code.js";
14
15
  import { AGENTS_MD_TEMPLATE } from "./init.js";
15
16
  import { decideDirImport } from "../lib/dirEquals.js";
16
17
  import { deepEqual } from "../lib/deepEqual.js";
17
- import { readClaudeCodeMcpDefs, readCodexMcpDefs, readKiroMcpDefs, resolvedEnvTextMap } from "../lib/mcpMigrateRead.js";
18
+ import { readClaudeCodeMcpDefs, readCodexMcpDefs, readKiroMcpDefs, readKimiCodeMcpDefs, resolvedEnvTextMap } from "../lib/mcpMigrateRead.js";
18
19
  import { parseDotenv, writeLocalSecretValue } from "../lib/secretEnv.js";
19
20
  import { findLiteralSecret } from "../adapters/mcpPlan.js";
20
21
  import { ensureGitignoreEntry, ensureShellEnvSource, loadCanonicalSource, upsertServerYaml, writeSecretsPolicyExtraction } from "../core/canonical.js";
21
22
  import { ALL_AGENTS } from "../core/types.js";
23
+ import { discoverNativeMemory, MAX_NATIVE_MEMORY_BYTES, renderNativeMemory } from "../lib/nativeMemory.js";
22
24
  /** Where a `staticEnv` literal secret's real value goes when
23
25
  * `secrets.policy.yaml` doesn't already have its own `env_file`
24
26
  * (trellis-migrate-extract-static-env-secrets design.md D3) — a sibling
@@ -48,6 +50,7 @@ const PROBES = {
48
50
  codex: (homeDir) => codexProbe.probe(homeDir),
49
51
  kiro: (homeDir) => kiroProbe.probe(homeDir),
50
52
  pi: (homeDir) => piProbe.probe(homeDir),
53
+ "kimi-code": (homeDir) => kimiCodeProbe.probe(homeDir),
51
54
  };
52
55
  /** pi has no static MCP config to read at all (roadmap.md P14/
53
56
  * trellis-migrate-mcp-servers) — deliberately absent, not an oversight;
@@ -56,6 +59,7 @@ const MCP_READERS = {
56
59
  "claude-code": readClaudeCodeMcpDefs,
57
60
  kiro: readKiroMcpDefs,
58
61
  codex: readCodexMcpDefs,
62
+ "kimi-code": readKimiCodeMcpDefs,
59
63
  };
60
64
  function planSkill(name, sourceDir, isSymlink, caseCorrect, canonicalDir) {
61
65
  if (isSymlink) {
@@ -116,6 +120,32 @@ function planInstructions(snapshot, canonicalAgentsMd) {
116
120
  remediation: `compare \`~/.trellis/agents.md\` against ${snapshot.instructionsFile.path} and either merge by hand or delete whichever copy you don't want to keep`,
117
121
  };
118
122
  }
123
+ function planNativeMemoryCandidate(candidate, homeDir) {
124
+ const targetPath = join(homeDir, ".trellis", "memories", `${candidate.targetName}.md`);
125
+ const rendered = renderNativeMemory(candidate);
126
+ if (!existsSync(targetPath)) {
127
+ return {
128
+ kind: "memory",
129
+ name: candidate.targetName,
130
+ action: "create",
131
+ detail: `will import ${candidate.displayName} from ${candidate.sourceAgent} native memory`,
132
+ memorySourcePath: candidate.sourcePath,
133
+ memorySourceId: candidate.sourceId,
134
+ memoryTargetPath: targetPath,
135
+ };
136
+ }
137
+ const current = readFileSync(targetPath, "utf8");
138
+ if (current === rendered) {
139
+ return { kind: "memory", name: candidate.targetName, action: "already-migrated", detail: "canonical memory is byte-identical" };
140
+ }
141
+ return {
142
+ kind: "memory",
143
+ name: candidate.targetName,
144
+ action: "conflict",
145
+ detail: `canonical memories/${candidate.targetName}.md already has different content — resolve by hand`,
146
+ remediation: `compare the canonical file with ${candidate.sourcePath} and decide which memory to keep before re-running migration`,
147
+ };
148
+ }
119
149
  /**
120
150
  * True when `existing` and `def` differ ONLY in which of `env`/
121
151
  * `envAliases`/`staticEnv` an env value is filed under, while every
@@ -273,13 +303,14 @@ function planMcpServer(name, def, existing, homeDir, policy) {
273
303
  * conflict. Omitting `only` (or passing both kinds) is exactly today's
274
304
  * behavior.
275
305
  */
276
- export async function collectMigratePlan(agent, homeDir = homedir(), only) {
306
+ export async function collectMigratePlan(agent, homeDir = homedir(), only, workspaceDir = process.cwd()) {
277
307
  const snapshot = await PROBES[agent](homeDir);
278
308
  if (!snapshot.present) {
279
309
  return { agent, present: false, items: [] };
280
310
  }
281
311
  const canonicalRoot = join(homeDir, ".trellis");
282
312
  const items = [];
313
+ let memoryDiscovery;
283
314
  const wants = (kind) => !only || only.includes(kind);
284
315
  if (wants("skill")) {
285
316
  for (const root of snapshot.skillRoots) {
@@ -306,7 +337,14 @@ export async function collectMigratePlan(agent, homeDir = homedir(), only) {
306
337
  }
307
338
  }
308
339
  }
309
- return { agent, present: true, items };
340
+ if (wants("memory")) {
341
+ const discovery = discoverNativeMemory(agent, homeDir, workspaceDir);
342
+ memoryDiscovery = { ...discovery, candidates: discovery.candidates.map(({ content: _content, ...safe }) => safe) };
343
+ for (const candidate of discovery.candidates) {
344
+ items.push(planNativeMemoryCandidate(candidate, homeDir));
345
+ }
346
+ }
347
+ return { agent, present: true, items, ...(memoryDiscovery ? { memoryDiscovery } : {}) };
310
348
  }
311
349
  /**
312
350
  * Re-reads the source agent's real MCP entries at apply time to recover
@@ -319,18 +357,31 @@ export async function collectMigratePlan(agent, homeDir = homedir(), only) {
319
357
  * written under, design.md D11) are looked up and written under
320
358
  * separately — they are not, in general, the same string.
321
359
  */
322
- function applyStaticEnvExtraction(agent, serverName, sourceKey, varName, targetPath, homeDir) {
360
+ function applyStaticEnvExtraction(agent, serverName, sourceKey, varName, targetPath, homeDir, backup) {
323
361
  const reader = MCP_READERS[agent];
324
362
  const realValue = reader?.(homeDir).entries.find((e) => e.name === serverName)?.def.staticEnv?.[sourceKey];
325
363
  if (realValue === undefined)
326
364
  return; // source changed between plan and apply; nothing left to extract
327
365
  if (targetPath === defaultLocalSecretsEnvFilePath(homeDir)) {
328
- ensureGitignoreEntry(join(homeDir, ".trellis", ".gitignore"), "mcp/servers.local.env");
366
+ ensureGitignoreEntry(join(homeDir, ".trellis", ".gitignore"), "mcp/servers.local.env", backup);
367
+ }
368
+ writeLocalSecretValue(targetPath, varName, realValue, backup);
369
+ writeSecretsPolicyExtraction(join(homeDir, ".trellis", "secrets.policy.yaml"), { varName, envFilePath: DEFAULT_LOCAL_SECRETS_ENV_FILE_TILDE }, backup);
370
+ }
371
+ function copyDirectoryThroughBackup(sourceDir, destDir, backup) {
372
+ for (const entry of readdirSync(sourceDir)) {
373
+ const source = join(sourceDir, entry);
374
+ const dest = join(destDir, entry);
375
+ if (statSync(source).isDirectory()) {
376
+ mkdirSync(dest, { recursive: true });
377
+ copyDirectoryThroughBackup(source, dest, backup);
378
+ }
379
+ else {
380
+ backup.writeFile(dest, readFileSync(source, "utf-8"));
381
+ }
329
382
  }
330
- writeLocalSecretValue(targetPath, varName, realValue);
331
- writeSecretsPolicyExtraction(join(homeDir, ".trellis", "secrets.policy.yaml"), { varName, envFilePath: DEFAULT_LOCAL_SECRETS_ENV_FILE_TILDE });
332
383
  }
333
- export function applyMigratePlan(plan, homeDir = homedir()) {
384
+ export function applyMigratePlan(plan, homeDir = homedir(), backup) {
334
385
  const canonicalRoot = join(homeDir, ".trellis");
335
386
  for (const item of plan.items) {
336
387
  if (item.action !== "create" && item.action !== "reclassify" && item.action !== "extract-secret")
@@ -338,18 +389,35 @@ export function applyMigratePlan(plan, homeDir = homedir()) {
338
389
  if (item.kind === "skill" && item.sourceDir) {
339
390
  const dest = join(canonicalRoot, "skills", item.name);
340
391
  mkdirSync(dest, { recursive: true });
341
- cpSync(item.sourceDir, dest, { recursive: true });
392
+ if (backup)
393
+ copyDirectoryThroughBackup(item.sourceDir, dest, backup);
394
+ else
395
+ cpSync(item.sourceDir, dest, { recursive: true });
342
396
  }
343
397
  else if (item.kind === "instructions" && item.sourceContent !== undefined) {
344
398
  mkdirSync(canonicalRoot, { recursive: true });
345
- writeFileSync(join(canonicalRoot, "agents.md"), item.sourceContent);
399
+ if (backup)
400
+ backup.writeFile(join(canonicalRoot, "agents.md"), item.sourceContent);
401
+ else
402
+ writeFileSync(join(canonicalRoot, "agents.md"), item.sourceContent);
346
403
  }
347
404
  else if (item.kind === "mcp" && item.mcpDef) {
348
- upsertServerYaml(join(canonicalRoot, "mcp", "servers.yaml"), item.name, item.mcpDef);
405
+ upsertServerYaml(join(canonicalRoot, "mcp", "servers.yaml"), item.name, item.mcpDef, backup);
349
406
  if (item.action === "extract-secret" && item.extractVarName && item.extractTargetPath && item.extractSourceKey) {
350
- applyStaticEnvExtraction(plan.agent, item.name, item.extractSourceKey, item.extractVarName, item.extractTargetPath, homeDir);
407
+ applyStaticEnvExtraction(plan.agent, item.name, item.extractSourceKey, item.extractVarName, item.extractTargetPath, homeDir, backup);
351
408
  }
352
409
  }
410
+ else if (item.kind === "memory" && item.memorySourcePath && item.memorySourceId && item.memoryTargetPath) {
411
+ if (statSync(item.memorySourcePath).size > MAX_NATIVE_MEMORY_BYTES)
412
+ throw new Error(`native memory source exceeds the ${MAX_NATIVE_MEMORY_BYTES}-byte limit: ${item.memorySourcePath}`);
413
+ const content = readFileSync(item.memorySourcePath, "utf8");
414
+ const imported = renderNativeMemory({ sourceAgent: plan.agent, sourceId: item.memorySourceId, content });
415
+ mkdirSync(dirname(item.memoryTargetPath), { recursive: true });
416
+ if (backup)
417
+ backup.writeFile(item.memoryTargetPath, imported);
418
+ else
419
+ writeFileSync(item.memoryTargetPath, imported);
420
+ }
353
421
  }
354
422
  // Runs every real (non-dry-run) migrate invocation, not just the one that
355
423
  // performed a fresh extraction — a machine that already extracted a
@@ -357,10 +425,10 @@ export function applyMigratePlan(plan, homeDir = homedir()) {
357
425
  // migrate runs at all, not only on its next brand-new extraction.
358
426
  const envFile = loadCanonicalSource(homeDir).secretsPolicy.envFile;
359
427
  if (envFile) {
360
- ensureShellEnvSource(defaultShellRcPath(homeDir), envFile);
428
+ ensureShellEnvSource(defaultShellRcPath(homeDir), envFile, backup);
361
429
  }
362
430
  }
363
- const ONLY_VALUES = ["skills", "instructions", "mcp"];
431
+ const ONLY_VALUES = ["skills", "instructions", "mcp", "memory"];
364
432
  function isMigrateOnlyValue(value) {
365
433
  return ONLY_VALUES.includes(value);
366
434
  }
@@ -369,6 +437,8 @@ function toMigrateKinds(only) {
369
437
  return ["skill"];
370
438
  if (only === "instructions")
371
439
  return ["instructions"];
440
+ if (only === "memory")
441
+ return ["memory"];
372
442
  return ["mcp"];
373
443
  }
374
444
  export async function runMigrate(opts = {}) {
@@ -405,12 +475,15 @@ export async function runMigrate(opts = {}) {
405
475
  * this formatting (including the empty-plan "nothing to migrate" case). */
406
476
  export function printPlan(plan, dryRun) {
407
477
  console.log(`${dryRun ? "[dry run] " : ""}migrate --from ${plan.agent}`);
478
+ if (plan.memoryDiscovery && plan.memoryDiscovery.status !== "supported") {
479
+ console.log(` memory source — [${plan.memoryDiscovery.status}] ${plan.memoryDiscovery.detail}`);
480
+ }
408
481
  if (plan.items.length === 0) {
409
482
  console.log(" nothing to migrate");
410
483
  return;
411
484
  }
412
485
  for (const item of plan.items) {
413
- const label = item.kind === "skill" ? `skill "${item.name}"` : item.kind === "mcp" ? `mcp server "${item.name}"` : "instructions";
486
+ const label = item.kind === "skill" ? `skill "${item.name}"` : item.kind === "mcp" ? `mcp server "${item.name}"` : item.kind === "memory" ? `memory "${item.name}"` : "instructions";
414
487
  console.log(` [${item.action}] ${label} — ${item.detail}`);
415
488
  }
416
489
  }
@@ -12,15 +12,39 @@
12
12
  * new skill-copy, symlink, conflict-detection, or secrets-scanning
13
13
  * judgment is made here.
14
14
  */
15
- import type { AgentId } from "../core/types.js";
15
+ import type { AgentId, McpConfig, McpRouteMode } from "../core/types.js";
16
+ import { type CapabilityInventory } from "../core/capabilitySelection.js";
17
+ import { type NativeMemoryStatus } from "../lib/nativeMemory.js";
16
18
  import type { MigrateKind, MigratePlan } from "./migrate.js";
17
19
  import type { SyncReport } from "./sync.js";
18
20
  import type { McpSyncReport } from "./mcp.js";
19
21
  import type { SecretsAuditReport } from "./secretsAudit.js";
20
22
  import type { MemorySyncResult } from "./memory.js";
21
23
  import type { DoctorReport } from "./doctor.js";
24
+ import type { RollbackReport } from "./rollback.js";
22
25
  import type { ConfirmAndInstallOptions } from "../lib/installAgent.js";
23
26
  import type { VerdictItem } from "./onboardVerdict.js";
27
+ /**
28
+ * Scores only real source-side content. The recommendation is a hint for a
29
+ * first-time user, never a filter: every candidate remains selectable.
30
+ */
31
+ export declare function migrationSourceScore(summary: Pick<OnboardAgentSummary, "skillCount" | "mcpServerCount" | "hasRealInstructions">): number;
32
+ export declare function recommendedMigrationSource(summaries: readonly (Pick<OnboardAgentSummary, "agent" | "skillCount" | "mcpServerCount" | "hasRealInstructions">)[]): AgentId | undefined;
33
+ export declare const MCP_ROUTE_OPTIONS: ({
34
+ mode: "gateway";
35
+ label: string;
36
+ } | {
37
+ mode: "direct";
38
+ label: string;
39
+ } | {
40
+ mode: "hub";
41
+ label: string;
42
+ })[];
43
+ export declare function interactiveMcpRouteOptions(hubConfigured: boolean): Array<{
44
+ mode: McpRouteMode;
45
+ label: string;
46
+ disabled?: boolean;
47
+ }>;
24
48
  export interface OnboardAgentSummary {
25
49
  agent: AgentId;
26
50
  present: boolean;
@@ -37,8 +61,13 @@ export interface OnboardAgentSummary {
37
61
  * memory). 0 for pi, which has no MCP reader at all — not a gap here,
38
62
  * the same fact `migrate.ts` already establishes. */
39
63
  mcpServerCount: number;
64
+ mcpServerNames: string[];
65
+ nativeMemoryStatus: NativeMemoryStatus;
66
+ nativeMemoryCount: number;
67
+ nativeMemoryNames: string[];
68
+ nativeMemoryDetail: string;
40
69
  }
41
- export declare function collectOnboardSummary(homeDir?: string): Promise<OnboardAgentSummary[]>;
70
+ export declare function collectOnboardSummary(homeDir?: string, workspaceDir?: string): Promise<OnboardAgentSummary[]>;
42
71
  export interface RunOnboardOptions {
43
72
  /** Non-interactive migration-source choice. */
44
73
  agent?: string;
@@ -60,10 +89,19 @@ export interface RunOnboardOptions {
60
89
  * Omitted leaves whatever's already configured untouched — same
61
90
  * no-prompt posture as `mcpMode` (design.md D12). */
62
91
  memory?: string;
92
+ /** Non-interactive native-source memory migration toggle: `"on"` or
93
+ * `"off"`. Omitted preserves the current state and prompts only when
94
+ * supported source candidates are available in a real terminal. */
95
+ memoryMigrate?: string;
96
+ /** Optional YAML/JSON item-level capability selection for automation. */
97
+ selectionFile?: string;
63
98
  dryRun?: boolean;
64
99
  json?: boolean;
65
100
  /** Defaults to the real `~`; overridable for tests only. */
66
101
  homeDir?: string;
102
+ /** Defaults to the current working directory; controls project-scoped
103
+ * native-memory discovery and is overridable for tests. */
104
+ workspaceDir?: string;
67
105
  /** Test-only: overrides the real `process.stdin.isTTY` check so the
68
106
  * interactive-vs-refuse branch is exercisable without a real terminal. */
69
107
  isTTY?: boolean;
@@ -84,6 +122,13 @@ export interface RunOnboardOptions {
84
122
  * (design.md D9). `true` means "apply for real", matching what
85
123
  * accepting the real picker's "Yes, apply now" option means. */
86
124
  promptToApply?: () => Promise<boolean>;
125
+ /** Test-only: replaces the real mode-transition confirmation. */
126
+ promptForModeChange?: (previous: "direct" | "hub" | "gateway", next: "direct" | "hub" | "gateway", agents: readonly AgentId[]) => Promise<boolean>;
127
+ /** Test-only: replaces the interactive shared-Memory choice. `keep` leaves
128
+ * the existing state untouched; the real picker puts that choice first. */
129
+ promptForMemory?: (current: "on" | "off") => Promise<"keep" | "on" | "off">;
130
+ /** Test-only: replaces the interactive native-memory migration choice. */
131
+ promptForMemoryMigration?: (source: AgentId, count: number) => Promise<"keep" | "on" | "off">;
87
132
  /** Test-only: injected into every `confirmAndInstall` call for a
88
133
  * selected, not-yet-present agent. Never a real terminal prompt or a
89
134
  * real `npm install` in a unit test. */
@@ -96,6 +141,23 @@ export interface OnboardInstallResult {
96
141
  }
97
142
  export interface OnboardResult {
98
143
  summary: OnboardAgentSummary[];
144
+ inventory?: CapabilityInventory;
145
+ capabilitySummary?: {
146
+ awarenessSkill: boolean;
147
+ globalInstructions: {
148
+ available: boolean;
149
+ native: boolean;
150
+ runtimeReadable: boolean;
151
+ };
152
+ skills: number;
153
+ memories: number;
154
+ mcpServers: number;
155
+ };
156
+ managedAgentRuntime?: Array<{
157
+ agent: AgentId;
158
+ delivery: "native" | "mcp" | "both";
159
+ route: "direct" | "gateway" | "hub";
160
+ }>;
99
161
  source?: AgentId;
100
162
  sourceReason?: "auto-selected" | "flag" | "prompt";
101
163
  /** The full managed set this run acted against — the union of whatever
@@ -131,6 +193,8 @@ export interface OnboardResult {
131
193
  * inconsistent across agents independent of this run.
132
194
  */
133
195
  doctorReport?: DoctorReport;
196
+ /** Present when a blocking real run was automatically restored. */
197
+ rollback?: RollbackReport;
134
198
  /**
135
199
  * The resolved MCP mode after this run (trellis-onboard-mcp-mode
136
200
  * design.md D7) — `current` reflects canonical's state whether or not
@@ -165,6 +229,14 @@ export interface OnboardResult {
165
229
  */
166
230
  verdict: VerdictItem[];
167
231
  }
232
+ /** Converges explicit per-Agent route lists with the shared Memory toggle.
233
+ * Legacy/top-level routes without a `servers` list already expose every
234
+ * eligible server and need no rewrite. Hub routes are intentionally opaque:
235
+ * the external hub owns its upstream set. */
236
+ export declare function mergeMemoryIntoExplicitRoutes(mcp: McpConfig, managedAgents: readonly AgentId[], memoryEnabled: boolean): {
237
+ mcp: McpConfig;
238
+ changed: boolean;
239
+ };
168
240
  export declare function collectOnboardPlan(opts?: RunOnboardOptions): Promise<OnboardResult>;
169
241
  export declare function runOnboard(opts?: RunOnboardOptions): Promise<{
170
242
  exitCode: number;