@app-vitals/agent-runtime 0.6.0 → 0.6.1
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 +3 -3
- package/setup.ts +18 -3
- package/setup.unit.test.ts +100 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@app-vitals/agent-runtime",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/app-vitals/agent.git",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"./workspace-paths": "./workspace-paths.ts"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@app-vitals/agent-admin": "0.6.
|
|
44
|
-
"@app-vitals/agent-lib": "0.6.
|
|
43
|
+
"@app-vitals/agent-admin": "0.6.1",
|
|
44
|
+
"@app-vitals/agent-lib": "0.6.1",
|
|
45
45
|
"@octokit/auth-app": "^8.2.0",
|
|
46
46
|
"@sentry/bun": "^10.63.0",
|
|
47
47
|
"@slack/bolt": "^5.0.0",
|
package/setup.ts
CHANGED
|
@@ -40,7 +40,18 @@ const WORKSPACE_TEMPLATE_DIR =
|
|
|
40
40
|
// Repo root — two levels up from agent/src/. In Docker this is /app; on the Pi
|
|
41
41
|
// it resolves to the checkout root. Uses a local marketplace so plugins are always
|
|
42
42
|
// available regardless of whether the GitHub repo is accessible.
|
|
43
|
-
const
|
|
43
|
+
const DEFAULT_SHIPWRIGHT_REPO_ROOT = join(import.meta.dir, "..", "..", "..");
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The repo root used for the built-in marketplace and specialty lookup.
|
|
47
|
+
* `SHIPWRIGHT_REPO_ROOT` overrides the computed default (which resolves to `/`
|
|
48
|
+
* in the platform image layout); unset or empty keeps the computed default.
|
|
49
|
+
*/
|
|
50
|
+
export function resolveShipwrightRepoRoot(
|
|
51
|
+
env: Record<string, string | undefined> = process.env,
|
|
52
|
+
): string {
|
|
53
|
+
return env.SHIPWRIGHT_REPO_ROOT || DEFAULT_SHIPWRIGHT_REPO_ROOT;
|
|
54
|
+
}
|
|
44
55
|
|
|
45
56
|
// Local marketplace name — matches the `name` field in .claude-plugin/marketplace.json.
|
|
46
57
|
const SHIPWRIGHT_MARKETPLACE = "shipwright";
|
|
@@ -73,10 +84,11 @@ const REQUIRED_TEMPLATES: readonly string[] = [
|
|
|
73
84
|
*/
|
|
74
85
|
export function resolveTemplatesDir(
|
|
75
86
|
requestedType: string | undefined,
|
|
76
|
-
|
|
87
|
+
repoRootOverride?: string,
|
|
77
88
|
warn: (message: string) => void = (m) => console.warn(m),
|
|
78
89
|
env: Record<string, string | undefined> = process.env,
|
|
79
90
|
): string {
|
|
91
|
+
const repoRoot = repoRootOverride ?? resolveShipwrightRepoRoot(env);
|
|
80
92
|
const typeName =
|
|
81
93
|
requestedType ||
|
|
82
94
|
env.SHIPWRIGHT_DEFAULT_AGENT_TYPE ||
|
|
@@ -393,7 +405,7 @@ export async function installPlugins(
|
|
|
393
405
|
execFn: ExecFn = defaultExec,
|
|
394
406
|
cwd: string = process.cwd(),
|
|
395
407
|
agentPlugins: AgentPlugin[] = [],
|
|
396
|
-
|
|
408
|
+
shipwrightRepoRootOverride?: string,
|
|
397
409
|
pluginManifestPath: string = join(
|
|
398
410
|
process.env.HOME ?? "/root",
|
|
399
411
|
".claude",
|
|
@@ -402,7 +414,10 @@ export async function installPlugins(
|
|
|
402
414
|
),
|
|
403
415
|
extraMarketplaceDirs?: string[],
|
|
404
416
|
extraMarketplacesRoot: string = BAKED_MARKETPLACES_ROOT,
|
|
417
|
+
env: Record<string, string | undefined> = process.env,
|
|
405
418
|
): Promise<void> {
|
|
419
|
+
const shipwrightRepoRoot =
|
|
420
|
+
shipwrightRepoRootOverride ?? resolveShipwrightRepoRoot(env);
|
|
406
421
|
try {
|
|
407
422
|
// Determine which extra marketplace dirs to register.
|
|
408
423
|
// Explicit list (injected via tests) takes precedence over discovery.
|
package/setup.unit.test.ts
CHANGED
|
@@ -5,7 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { describe, expect, it } from "bun:test";
|
|
8
|
-
import {
|
|
8
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import {
|
|
12
|
+
discoverBakedMarketplaces,
|
|
13
|
+
installPlugins,
|
|
14
|
+
resolveShipwrightRepoRoot,
|
|
15
|
+
resolveTemplatesDir,
|
|
16
|
+
} from "./setup.ts";
|
|
9
17
|
|
|
10
18
|
// Explicit empty extra-marketplace list — every call in this describe block
|
|
11
19
|
// must pass this (or an intentional array) instead of omitting the arg.
|
|
@@ -284,3 +292,94 @@ describe("resolveTemplatesDir option resolution (AEP-1.2)", () => {
|
|
|
284
292
|
expect(dir).toMatch(/workspace$/);
|
|
285
293
|
});
|
|
286
294
|
});
|
|
295
|
+
|
|
296
|
+
describe("SHIPWRIGHT_REPO_ROOT override (PCB-1.1)", () => {
|
|
297
|
+
const recordExec = () => {
|
|
298
|
+
const calls: string[][] = [];
|
|
299
|
+
const exec = async (_cmd: string, args: string[]) => {
|
|
300
|
+
calls.push(args);
|
|
301
|
+
return { stdout: "", exitCode: 0 };
|
|
302
|
+
};
|
|
303
|
+
return { calls, exec };
|
|
304
|
+
};
|
|
305
|
+
const registerRoot = async (env: Record<string, string | undefined>) => {
|
|
306
|
+
const { calls, exec } = recordExec();
|
|
307
|
+
await installPlugins(
|
|
308
|
+
exec,
|
|
309
|
+
"/tmp/cwd",
|
|
310
|
+
[],
|
|
311
|
+
undefined,
|
|
312
|
+
"/tmp/nonexistent-manifest.json",
|
|
313
|
+
NO_EXTRA_MARKETPLACES,
|
|
314
|
+
"/tmp/nonexistent-baked-root",
|
|
315
|
+
env,
|
|
316
|
+
);
|
|
317
|
+
return calls[0][3];
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
it("installPlugins registers the marketplace from SHIPWRIGHT_REPO_ROOT when set", async () => {
|
|
321
|
+
expect(await registerRoot({ SHIPWRIGHT_REPO_ROOT: "/opt/custom" })).toBe(
|
|
322
|
+
"/opt/custom",
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("installPlugins keeps the computed default when unset or empty", async () => {
|
|
327
|
+
const unset = await registerRoot({});
|
|
328
|
+
expect(unset).toBe(resolveShipwrightRepoRoot({}));
|
|
329
|
+
expect(unset).not.toBe("/opt/custom");
|
|
330
|
+
expect(await registerRoot({ SHIPWRIGHT_REPO_ROOT: "" })).toBe(unset);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
describe("resolveTemplatesDir", () => {
|
|
334
|
+
const makeRoot = () => {
|
|
335
|
+
const root = mkdtempSync(join(tmpdir(), "repo-root-"));
|
|
336
|
+
const dir = join(root, "specialties", "foo");
|
|
337
|
+
mkdirSync(join(dir, "tpl"), { recursive: true });
|
|
338
|
+
writeFileSync(join(dir, "manifest.yaml"), "identity:\n templatesDir: tpl\n");
|
|
339
|
+
for (const f of [
|
|
340
|
+
"CLAUDE.md.template",
|
|
341
|
+
"SOUL.md.template",
|
|
342
|
+
"IDENTITY.md.template",
|
|
343
|
+
]) {
|
|
344
|
+
writeFileSync(join(dir, "tpl", f), "x");
|
|
345
|
+
}
|
|
346
|
+
return { root, tpl: join(dir, "tpl") };
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
it("looks up specialties under SHIPWRIGHT_REPO_ROOT when set", () => {
|
|
350
|
+
const { root, tpl } = makeRoot();
|
|
351
|
+
try {
|
|
352
|
+
const warnings: string[] = [];
|
|
353
|
+
const dir = resolveTemplatesDir(
|
|
354
|
+
"foo",
|
|
355
|
+
undefined,
|
|
356
|
+
(m) => warnings.push(m),
|
|
357
|
+
{ SHIPWRIGHT_REPO_ROOT: root },
|
|
358
|
+
);
|
|
359
|
+
expect(warnings).toEqual([]);
|
|
360
|
+
expect(dir).toBe(tpl);
|
|
361
|
+
} finally {
|
|
362
|
+
rmSync(root, { recursive: true, force: true });
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("does not use the override when unset or empty", () => {
|
|
367
|
+
const { root, tpl } = makeRoot();
|
|
368
|
+
try {
|
|
369
|
+
for (const env of [{}, { SHIPWRIGHT_REPO_ROOT: "" }]) {
|
|
370
|
+
const warnings: string[] = [];
|
|
371
|
+
const dir = resolveTemplatesDir(
|
|
372
|
+
"foo",
|
|
373
|
+
undefined,
|
|
374
|
+
(m) => warnings.push(m),
|
|
375
|
+
env,
|
|
376
|
+
);
|
|
377
|
+
expect(dir).not.toBe(tpl);
|
|
378
|
+
expect(warnings).toHaveLength(1);
|
|
379
|
+
}
|
|
380
|
+
} finally {
|
|
381
|
+
rmSync(root, { recursive: true, force: true });
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
});
|