agentplane 0.2.6 → 0.2.13
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/README.md +11 -0
- package/assets/AGENTS.md +35 -0
- package/assets/agents/CODER.json +0 -1
- package/assets/agents/INTEGRATOR.json +0 -1
- package/assets/agents/ORCHESTRATOR.json +1 -2
- package/assets/agents/PLANNER.json +1 -3
- package/assets/agents/TESTER.json +0 -1
- package/assets/agents/UPGRADER.json +17 -15
- package/dist/cli/archive.d.ts.map +1 -1
- package/dist/cli/archive.js +61 -36
- package/dist/cli/command-guide.d.ts.map +1 -1
- package/dist/cli/command-guide.js +5 -3
- package/dist/cli/run-cli/command-catalog.d.ts +4 -1
- package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
- package/dist/cli/run-cli/command-catalog.js +44 -26
- package/dist/cli/run-cli/commands/config.d.ts +5 -4
- package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/config.js +47 -58
- package/dist/cli/run-cli/commands/core.d.ts +2 -1
- package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/core.js +187 -51
- package/dist/cli/run-cli/commands/ide.d.ts +3 -1
- package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/ide.js +7 -12
- package/dist/cli/run-cli/commands/init/ide-sync.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/ide-sync.js +10 -1
- package/dist/cli/run-cli/commands/init/write-agents.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init/write-agents.js +4 -24
- package/dist/cli/run-cli/commands/init/write-gitignore.d.ts +5 -0
- package/dist/cli/run-cli/commands/init/write-gitignore.d.ts.map +1 -0
- package/dist/cli/run-cli/commands/init/write-gitignore.js +48 -0
- package/dist/cli/run-cli/commands/init.d.ts +1 -0
- package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
- package/dist/cli/run-cli/commands/init.js +34 -8
- package/dist/cli/run-cli/commands/wrap-command.d.ts +6 -0
- package/dist/cli/run-cli/commands/wrap-command.d.ts.map +1 -0
- package/dist/cli/run-cli/commands/wrap-command.js +17 -0
- package/dist/cli/run-cli/registry.run.d.ts +6 -2
- package/dist/cli/run-cli/registry.run.d.ts.map +1 -1
- package/dist/cli/run-cli/registry.run.js +7 -2
- package/dist/cli/run-cli.d.ts.map +1 -1
- package/dist/cli/run-cli.js +96 -75
- package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
- package/dist/cli/run-cli.test-helpers.js +99 -3
- package/dist/cli/spec/parse-utils.d.ts +11 -0
- package/dist/cli/spec/parse-utils.d.ts.map +1 -0
- package/dist/cli/spec/parse-utils.js +28 -0
- package/dist/commands/block.command.d.ts +3 -18
- package/dist/commands/block.command.d.ts.map +1 -1
- package/dist/commands/block.command.js +2 -143
- package/dist/commands/block.run.d.ts +5 -0
- package/dist/commands/block.run.d.ts.map +1 -0
- package/dist/commands/block.run.js +22 -0
- package/dist/commands/block.spec.d.ts +17 -0
- package/dist/commands/block.spec.d.ts.map +1 -0
- package/dist/commands/block.spec.js +115 -0
- package/dist/commands/doctor.command.d.ts +2 -7
- package/dist/commands/doctor.command.d.ts.map +1 -1
- package/dist/commands/doctor.command.js +2 -137
- package/dist/commands/doctor.run.d.ts +4 -0
- package/dist/commands/doctor.run.d.ts.map +1 -0
- package/dist/commands/doctor.run.js +174 -0
- package/dist/commands/doctor.spec.d.ts +7 -0
- package/dist/commands/doctor.spec.d.ts.map +1 -0
- package/dist/commands/doctor.spec.js +20 -0
- package/dist/commands/finish.command.d.ts +3 -27
- package/dist/commands/finish.command.d.ts.map +1 -1
- package/dist/commands/finish.command.js +2 -237
- package/dist/commands/finish.run.d.ts +5 -0
- package/dist/commands/finish.run.d.ts.map +1 -0
- package/dist/commands/finish.run.js +40 -0
- package/dist/commands/finish.spec.d.ts +26 -0
- package/dist/commands/finish.spec.d.ts.map +1 -0
- package/dist/commands/finish.spec.js +193 -0
- package/dist/commands/recipes/install.command.d.ts +2 -11
- package/dist/commands/recipes/install.command.d.ts.map +1 -1
- package/dist/commands/recipes/install.command.js +2 -161
- package/dist/commands/recipes/install.run.d.ts +4 -0
- package/dist/commands/recipes/install.run.d.ts.map +1 -0
- package/dist/commands/recipes/install.run.js +23 -0
- package/dist/commands/recipes/install.spec.d.ts +11 -0
- package/dist/commands/recipes/install.spec.d.ts.map +1 -0
- package/dist/commands/recipes/install.spec.js +140 -0
- package/dist/commands/release/apply.command.d.ts +11 -0
- package/dist/commands/release/apply.command.d.ts.map +1 -0
- package/dist/commands/release/apply.command.js +343 -0
- package/dist/commands/release/plan.command.d.ts +12 -0
- package/dist/commands/release/plan.command.d.ts.map +1 -0
- package/dist/commands/release/plan.command.js +206 -0
- package/dist/commands/release/release.command.d.ts +5 -0
- package/dist/commands/release/release.command.d.ts.map +1 -0
- package/dist/commands/release/release.command.js +18 -0
- package/dist/commands/shared/git-context.d.ts +3 -0
- package/dist/commands/shared/git-context.d.ts.map +1 -1
- package/dist/commands/shared/git-context.js +10 -0
- package/dist/commands/shared/task-backend.d.ts +1 -0
- package/dist/commands/shared/task-backend.d.ts.map +1 -1
- package/dist/commands/start.command.d.ts +3 -18
- package/dist/commands/start.command.d.ts.map +1 -1
- package/dist/commands/start.command.js +2 -143
- package/dist/commands/start.run.d.ts +5 -0
- package/dist/commands/start.run.d.ts.map +1 -0
- package/dist/commands/start.run.js +22 -0
- package/dist/commands/start.spec.d.ts +17 -0
- package/dist/commands/start.spec.d.ts.map +1 -0
- package/dist/commands/start.spec.js +115 -0
- package/dist/commands/task/add.command.d.ts.map +1 -1
- package/dist/commands/task/add.command.js +1 -7
- package/dist/commands/task/derive.command.d.ts.map +1 -1
- package/dist/commands/task/derive.command.js +1 -7
- package/dist/commands/task/finish.d.ts.map +1 -1
- package/dist/commands/task/finish.js +34 -2
- package/dist/commands/task/list.command.d.ts +3 -8
- package/dist/commands/task/list.command.d.ts.map +1 -1
- package/dist/commands/task/list.command.js +2 -67
- package/dist/commands/task/list.run.d.ts +5 -0
- package/dist/commands/task/list.run.d.ts.map +1 -0
- package/dist/commands/task/list.run.js +10 -0
- package/dist/commands/task/list.spec.d.ts +7 -0
- package/dist/commands/task/list.spec.d.ts.map +1 -0
- package/dist/commands/task/list.spec.js +51 -0
- package/dist/commands/task/next.command.d.ts +3 -8
- package/dist/commands/task/next.command.d.ts.map +1 -1
- package/dist/commands/task/next.command.js +2 -89
- package/dist/commands/task/next.run.d.ts +5 -0
- package/dist/commands/task/next.run.d.ts.map +1 -0
- package/dist/commands/task/next.run.js +11 -0
- package/dist/commands/task/next.spec.d.ts +7 -0
- package/dist/commands/task/next.spec.d.ts.map +1 -0
- package/dist/commands/task/next.spec.js +69 -0
- package/dist/commands/task/search.command.d.ts +3 -10
- package/dist/commands/task/search.command.d.ts.map +1 -1
- package/dist/commands/task/search.command.js +2 -101
- package/dist/commands/task/search.run.d.ts +5 -0
- package/dist/commands/task/search.run.d.ts.map +1 -0
- package/dist/commands/task/search.run.js +13 -0
- package/dist/commands/task/search.spec.d.ts +9 -0
- package/dist/commands/task/search.spec.d.ts.map +1 -0
- package/dist/commands/task/search.spec.js +79 -0
- package/dist/commands/task/set-status.command.d.ts.map +1 -1
- package/dist/commands/task/set-status.command.js +1 -7
- package/dist/commands/task/shared.d.ts.map +1 -1
- package/dist/commands/task/shared.js +15 -8
- package/dist/commands/task/show.command.d.ts +3 -7
- package/dist/commands/task/show.command.d.ts.map +1 -1
- package/dist/commands/task/show.command.js +2 -19
- package/dist/commands/task/show.run.d.ts +5 -0
- package/dist/commands/task/show.run.d.ts.map +1 -0
- package/dist/commands/task/show.run.js +11 -0
- package/dist/commands/task/show.spec.d.ts +6 -0
- package/dist/commands/task/show.spec.d.ts.map +1 -0
- package/dist/commands/task/show.spec.js +8 -0
- package/dist/commands/task/update.command.d.ts.map +1 -1
- package/dist/commands/task/update.command.js +1 -7
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +171 -32
- package/dist/commands/verify.command.d.ts +3 -15
- package/dist/commands/verify.command.d.ts.map +1 -1
- package/dist/commands/verify.command.js +2 -113
- package/dist/commands/verify.run.d.ts +5 -0
- package/dist/commands/verify.run.d.ts.map +1 -0
- package/dist/commands/verify.run.js +17 -0
- package/dist/commands/verify.spec.d.ts +14 -0
- package/dist/commands/verify.spec.d.ts.map +1 -0
- package/dist/commands/verify.spec.js +96 -0
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { writeTextIfChanged } from "../../../../shared/write-if-changed.js";
|
|
4
|
+
async function readTextIfExists(filePath) {
|
|
5
|
+
try {
|
|
6
|
+
return await readFile(filePath, "utf8");
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
const code = err?.code;
|
|
10
|
+
if (code === "ENOENT")
|
|
11
|
+
return null;
|
|
12
|
+
throw err;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const RUNTIME_IGNORE_LINES = [
|
|
16
|
+
"# agentplane: ignore runtime/transient workspace artifacts",
|
|
17
|
+
".agentplane/worktrees",
|
|
18
|
+
".agentplane/cache",
|
|
19
|
+
".agentplane/recipes-cache",
|
|
20
|
+
".agentplane/.upgrade",
|
|
21
|
+
".agentplane/.release",
|
|
22
|
+
".agentplane/upgrade",
|
|
23
|
+
".agentplane/tasks.json",
|
|
24
|
+
];
|
|
25
|
+
const AGENT_PROMPT_IGNORE_LINES = [
|
|
26
|
+
"# agentplane: ignore local agent prompts/templates",
|
|
27
|
+
"AGENTS.md",
|
|
28
|
+
".agentplane/agents/",
|
|
29
|
+
];
|
|
30
|
+
export async function ensureInitGitignore(opts) {
|
|
31
|
+
const gitignorePath = path.join(opts.gitRoot, ".gitignore");
|
|
32
|
+
const existing = (await readTextIfExists(gitignorePath)) ?? "";
|
|
33
|
+
const ensuredLines = opts.includeAgentPromptFiles
|
|
34
|
+
? [...RUNTIME_IGNORE_LINES, ...AGENT_PROMPT_IGNORE_LINES]
|
|
35
|
+
: [...RUNTIME_IGNORE_LINES];
|
|
36
|
+
const existingLines = existing.split(/\r?\n/);
|
|
37
|
+
const existingSet = new Set(existingLines.map((line) => line.trimEnd()));
|
|
38
|
+
const missing = ensuredLines.filter((line) => !existingSet.has(line));
|
|
39
|
+
if (missing.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
const nextLines = [...existingLines];
|
|
42
|
+
// Keep content stable and append a trailing newline.
|
|
43
|
+
if (nextLines.length > 0 && nextLines.at(-1) !== "")
|
|
44
|
+
nextLines.push("");
|
|
45
|
+
nextLines.push(...missing, "");
|
|
46
|
+
const nextText = `${nextLines.join("\n")}`.replaceAll(/\n{2,}$/g, "\n");
|
|
47
|
+
await writeTextIfChanged(gitignorePath, nextText);
|
|
48
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/init.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/init.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAetE,KAAK,SAAS,GAAG;IACf,GAAG,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IACtC,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAsBF,KAAK,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG;IAAE,GAAG,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5D,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,UAAU,CAsJ5C,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CACmB,CAAC"}
|
|
@@ -7,6 +7,7 @@ import { usageError } from "../../spec/errors.js";
|
|
|
7
7
|
import { CliError } from "../../../shared/errors.js";
|
|
8
8
|
import { getVersion } from "../../../meta/version.js";
|
|
9
9
|
import { cmdHooksInstall, ensureInitCommit } from "../../../commands/workflow.js";
|
|
10
|
+
import { setPinnedBaseBranch } from "@agentplaneorg/core";
|
|
10
11
|
import { resolveInitBaseBranchForInit } from "./init/base-branch.js";
|
|
11
12
|
import { collectInitConflicts, handleInitConflicts } from "./init/conflicts.js";
|
|
12
13
|
import { ensureGitRoot } from "./init/git.js";
|
|
@@ -14,6 +15,7 @@ import { maybeSyncIde } from "./init/ide-sync.js";
|
|
|
14
15
|
import { maybeInstallBundledRecipes } from "./init/recipes.js";
|
|
15
16
|
import { ensureAgentplaneDirs, writeBackendStubs, writeInitConfig } from "./init/write-config.js";
|
|
16
17
|
import { ensureAgentsFiles } from "./init/write-agents.js";
|
|
18
|
+
import { ensureInitGitignore } from "./init/write-gitignore.js";
|
|
17
19
|
function parseBooleanValueForInit(flag, value) {
|
|
18
20
|
const normalized = value.trim().toLowerCase();
|
|
19
21
|
if (["1", "true", "yes", "y", "on"].includes(normalized))
|
|
@@ -39,7 +41,7 @@ export const initSpec = {
|
|
|
39
41
|
id: ["init"],
|
|
40
42
|
group: "Setup",
|
|
41
43
|
summary: "Initialize agentplane project files under .agentplane/.",
|
|
42
|
-
description: "Creates .agentplane/ config, backend stubs, and agent templates in the target directory. If the target directory is not a git repository, it initializes one and writes an initial install commit. In interactive mode it prompts for missing inputs; use --yes for non-interactive mode.",
|
|
44
|
+
description: "Creates .agentplane/ config, backend stubs, and agent templates in the target directory. If the target directory is not a git repository, it initializes one and (by default) writes an initial install commit. Use --gitignore-agents to keep agent templates local (gitignored) and skip the install commit. In interactive mode it prompts for missing inputs; use --yes for non-interactive mode.",
|
|
43
45
|
options: [
|
|
44
46
|
{
|
|
45
47
|
kind: "string",
|
|
@@ -112,6 +114,12 @@ export const initSpec = {
|
|
|
112
114
|
default: false,
|
|
113
115
|
description: "Non-interactive mode (do not prompt; use defaults for missing flags).",
|
|
114
116
|
},
|
|
117
|
+
{
|
|
118
|
+
kind: "boolean",
|
|
119
|
+
name: "gitignore-agents",
|
|
120
|
+
default: false,
|
|
121
|
+
description: "Add agent files (AGENTS.md and .agentplane/agents/) to .gitignore and skip the initial install commit.",
|
|
122
|
+
},
|
|
115
123
|
],
|
|
116
124
|
examples: [
|
|
117
125
|
{ cmd: "agentplane init", why: "Interactive setup (prompts for missing values)." },
|
|
@@ -123,6 +131,10 @@ export const initSpec = {
|
|
|
123
131
|
cmd: "agentplane init --force --yes",
|
|
124
132
|
why: "Re-initialize, overwriting conflicts (non-interactive).",
|
|
125
133
|
},
|
|
134
|
+
{
|
|
135
|
+
cmd: "agentplane init --yes --gitignore-agents",
|
|
136
|
+
why: "Initialize without committing and keep agent prompts/templates local (gitignored).",
|
|
137
|
+
},
|
|
126
138
|
],
|
|
127
139
|
validateRaw: (raw) => {
|
|
128
140
|
if (raw.extra.length > 0) {
|
|
@@ -157,6 +169,7 @@ export const initSpec = {
|
|
|
157
169
|
force: raw.opts.force === true,
|
|
158
170
|
backup: raw.opts.backup === true,
|
|
159
171
|
yes: raw.opts.yes === true,
|
|
172
|
+
gitignoreAgents: raw.opts["gitignore-agents"] === true,
|
|
160
173
|
};
|
|
161
174
|
},
|
|
162
175
|
validate: (p) => {
|
|
@@ -299,6 +312,17 @@ async function cmdInit(opts) {
|
|
|
299
312
|
configPathAbs: configPath,
|
|
300
313
|
backendPathAbs: backendPath,
|
|
301
314
|
});
|
|
315
|
+
await ensureInitGitignore({
|
|
316
|
+
gitRoot: resolved.gitRoot,
|
|
317
|
+
includeAgentPromptFiles: flags.gitignoreAgents === true,
|
|
318
|
+
});
|
|
319
|
+
if (flags.gitignoreAgents) {
|
|
320
|
+
await setPinnedBaseBranch({
|
|
321
|
+
cwd: resolved.gitRoot,
|
|
322
|
+
rootOverride: resolved.gitRoot,
|
|
323
|
+
value: initBaseBranch,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
302
326
|
if (hooks) {
|
|
303
327
|
await cmdHooksInstall({ cwd: opts.cwd, rootOverride: opts.rootOverride, quiet: true });
|
|
304
328
|
}
|
|
@@ -310,13 +334,15 @@ async function cmdInit(opts) {
|
|
|
310
334
|
});
|
|
311
335
|
installPaths.push(...ideRes.installPaths);
|
|
312
336
|
maybeInstallBundledRecipes(recipes);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
337
|
+
if (!flags.gitignoreAgents) {
|
|
338
|
+
await ensureInitCommit({
|
|
339
|
+
gitRoot: resolved.gitRoot,
|
|
340
|
+
baseBranch: initBaseBranch,
|
|
341
|
+
installPaths,
|
|
342
|
+
version: getVersion(),
|
|
343
|
+
skipHooks: hooks,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
320
346
|
process.stdout.write(`${path.relative(resolved.gitRoot, resolved.agentplaneDir)}\n`);
|
|
321
347
|
return 0;
|
|
322
348
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap-command.d.ts","sourceRoot":"","sources":["../../../../src/cli/run-cli/commands/wrap-command.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,CAAC,EACjC,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC,EACD,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAYZ"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { mapCoreError } from "../../error-map.js";
|
|
2
|
+
import { CliError } from "../../../shared/errors.js";
|
|
3
|
+
export async function wrapCommand(opts, fn) {
|
|
4
|
+
try {
|
|
5
|
+
return await fn();
|
|
6
|
+
}
|
|
7
|
+
catch (err) {
|
|
8
|
+
if (err instanceof CliError)
|
|
9
|
+
throw err;
|
|
10
|
+
const context = opts.context ?? {};
|
|
11
|
+
throw mapCoreError(err, {
|
|
12
|
+
command: opts.command,
|
|
13
|
+
root: opts.rootOverride ?? null,
|
|
14
|
+
...context,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { CommandRegistry } from "../spec/registry.js";
|
|
2
|
-
import type
|
|
3
|
-
export declare function buildRegistry(
|
|
2
|
+
import { type RunDeps } from "./command-catalog.js";
|
|
3
|
+
export declare function buildRegistry(opts: {
|
|
4
|
+
getCtx: RunDeps["getCtx"];
|
|
5
|
+
getResolvedProject: RunDeps["getResolvedProject"];
|
|
6
|
+
getLoadedConfig: RunDeps["getLoadedConfig"];
|
|
7
|
+
}): CommandRegistry;
|
|
4
8
|
//# sourceMappingURL=registry.run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.run.d.ts","sourceRoot":"","sources":["../../../src/cli/run-cli/registry.run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.run.d.ts","sourceRoot":"","sources":["../../../src/cli/run-cli/registry.run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAItD,OAAO,EAAY,KAAK,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE9D,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClD,eAAe,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC7C,GAAG,eAAe,CAmBlB"}
|
|
@@ -2,10 +2,15 @@ import { CommandRegistry } from "../spec/registry.js";
|
|
|
2
2
|
import { helpSpec, makeHelpHandler } from "../spec/help.js";
|
|
3
3
|
import { makeHelpJsonFromSpecs } from "../../commands/docs/cli.command.js";
|
|
4
4
|
import { COMMANDS } from "./command-catalog.js";
|
|
5
|
-
export function buildRegistry(
|
|
5
|
+
export function buildRegistry(opts) {
|
|
6
6
|
const registry = new CommandRegistry();
|
|
7
7
|
const getHelpJsonForDocs = () => makeHelpJsonFromSpecs(registry.list().map((e) => e.spec));
|
|
8
|
-
const deps = {
|
|
8
|
+
const deps = {
|
|
9
|
+
getCtx: opts.getCtx,
|
|
10
|
+
getResolvedProject: opts.getResolvedProject,
|
|
11
|
+
getLoadedConfig: opts.getLoadedConfig,
|
|
12
|
+
getHelpJsonForDocs,
|
|
13
|
+
};
|
|
9
14
|
for (const entry of COMMANDS) {
|
|
10
15
|
let loaded = null;
|
|
11
16
|
registry.register(entry.spec, async (ctx, parsed) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":"AAmWA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuK5D"}
|
package/dist/cli/run-cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { loadConfig, resolveProject } from "@agentplaneorg/core";
|
|
3
|
+
import { loadConfig, resolveProject, } from "@agentplaneorg/core";
|
|
4
4
|
import { mapCoreError } from "./error-map.js";
|
|
5
5
|
import { exitCodeForError } from "./exit-codes.js";
|
|
6
6
|
import { warnMessage } from "./output.js";
|
|
@@ -14,43 +14,35 @@ import { helpSpec } from "./spec/help.js";
|
|
|
14
14
|
import { usageError } from "./spec/errors.js";
|
|
15
15
|
import { suggestOne } from "./spec/suggest.js";
|
|
16
16
|
import { COMMANDS } from "./run-cli/command-catalog.js";
|
|
17
|
+
const GLOBAL_FLAGS = [
|
|
18
|
+
{ key: "help", forms: ["--help", "-h"], takesValue: false, scoped: false },
|
|
19
|
+
{ key: "version", forms: ["--version", "-v"], takesValue: false, scoped: false },
|
|
20
|
+
{ key: "noUpdateCheck", forms: ["--no-update-check"], takesValue: false, scoped: false },
|
|
21
|
+
{ key: "allowNetwork", forms: ["--allow-network"], takesValue: false, scoped: true },
|
|
22
|
+
{ key: "jsonErrors", forms: ["--json-errors"], takesValue: false, scoped: true },
|
|
23
|
+
{ key: "root", forms: ["--root"], takesValue: true, scoped: false },
|
|
24
|
+
];
|
|
25
|
+
const GLOBAL_FLAG_FORMS = new Map(GLOBAL_FLAGS.flatMap((def) => def.forms.map((form) => [form, def])));
|
|
17
26
|
function prescanJsonErrors(argv) {
|
|
18
27
|
// If parseGlobalArgs throws (e.g. missing --root value), we still want to honor
|
|
19
|
-
// `--json` in the "scoped global" zone (before the command id).
|
|
28
|
+
// `--json-errors` in the "scoped global" zone (before the command id).
|
|
20
29
|
let hasRest = false;
|
|
21
30
|
for (let i = 0; i < argv.length; i++) {
|
|
22
31
|
const arg = argv[i];
|
|
23
32
|
if (!arg)
|
|
24
33
|
continue;
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (arg === "--no-update-check")
|
|
31
|
-
continue;
|
|
32
|
-
if (arg === "--allow-network")
|
|
33
|
-
continue;
|
|
34
|
-
// Scoped global: only before the command id.
|
|
35
|
-
if (arg === "--json-errors") {
|
|
36
|
-
if (!hasRest)
|
|
37
|
-
return true;
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (arg === "--json") {
|
|
41
|
-
if (!hasRest)
|
|
42
|
-
return true;
|
|
43
|
-
continue;
|
|
34
|
+
const def = GLOBAL_FLAG_FORMS.get(arg);
|
|
35
|
+
if (!def) {
|
|
36
|
+
// First non-global token is treated as the start of the command id.
|
|
37
|
+
hasRest = true;
|
|
38
|
+
break;
|
|
44
39
|
}
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
if (def.key === "jsonErrors" && !hasRest)
|
|
41
|
+
return true;
|
|
42
|
+
if (def.takesValue) {
|
|
47
43
|
// Skip the value if present; do not throw on missing value here.
|
|
48
44
|
i++;
|
|
49
|
-
continue;
|
|
50
45
|
}
|
|
51
|
-
// First non-global token is treated as the start of the command id.
|
|
52
|
-
hasRest = true;
|
|
53
|
-
break;
|
|
54
46
|
}
|
|
55
47
|
return false;
|
|
56
48
|
}
|
|
@@ -66,61 +58,56 @@ function parseGlobalArgs(argv) {
|
|
|
66
58
|
const arg = argv[i];
|
|
67
59
|
if (!arg)
|
|
68
60
|
continue;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
if (arg === "--version" || arg === "-v") {
|
|
74
|
-
version = true;
|
|
61
|
+
const def = GLOBAL_FLAG_FORMS.get(arg);
|
|
62
|
+
if (!def) {
|
|
63
|
+
rest.push(arg);
|
|
75
64
|
continue;
|
|
76
65
|
}
|
|
77
|
-
|
|
78
|
-
|
|
66
|
+
// Scoped globals are only recognized before the command id token.
|
|
67
|
+
if (def.scoped && rest.length > 0) {
|
|
68
|
+
rest.push(arg);
|
|
79
69
|
continue;
|
|
80
70
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
switch (def.key) {
|
|
72
|
+
case "help": {
|
|
73
|
+
help = true;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case "version": {
|
|
77
|
+
version = true;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "noUpdateCheck": {
|
|
81
|
+
noUpdateCheck = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "allowNetwork": {
|
|
85
85
|
allowNetwork = true;
|
|
86
|
-
|
|
86
|
+
break;
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (arg === "--json-errors") {
|
|
92
|
-
// Scoped global: only treat `--json-errors` as "JSON errors" if it appears
|
|
93
|
-
// before the command id. This mirrors the existing `--json` behavior.
|
|
94
|
-
if (rest.length === 0) {
|
|
88
|
+
case "jsonErrors": {
|
|
95
89
|
jsonErrors = true;
|
|
96
|
-
|
|
90
|
+
break;
|
|
97
91
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
92
|
+
case "root": {
|
|
93
|
+
const next = argv[i + 1];
|
|
94
|
+
if (!next) {
|
|
95
|
+
throw new CliError({
|
|
96
|
+
exitCode: 2,
|
|
97
|
+
code: "E_USAGE",
|
|
98
|
+
message: "Missing value after --root (expected repository path)",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
root = next;
|
|
102
|
+
i++;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
default: {
|
|
106
|
+
// Exhaustive by construction; keep a defensive fallback.
|
|
107
|
+
rest.push(arg);
|
|
108
|
+
break;
|
|
107
109
|
}
|
|
108
|
-
rest.push(arg);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
if (arg === "--root") {
|
|
112
|
-
const next = argv[i + 1];
|
|
113
|
-
if (!next)
|
|
114
|
-
throw new CliError({
|
|
115
|
-
exitCode: 2,
|
|
116
|
-
code: "E_USAGE",
|
|
117
|
-
message: "Missing value after --root (expected repository path)",
|
|
118
|
-
});
|
|
119
|
-
root = next;
|
|
120
|
-
i++;
|
|
121
|
-
continue;
|
|
122
110
|
}
|
|
123
|
-
rest.push(arg);
|
|
124
111
|
}
|
|
125
112
|
return { globals: { help, version, noUpdateCheck, root, jsonErrors, allowNetwork }, rest };
|
|
126
113
|
}
|
|
@@ -318,7 +305,12 @@ export async function runCli(argv) {
|
|
|
318
305
|
}
|
|
319
306
|
const runCli2HelpFast = async (helpArgv) => {
|
|
320
307
|
const { buildRegistry } = await import("./run-cli/registry.run.js");
|
|
321
|
-
const
|
|
308
|
+
const reject = (name) => (_cmd) => Promise.reject(new Error(`${name} should not be called for help`));
|
|
309
|
+
const registry = buildRegistry({
|
|
310
|
+
getCtx: reject("getCtx"),
|
|
311
|
+
getResolvedProject: reject("getResolvedProject"),
|
|
312
|
+
getLoadedConfig: reject("getLoadedConfig"),
|
|
313
|
+
});
|
|
322
314
|
const match = registry.match(helpArgv);
|
|
323
315
|
if (!match) {
|
|
324
316
|
throw new CliError({
|
|
@@ -352,12 +344,37 @@ export async function runCli(argv) {
|
|
|
352
344
|
if (resolved) {
|
|
353
345
|
await loadDotEnv(resolved.gitRoot);
|
|
354
346
|
}
|
|
347
|
+
let projectPromise = resolved
|
|
348
|
+
? Promise.resolve(resolved)
|
|
349
|
+
: null;
|
|
350
|
+
const getResolvedProject = async (commandForErrorContext) => {
|
|
351
|
+
projectPromise ??= resolveProject({ cwd, rootOverride: globals.root ?? null });
|
|
352
|
+
try {
|
|
353
|
+
return await projectPromise;
|
|
354
|
+
}
|
|
355
|
+
catch (err) {
|
|
356
|
+
throw mapCoreError(err, { command: commandForErrorContext, root: globals.root ?? null });
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
let configPromise = null;
|
|
360
|
+
const getLoadedConfig = async (commandForErrorContext) => {
|
|
361
|
+
configPromise ??= (async () => {
|
|
362
|
+
const project = await getResolvedProject(commandForErrorContext);
|
|
363
|
+
return await loadConfig(project.agentplaneDir);
|
|
364
|
+
})();
|
|
365
|
+
try {
|
|
366
|
+
return await configPromise;
|
|
367
|
+
}
|
|
368
|
+
catch (err) {
|
|
369
|
+
throw mapCoreError(err, { command: commandForErrorContext, root: globals.root ?? null });
|
|
370
|
+
}
|
|
371
|
+
};
|
|
355
372
|
// `require_network=true` means "no network without explicit approval".
|
|
356
373
|
// Update-check is an optional network call, so it must be gated after config load.
|
|
357
374
|
let skipUpdateCheckForPolicy = true;
|
|
358
375
|
if (resolved && matched?.entry.needsConfig !== false) {
|
|
359
376
|
try {
|
|
360
|
-
const loaded = await
|
|
377
|
+
const loaded = await getLoadedConfig("update-check");
|
|
361
378
|
const requireNetwork = loaded.config.agents?.approvals.require_network === true;
|
|
362
379
|
const explicitlyApproved = globals.allowNetwork;
|
|
363
380
|
skipUpdateCheckForPolicy = requireNetwork && !explicitlyApproved;
|
|
@@ -394,7 +411,11 @@ export async function runCli(argv) {
|
|
|
394
411
|
};
|
|
395
412
|
// cli2 command routing (single router).
|
|
396
413
|
const { buildRegistry } = await import("./run-cli/registry.run.js");
|
|
397
|
-
const registry = buildRegistry(
|
|
414
|
+
const registry = buildRegistry({
|
|
415
|
+
getCtx: getCtxOrThrow,
|
|
416
|
+
getResolvedProject,
|
|
417
|
+
getLoadedConfig,
|
|
418
|
+
});
|
|
398
419
|
const match = registry.match(rest);
|
|
399
420
|
if (match) {
|
|
400
421
|
const tail = rest.slice(match.consumed);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.test-helpers.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.test-helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-cli.test-helpers.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.test-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import os from "node:os";
|
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { promisify } from "node:util";
|
|
8
|
+
import { gzipSync } from "node:zlib";
|
|
8
9
|
import { afterAll, beforeAll } from "vitest";
|
|
9
10
|
import { defaultConfig } from "@agentplaneorg/core";
|
|
10
11
|
import { runCli } from "./run-cli.js";
|
|
@@ -12,6 +13,10 @@ const execFileAsync = promisify(execFile);
|
|
|
12
13
|
let agentplaneHome = null;
|
|
13
14
|
const originalAgentplaneHome = process.env.AGENTPLANE_HOME;
|
|
14
15
|
const originalNoUpdateCheck = process.env.AGENTPLANE_NO_UPDATE_CHECK;
|
|
16
|
+
const originalGitAuthorName = process.env.GIT_AUTHOR_NAME;
|
|
17
|
+
const originalGitAuthorEmail = process.env.GIT_AUTHOR_EMAIL;
|
|
18
|
+
const originalGitCommitterName = process.env.GIT_COMMITTER_NAME;
|
|
19
|
+
const originalGitCommitterEmail = process.env.GIT_COMMITTER_EMAIL;
|
|
15
20
|
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
16
21
|
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
17
22
|
let stdioSilenceDepth = 0;
|
|
@@ -24,6 +29,12 @@ async function ensureGitTemplateRoot() {
|
|
|
24
29
|
gitTemplatePromise ??= (async () => {
|
|
25
30
|
const root = await mkdtemp(path.join(os.tmpdir(), "agentplane-git-template-"));
|
|
26
31
|
await execFileAsync("git", ["init", "-q"], { cwd: root });
|
|
32
|
+
// Tests must not rely on global git config. Configure author identity locally
|
|
33
|
+
// so any helper that creates commits works in CI.
|
|
34
|
+
await execFileAsync("git", ["config", "user.email", "agentplane-test@example.com"], {
|
|
35
|
+
cwd: root,
|
|
36
|
+
});
|
|
37
|
+
await execFileAsync("git", ["config", "user.name", "agentplane-test"], { cwd: root });
|
|
27
38
|
return root;
|
|
28
39
|
})();
|
|
29
40
|
gitTemplateRoot = await gitTemplatePromise;
|
|
@@ -38,6 +49,11 @@ export function registerAgentplaneHome() {
|
|
|
38
49
|
agentplaneHome = await mkdtemp(path.join(os.tmpdir(), "agentplane-home-"));
|
|
39
50
|
process.env.AGENTPLANE_HOME = agentplaneHome;
|
|
40
51
|
process.env.AGENTPLANE_NO_UPDATE_CHECK = "1";
|
|
52
|
+
// Keep tests hermetic: never rely on global git config for commit authorship.
|
|
53
|
+
process.env.GIT_AUTHOR_NAME ??= "agentplane-test";
|
|
54
|
+
process.env.GIT_AUTHOR_EMAIL ??= "agentplane-test@example.com";
|
|
55
|
+
process.env.GIT_COMMITTER_NAME ??= "agentplane-test";
|
|
56
|
+
process.env.GIT_COMMITTER_EMAIL ??= "agentplane-test@example.com";
|
|
41
57
|
});
|
|
42
58
|
afterAll(async () => {
|
|
43
59
|
if (agentplaneHome) {
|
|
@@ -55,6 +71,22 @@ export function registerAgentplaneHome() {
|
|
|
55
71
|
else {
|
|
56
72
|
process.env.AGENTPLANE_NO_UPDATE_CHECK = originalNoUpdateCheck;
|
|
57
73
|
}
|
|
74
|
+
if (originalGitAuthorName === undefined)
|
|
75
|
+
delete process.env.GIT_AUTHOR_NAME;
|
|
76
|
+
else
|
|
77
|
+
process.env.GIT_AUTHOR_NAME = originalGitAuthorName;
|
|
78
|
+
if (originalGitAuthorEmail === undefined)
|
|
79
|
+
delete process.env.GIT_AUTHOR_EMAIL;
|
|
80
|
+
else
|
|
81
|
+
process.env.GIT_AUTHOR_EMAIL = originalGitAuthorEmail;
|
|
82
|
+
if (originalGitCommitterName === undefined)
|
|
83
|
+
delete process.env.GIT_COMMITTER_NAME;
|
|
84
|
+
else
|
|
85
|
+
process.env.GIT_COMMITTER_NAME = originalGitCommitterName;
|
|
86
|
+
if (originalGitCommitterEmail === undefined)
|
|
87
|
+
delete process.env.GIT_COMMITTER_EMAIL;
|
|
88
|
+
else
|
|
89
|
+
process.env.GIT_COMMITTER_EMAIL = originalGitCommitterEmail;
|
|
58
90
|
});
|
|
59
91
|
}
|
|
60
92
|
export function getAgentplaneHome() {
|
|
@@ -278,11 +310,75 @@ export async function createUnsafeRecipeArchive(opts) {
|
|
|
278
310
|
const entryPath = opts.entryPath ?? "../evil.txt";
|
|
279
311
|
await writeFile(path.join(baseDir, "evil.txt"), "evil", "utf8");
|
|
280
312
|
const archivePath = opts.format === "zip" ? path.join(baseDir, "unsafe.zip") : path.join(baseDir, "unsafe.tar.gz");
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
313
|
+
if (opts.format === "zip") {
|
|
314
|
+
await execFileAsync("zip", ["-qr", archivePath, ".", entryPath], { cwd: recipeDir });
|
|
315
|
+
return archivePath;
|
|
316
|
+
}
|
|
317
|
+
// Build a deterministic tar.gz containing a traversal entry, without relying on system tar behavior.
|
|
318
|
+
// This keeps the archive validation tests stable across GNU tar / bsdtar.
|
|
319
|
+
const tar = buildTar([
|
|
320
|
+
{
|
|
321
|
+
name: "./manifest.json",
|
|
322
|
+
data: Buffer.from(JSON.stringify(manifest, null, 2) + "\n", "utf8"),
|
|
323
|
+
},
|
|
324
|
+
{ name: entryPath, data: Buffer.from("evil\n", "utf8") },
|
|
325
|
+
]);
|
|
326
|
+
const gz = gzipSync(tar);
|
|
327
|
+
await writeFile(archivePath, gz);
|
|
284
328
|
return archivePath;
|
|
285
329
|
}
|
|
330
|
+
function buildTar(entries) {
|
|
331
|
+
const out = [];
|
|
332
|
+
for (const ent of entries) {
|
|
333
|
+
const header = tarHeader({
|
|
334
|
+
name: ent.name,
|
|
335
|
+
size: ent.data.length,
|
|
336
|
+
mtime: 0,
|
|
337
|
+
typeflag: "0",
|
|
338
|
+
});
|
|
339
|
+
out.push(header, ent.data, zeroPadTo512(ent.data.length));
|
|
340
|
+
}
|
|
341
|
+
// Two empty blocks mark end-of-archive.
|
|
342
|
+
out.push(Buffer.alloc(1024, 0));
|
|
343
|
+
return Buffer.concat(out);
|
|
344
|
+
}
|
|
345
|
+
function zeroPadTo512(n) {
|
|
346
|
+
const rem = n % 512;
|
|
347
|
+
if (rem === 0)
|
|
348
|
+
return Buffer.alloc(0);
|
|
349
|
+
return Buffer.alloc(512 - rem, 0);
|
|
350
|
+
}
|
|
351
|
+
function tarHeader(opts) {
|
|
352
|
+
const buf = Buffer.alloc(512, 0);
|
|
353
|
+
writeTarString(buf, 0, 100, opts.name);
|
|
354
|
+
writeTarOctal(buf, 100, 8, 0o644); // mode
|
|
355
|
+
writeTarOctal(buf, 108, 8, 0); // uid
|
|
356
|
+
writeTarOctal(buf, 116, 8, 0); // gid
|
|
357
|
+
writeTarOctal(buf, 124, 12, opts.size);
|
|
358
|
+
writeTarOctal(buf, 136, 12, opts.mtime);
|
|
359
|
+
// checksum field must be treated as spaces for calculation
|
|
360
|
+
buf.fill(0x20, 148, 156);
|
|
361
|
+
writeTarString(buf, 156, 1, opts.typeflag);
|
|
362
|
+
writeTarString(buf, 257, 6, "ustar"); // magic
|
|
363
|
+
writeTarString(buf, 263, 2, "00"); // version
|
|
364
|
+
const sum = buf.reduce((acc, b) => acc + b, 0);
|
|
365
|
+
writeTarChecksum(buf, sum);
|
|
366
|
+
return buf;
|
|
367
|
+
}
|
|
368
|
+
function writeTarString(buf, offset, length, value) {
|
|
369
|
+
const b = Buffer.from(value, "utf8");
|
|
370
|
+
b.copy(buf, offset, 0, Math.min(length, b.length));
|
|
371
|
+
}
|
|
372
|
+
function writeTarOctal(buf, offset, length, value) {
|
|
373
|
+
const raw = Math.max(0, value).toString(8);
|
|
374
|
+
const padded = raw.padStart(length - 1, "0") + "\0";
|
|
375
|
+
writeTarString(buf, offset, length, padded);
|
|
376
|
+
}
|
|
377
|
+
function writeTarChecksum(buf, sum) {
|
|
378
|
+
// 6 digits, NUL, space (common convention).
|
|
379
|
+
const raw = Math.max(0, sum).toString(8).padStart(6, "0");
|
|
380
|
+
writeTarString(buf, 148, 8, `${raw}\0 `);
|
|
381
|
+
}
|
|
286
382
|
export async function createUpgradeBundle(files) {
|
|
287
383
|
const manifestUrl = new URL("../../assets/framework.manifest.json", import.meta.url);
|
|
288
384
|
const manifestText = typeof files["framework.manifest.json"] === "string"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CommandSpec } from "./spec.js";
|
|
2
|
+
export declare function asTrimmedString(value: unknown): string;
|
|
3
|
+
export declare function toStringList(value: unknown): string[];
|
|
4
|
+
export declare function assertNonEmptyStrings(opts: {
|
|
5
|
+
list: readonly string[];
|
|
6
|
+
flagName: string;
|
|
7
|
+
spec: CommandSpec<unknown>;
|
|
8
|
+
command: string;
|
|
9
|
+
message?: string;
|
|
10
|
+
}): void;
|
|
11
|
+
//# sourceMappingURL=parse-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-utils.d.ts","sourceRoot":"","sources":["../../../src/cli/spec/parse-utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQtD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAGrD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAYP"}
|