agentplane 0.2.14 → 0.2.17

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":"redmine-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/redmine-backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redmine-backend.d.ts","sourceRoot":"","sources":["../../../src/backends/task-backend/redmine-backend.ts"],"names":[],"mappings":"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"}
@@ -37,8 +37,15 @@ export class RedmineBackend {
37
37
  this.batchPause = typeof settings.batch_pause === "number" ? settings.batch_pause : 0.5;
38
38
  this.ownerAgent = firstNonEmptyString(envOwner, settings.owner_agent, "REDMINE");
39
39
  this.cache = opts.cache ?? null;
40
- if (!this.baseUrl || !this.apiKey || !this.projectId) {
41
- throw new BackendError(redmineConfigMissingMessage("url, api_key, project_id"), "E_BACKEND");
40
+ const missingEnvKeys = [];
41
+ if (!this.baseUrl)
42
+ missingEnvKeys.push("AGENTPLANE_REDMINE_URL");
43
+ if (!this.apiKey)
44
+ missingEnvKeys.push("AGENTPLANE_REDMINE_API_KEY");
45
+ if (!this.projectId)
46
+ missingEnvKeys.push("AGENTPLANE_REDMINE_PROJECT_ID");
47
+ if (missingEnvKeys.length > 0) {
48
+ throw new BackendError(redmineConfigMissingMessage(missingEnvKeys.join(", ")), "E_BACKEND");
42
49
  }
43
50
  if (!this.customFields?.task_id) {
44
51
  throw new BackendError(redmineConfigMissingMessage("custom_fields.task_id"), "E_BACKEND");
@@ -11,7 +11,7 @@ export class RedmineUnavailable extends BackendError {
11
11
  }
12
12
  }
13
13
  export function redmineConfigMissingMessage(detail) {
14
- return `Missing required Redmine config: ${detail}`;
14
+ return `Missing required Redmine configuration. Set ${detail} in environment variables (for example via .env).`;
15
15
  }
16
16
  export function redmineIssueIdMissingMessage() {
17
17
  return "Missing Redmine issue id for task";
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/ui.ts"],"names":[],"mappings":"AAsBA,wBAAgB,iBAAiB,IAAI,MAAM,CAa1C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG5E"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/ui.ts"],"names":[],"mappings":"AAsBA,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG5E"}
@@ -20,19 +20,18 @@ function box(lines) {
20
20
  }
21
21
  export function renderInitWelcome() {
22
22
  const logo = [
23
- " ___ ____ ____ _ _ _____ ",
24
- " / _ | / __// __// | / / ___/ ",
25
- " / __ |/ _/ / _/ / |/ / /__ ",
26
- String.raw `/_/ |_|\__/ /___//_/|_/\___/ `,
27
- " agent/plane ",
23
+ "░█▀█░█▀▀░█▀▀░█▀█░▀█▀░░░█░█▀█░█░░░█▀█░█▀█░█▀▀",
24
+ "░█▀█░█░█░█▀▀░█░█░░█░░▄▀░░█▀▀░█░░░█▀█░█░█░█▀▀",
25
+ "░▀░▀░▀▀▀░▀▀▀░▀░▀░░▀░░▀░░░▀░░░▀▀▀░▀░▀░▀░▀░▀▀▀",
28
26
  ].map((line) => color(line, "36"));
27
+ const subtitle = color("agent/plane", "36");
29
28
  const intro = [
30
29
  color("Bootstrap an agent-first workflow in this repository.", "1"),
31
30
  "This interactive setup runs once; daily work is executed by agents.",
32
31
  ];
33
- return `${logo.join("\n")}\n\n${box(intro)}\n`;
32
+ return `${logo.join("\n")}\n${subtitle}\n\n${box(intro)}\n\n`;
34
33
  }
35
34
  export function renderInitSection(title, description) {
36
35
  const header = color(`[${title}]`, "33");
37
- return `${header}\n${description}\n`;
36
+ return `${header}\n${description}\n\n`;
38
37
  }
@@ -10,7 +10,7 @@ export type InitExecutionConfig = {
10
10
  handoff_conditions: string[];
11
11
  unsafe_actions_requiring_explicit_user_ok: string[];
12
12
  };
13
- export declare function ensureAgentplaneDirs(agentplaneDir: string): Promise<void>;
13
+ export declare function ensureAgentplaneDirs(agentplaneDir: string, backend: "local" | "redmine"): Promise<void>;
14
14
  export declare function writeInitConfig(opts: {
15
15
  agentplaneDir: string;
16
16
  gitRoot: string;
@@ -22,7 +22,7 @@ export declare function writeInitConfig(opts: {
22
22
  execution: InitExecutionConfig;
23
23
  }): Promise<void>;
24
24
  export declare function writeBackendStubs(opts: {
25
- localBackendPath: string;
26
- redmineBackendPath: string;
25
+ backend: "local" | "redmine";
26
+ backendPath: string;
27
27
  }): Promise<void>;
28
28
  //# sourceMappingURL=write-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-config.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-config.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;IACpD,gBAAgB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC5C,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,yCAAyC,EAAE,MAAM,EAAE,CAAC;CACrD,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO/E;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sBAAsB,EAAE,OAAO,CAAC;IAChC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,mBAAmB,CAAC;CAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBhB"}
1
+ {"version":3,"file":"write-config.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-config.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;IACpD,gBAAgB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC5C,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,yCAAyC,EAAE,MAAM,EAAE,CAAC;CACrD,CAAC;AAEF,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,GAAG,SAAS,GAC3B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,GAAG,WAAW,CAAC;IACjC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sBAAsB,EAAE,OAAO,CAAC;IAChC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,mBAAmB,CAAC;CAChC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBhB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBhB"}
@@ -2,13 +2,13 @@ import { mkdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { defaultConfig, saveConfig, setByDottedKey } from "@agentplaneorg/core";
4
4
  import { writeJsonStableIfChanged } from "../../../../shared/write-if-changed.js";
5
- export async function ensureAgentplaneDirs(agentplaneDir) {
5
+ export async function ensureAgentplaneDirs(agentplaneDir, backend) {
6
6
  await mkdir(agentplaneDir, { recursive: true });
7
7
  await mkdir(path.join(agentplaneDir, "tasks"), { recursive: true });
8
8
  await mkdir(path.join(agentplaneDir, "agents"), { recursive: true });
9
9
  await mkdir(path.join(agentplaneDir, "cache"), { recursive: true });
10
- await mkdir(path.join(agentplaneDir, "backends", "local"), { recursive: true });
11
- await mkdir(path.join(agentplaneDir, "backends", "redmine"), { recursive: true });
10
+ await mkdir(path.join(agentplaneDir, "backends"), { recursive: true });
11
+ await mkdir(path.join(agentplaneDir, "backends", backend), { recursive: true });
12
12
  }
13
13
  export async function writeInitConfig(opts) {
14
14
  const rawConfig = defaultConfig();
@@ -30,13 +30,10 @@ export async function writeBackendStubs(opts) {
30
30
  id: "redmine",
31
31
  version: 1,
32
32
  settings: {
33
- url: "https://redmine.example",
34
- api_key: "replace-me",
35
- project_id: "replace-me",
36
33
  owner_agent: "REDMINE",
37
34
  custom_fields: { task_id: 1 },
38
35
  },
39
36
  };
40
- await writeJsonStableIfChanged(opts.localBackendPath, localBackendPayload);
41
- await writeJsonStableIfChanged(opts.redmineBackendPath, redmineBackendPayload);
37
+ const payload = opts.backend === "redmine" ? redmineBackendPayload : localBackendPayload;
38
+ await writeJsonStableIfChanged(opts.backendPath, payload);
42
39
  }
@@ -0,0 +1,4 @@
1
+ export declare function ensureInitRedmineEnvTemplate(opts: {
2
+ gitRoot: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=write-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-env.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-env.ts"],"names":[],"mappings":"AAkEA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC3F"}
@@ -0,0 +1,89 @@
1
+ import path from "node:path";
2
+ import { readFile } from "node:fs/promises";
3
+ import { writeTextIfChanged } from "../../../../shared/write-if-changed.js";
4
+ const REDMINE_ENV_TEMPLATE = [
5
+ {
6
+ key: "AGENTPLANE_REDMINE_URL",
7
+ value: "https://redmine.example",
8
+ comment: "Redmine base URL.",
9
+ required: true,
10
+ },
11
+ {
12
+ key: "AGENTPLANE_REDMINE_API_KEY",
13
+ value: "replace-me",
14
+ comment: "Redmine API key.",
15
+ required: true,
16
+ },
17
+ {
18
+ key: "AGENTPLANE_REDMINE_PROJECT_ID",
19
+ value: "replace-me",
20
+ comment: "Project identifier (numeric ID or project slug).",
21
+ required: true,
22
+ },
23
+ {
24
+ key: "AGENTPLANE_REDMINE_OWNER_AGENT",
25
+ value: "REDMINE",
26
+ comment: "Optional default owner agent.",
27
+ required: false,
28
+ },
29
+ {
30
+ key: "AGENTPLANE_REDMINE_ASSIGNEE_ID",
31
+ value: "",
32
+ comment: "Optional assignee numeric ID.",
33
+ required: false,
34
+ },
35
+ ];
36
+ async function readTextIfExists(filePath) {
37
+ try {
38
+ return await readFile(filePath, "utf8");
39
+ }
40
+ catch (err) {
41
+ const code = err?.code;
42
+ if (code === "ENOENT")
43
+ return null;
44
+ throw err;
45
+ }
46
+ }
47
+ function collectDefinedEnvKeys(dotEnvText) {
48
+ const keys = new Set();
49
+ for (const line of dotEnvText.split(/\r?\n/u)) {
50
+ const trimmed = line.trim();
51
+ if (!trimmed || trimmed.startsWith("#"))
52
+ continue;
53
+ const match = /^([A-Za-z_][A-Za-z0-9_]*)\s*=/u.exec(trimmed);
54
+ if (match?.[1])
55
+ keys.add(match[1]);
56
+ }
57
+ return keys;
58
+ }
59
+ export async function ensureInitRedmineEnvTemplate(opts) {
60
+ const dotEnvPath = path.join(opts.gitRoot, ".env");
61
+ const existing = (await readTextIfExists(dotEnvPath)) ?? "";
62
+ const definedKeys = collectDefinedEnvKeys(existing);
63
+ const missing = REDMINE_ENV_TEMPLATE.filter((entry) => !definedKeys.has(entry.key));
64
+ if (missing.length === 0)
65
+ return;
66
+ const required = missing.filter((item) => item.required);
67
+ const optional = missing.filter((item) => !item.required);
68
+ const requiredLines = required.flatMap((entry) => [
69
+ `# ${entry.comment}`,
70
+ `${entry.key}=${entry.value}`,
71
+ ]);
72
+ const optionalLines = optional.length === 0
73
+ ? []
74
+ : [
75
+ "",
76
+ "# Optional values:",
77
+ ...optional.flatMap((entry) => [`# ${entry.comment}`, `${entry.key}=${entry.value}`]),
78
+ ];
79
+ const lines = [
80
+ "# agentplane: redmine backend configuration",
81
+ "# Required values:",
82
+ ...requiredLines,
83
+ ...optionalLines,
84
+ ];
85
+ const block = `${lines.join("\n")}\n`;
86
+ const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n\n" : existing.length > 0 ? "\n" : "";
87
+ const next = `${existing}${prefix}${block}`;
88
+ await writeTextIfChanged(dotEnvPath, next);
89
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"write-gitignore.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-gitignore.ts"],"names":[],"mappings":"AAgCA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB"}
1
+ {"version":3,"file":"write-gitignore.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-gitignore.ts"],"names":[],"mappings":"AAiCA,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB"}
@@ -14,6 +14,7 @@ async function readTextIfExists(filePath) {
14
14
  }
15
15
  const RUNTIME_IGNORE_LINES = [
16
16
  "# agentplane: ignore runtime/transient workspace artifacts",
17
+ ".env",
17
18
  ".agentplane/worktrees",
18
19
  ".agentplane/cache",
19
20
  ".agentplane/recipes-cache",
@@ -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;AAqBtE,KAAK,gBAAgB,GAAG,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;AAuEnE,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,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,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,CA2K5C,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CACmB,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;AAsBtE,KAAK,gBAAgB,GAAG,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;AAuEnE,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,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,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,CA2K5C,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,cAAc,CAAC,UAAU,CACmB,CAAC"}
@@ -16,6 +16,7 @@ import { maybeInstallBundledRecipes } from "./init/recipes.js";
16
16
  import { ensureAgentplaneDirs, writeBackendStubs, writeInitConfig, } from "./init/write-config.js";
17
17
  import { ensureAgentsFiles } from "./init/write-agents.js";
18
18
  import { ensureInitGitignore } from "./init/write-gitignore.js";
19
+ import { ensureInitRedmineEnvTemplate } from "./init/write-env.js";
19
20
  import { renderInitSection, renderInitWelcome } from "./init/ui.js";
20
21
  function buildInitExecutionProfile(profile, opts) {
21
22
  const shared = {
@@ -305,41 +306,56 @@ async function cmdInit(opts) {
305
306
  });
306
307
  }
307
308
  if (isInteractive) {
309
+ const askChoice = async (label, choices, defaultValue) => {
310
+ const result = await promptChoice(`\n${label}`, choices, defaultValue);
311
+ process.stdout.write("\n");
312
+ return result;
313
+ };
314
+ const askYesNo = async (label, defaultValue) => {
315
+ const result = await promptYesNo(`\n${label}`, defaultValue);
316
+ process.stdout.write("\n");
317
+ return result;
318
+ };
319
+ const askInput = async (label) => {
320
+ const result = await promptInput(`\n${label}`);
321
+ process.stdout.write("\n");
322
+ return result;
323
+ };
308
324
  process.stdout.write(renderInitWelcome());
309
325
  process.stdout.write(renderInitSection("Workflow", "Choose how branches/backends/approvals should be initialized for this repository."));
310
326
  ide = flags.ide ?? defaults.ide;
311
327
  if (!flags.workflow) {
312
- const choice = await promptChoice("Workflow mode", ["direct", "branch_pr"], workflow);
328
+ const choice = await askChoice("Workflow mode", ["direct", "branch_pr"], workflow);
313
329
  workflow = choice === "branch_pr" ? "branch_pr" : "direct";
314
330
  }
315
331
  if (!flags.backend) {
316
- const choice = await promptChoice("Task backend", ["local", "redmine"], backend);
332
+ const choice = await askChoice("Task backend", ["local", "redmine"], backend);
317
333
  backend = choice === "redmine" ? "redmine" : "local";
318
334
  }
319
335
  if (flags.hooks === undefined) {
320
- hooks = await promptYesNo("Install managed git hooks now?", hooks);
336
+ hooks = await askYesNo("Install managed git hooks now?", hooks);
321
337
  }
322
338
  process.stdout.write(renderInitSection("Execution Profile", "Set default autonomy/effort for agents. You can change this later in config."));
323
339
  if (!flags.executionProfile) {
324
- executionProfile = (await promptChoice("Execution profile", ["conservative", "balanced", "aggressive"], executionProfile));
340
+ executionProfile = (await askChoice("Execution profile", ["conservative", "balanced", "aggressive"], executionProfile));
325
341
  }
326
342
  if (flags.strictUnsafeConfirm === undefined) {
327
- strictUnsafeConfirm = await promptYesNo("Require strict explicit confirmation for extra unsafe actions?", strictUnsafeConfirm);
343
+ strictUnsafeConfirm = await askYesNo("Require strict explicit confirmation for extra unsafe actions?", strictUnsafeConfirm);
328
344
  }
329
345
  process.stdout.write(renderInitSection("Approvals", "Control whether plan/network/verification actions require explicit approval by default."));
330
346
  if (flags.requirePlanApproval === undefined) {
331
- requirePlanApproval = await promptYesNo("Require plan approval before work starts?", requirePlanApproval);
347
+ requirePlanApproval = await askYesNo("Require plan approval before work starts?", requirePlanApproval);
332
348
  }
333
349
  if (flags.requireNetworkApproval === undefined) {
334
- requireNetworkApproval = await promptYesNo("Require explicit approval for network actions?", requireNetworkApproval);
350
+ requireNetworkApproval = await askYesNo("Require explicit approval for network actions?", requireNetworkApproval);
335
351
  }
336
352
  if (flags.requireVerifyApproval === undefined) {
337
- requireVerifyApproval = await promptYesNo("Require explicit approval before recording verification?", requireVerifyApproval);
353
+ requireVerifyApproval = await askYesNo("Require explicit approval before recording verification?", requireVerifyApproval);
338
354
  }
339
355
  process.stdout.write(renderInitSection("Recipes", "Optional: install recipe packs now (comma-separated IDs) or choose none."));
340
356
  if (!flags.recipes) {
341
357
  process.stdout.write(`${renderBundledRecipesHint()}\n`);
342
- const answer = await promptInput("Install optional recipes (comma separated, or none): ");
358
+ const answer = await askInput("Install optional recipes (comma separated, or none): ");
343
359
  recipes = answer
344
360
  ? answer
345
361
  .split(",")
@@ -383,10 +399,9 @@ async function cmdInit(opts) {
383
399
  path.join(resolved.agentplaneDir, "agents"),
384
400
  path.join(resolved.agentplaneDir, "cache"),
385
401
  path.join(resolved.agentplaneDir, "backends"),
386
- path.join(resolved.agentplaneDir, "backends", "local"),
387
- path.join(resolved.agentplaneDir, "backends", "redmine"),
402
+ path.join(resolved.agentplaneDir, "backends", backend),
388
403
  ];
389
- const initFiles = [configPath, localBackendPath, redmineBackendPath];
404
+ const initFiles = [configPath, backendPath];
390
405
  const conflicts = await collectInitConflicts({ initDirs, initFiles });
391
406
  await handleInitConflicts({
392
407
  gitRoot: resolved.gitRoot,
@@ -394,7 +409,7 @@ async function cmdInit(opts) {
394
409
  backup: flags.backup === true,
395
410
  force: flags.force === true,
396
411
  });
397
- await ensureAgentplaneDirs(resolved.agentplaneDir);
412
+ await ensureAgentplaneDirs(resolved.agentplaneDir, backend);
398
413
  const execution = buildInitExecutionProfile(executionProfile, { strictUnsafeConfirm });
399
414
  await writeInitConfig({
400
415
  agentplaneDir: resolved.agentplaneDir,
@@ -406,7 +421,10 @@ async function cmdInit(opts) {
406
421
  requireVerifyApproval,
407
422
  execution,
408
423
  });
409
- await writeBackendStubs({ localBackendPath, redmineBackendPath });
424
+ await writeBackendStubs({ backend, backendPath });
425
+ if (backend === "redmine") {
426
+ await ensureInitRedmineEnvTemplate({ gitRoot: resolved.gitRoot });
427
+ }
410
428
  const { installPaths } = await ensureAgentsFiles({
411
429
  gitRoot: resolved.gitRoot,
412
430
  agentplaneDir: resolved.agentplaneDir,
@@ -418,6 +436,7 @@ async function cmdInit(opts) {
418
436
  gitRoot: resolved.gitRoot,
419
437
  includeAgentPromptFiles: flags.gitignoreAgents === true,
420
438
  });
439
+ installPaths.push(".gitignore");
421
440
  if (flags.gitignoreAgents) {
422
441
  await setPinnedBaseBranch({
423
442
  cwd: resolved.gitRoot,
@@ -427,6 +446,7 @@ async function cmdInit(opts) {
427
446
  }
428
447
  if (hooks) {
429
448
  await cmdHooksInstall({ cwd: opts.cwd, rootOverride: opts.rootOverride, quiet: true });
449
+ installPaths.push(".agentplane/bin/agentplane");
430
450
  }
431
451
  const ideRes = await maybeSyncIde({
432
452
  cwd: opts.cwd,
@@ -1 +1 @@
1
- {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAS1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AA0KnD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAwE5D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,kBAAkB,CA+H9D,CAAC"}
1
+ {"version":3,"file":"apply.command.d.ts","sourceRoot":"","sources":["../../../src/commands/release/apply.command.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAU1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAuOnD,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAwE5D,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,cAAc,CAAC,kBAAkB,CA6H9D,CAAC"}
@@ -1,11 +1,12 @@
1
1
  import { readFile, writeFile, readdir } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { resolveProject } from "@agentplaneorg/core";
3
+ import { resolveProject, loadConfig } from "@agentplaneorg/core";
4
4
  import { usageError } from "../../cli/spec/errors.js";
5
5
  import { exitCodeForError } from "../../cli/exit-codes.js";
6
6
  import { CliError } from "../../shared/errors.js";
7
7
  import { execFileAsync, gitEnv } from "../shared/git.js";
8
8
  import { GitContext } from "../shared/git-context.js";
9
+ import { ensureNetworkApproved } from "../shared/network-approval.js";
9
10
  async function fileExists(p) {
10
11
  try {
11
12
  await readFile(p, "utf8");
@@ -154,6 +155,63 @@ async function maybeUpdateBunLockfile(gitRoot) {
154
155
  });
155
156
  }
156
157
  }
158
+ async function ensureCleanTrackedTree(gitRoot) {
159
+ const { stdout } = await execFileAsync("git", ["status", "--short", "--untracked-files=no"], {
160
+ cwd: gitRoot,
161
+ env: gitEnv(),
162
+ maxBuffer: 10 * 1024 * 1024,
163
+ });
164
+ const dirty = String(stdout ?? "")
165
+ .split(/\r?\n/u)
166
+ .map((line) => line.trimEnd())
167
+ .filter((line) => line.length > 0);
168
+ if (dirty.length === 0)
169
+ return;
170
+ throw new CliError({
171
+ exitCode: exitCodeForError("E_GIT"),
172
+ code: "E_GIT",
173
+ message: "Release apply requires a clean tracked working tree.\n" +
174
+ `Found tracked changes:\n${dirty.map((line) => ` ${line}`).join("\n")}`,
175
+ });
176
+ }
177
+ async function ensureTagDoesNotExist(gitRoot, tag) {
178
+ try {
179
+ await execFileAsync("git", ["rev-parse", "-q", "--verify", `refs/tags/${tag}`], {
180
+ cwd: gitRoot,
181
+ env: gitEnv(),
182
+ });
183
+ throw new CliError({
184
+ exitCode: exitCodeForError("E_GIT"),
185
+ code: "E_GIT",
186
+ message: `Tag already exists: ${tag}`,
187
+ });
188
+ }
189
+ catch (err) {
190
+ const code = err?.code;
191
+ if (code !== 1)
192
+ throw err;
193
+ }
194
+ }
195
+ async function ensureNpmVersionsAvailable(gitRoot, version) {
196
+ const scriptPath = path.join(gitRoot, "scripts", "check-npm-version-availability.mjs");
197
+ try {
198
+ await execFileAsync("node", [scriptPath, "--version", version], {
199
+ cwd: gitRoot,
200
+ env: process.env,
201
+ maxBuffer: 10 * 1024 * 1024,
202
+ });
203
+ }
204
+ catch (err) {
205
+ const details = String(err?.stderr ?? "").trim();
206
+ throw new CliError({
207
+ exitCode: exitCodeForError("E_VALIDATION"),
208
+ code: "E_VALIDATION",
209
+ message: `Pre-publish npm check failed for version ${version}. ` +
210
+ "Ensure this version is not already published for @agentplaneorg/core and agentplane." +
211
+ (details ? `\n\n${details}` : ""),
212
+ });
213
+ }
214
+ }
157
215
  export const releaseApplySpec = {
158
216
  id: ["release", "apply"],
159
217
  group: "Release",
@@ -276,6 +334,18 @@ export const runReleaseApply = async (ctx, flags) => {
276
334
  });
277
335
  }
278
336
  const git = new GitContext({ gitRoot });
337
+ await ensureCleanTrackedTree(gitRoot);
338
+ await ensureTagDoesNotExist(gitRoot, plan.nextTag);
339
+ if (flags.push) {
340
+ const loaded = await loadConfig(resolved.agentplaneDir);
341
+ await ensureNetworkApproved({
342
+ config: loaded.config,
343
+ yes: flags.yes,
344
+ reason: "release apply --push validates npm version availability and pushes over network",
345
+ interactive: Boolean(process.stdin.isTTY),
346
+ });
347
+ await ensureNpmVersionsAvailable(gitRoot, plan.nextVersion);
348
+ }
279
349
  if (coreVersion === plan.prevVersion) {
280
350
  await Promise.all([
281
351
  replacePackageVersionInFile(corePkgPath, plan.nextVersion),
@@ -309,23 +379,6 @@ export const runReleaseApply = async (ctx, flags) => {
309
379
  const subject = `✨ release: ${plan.nextTag}`;
310
380
  await git.commit({ message: subject, env: cleanHookEnv() });
311
381
  }
312
- // Create tag (idempotency: refuse to overwrite).
313
- try {
314
- await execFileAsync("git", ["rev-parse", "-q", "--verify", `refs/tags/${plan.nextTag}`], {
315
- cwd: gitRoot,
316
- env: gitEnv(),
317
- });
318
- throw new CliError({
319
- exitCode: exitCodeForError("E_GIT"),
320
- code: "E_GIT",
321
- message: `Tag already exists: ${plan.nextTag}`,
322
- });
323
- }
324
- catch (err) {
325
- const code = err?.code;
326
- if (code !== 1)
327
- throw err;
328
- }
329
382
  await execFileAsync("git", ["tag", plan.nextTag], { cwd: gitRoot, env: gitEnv() });
330
383
  process.stdout.write(`Release tag created: ${plan.nextTag}\n`);
331
384
  if (flags.push) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentplane",
3
- "version": "0.2.14",
3
+ "version": "0.2.17",
4
4
  "description": "Agent Plane CLI for task workflows, recipes, and project automation.",
5
5
  "keywords": [
6
6
  "agentplane",