agent-trellis 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/memory.d.ts +8 -0
- package/dist/commands/memory.js +21 -10
- package/dist/commands/onboard.d.ts +9 -0
- package/dist/commands/onboard.js +50 -33
- package/docs/getting-started.md +15 -6
- package/docs/roadmap.md +30 -0
- package/package.json +1 -1
|
@@ -34,6 +34,14 @@ export type MemorySyncResult = {
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function collectMemorySyncResult(homeDir?: string): MemorySyncResult;
|
|
36
36
|
export declare function applyMemorySync(result: MemorySyncResult): void;
|
|
37
|
+
/**
|
|
38
|
+
* Extracted from `runMemorySync` (trellis-onboard-mcp-memory) so
|
|
39
|
+
* `onboard`'s own chained output can print this stage in the exact same
|
|
40
|
+
* format without a second, drifting copy — mirrors the
|
|
41
|
+
* `collect...Report`/`print...Report` export pair every other chained
|
|
42
|
+
* stage (`sync`, `mcp sync`, `secrets audit`) already has.
|
|
43
|
+
*/
|
|
44
|
+
export declare function printMemorySyncResult(result: MemorySyncResult, dryRun: boolean): void;
|
|
37
45
|
export declare function runMemorySync(opts?: RunMemorySyncOptions): {
|
|
38
46
|
exitCode: number;
|
|
39
47
|
};
|
package/dist/commands/memory.js
CHANGED
|
@@ -45,6 +45,26 @@ export function applyMemorySync(result) {
|
|
|
45
45
|
mkdirSync(dirname(result.graphPath), { recursive: true });
|
|
46
46
|
writeFileSync(result.graphPath, renderMemoryGraph(result.plan.nextGraph));
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Extracted from `runMemorySync` (trellis-onboard-mcp-memory) so
|
|
50
|
+
* `onboard`'s own chained output can print this stage in the exact same
|
|
51
|
+
* format without a second, drifting copy — mirrors the
|
|
52
|
+
* `collect...Report`/`print...Report` export pair every other chained
|
|
53
|
+
* stage (`sync`, `mcp sync`, `secrets audit`) already has.
|
|
54
|
+
*/
|
|
55
|
+
export function printMemorySyncResult(result, dryRun) {
|
|
56
|
+
if (!result.configured) {
|
|
57
|
+
console.log(result.reason);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(`${dryRun ? "[dry run] " : ""}memory sync — ${result.graphPath}`);
|
|
61
|
+
if (result.plan.items.length === 0) {
|
|
62
|
+
console.log(" nothing in canonical memories/ yet");
|
|
63
|
+
}
|
|
64
|
+
for (const item of result.plan.items) {
|
|
65
|
+
console.log(` [${item.action}] "${item.name}" — ${item.detail}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
48
68
|
export function runMemorySync(opts = {}) {
|
|
49
69
|
const homeDir = opts.homeDir ?? homedir();
|
|
50
70
|
let result;
|
|
@@ -61,17 +81,8 @@ export function runMemorySync(opts = {}) {
|
|
|
61
81
|
if (opts.json) {
|
|
62
82
|
console.log(JSON.stringify(result, null, 2));
|
|
63
83
|
}
|
|
64
|
-
else if (!result.configured) {
|
|
65
|
-
console.log(result.reason);
|
|
66
|
-
}
|
|
67
84
|
else {
|
|
68
|
-
|
|
69
|
-
if (result.plan.items.length === 0) {
|
|
70
|
-
console.log(" nothing in canonical memories/ yet");
|
|
71
|
-
}
|
|
72
|
-
for (const item of result.plan.items) {
|
|
73
|
-
console.log(` [${item.action}] "${item.name}" — ${item.detail}`);
|
|
74
|
-
}
|
|
85
|
+
printMemorySyncResult(result, opts.dryRun ?? false);
|
|
75
86
|
}
|
|
76
87
|
const hasConflict = result.configured && result.plan.items.some((i) => i.action === "conflict");
|
|
77
88
|
return { exitCode: hasConflict ? 1 : 0 };
|
|
@@ -17,6 +17,7 @@ import type { MigrateKind, MigratePlan } from "./migrate.js";
|
|
|
17
17
|
import type { SyncReport } from "./sync.js";
|
|
18
18
|
import type { McpSyncReport } from "./mcp.js";
|
|
19
19
|
import type { SecretsAuditReport } from "./secretsAudit.js";
|
|
20
|
+
import type { MemorySyncResult } from "./memory.js";
|
|
20
21
|
import type { ConfirmAndInstallOptions } from "../lib/installAgent.js";
|
|
21
22
|
export interface OnboardAgentSummary {
|
|
22
23
|
agent: AgentId;
|
|
@@ -27,6 +28,13 @@ export interface OnboardAgentSummary {
|
|
|
27
28
|
* of that agent's own to potentially migrate, not a judgment about
|
|
28
29
|
* its quality or length. */
|
|
29
30
|
hasRealInstructions: boolean;
|
|
31
|
+
/** How many real MCP servers `migrate --only mcp` would find for this
|
|
32
|
+
* agent — computed via `collectMigratePlan(agent, homeDir, ["mcp"])`
|
|
33
|
+
* rather than a second reader dispatch, so this always agrees with
|
|
34
|
+
* what migrate itself will do (design.md D1, trellis-onboard-mcp-
|
|
35
|
+
* memory). 0 for pi, which has no MCP reader at all — not a gap here,
|
|
36
|
+
* the same fact `migrate.ts` already establishes. */
|
|
37
|
+
mcpServerCount: number;
|
|
30
38
|
}
|
|
31
39
|
export declare function collectOnboardSummary(homeDir?: string): Promise<OnboardAgentSummary[]>;
|
|
32
40
|
export interface RunOnboardOptions {
|
|
@@ -82,6 +90,7 @@ export interface OnboardResult {
|
|
|
82
90
|
migrateSkipped?: string;
|
|
83
91
|
syncReport?: SyncReport;
|
|
84
92
|
mcpSyncReport?: McpSyncReport;
|
|
93
|
+
memorySyncResult?: MemorySyncResult;
|
|
85
94
|
secretsAuditReport?: SecretsAuditReport;
|
|
86
95
|
refusal?: string;
|
|
87
96
|
/** Only set when no agent is present — the same values `--json` and
|
package/dist/commands/onboard.js
CHANGED
|
@@ -28,6 +28,7 @@ import { applyMigratePlan, collectMigratePlan, printPlan as printMigratePlan } f
|
|
|
28
28
|
import { collectSyncReport, printReport as printSyncReport } from "./sync.js";
|
|
29
29
|
import { collectMcpSyncReport, printReport as printMcpSyncReport } from "./mcp.js";
|
|
30
30
|
import { collectSecretsAuditReport, printReport as printSecretsAuditReport } from "./secretsAudit.js";
|
|
31
|
+
import { applyMemorySync, collectMemorySyncResult, printMemorySyncResult } from "./memory.js";
|
|
31
32
|
import { openBackupSession } from "../lib/backup.js";
|
|
32
33
|
import { confirmAndInstall } from "../lib/installAgent.js";
|
|
33
34
|
const PROBES = {
|
|
@@ -40,19 +41,20 @@ export async function collectOnboardSummary(homeDir = homedir()) {
|
|
|
40
41
|
return Promise.all(ALL_AGENTS.map(async (agent) => {
|
|
41
42
|
const snapshot = await PROBES[agent](homeDir);
|
|
42
43
|
if (!snapshot.present) {
|
|
43
|
-
return { agent, present: false, skillCount: 0, skillNames: [], hasRealInstructions: false };
|
|
44
|
+
return { agent, present: false, skillCount: 0, skillNames: [], hasRealInstructions: false, mcpServerCount: 0 };
|
|
44
45
|
}
|
|
45
46
|
const skillNames = snapshot.skillRoots.flatMap((root) => root.skills.map((s) => s.name));
|
|
46
47
|
const hasRealInstructions = snapshot.instructionsFile !== undefined && !snapshot.instructionsFile.isSymlink;
|
|
47
|
-
|
|
48
|
+
const mcpPlan = await collectMigratePlan(agent, homeDir, ["mcp"]);
|
|
49
|
+
return { agent, present: true, skillCount: skillNames.length, skillNames, hasRealInstructions, mcpServerCount: mcpPlan.items.length };
|
|
48
50
|
}));
|
|
49
51
|
}
|
|
50
52
|
function hasContent(s) {
|
|
51
|
-
return s.skillCount > 0 || s.hasRealInstructions;
|
|
53
|
+
return s.skillCount > 0 || s.hasRealInstructions || s.mcpServerCount > 0;
|
|
52
54
|
}
|
|
53
55
|
function agentSummaryLabel(s) {
|
|
54
56
|
const skills = s.skillCount > 0 ? ` (${s.skillNames.join(", ")})` : "";
|
|
55
|
-
return `${s.agent} — ${s.skillCount} skill(s)${skills}, instructions: ${s.hasRealInstructions ? "yes" : "no"}`;
|
|
57
|
+
return `${s.agent} — ${s.skillCount} skill(s)${skills}, instructions: ${s.hasRealInstructions ? "yes" : "no"}, mcp: ${s.mcpServerCount}`;
|
|
56
58
|
}
|
|
57
59
|
/** Numbered-typing fallback (trellis-onboard-interactive-picker design.md
|
|
58
60
|
* D2) — used only when the terminal can't support the raw-mode picker
|
|
@@ -144,48 +146,47 @@ async function promptForManagedAgentsReal(candidates, alreadyManaged) {
|
|
|
144
146
|
}
|
|
145
147
|
/**
|
|
146
148
|
* Resolves which categories (skills, instructions) to migrate from a
|
|
147
|
-
* resolved source (trellis-migrate-category-selection
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
149
|
+
* resolved source (trellis-migrate-category-selection, extended to a
|
|
150
|
+
* third category by trellis-onboard-mcp-memory design.md D2). Unlike the
|
|
151
|
+
* two pickers above, there is no numbered-text fallback to preserve
|
|
152
|
+
* parity with — this concept never existed before this change, so
|
|
153
|
+
* "can't prompt" simply means "default to whichever kind(s) actually
|
|
154
|
+
* have real content, silently" (design.md D4). The picker itself is
|
|
155
|
+
* only offered when the choice is meaningful — two or more kinds
|
|
156
|
+
* present, a capable terminal, and not a `--json` run (design.md D5).
|
|
157
|
+
* An empty result is a valid answer: "skip migrate for this run"
|
|
158
|
+
* (design.md D6), left for the caller to act on.
|
|
156
159
|
*/
|
|
157
160
|
async function resolveMigrateCategories(source, opts) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (
|
|
161
|
+
// Built dynamically, in skill/instructions/mcp display order — not a
|
|
162
|
+
// fixed two- or three-slot structure, so a fourth category some day
|
|
163
|
+
// would only need an entry here, not a rewritten branch (design.md D2).
|
|
164
|
+
const candidates = [];
|
|
165
|
+
if (source.skillCount > 0)
|
|
166
|
+
candidates.push({ kind: "skill", label: "skills" });
|
|
167
|
+
if (source.hasRealInstructions)
|
|
168
|
+
candidates.push({ kind: "instructions", label: "instructions" });
|
|
169
|
+
if (source.mcpServerCount > 0)
|
|
170
|
+
candidates.push({ kind: "mcp", label: "mcp" });
|
|
171
|
+
// The choice is only meaningful when two or more kinds are real — same
|
|
172
|
+
// gate for the injected test seam as for the real picker, mirroring
|
|
173
|
+
// how `promptForAgent`/`promptForManagedAgents` are only ever
|
|
174
|
+
// consulted when their own real prompt would actually apply.
|
|
175
|
+
if (candidates.length > 1 && !opts.json) {
|
|
165
176
|
if (opts.promptForMigrateCategories) {
|
|
166
177
|
return opts.promptForMigrateCategories(source);
|
|
167
178
|
}
|
|
168
179
|
if (canUseInteractivePicker()) {
|
|
169
180
|
console.log(`Which categories should be migrated from ${source.agent}? Space to toggle, Enter to confirm:`);
|
|
170
|
-
const indices = await runMultiSelectPicker(
|
|
181
|
+
const indices = await runMultiSelectPicker(candidates.map((c) => c.label), candidates.map(() => true));
|
|
171
182
|
if (indices === null) {
|
|
172
183
|
console.log("cancelled, no changes made");
|
|
173
184
|
process.exit(1);
|
|
174
185
|
}
|
|
175
|
-
|
|
176
|
-
if (indices.includes(0))
|
|
177
|
-
kinds.push("skill");
|
|
178
|
-
if (indices.includes(1))
|
|
179
|
-
kinds.push("instructions");
|
|
180
|
-
return kinds;
|
|
186
|
+
return indices.map((i) => candidates[i].kind);
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
|
-
|
|
184
|
-
if (wantsSkills)
|
|
185
|
-
kinds.push("skill");
|
|
186
|
-
if (wantsInstructions)
|
|
187
|
-
kinds.push("instructions");
|
|
188
|
-
return kinds;
|
|
189
|
+
return candidates.map((c) => c.kind);
|
|
189
190
|
}
|
|
190
191
|
/** Shared by `--manage` and the interactive prompt's answer — same
|
|
191
192
|
* grammar either way (design.md D4): a real agent id list, comma- or
|
|
@@ -343,6 +344,15 @@ export async function collectOnboardPlan(opts = {}) {
|
|
|
343
344
|
const syncReport = await collectSyncReport({ homeDir, dryRun: opts.dryRun, managedAgents, backupSession });
|
|
344
345
|
const mcpSyncReport = await collectMcpSyncReport({ homeDir, dryRun: opts.dryRun, managedAgents, backupSession });
|
|
345
346
|
backupSession?.finalize();
|
|
347
|
+
// Independent of `managedAgents` — the shared memory server is not
|
|
348
|
+
// per-agent (design.md D4, trellis-onboard-mcp-memory), unlike
|
|
349
|
+
// sync/mcp-sync above. Runs unconditionally once reached; an
|
|
350
|
+
// unconfigured `memory` server is a legitimate "nothing to do yet"
|
|
351
|
+
// state (design.md D5), not gated on any prior step here.
|
|
352
|
+
const memorySyncResult = collectMemorySyncResult(homeDir);
|
|
353
|
+
if (!opts.dryRun) {
|
|
354
|
+
applyMemorySync(memorySyncResult);
|
|
355
|
+
}
|
|
346
356
|
// Read-only, no dryRun concept — same report either way, run last since
|
|
347
357
|
// it audits the config mcp sync just wrote (or, on --dry-run, whatever
|
|
348
358
|
// was already there before this run).
|
|
@@ -357,6 +367,7 @@ export async function collectOnboardPlan(opts = {}) {
|
|
|
357
367
|
migrateSkipped,
|
|
358
368
|
syncReport,
|
|
359
369
|
mcpSyncReport,
|
|
370
|
+
memorySyncResult,
|
|
360
371
|
secretsAuditReport,
|
|
361
372
|
};
|
|
362
373
|
}
|
|
@@ -370,9 +381,11 @@ export async function runOnboard(opts = {}) {
|
|
|
370
381
|
}
|
|
371
382
|
if (result.refusal)
|
|
372
383
|
return { exitCode: 1 };
|
|
384
|
+
const memorySyncConflict = result.memorySyncResult?.configured === true && result.memorySyncResult.plan.items.some((i) => i.action === "conflict");
|
|
373
385
|
const hasConflict = (result.migratePlan?.items.some((i) => i.action === "conflict") ?? false) ||
|
|
374
386
|
(result.syncReport?.reports.some((r) => r.items.some((i) => i.action === "conflict")) ?? false) ||
|
|
375
387
|
(result.mcpSyncReport?.reports.some((r) => r.items.some((i) => i.action === "conflict")) ?? false) ||
|
|
388
|
+
memorySyncConflict ||
|
|
376
389
|
(result.secretsAuditReport?.findings.length ?? 0) > 0;
|
|
377
390
|
return { exitCode: hasConflict ? 1 : 0 };
|
|
378
391
|
}
|
|
@@ -431,6 +444,10 @@ function printResult(result, dryRun) {
|
|
|
431
444
|
console.log("\nmcp sync");
|
|
432
445
|
printMcpSyncReport(result.mcpSyncReport, false);
|
|
433
446
|
}
|
|
447
|
+
if (result.memorySyncResult) {
|
|
448
|
+
console.log("\nmemory sync");
|
|
449
|
+
printMemorySyncResult(result.memorySyncResult, false);
|
|
450
|
+
}
|
|
434
451
|
if (result.secretsAuditReport) {
|
|
435
452
|
console.log("\nsecrets audit");
|
|
436
453
|
printSecretsAuditReport(result.secretsAuditReport);
|
package/docs/getting-started.md
CHANGED
|
@@ -17,17 +17,23 @@ $ trellis onboard
|
|
|
17
17
|
|
|
18
18
|
Runs `init`, detects which of Claude Code/Codex/Kiro/pi are on this machine,
|
|
19
19
|
then resolves two independent choices before running `migrate`, `sync`,
|
|
20
|
-
`mcp sync`, and `secrets audit` — the whole onboarding path,
|
|
21
|
-
commands to type by hand:
|
|
20
|
+
`mcp sync`, `memory sync`, and `secrets audit` — the whole onboarding path,
|
|
21
|
+
no follow-up commands to type by hand:
|
|
22
22
|
|
|
23
23
|
1. **Migration source** — read from, at most one, never written back to.
|
|
24
|
+
"Real content" means skills, custom instructions, *or* real MCP servers
|
|
25
|
+
— an agent whose only real content is its MCP servers is still a valid
|
|
26
|
+
source.
|
|
24
27
|
- **No agent has real content**: skipped — canonical starts from `init`'s
|
|
25
28
|
placeholder.
|
|
26
29
|
- **Exactly one agent has real content**: auto-selected, no prompt.
|
|
27
30
|
- **Two or more**: prompts you to choose (Up/Down or j/k, Enter to confirm,
|
|
28
31
|
on a real terminal that supports it — falls back to a numbered
|
|
29
32
|
type-a-digit prompt otherwise), or pass `--agent <id>` to skip the
|
|
30
|
-
prompt entirely.
|
|
33
|
+
prompt entirely. Which *categories* to bring in from that source
|
|
34
|
+
(skills, instructions, mcp) is its own checkbox, shown only when the
|
|
35
|
+
source has real content in two or more of them — with just one, that
|
|
36
|
+
one is migrated unprompted.
|
|
31
37
|
2. **Managed set** — zero or more agents to actually write to. Always an
|
|
32
38
|
explicit choice: pass `--manage <ids>` (comma-separated, e.g. `--manage
|
|
33
39
|
pi,codex`) or `--manage none`, or answer the interactive checkbox prompt
|
|
@@ -54,6 +60,9 @@ sync
|
|
|
54
60
|
mcp sync
|
|
55
61
|
✅ pi — already in sync
|
|
56
62
|
|
|
63
|
+
memory sync
|
|
64
|
+
no "memory" MCP server with static_env.MEMORY_FILE_PATH configured in servers.yaml — see schema/servers.example.yaml
|
|
65
|
+
|
|
57
66
|
secrets audit
|
|
58
67
|
✅ no findings — every present agent's real config and every declared env var passed all checks
|
|
59
68
|
```
|
|
@@ -63,9 +72,9 @@ it's present and was the migration source, but it isn't managed, so it's
|
|
|
63
72
|
never even probed as a sync target, not just left with zero items.
|
|
64
73
|
|
|
65
74
|
Add `--dry-run` to preview the entire chain — init/migrate/sync/mcp
|
|
66
|
-
sync, including what would be written to
|
|
67
|
-
zero writes anywhere (secrets audit is
|
|
68
|
-
the flag).
|
|
75
|
+
sync/memory sync, including what would be written to
|
|
76
|
+
`~/.trellis/managed.yaml` — with zero writes anywhere (secrets audit is
|
|
77
|
+
always read-only, with or without the flag).
|
|
69
78
|
|
|
70
79
|
**A managed agent's own real content still isn't overwritten.** If you
|
|
71
80
|
explicitly include the source in `--manage`, sync still never overwrites
|
package/docs/roadmap.md
CHANGED
|
@@ -899,6 +899,35 @@ byte-identical for both transports, now covered by its own test), so
|
|
|
899
899
|
that distinction was never stored in the first place. 350/350 tests
|
|
900
900
|
passing.
|
|
901
901
|
|
|
902
|
+
**P17 (✅ done, archived
|
|
903
|
+
[2026-09-13-trellis-onboard-mcp-memory](../openspec/changes/archive/2026-09-13-trellis-onboard-mcp-memory/)):
|
|
904
|
+
`onboard` catches up to P15/P16 — mcp and memory were never wired into
|
|
905
|
+
its own orchestration.** Found by live dogfooding on a real machine:
|
|
906
|
+
`onboard`'s migrate-category picker hardcoded `["skills",
|
|
907
|
+
"instructions"]` — `mcp` was invisible to it regardless of how many real
|
|
908
|
+
MCP servers the source agent had — and `trellis memory sync` was never
|
|
909
|
+
called anywhere in `onboard`'s chain at all, despite its own docstring
|
|
910
|
+
naming a complete chain. `OnboardAgentSummary` gains an
|
|
911
|
+
`mcpServerCount`, computed via the already-exported
|
|
912
|
+
`collectMigratePlan(agent, homeDir, ["mcp"])` rather than a second reader
|
|
913
|
+
dispatch — so it always agrees with what `migrate` itself would do, and
|
|
914
|
+
an agent whose only real content is MCP servers is now a valid migration
|
|
915
|
+
source (previously invisible to `hasContent` entirely).
|
|
916
|
+
`resolveMigrateCategories` was rewritten from a fixed two-slot structure
|
|
917
|
+
to a dynamically-built list of whichever of skill/instructions/mcp have
|
|
918
|
+
real content, offering the checkbox only when two or more do — not a
|
|
919
|
+
bolted-on special case for a third option. `memory sync` runs as a new
|
|
920
|
+
final chained stage, after `mcp sync` and before `secrets audit`,
|
|
921
|
+
independent of the resolved managed-agent set (the memory server is
|
|
922
|
+
shared, not per-agent); `runMemorySync`'s inline printing was extracted
|
|
923
|
+
into an exported `printMemorySyncResult` so `onboard` reuses the exact
|
|
924
|
+
same output format rather than a second, drifting copy of it —
|
|
925
|
+
`memory.ts`'s own standalone command behavior is unchanged, confirmed by
|
|
926
|
+
its existing tests passing unmodified. No change to `migrate.ts`,
|
|
927
|
+
`mcp.ts`, or `memory.ts`'s own command behavior — purely `onboard`'s
|
|
928
|
+
orchestration layer catching up to commands that already existed. 357/357
|
|
929
|
+
tests passing.
|
|
930
|
+
|
|
902
931
|
| Phase | Deliverable | Depends on |
|
|
903
932
|
|---|---|---|
|
|
904
933
|
| P0 | ✅ `trellis doctor` — read-only, opt-in-for-handshakes scan of all four agents' current skills/MCP/instructions state, reports drift and duplicates | nothing |
|
|
@@ -918,6 +947,7 @@ passing.
|
|
|
918
947
|
| P14 | ✅ MCP server lifecycle parity with skills: ownership-tracked safe removal on sync (migrate-in closed separately by P16) | P2, P13 |
|
|
919
948
|
| P15 | ✅ Shared memory: ingest canonical `memories/*.md` into the `server-memory` store's own graph file (per-agent extraction into canonical remains a separate, open gap) | P6 |
|
|
920
949
|
| P16 | ✅ MCP migrate-in: `trellis migrate --only mcp` for claude-code/kiro/codex (codex remote transport + probe HOME-scoping closed same-day, see prose above), closing the gap P14 named | P12, P14 |
|
|
950
|
+
| P17 | ✅ `onboard` orchestration catches up to P15/P16: three-way migrate-category selection (mcp added), `memory sync` wired in as a chained stage | P15, P16 |
|
|
921
951
|
|
|
922
952
|
No dates. This is scoped by verification milestones, not calendar time.
|
|
923
953
|
Execution order for P11–P16: P11 → P12 → P13 → P14 → P15 → P16 — CRUD
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-trellis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A single source of capability for every coding agent — skills, MCP, subagents, memory, and secret policy, adapted natively into Claude Code, Codex, Kiro, and pi.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Paul Leo",
|