@ag-eco/agentplate-cli 0.13.1 → 0.13.3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ag-eco/agentplate-cli",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.3",
|
|
4
4
|
"description": "Multi-agent orchestration for AI coding agents — spawn workers in git worktrees via tmux, coordinate through SQLite mail, merge with tiered conflict resolution. Pluggable runtime adapters for Claude Code, Pi, and more.",
|
|
5
5
|
"author": "Jaymin West",
|
|
6
6
|
"license": "MIT",
|
|
@@ -473,6 +473,23 @@ describe("initCommand: --name flag", () => {
|
|
|
473
473
|
* Build a Spawner that returns preset responses keyed by "arg0 arg1 ..." prefix.
|
|
474
474
|
* Records all calls for assertion.
|
|
475
475
|
*/
|
|
476
|
+
/**
|
|
477
|
+
* Normalize the bundled tool invocation `[bun, <…/tools/<tool>/entry.ts>, ...cmd]`
|
|
478
|
+
* back to the logical `[cli, ...cmd]` (e.g. `["lm", "init"]`) so tests can keep
|
|
479
|
+
* asserting on the user-facing command shape regardless of how init spawns it.
|
|
480
|
+
*/
|
|
481
|
+
function normalizeToolArgs(args: string[]): string[] {
|
|
482
|
+
const entry = args[1] ?? "";
|
|
483
|
+
const cli = entry.includes("/tools/loam/")
|
|
484
|
+
? "lm"
|
|
485
|
+
: entry.includes("/tools/sprout/")
|
|
486
|
+
? "sr"
|
|
487
|
+
: entry.includes("/tools/trellis/")
|
|
488
|
+
? "tl"
|
|
489
|
+
: null;
|
|
490
|
+
return cli ? [cli, ...args.slice(2)] : args;
|
|
491
|
+
}
|
|
492
|
+
|
|
476
493
|
function createMockSpawner(
|
|
477
494
|
responses: Record<string, { exitCode: number; stdout: string; stderr: string }>,
|
|
478
495
|
): {
|
|
@@ -480,7 +497,8 @@ function createMockSpawner(
|
|
|
480
497
|
calls: string[][];
|
|
481
498
|
} {
|
|
482
499
|
const calls: string[][] = [];
|
|
483
|
-
const spawner: Spawner = async (
|
|
500
|
+
const spawner: Spawner = async (rawArgs) => {
|
|
501
|
+
const args = normalizeToolArgs(rawArgs);
|
|
484
502
|
calls.push(args);
|
|
485
503
|
const key = args.join(" ");
|
|
486
504
|
// Longest prefix match
|
package/src/commands/init.ts
CHANGED
|
@@ -52,17 +52,54 @@ const defaultSpawner: Spawner = async (args, opts) => {
|
|
|
52
52
|
interface SiblingTool {
|
|
53
53
|
name: string;
|
|
54
54
|
cli: string;
|
|
55
|
+
/** Bundled entrypoint, relative to this file (src/commands/). */
|
|
56
|
+
entry: string;
|
|
55
57
|
dotDir: string;
|
|
56
58
|
initCmd: string[];
|
|
57
59
|
onboardCmd: string[];
|
|
58
60
|
}
|
|
59
61
|
|
|
62
|
+
// loam/sprout/trellis are bundled inside this package (src/tools/*), so they are
|
|
63
|
+
// invoked via their bundled entrypoints with the current bun runtime rather than
|
|
64
|
+
// looked up as `lm`/`sr`/`tl` on PATH. This makes `ap init` work even when
|
|
65
|
+
// ~/.npm-global/bin (or wherever the package bins live) isn't on the PATH of the
|
|
66
|
+
// `ap` process — the cause of spurious "loam/sprout/trellis not installed" errors.
|
|
60
67
|
const SIBLING_TOOLS: SiblingTool[] = [
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
{
|
|
69
|
+
name: "loam",
|
|
70
|
+
cli: "lm",
|
|
71
|
+
entry: "../tools/loam/cli.ts",
|
|
72
|
+
dotDir: ".loam",
|
|
73
|
+
initCmd: ["init"],
|
|
74
|
+
onboardCmd: ["onboard"],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "sprout",
|
|
78
|
+
cli: "sr",
|
|
79
|
+
entry: "../tools/sprout/index.ts",
|
|
80
|
+
dotDir: ".sprout",
|
|
81
|
+
initCmd: ["init"],
|
|
82
|
+
onboardCmd: ["onboard"],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "trellis",
|
|
86
|
+
cli: "tl",
|
|
87
|
+
entry: "../tools/trellis/index.ts",
|
|
88
|
+
dotDir: ".trellis",
|
|
89
|
+
initCmd: ["init"],
|
|
90
|
+
onboardCmd: ["onboard"],
|
|
91
|
+
},
|
|
64
92
|
];
|
|
65
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Build the argv to run a bundled tool's CLI: the current bun runtime plus the
|
|
96
|
+
* tool's entrypoint resolved inside this package. PATH-independent.
|
|
97
|
+
*/
|
|
98
|
+
function toolArgv(tool: SiblingTool, ...cmd: string[]): string[] {
|
|
99
|
+
const entryPath = new URL(tool.entry, import.meta.url).pathname;
|
|
100
|
+
return [process.execPath, entryPath, ...cmd];
|
|
101
|
+
}
|
|
102
|
+
|
|
66
103
|
type ToolStatus = "initialized" | "already_initialized" | "skipped";
|
|
67
104
|
type OnboardStatus = "appended" | "current";
|
|
68
105
|
|
|
@@ -85,9 +122,9 @@ export function resolveToolSet(opts: InitOptions): SiblingTool[] {
|
|
|
85
122
|
});
|
|
86
123
|
}
|
|
87
124
|
|
|
88
|
-
async function isToolInstalled(
|
|
125
|
+
async function isToolInstalled(tool: SiblingTool, spawner: Spawner): Promise<boolean> {
|
|
89
126
|
try {
|
|
90
|
-
const result = await spawner(
|
|
127
|
+
const result = await spawner(toolArgv(tool, "--version"));
|
|
91
128
|
return result.exitCode === 0;
|
|
92
129
|
} catch {
|
|
93
130
|
return false;
|
|
@@ -99,18 +136,20 @@ async function initSiblingTool(
|
|
|
99
136
|
projectRoot: string,
|
|
100
137
|
spawner: Spawner,
|
|
101
138
|
): Promise<ToolStatus> {
|
|
102
|
-
const installed = await isToolInstalled(tool
|
|
139
|
+
const installed = await isToolInstalled(tool, spawner);
|
|
103
140
|
if (!installed) {
|
|
141
|
+
// Bundled in this package — if this fires, the agentplate install itself
|
|
142
|
+
// is incomplete rather than a missing separate package.
|
|
104
143
|
printWarning(
|
|
105
|
-
`${tool.name}
|
|
106
|
-
|
|
144
|
+
`${tool.name} unavailable — skipping`,
|
|
145
|
+
"bundled in @ag-eco/agentplate-cli; try reinstalling: npm i -g @ag-eco/agentplate-cli",
|
|
107
146
|
);
|
|
108
147
|
return "skipped";
|
|
109
148
|
}
|
|
110
149
|
|
|
111
150
|
let result: { exitCode: number; stdout: string; stderr: string };
|
|
112
151
|
try {
|
|
113
|
-
result = await spawner(
|
|
152
|
+
result = await spawner(toolArgv(tool, ...tool.initCmd), { cwd: projectRoot });
|
|
114
153
|
} catch (err) {
|
|
115
154
|
// Spawn failure (e.g. ENOENT) — treat as not installed
|
|
116
155
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -138,11 +177,11 @@ async function onboardTool(
|
|
|
138
177
|
projectRoot: string,
|
|
139
178
|
spawner: Spawner,
|
|
140
179
|
): Promise<OnboardStatus> {
|
|
141
|
-
const installed = await isToolInstalled(tool
|
|
180
|
+
const installed = await isToolInstalled(tool, spawner);
|
|
142
181
|
if (!installed) return "current";
|
|
143
182
|
|
|
144
183
|
try {
|
|
145
|
-
const result = await spawner(
|
|
184
|
+
const result = await spawner(toolArgv(tool, ...tool.onboardCmd), { cwd: projectRoot });
|
|
146
185
|
return result.exitCode === 0 ? "appended" : "current";
|
|
147
186
|
} catch {
|
|
148
187
|
return "current";
|
|
@@ -49,14 +49,17 @@ describe("checkDatabases", () => {
|
|
|
49
49
|
rmSync(tempDir, { recursive: true, force: true });
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
test("fails
|
|
52
|
+
test("fails only for sessions.db when no databases exist (mail/metrics/merge-queue are optional)", () => {
|
|
53
53
|
const checks = checkDatabases(mockConfig, tempDir) as DoctorCheck[];
|
|
54
54
|
|
|
55
55
|
expect(checks).toHaveLength(4);
|
|
56
|
-
|
|
56
|
+
// mail.db and metrics.db are created lazily on first write (first mail /
|
|
57
|
+
// first session-end metric) — their absence in a fresh project is normal.
|
|
58
|
+
expect(checks[0]?.status).toBe("pass");
|
|
57
59
|
expect(checks[0]?.name).toBe("mail.db exists");
|
|
58
|
-
expect(checks[1]?.status).toBe("
|
|
60
|
+
expect(checks[1]?.status).toBe("pass");
|
|
59
61
|
expect(checks[1]?.name).toBe("metrics.db exists");
|
|
62
|
+
// sessions.db is created at `ap init` (run creation), so its absence is a failure.
|
|
60
63
|
expect(checks[2]?.status).toBe("fail");
|
|
61
64
|
expect(checks[2]?.name).toBe("sessions.db exists");
|
|
62
65
|
// merge-queue.db is created lazily on first merge — its absence is normal.
|
package/src/doctor/databases.ts
CHANGED
|
@@ -21,6 +21,7 @@ export const checkDatabases: DoctorCheckFn = (_config, agentplateDir): DoctorChe
|
|
|
21
21
|
}> = [
|
|
22
22
|
{
|
|
23
23
|
name: "mail.db",
|
|
24
|
+
optional: true,
|
|
24
25
|
tables: ["messages"],
|
|
25
26
|
requiredColumns: {
|
|
26
27
|
messages: [
|
|
@@ -40,6 +41,7 @@ export const checkDatabases: DoctorCheckFn = (_config, agentplateDir): DoctorChe
|
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
43
|
name: "metrics.db",
|
|
44
|
+
optional: true,
|
|
43
45
|
tables: ["sessions"],
|
|
44
46
|
requiredColumns: {
|
|
45
47
|
sessions: [
|
|
@@ -246,7 +246,9 @@ describe("checkEcosystem", () => {
|
|
|
246
246
|
const results = await check(mockConfig, "/tmp/.agentplate");
|
|
247
247
|
|
|
248
248
|
const loam = results.find((r) => r.name === "loam semver");
|
|
249
|
-
|
|
249
|
+
// loam/sprout/trellis are bundled into @ag-eco/agentplate-cli now, so the
|
|
250
|
+
// install hint points at the single package, not a standalone @ag-eco/loam-cli.
|
|
251
|
+
const hasHint = loam?.details?.some((d) => d.includes("@ag-eco/agentplate-cli"));
|
|
250
252
|
expect(hasHint).toBe(true);
|
|
251
253
|
});
|
|
252
254
|
|
package/src/version.ts
CHANGED