agentplane 0.2.1 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/cli/http.ts"],"names":[],"mappings":"AAOA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B7F;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B5F;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAqB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/cli/http.ts"],"names":[],"mappings":"AAQA,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,SAAS,SAA2B,GACnC,OAAO,CAAC,OAAO,CAAC,CA0BlB;AAED,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,SAAS,SAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAED,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,SAAS,SAA8B,GACtC,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
package/dist/cli/http.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { writeFile } from "node:fs/promises";
2
2
  import { exitCodeForError } from "./exit-codes.js";
3
3
  import { CliError } from "../shared/errors.js";
4
- const DEFAULT_TIMEOUT_MS = 1500;
5
- export async function fetchJson(url, timeoutMs = DEFAULT_TIMEOUT_MS) {
4
+ const DEFAULT_FETCH_TIMEOUT_MS = 1500;
5
+ const DEFAULT_DOWNLOAD_TIMEOUT_MS = 30_000;
6
+ export async function fetchJson(url, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
6
7
  const controller = new AbortController();
7
8
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
8
9
  try {
@@ -32,7 +33,7 @@ export async function fetchJson(url, timeoutMs = DEFAULT_TIMEOUT_MS) {
32
33
  clearTimeout(timeout);
33
34
  }
34
35
  }
35
- export async function fetchText(url, timeoutMs = DEFAULT_TIMEOUT_MS) {
36
+ export async function fetchText(url, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
36
37
  const controller = new AbortController();
37
38
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
38
39
  try {
@@ -62,7 +63,7 @@ export async function fetchText(url, timeoutMs = DEFAULT_TIMEOUT_MS) {
62
63
  clearTimeout(timeout);
63
64
  }
64
65
  }
65
- export async function downloadToFile(url, destPath, timeoutMs = DEFAULT_TIMEOUT_MS) {
66
+ export async function downloadToFile(url, destPath, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
66
67
  const controller = new AbortController();
67
68
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
68
69
  try {
@@ -9,15 +9,37 @@ export type UpgradeFlags = {
9
9
  backup: boolean;
10
10
  yes: boolean;
11
11
  };
12
+ type GitHubRelease = {
13
+ assets?: {
14
+ name?: string;
15
+ browser_download_url?: string;
16
+ }[];
17
+ tarball_url?: string;
18
+ };
12
19
  export declare function normalizeFrameworkSourceForUpgrade(source: string): {
13
20
  source: string;
14
21
  owner: string;
15
22
  repo: string;
16
23
  migrated: boolean;
17
24
  };
25
+ export declare function resolveUpgradeDownloadFromRelease(opts: {
26
+ release: GitHubRelease;
27
+ owner: string;
28
+ repo: string;
29
+ assetName: string;
30
+ checksumName: string;
31
+ }): {
32
+ kind: "assets";
33
+ bundleUrl: string;
34
+ checksumUrl: string;
35
+ } | {
36
+ kind: "tarball";
37
+ tarballUrl: string;
38
+ };
18
39
  export declare function cmdUpgradeParsed(opts: {
19
40
  cwd: string;
20
41
  rootOverride?: string;
21
42
  flags: UpgradeFlags;
22
43
  }): Promise<number>;
44
+ export {};
23
45
  //# sourceMappingURL=upgrade.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAuBA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAmBF,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,MAAM,GAAG;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,CAWA;AAkOD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,YAAY,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuQlB"}
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAmBF,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,MAAM,GAAG;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,CAWA;AAED,wBAAgB,iCAAiC,CAAC,IAAI,EAAE;IACtD,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,GACG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAqB1C;AAkOD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,YAAY,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgSlB"}
@@ -12,6 +12,7 @@ import { CliError } from "../shared/errors.js";
12
12
  import { ensureNetworkApproved } from "./shared/network-approval.js";
13
13
  const DEFAULT_UPGRADE_ASSET = "agentplane-upgrade.tar.gz";
14
14
  const DEFAULT_UPGRADE_CHECKSUM_ASSET = "agentplane-upgrade.tar.gz.sha256";
15
+ const UPGRADE_DOWNLOAD_TIMEOUT_MS = 60_000;
15
16
  function parseGitHubRepo(source) {
16
17
  const trimmed = source.trim();
17
18
  if (!trimmed)
@@ -42,6 +43,27 @@ export function normalizeFrameworkSourceForUpgrade(source) {
42
43
  }
43
44
  return { source: `https://github.com/${owner}/${repo}`, owner, repo, migrated: false };
44
45
  }
46
+ export function resolveUpgradeDownloadFromRelease(opts) {
47
+ const assets = Array.isArray(opts.release.assets) ? opts.release.assets : [];
48
+ const asset = assets.find((a) => a?.name === opts.assetName);
49
+ const checksumAsset = assets.find((a) => a?.name === opts.checksumName);
50
+ if (asset?.browser_download_url && checksumAsset?.browser_download_url) {
51
+ return {
52
+ kind: "assets",
53
+ bundleUrl: asset.browser_download_url,
54
+ checksumUrl: checksumAsset.browser_download_url,
55
+ };
56
+ }
57
+ const tarballUrl = typeof opts.release.tarball_url === "string" ? opts.release.tarball_url : "";
58
+ if (!tarballUrl) {
59
+ throw new CliError({
60
+ exitCode: exitCodeForError("E_NETWORK"),
61
+ code: "E_NETWORK",
62
+ message: `Upgrade assets not found in ${opts.owner}/${opts.repo} release`,
63
+ });
64
+ }
65
+ return { kind: "tarball", tarballUrl };
66
+ }
45
67
  async function resolveUpgradeRoot(extractedDir) {
46
68
  const entries = await readdir(extractedDir, { withFileTypes: true });
47
69
  const dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
@@ -293,12 +315,15 @@ export async function cmdUpgradeParsed(opts) {
293
315
  tempRoot = await mkdtemp(path.join(os.tmpdir(), "agentplane-upgrade-"));
294
316
  let bundlePath = "";
295
317
  let checksumPath = "";
318
+ // GitHub release tarballs contain the full repository. When we fall back to tarball_url,
319
+ // we must ignore non-upgrade paths instead of failing validation.
320
+ let allowNonUpgradePaths = false;
296
321
  if (flags.bundle) {
297
322
  const isUrl = flags.bundle.startsWith("http://") || flags.bundle.startsWith("https://");
298
323
  bundlePath = isUrl ? path.join(tempRoot, "bundle.tar.gz") : path.resolve(flags.bundle);
299
324
  if (isUrl) {
300
325
  await ensureApproved("upgrade downloads the bundle/checksum from the network");
301
- await downloadToFile(flags.bundle, bundlePath);
326
+ await downloadToFile(flags.bundle, bundlePath, UPGRADE_DOWNLOAD_TIMEOUT_MS);
302
327
  }
303
328
  const checksumValue = flags.checksum ?? "";
304
329
  const checksumIsUrl = checksumValue.startsWith("http://") || checksumValue.startsWith("https://");
@@ -307,7 +332,7 @@ export async function cmdUpgradeParsed(opts) {
307
332
  : path.resolve(checksumValue);
308
333
  if (checksumIsUrl) {
309
334
  await ensureApproved("upgrade downloads the bundle/checksum from the network");
310
- await downloadToFile(checksumValue, checksumPath);
335
+ await downloadToFile(checksumValue, checksumPath, UPGRADE_DOWNLOAD_TIMEOUT_MS);
311
336
  }
312
337
  }
313
338
  else {
@@ -316,39 +341,47 @@ export async function cmdUpgradeParsed(opts) {
316
341
  ? `https://api.github.com/repos/${owner}/${repo}/releases/tags/${flags.tag}`
317
342
  : `https://api.github.com/repos/${owner}/${repo}/releases/latest`;
318
343
  await ensureApproved("upgrade fetches release metadata and downloads assets from the network");
319
- const release = (await fetchJson(releaseUrl));
320
- const assets = Array.isArray(release.assets) ? release.assets : [];
321
344
  const assetName = flags.asset ?? DEFAULT_UPGRADE_ASSET;
322
345
  const checksumName = flags.checksumAsset ?? DEFAULT_UPGRADE_CHECKSUM_ASSET;
323
- const asset = assets.find((entry) => entry.name === assetName);
324
- const checksumAsset = assets.find((entry) => entry.name === checksumName);
325
- if (!asset?.browser_download_url || !checksumAsset?.browser_download_url) {
346
+ const release = (await fetchJson(releaseUrl));
347
+ const download = resolveUpgradeDownloadFromRelease({
348
+ release,
349
+ owner,
350
+ repo,
351
+ assetName,
352
+ checksumName,
353
+ });
354
+ if (download.kind === "assets") {
355
+ bundlePath = path.join(tempRoot, assetName);
356
+ checksumPath = path.join(tempRoot, checksumName);
357
+ await downloadToFile(download.bundleUrl, bundlePath, UPGRADE_DOWNLOAD_TIMEOUT_MS);
358
+ await downloadToFile(download.checksumUrl, checksumPath, UPGRADE_DOWNLOAD_TIMEOUT_MS);
359
+ }
360
+ else {
361
+ process.stderr.write(`${warnMessage(`upgrade release does not include ${assetName}/${checksumName}; falling back to tarball_url without checksum verification`)}\n`);
362
+ allowNonUpgradePaths = true;
363
+ bundlePath = path.join(tempRoot, "source.tar.gz");
364
+ await downloadToFile(download.tarballUrl, bundlePath, UPGRADE_DOWNLOAD_TIMEOUT_MS);
365
+ checksumPath = "";
366
+ }
367
+ }
368
+ if (checksumPath) {
369
+ const expected = parseSha256Text(await readFile(checksumPath, "utf8"));
370
+ if (!expected) {
326
371
  throw new CliError({
327
- exitCode: exitCodeForError("E_NETWORK"),
328
- code: "E_NETWORK",
329
- message: `Upgrade assets not found in ${owner}/${repo} release`,
372
+ exitCode: 3,
373
+ code: "E_VALIDATION",
374
+ message: "Upgrade checksum file is empty or invalid",
375
+ });
376
+ }
377
+ const actual = await sha256File(bundlePath);
378
+ if (actual !== expected) {
379
+ throw new CliError({
380
+ exitCode: 3,
381
+ code: "E_VALIDATION",
382
+ message: `Upgrade checksum mismatch (expected ${expected}, got ${actual})`,
330
383
  });
331
384
  }
332
- bundlePath = path.join(tempRoot, assetName);
333
- checksumPath = path.join(tempRoot, checksumName);
334
- await downloadToFile(asset.browser_download_url, bundlePath);
335
- await downloadToFile(checksumAsset.browser_download_url, checksumPath);
336
- }
337
- const expected = parseSha256Text(await readFile(checksumPath, "utf8"));
338
- if (!expected) {
339
- throw new CliError({
340
- exitCode: 3,
341
- code: "E_VALIDATION",
342
- message: "Upgrade checksum file is empty or invalid",
343
- });
344
- }
345
- const actual = await sha256File(bundlePath);
346
- if (actual !== expected) {
347
- throw new CliError({
348
- exitCode: 3,
349
- code: "E_VALIDATION",
350
- message: `Upgrade checksum mismatch (expected ${expected}, got ${actual})`,
351
- });
352
385
  }
353
386
  extractRoot = await mkdtemp(path.join(os.tmpdir(), "agentplane-upgrade-extract-"));
354
387
  await extractArchive({
@@ -387,6 +420,9 @@ export async function cmdUpgradeParsed(opts) {
387
420
  });
388
421
  }
389
422
  if (!isAllowedUpgradePath(rel)) {
423
+ if (allowNonUpgradePaths) {
424
+ continue;
425
+ }
390
426
  throw new CliError({
391
427
  exitCode: 3,
392
428
  code: "E_VALIDATION",
@@ -452,6 +488,13 @@ export async function cmdUpgradeParsed(opts) {
452
488
  }
453
489
  }
454
490
  }
491
+ if (fileContents.size === 0) {
492
+ throw new CliError({
493
+ exitCode: 3,
494
+ code: "E_VALIDATION",
495
+ message: "Upgrade bundle contains no applicable files (expected AGENTS.md and/or .agentplane/).",
496
+ });
497
+ }
455
498
  if (flags.dryRun) {
456
499
  process.stdout.write(`Upgrade dry-run: ${additions.length} add, ${updates.length} update, ${skipped.length} unchanged\n`);
457
500
  for (const rel of additions)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentplane",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Agent Plane CLI for task workflows, recipes, and project automation.",
5
5
  "keywords": [
6
6
  "agentplane",
@@ -54,7 +54,7 @@
54
54
  "prepublishOnly": "npm run prepack"
55
55
  },
56
56
  "dependencies": {
57
- "@agentplaneorg/core": "0.2.1",
57
+ "@agentplaneorg/core": "0.2.3",
58
58
  "yauzl": "^2.10.0"
59
59
  },
60
60
  "devDependencies": {