agentplane 0.2.17 → 0.2.18

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.
Files changed (93) hide show
  1. package/assets/AGENTS.md +14 -3
  2. package/dist/backends/task-backend/redmine/env.d.ts +16 -0
  3. package/dist/backends/task-backend/redmine/env.d.ts.map +1 -0
  4. package/dist/backends/task-backend/redmine/env.js +61 -0
  5. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
  6. package/dist/backends/task-backend/redmine/mapping.js +25 -3
  7. package/dist/backends/task-backend/redmine-backend.d.ts +1 -1
  8. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
  9. package/dist/backends/task-backend/redmine-backend.js +31 -21
  10. package/dist/backends/task-backend/shared/errors.d.ts +2 -1
  11. package/dist/backends/task-backend/shared/errors.d.ts.map +1 -1
  12. package/dist/backends/task-backend/shared/errors.js +6 -2
  13. package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
  14. package/dist/cli/run-cli/commands/init/ui.js +5 -3
  15. package/dist/cli/run-cli/commands/init/write-env.d.ts.map +1 -1
  16. package/dist/cli/run-cli/commands/init/write-env.js +14 -6
  17. package/dist/cli/run-cli/commands/init.d.ts +1 -1
  18. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  19. package/dist/cli/run-cli/commands/init.js +6 -68
  20. package/dist/cli/run-cli.d.ts.map +1 -1
  21. package/dist/cli/run-cli.js +5 -1
  22. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  23. package/dist/cli/run-cli.test-helpers.js +14 -2
  24. package/dist/cli/shared/ansi.d.ts +3 -0
  25. package/dist/cli/shared/ansi.d.ts.map +1 -0
  26. package/dist/cli/shared/ansi.js +19 -0
  27. package/dist/commands/block.run.d.ts.map +1 -1
  28. package/dist/commands/block.run.js +1 -0
  29. package/dist/commands/block.spec.d.ts +1 -0
  30. package/dist/commands/block.spec.d.ts.map +1 -1
  31. package/dist/commands/block.spec.js +7 -0
  32. package/dist/commands/branch/remove.command.d.ts +1 -0
  33. package/dist/commands/branch/remove.command.d.ts.map +1 -1
  34. package/dist/commands/branch/remove.command.js +8 -0
  35. package/dist/commands/branch/remove.d.ts +1 -0
  36. package/dist/commands/branch/remove.d.ts.map +1 -1
  37. package/dist/commands/branch/remove.js +9 -0
  38. package/dist/commands/doctor.run.d.ts.map +1 -1
  39. package/dist/commands/doctor.run.js +67 -0
  40. package/dist/commands/finish.run.d.ts.map +1 -1
  41. package/dist/commands/finish.run.js +1 -0
  42. package/dist/commands/finish.spec.d.ts +1 -0
  43. package/dist/commands/finish.spec.d.ts.map +1 -1
  44. package/dist/commands/finish.spec.js +7 -0
  45. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  46. package/dist/commands/guard/impl/commands.js +50 -0
  47. package/dist/commands/guard/impl/comment-commit.js +1 -1
  48. package/dist/commands/release/apply.command.d.ts.map +1 -1
  49. package/dist/commands/release/apply.command.js +39 -1
  50. package/dist/commands/shared/approval-requirements.d.ts +18 -0
  51. package/dist/commands/shared/approval-requirements.d.ts.map +1 -0
  52. package/dist/commands/shared/approval-requirements.js +77 -0
  53. package/dist/commands/shared/network-approval.d.ts.map +1 -1
  54. package/dist/commands/shared/network-approval.js +8 -23
  55. package/dist/commands/start.run.d.ts.map +1 -1
  56. package/dist/commands/start.run.js +1 -0
  57. package/dist/commands/start.spec.d.ts +1 -0
  58. package/dist/commands/start.spec.d.ts.map +1 -1
  59. package/dist/commands/start.spec.js +7 -0
  60. package/dist/commands/task/block.d.ts +1 -0
  61. package/dist/commands/task/block.d.ts.map +1 -1
  62. package/dist/commands/task/block.js +9 -0
  63. package/dist/commands/task/finish.d.ts +1 -0
  64. package/dist/commands/task/finish.d.ts.map +1 -1
  65. package/dist/commands/task/finish.js +9 -0
  66. package/dist/commands/task/migrate.command.d.ts +1 -0
  67. package/dist/commands/task/migrate.command.d.ts.map +1 -1
  68. package/dist/commands/task/migrate.command.js +8 -0
  69. package/dist/commands/task/migrate.d.ts +1 -0
  70. package/dist/commands/task/migrate.d.ts.map +1 -1
  71. package/dist/commands/task/migrate.js +9 -3
  72. package/dist/commands/task/normalize.command.d.ts +1 -0
  73. package/dist/commands/task/normalize.command.d.ts.map +1 -1
  74. package/dist/commands/task/normalize.command.js +8 -0
  75. package/dist/commands/task/normalize.d.ts +1 -0
  76. package/dist/commands/task/normalize.d.ts.map +1 -1
  77. package/dist/commands/task/normalize.js +9 -3
  78. package/dist/commands/task/scaffold.command.d.ts +1 -0
  79. package/dist/commands/task/scaffold.command.d.ts.map +1 -1
  80. package/dist/commands/task/scaffold.command.js +8 -0
  81. package/dist/commands/task/scaffold.d.ts +1 -0
  82. package/dist/commands/task/scaffold.d.ts.map +1 -1
  83. package/dist/commands/task/scaffold.js +9 -0
  84. package/dist/commands/task/set-status.command.d.ts +1 -0
  85. package/dist/commands/task/set-status.command.d.ts.map +1 -1
  86. package/dist/commands/task/set-status.command.js +8 -0
  87. package/dist/commands/task/set-status.d.ts +1 -0
  88. package/dist/commands/task/set-status.d.ts.map +1 -1
  89. package/dist/commands/task/set-status.js +7 -8
  90. package/dist/commands/task/start.d.ts +1 -0
  91. package/dist/commands/task/start.d.ts.map +1 -1
  92. package/dist/commands/task/start.js +9 -0
  93. package/package.json +2 -2
package/assets/AGENTS.md CHANGED
@@ -118,10 +118,21 @@ Outside-repo includes (non-exhaustive):
118
118
  - `handoff_conditions`: conditions that trigger handoff to another role
119
119
  - `unsafe_actions_requiring_explicit_user_ok`: actions that require explicit user confirmation
120
120
 
121
- Scope and precedence:
121
+ Approval escalation semantics:
122
122
 
123
- - These settings tune execution style only (autonomy, effort, budget, stop/handoff heuristics).
124
- - They MUST NOT override role authority boundaries, source-of-truth order, approval gates, or hard invariants defined in this `AGENTS.md`.
123
+ - `execution` MAY raise approval requirements for specific actions (`network_access`, `force_action`).
124
+ - `execution` does not add new CLI capabilities; it only changes whether explicit approval is required.
125
+ - Capability boundaries remain defined by CLI commands + this policy.
126
+
127
+ Profile matrix:
128
+
129
+ - `conservative`: require approval for `network_access` and `force_action` (even if baseline approvals disable them).
130
+ - `balanced`: use baseline approvals from `agents.approvals`.
131
+ - `aggressive`: use baseline approvals from `agents.approvals`.
132
+
133
+ Precedence:
134
+
135
+ - Role authority boundaries, source-of-truth order, and hard invariants in this `AGENTS.md` still take precedence.
125
136
  - If `execution` config conflicts with policy, `AGENTS.md` policy wins.
126
137
 
127
138
  ## Framework Upgrade / Prompt Merge
@@ -0,0 +1,16 @@
1
+ export type RedmineEnvConfig = {
2
+ url?: string;
3
+ apiKey?: string;
4
+ projectId?: string;
5
+ assigneeId?: number;
6
+ ownerAgent?: string;
7
+ customFields: Partial<Record<RedmineCustomFieldKey, number>>;
8
+ batch: {
9
+ size?: number;
10
+ pauseMs?: number;
11
+ };
12
+ };
13
+ type RedmineCustomFieldKey = "task_id" | "doc" | "doc_version" | "doc_updated_at" | "doc_updated_by" | "tags" | "priority" | "owner";
14
+ export declare function readRedmineEnv(): RedmineEnvConfig;
15
+ export {};
16
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/redmine/env.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7D,KAAK,EAAE;QACL,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAEF,KAAK,qBAAqB,GACtB,SAAS,GACT,KAAK,GACL,aAAa,GACb,gBAAgB,GAChB,gBAAgB,GAChB,MAAM,GACN,UAAU,GACV,OAAO,CAAC;AA6BZ,wBAAgB,cAAc,IAAI,gBAAgB,CAiCjD"}
@@ -0,0 +1,61 @@
1
+ import { BackendError, redmineConfigInvalidEnvMessage } from "../shared.js";
2
+ function nonEmptyEnv(key) {
3
+ const value = process.env[key];
4
+ if (typeof value !== "string")
5
+ return undefined;
6
+ const trimmed = value.trim();
7
+ return trimmed.length > 0 ? trimmed : undefined;
8
+ }
9
+ function parsePositiveIntEnv(key, opts) {
10
+ const raw = nonEmptyEnv(key);
11
+ if (!raw)
12
+ return undefined;
13
+ if (!/^\d+$/u.test(raw)) {
14
+ throw new BackendError(redmineConfigInvalidEnvMessage(key, "a positive integer"), "E_BACKEND");
15
+ }
16
+ const parsed = Number(raw);
17
+ const min = opts?.min ?? (opts?.allowZero ? 0 : 1);
18
+ if (!Number.isFinite(parsed) || parsed < min) {
19
+ throw new BackendError(redmineConfigInvalidEnvMessage(key, `an integer >= ${min}`), "E_BACKEND");
20
+ }
21
+ return parsed;
22
+ }
23
+ export function readRedmineEnv() {
24
+ const customFields = {};
25
+ const taskId = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_TASK_ID");
26
+ if (taskId !== undefined)
27
+ customFields.task_id = taskId;
28
+ const doc = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_DOC");
29
+ if (doc !== undefined)
30
+ customFields.doc = doc;
31
+ const docVersion = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_DOC_VERSION");
32
+ if (docVersion !== undefined)
33
+ customFields.doc_version = docVersion;
34
+ const docUpdatedAt = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_DOC_UPDATED_AT");
35
+ if (docUpdatedAt !== undefined)
36
+ customFields.doc_updated_at = docUpdatedAt;
37
+ const docUpdatedBy = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_DOC_UPDATED_BY");
38
+ if (docUpdatedBy !== undefined)
39
+ customFields.doc_updated_by = docUpdatedBy;
40
+ const tags = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_TAGS");
41
+ if (tags !== undefined)
42
+ customFields.tags = tags;
43
+ const priority = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_PRIORITY");
44
+ if (priority !== undefined)
45
+ customFields.priority = priority;
46
+ const owner = parsePositiveIntEnv("AGENTPLANE_REDMINE_CUSTOM_FIELDS_OWNER");
47
+ if (owner !== undefined)
48
+ customFields.owner = owner;
49
+ return {
50
+ url: nonEmptyEnv("AGENTPLANE_REDMINE_URL"),
51
+ apiKey: nonEmptyEnv("AGENTPLANE_REDMINE_API_KEY"),
52
+ projectId: nonEmptyEnv("AGENTPLANE_REDMINE_PROJECT_ID"),
53
+ assigneeId: parsePositiveIntEnv("AGENTPLANE_REDMINE_ASSIGNEE_ID"),
54
+ ownerAgent: nonEmptyEnv("AGENTPLANE_REDMINE_OWNER") ?? nonEmptyEnv("AGENTPLANE_REDMINE_OWNER_AGENT"),
55
+ customFields,
56
+ batch: {
57
+ size: parsePositiveIntEnv("AGENTPLANE_REDMINE_BATCH_SIZE"),
58
+ pauseMs: parsePositiveIntEnv("AGENTPLANE_REDMINE_BATCH_PAUSE", { allowZero: true, min: 0 }),
59
+ },
60
+ };
61
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/redmine/mapping.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AAMtB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,GAAG,QAAQ,GAAG,IAAI,CAwDlB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7F,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsC1B"}
1
+ {"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/redmine/mapping.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,cAAc,CAAC;AAMtB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASjE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,GAAG,QAAQ,GAAG,IAAI,CAwElB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7F,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyC1B"}
@@ -36,6 +36,9 @@ export function issueToTask(opts) {
36
36
  const commitVal = customFieldValue(opts.issue, opts.customFields.commit);
37
37
  const docVal = customFieldValue(opts.issue, opts.customFields.doc);
38
38
  const commentsVal = customFieldValue(opts.issue, opts.customFields.comments);
39
+ const tagsVal = customFieldValue(opts.issue, opts.customFields.tags);
40
+ const priorityFieldVal = customFieldValue(opts.issue, opts.customFields.priority);
41
+ const ownerFieldVal = customFieldValue(opts.issue, opts.customFields.owner);
39
42
  const docVersionVal = customFieldValue(opts.issue, opts.customFields.doc_version);
40
43
  const docUpdatedAtVal = customFieldValue(opts.issue, opts.customFields.doc_updated_at);
41
44
  const docUpdatedByVal = customFieldValue(opts.issue, opts.customFields.doc_updated_by);
@@ -45,7 +48,7 @@ export function issueToTask(opts) {
45
48
  ? opts.issue.created_on
46
49
  : null;
47
50
  const priorityVal = isRecord(opts.issue.priority) ? opts.issue.priority : null;
48
- const priorityName = normalizePriority(priorityVal?.name);
51
+ const priorityName = normalizePriority(priorityVal?.name ?? priorityFieldVal);
49
52
  const tags = [];
50
53
  if (Array.isArray(opts.issue.tags)) {
51
54
  for (const tag of opts.issue.tags) {
@@ -53,14 +56,30 @@ export function issueToTask(opts) {
53
56
  tags.push(toStringSafe(tag.name));
54
57
  }
55
58
  }
59
+ const tagsFromField = maybeParseJson(tagsVal);
60
+ if (Array.isArray(tagsFromField)) {
61
+ for (const tag of tagsFromField) {
62
+ const text = toStringSafe(tag).trim();
63
+ if (text)
64
+ tags.push(text);
65
+ }
66
+ }
67
+ else if (typeof tagsFromField === "string") {
68
+ for (const tag of tagsFromField.split(",")) {
69
+ const text = tag.trim();
70
+ if (text)
71
+ tags.push(text);
72
+ }
73
+ }
74
+ const mergedTags = [...new Set(tags)];
56
75
  const task = {
57
76
  id: toStringSafe(taskId),
58
77
  title: toStringSafe(opts.issue.subject),
59
78
  description: toStringSafe(opts.issue.description),
60
79
  status: status ?? "TODO",
61
80
  priority: priorityName,
62
- owner: opts.ownerAgent,
63
- tags,
81
+ owner: toStringSafe(ownerFieldVal ?? opts.ownerAgent),
82
+ tags: mergedTags,
64
83
  depends_on: [],
65
84
  verify: maybeParseJson(verifyVal),
66
85
  commit: maybeParseJson(commitVal),
@@ -108,6 +127,9 @@ export function taskToIssuePayload(opts) {
108
127
  opts.appendCustomField(customFields, "doc_version", opts.task.doc_version);
109
128
  opts.appendCustomField(customFields, "doc_updated_at", opts.task.doc_updated_at);
110
129
  opts.appendCustomField(customFields, "doc_updated_by", opts.task.doc_updated_by);
130
+ opts.appendCustomField(customFields, "tags", opts.task.tags);
131
+ opts.appendCustomField(customFields, "priority", opts.task.priority);
132
+ opts.appendCustomField(customFields, "owner", opts.task.owner);
111
133
  if (customFields.length > 0)
112
134
  payload.custom_fields = customFields;
113
135
  return payload;
@@ -21,7 +21,7 @@ export declare class RedmineBackend implements TaskBackend {
21
21
  statusMap: Record<string, unknown>;
22
22
  customFields: Record<string, unknown>;
23
23
  batchSize: number;
24
- batchPause: number;
24
+ batchPauseMs: number;
25
25
  cache: LocalBackend | null;
26
26
  issueCache: Map<string, Record<string, unknown>>;
27
27
  reverseStatus: Map<number, string>;
@@ -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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"}
@@ -6,7 +6,8 @@ import { appendCustomField as appendRedmineCustomField, customFieldValue as redm
6
6
  import { doneRatioForStatus, issueToTask as issueToTaskImpl, startDateFromTaskId, taskToIssuePayload as taskToIssuePayloadImpl, } from "./redmine/mapping.js";
7
7
  import { coerceDocVersion as coerceRedmineDocVersion, maybeParseJson as maybeParseRedmineJson, } from "./redmine/parse.js";
8
8
  import { findIssueByTaskId as findIssueByTaskIdImpl, listTasksRemote as listTasksRemoteImpl, } from "./redmine/remote.js";
9
- import { BackendError, DEFAULT_DOC_UPDATED_BY, DOC_VERSION, RedmineUnavailable, ensureDocMetadata, firstNonEmptyString, generateTaskId, mapLimit, missingTaskIdMessage, nowIso, redmineConfigMissingMessage, redmineIssueIdMissingMessage, sleep, toStringSafe, unknownTaskIdMessage, validateTaskId, writeTasksExportFromTasks, } from "./shared.js";
9
+ import { readRedmineEnv } from "./redmine/env.js";
10
+ import { BackendError, DEFAULT_DOC_UPDATED_BY, DOC_VERSION, RedmineUnavailable, ensureDocMetadata, firstNonEmptyString, generateTaskId, mapLimit, missingTaskIdMessage, nowIso, redmineConfigMissingEnvMessage, redmineIssueIdMissingMessage, sleep, toStringSafe, unknownTaskIdMessage, validateTaskId, writeTasksExportFromTasks, } from "./shared.js";
10
11
  export class RedmineBackend {
11
12
  id = "redmine";
12
13
  baseUrl;
@@ -17,25 +18,34 @@ export class RedmineBackend {
17
18
  statusMap;
18
19
  customFields;
19
20
  batchSize;
20
- batchPause;
21
+ batchPauseMs;
21
22
  cache;
22
23
  issueCache = new Map();
23
24
  reverseStatus = new Map();
24
25
  constructor(settings, opts) {
25
- const envUrl = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_URL);
26
- const envApiKey = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_API_KEY);
27
- const envProjectId = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_PROJECT_ID);
28
- const envAssignee = (process.env.AGENTPLANE_REDMINE_ASSIGNEE_ID ?? "").trim();
29
- const envOwner = firstNonEmptyString(process.env.AGENTPLANE_REDMINE_OWNER, process.env.AGENTPLANE_REDMINE_OWNER_AGENT);
30
- this.baseUrl = firstNonEmptyString(envUrl, settings.url).replaceAll(/\/+$/gu, "");
31
- this.apiKey = firstNonEmptyString(envApiKey, settings.api_key);
32
- this.projectId = firstNonEmptyString(envProjectId, settings.project_id);
33
- this.assigneeId = envAssignee && /^\d+$/u.test(envAssignee) ? Number(envAssignee) : null;
26
+ const env = readRedmineEnv();
27
+ this.baseUrl = firstNonEmptyString(env.url, settings.url).replaceAll(/\/+$/gu, "");
28
+ this.apiKey = firstNonEmptyString(env.apiKey, settings.api_key);
29
+ this.projectId = firstNonEmptyString(env.projectId, settings.project_id);
30
+ this.assigneeId = env.assigneeId ?? null;
34
31
  this.statusMap = isRecord(settings.status_map) ? settings.status_map : {};
35
- this.customFields = isRecord(settings.custom_fields) ? settings.custom_fields : {};
36
- this.batchSize = typeof settings.batch_size === "number" ? settings.batch_size : 20;
37
- this.batchPause = typeof settings.batch_pause === "number" ? settings.batch_pause : 0.5;
38
- this.ownerAgent = firstNonEmptyString(envOwner, settings.owner_agent, "REDMINE");
32
+ this.customFields = {
33
+ ...(isRecord(settings.custom_fields) ? settings.custom_fields : {}),
34
+ ...env.customFields,
35
+ };
36
+ this.batchSize =
37
+ env.batch.size ??
38
+ (typeof settings.batch_size === "number" && Number.isFinite(settings.batch_size)
39
+ ? Math.max(1, Math.trunc(settings.batch_size))
40
+ : 20);
41
+ this.batchPauseMs =
42
+ env.batch.pauseMs ??
43
+ (typeof settings.batch_pause === "number" && Number.isFinite(settings.batch_pause)
44
+ ? settings.batch_pause >= 1
45
+ ? Math.trunc(settings.batch_pause)
46
+ : Math.round(settings.batch_pause * 1000)
47
+ : 500);
48
+ this.ownerAgent = firstNonEmptyString(env.ownerAgent, settings.owner_agent, "REDMINE");
39
49
  this.cache = opts.cache ?? null;
40
50
  const missingEnvKeys = [];
41
51
  if (!this.baseUrl)
@@ -45,10 +55,10 @@ export class RedmineBackend {
45
55
  if (!this.projectId)
46
56
  missingEnvKeys.push("AGENTPLANE_REDMINE_PROJECT_ID");
47
57
  if (missingEnvKeys.length > 0) {
48
- throw new BackendError(redmineConfigMissingMessage(missingEnvKeys.join(", ")), "E_BACKEND");
58
+ throw new BackendError(redmineConfigMissingEnvMessage(missingEnvKeys), "E_BACKEND");
49
59
  }
50
60
  if (!this.customFields?.task_id) {
51
- throw new BackendError(redmineConfigMissingMessage("custom_fields.task_id"), "E_BACKEND");
61
+ throw new BackendError(redmineConfigMissingEnvMessage("AGENTPLANE_REDMINE_CUSTOM_FIELDS_TASK_ID"), "E_BACKEND");
52
62
  }
53
63
  for (const [key, value] of Object.entries(this.statusMap)) {
54
64
  if (typeof value === "number")
@@ -136,7 +146,7 @@ export class RedmineBackend {
136
146
  }
137
147
  async setTaskDoc(taskId, doc, updatedBy) {
138
148
  if (!this.customFields.doc) {
139
- throw new BackendError(redmineConfigMissingMessage("custom_fields.doc"), "E_BACKEND");
149
+ throw new BackendError(redmineConfigMissingEnvMessage("AGENTPLANE_REDMINE_CUSTOM_FIELDS_DOC"), "E_BACKEND");
140
150
  }
141
151
  try {
142
152
  const issue = await this.findIssueByTaskId(taskId);
@@ -281,8 +291,8 @@ export class RedmineBackend {
281
291
  async writeTasks(tasks) {
282
292
  for (const [index, task] of tasks.entries()) {
283
293
  await this.writeTask(task);
284
- if (this.batchPause && this.batchSize > 0 && (index + 1) % this.batchSize === 0) {
285
- await sleep(this.batchPause * 1000);
294
+ if (this.batchPauseMs > 0 && this.batchSize > 0 && (index + 1) % this.batchSize === 0) {
295
+ await sleep(this.batchPauseMs);
286
296
  }
287
297
  }
288
298
  }
@@ -408,7 +418,7 @@ export class RedmineBackend {
408
418
  const fieldId = this.customFields?.task_id;
409
419
  if (fieldId)
410
420
  return fieldId;
411
- throw new BackendError(redmineConfigMissingMessage("custom_fields.task_id"), "E_BACKEND");
421
+ throw new BackendError(redmineConfigMissingEnvMessage("AGENTPLANE_REDMINE_CUSTOM_FIELDS_TASK_ID"), "E_BACKEND");
412
422
  }
413
423
  setIssueCustomFieldValue(issue, fieldId, value) {
414
424
  setRedmineIssueCustomFieldValue(issue, fieldId, value);
@@ -5,6 +5,7 @@ export declare class BackendError extends Error {
5
5
  export declare class RedmineUnavailable extends BackendError {
6
6
  constructor(message: string);
7
7
  }
8
- export declare function redmineConfigMissingMessage(detail: string): string;
8
+ export declare function redmineConfigMissingEnvMessage(keys: string[] | string): string;
9
+ export declare function redmineConfigInvalidEnvMessage(key: string, expected: string): string;
9
10
  export declare function redmineIssueIdMissingMessage(): string;
10
11
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/shared/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;IACrC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;gBACpB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW;CAI7D;AAED,qBAAa,kBAAmB,SAAQ,YAAY;gBACtC,OAAO,EAAE,MAAM;CAG5B;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wBAAgB,4BAA4B,IAAI,MAAM,CAErD"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/backends/task-backend/shared/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAa,SAAQ,KAAK;IACrC,IAAI,EAAE,WAAW,GAAG,WAAW,CAAC;gBACpB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,WAAW;CAI7D;AAED,qBAAa,kBAAmB,SAAQ,YAAY;gBACtC,OAAO,EAAE,MAAM;CAG5B;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,MAAM,CAG9E;AAED,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpF;AAED,wBAAgB,4BAA4B,IAAI,MAAM,CAErD"}
@@ -10,8 +10,12 @@ export class RedmineUnavailable extends BackendError {
10
10
  super(message, "E_NETWORK");
11
11
  }
12
12
  }
13
- export function redmineConfigMissingMessage(detail) {
14
- return `Missing required Redmine configuration. Set ${detail} in environment variables (for example via .env).`;
13
+ export function redmineConfigMissingEnvMessage(keys) {
14
+ const list = Array.isArray(keys) ? keys : [keys];
15
+ return `Missing required Redmine configuration env key(s): ${list.join(", ")}. Set them in environment variables (for example via .env).`;
16
+ }
17
+ export function redmineConfigInvalidEnvMessage(key, expected) {
18
+ return `Invalid Redmine configuration env value for ${key}. Expected ${expected}.`;
15
19
  }
16
20
  export function redmineIssueIdMissingMessage() {
17
21
  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,CAY1C;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":"AAyBA,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG5E"}
@@ -1,3 +1,4 @@
1
+ import { visibleLen } from "../../../shared/ansi.js";
1
2
  function useColor() {
2
3
  return process.stdout.isTTY === true && (process.env.TERM ?? "dumb") !== "dumb";
3
4
  }
@@ -7,12 +8,13 @@ function color(text, code) {
7
8
  return `\u001B[${code}m${text}\u001B[0m`;
8
9
  }
9
10
  function padLine(line, width) {
10
- if (line.length >= width)
11
+ const lineLen = visibleLen(line);
12
+ if (lineLen >= width)
11
13
  return line;
12
- return `${line}${" ".repeat(width - line.length)}`;
14
+ return `${line}${" ".repeat(width - lineLen)}`;
13
15
  }
14
16
  function box(lines) {
15
- const width = Math.max(...lines.map((line) => line.length), 0);
17
+ const width = Math.max(...lines.map((line) => visibleLen(line)), 0);
16
18
  const top = `┌${"─".repeat(width + 2)}┐`;
17
19
  const body = lines.map((line) => `│ ${padLine(line, width)} │`);
18
20
  const bottom = `└${"─".repeat(width + 2)}┘`;
@@ -1 +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"}
1
+ {"version":3,"file":"write-env.d.ts","sourceRoot":"","sources":["../../../../../src/cli/run-cli/commands/init/write-env.ts"],"names":[],"mappings":"AAmGA,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAU3F"}
@@ -56,13 +56,11 @@ function collectDefinedEnvKeys(dotEnvText) {
56
56
  }
57
57
  return keys;
58
58
  }
59
- export async function ensureInitRedmineEnvTemplate(opts) {
60
- const dotEnvPath = path.join(opts.gitRoot, ".env");
61
- const existing = (await readTextIfExists(dotEnvPath)) ?? "";
59
+ function buildTemplateBlock(existing) {
62
60
  const definedKeys = collectDefinedEnvKeys(existing);
63
61
  const missing = REDMINE_ENV_TEMPLATE.filter((entry) => !definedKeys.has(entry.key));
64
62
  if (missing.length === 0)
65
- return;
63
+ return existing;
66
64
  const required = missing.filter((item) => item.required);
67
65
  const optional = missing.filter((item) => !item.required);
68
66
  const requiredLines = required.flatMap((entry) => [
@@ -84,6 +82,16 @@ export async function ensureInitRedmineEnvTemplate(opts) {
84
82
  ];
85
83
  const block = `${lines.join("\n")}\n`;
86
84
  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);
85
+ return `${existing}${prefix}${block}`;
86
+ }
87
+ export async function ensureInitRedmineEnvTemplate(opts) {
88
+ const dotEnvExamplePath = path.join(opts.gitRoot, ".env.example");
89
+ const existingExample = (await readTextIfExists(dotEnvExamplePath)) ?? "";
90
+ const nextExample = buildTemplateBlock(existingExample);
91
+ await writeTextIfChanged(dotEnvExamplePath, nextExample);
92
+ const dotEnvPath = path.join(opts.gitRoot, ".env");
93
+ const existingEnv = await readTextIfExists(dotEnvPath);
94
+ if (existingEnv !== null)
95
+ return;
96
+ await writeTextIfChanged(dotEnvPath, nextExample);
89
97
  }
@@ -1,5 +1,5 @@
1
1
  import type { CommandHandler, CommandSpec } from "../../spec/spec.js";
2
- type ExecutionProfile = "conservative" | "balanced" | "aggressive";
2
+ import { type ExecutionProfile } from "@agentplaneorg/core";
3
3
  type InitFlags = {
4
4
  ide?: "codex" | "cursor" | "windsurf";
5
5
  workflow?: "direct" | "branch_pr";
@@ -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;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"}
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;AAItE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,qBAAqB,CAAC;AAa7B,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"}
@@ -7,82 +7,17 @@ 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
+ import { buildExecutionProfile, setPinnedBaseBranch, } from "@agentplaneorg/core";
11
11
  import { resolveInitBaseBranchForInit } from "./init/base-branch.js";
12
12
  import { collectInitConflicts, handleInitConflicts } from "./init/conflicts.js";
13
13
  import { ensureGitRoot } from "./init/git.js";
14
14
  import { maybeSyncIde } from "./init/ide-sync.js";
15
15
  import { maybeInstallBundledRecipes } from "./init/recipes.js";
16
- import { ensureAgentplaneDirs, writeBackendStubs, writeInitConfig, } from "./init/write-config.js";
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
19
  import { ensureInitRedmineEnvTemplate } from "./init/write-env.js";
20
20
  import { renderInitSection, renderInitWelcome } from "./init/ui.js";
21
- function buildInitExecutionProfile(profile, opts) {
22
- const shared = {
23
- stop_conditions: [
24
- "Missing required input blocks correctness.",
25
- "Requested action expands scope or risk beyond approved plan.",
26
- "Verification fails and remediation changes scope.",
27
- ],
28
- handoff_conditions: [
29
- "Role boundary reached (for example CODER -> TESTER/REVIEWER).",
30
- "Task depends_on prerequisites are incomplete.",
31
- "Specialized agent is required.",
32
- ],
33
- };
34
- const byProfile = {
35
- conservative: {
36
- profile: "conservative",
37
- reasoning_effort: "high",
38
- tool_budget: { discovery: 4, implementation: 8, verification: 8 },
39
- ...shared,
40
- unsafe_actions_requiring_explicit_user_ok: [
41
- "Destructive git history operations.",
42
- "Outside-repo read/write.",
43
- "Credential, keychain, or SSH material changes.",
44
- "Network actions when approvals are enabled.",
45
- ],
46
- },
47
- balanced: {
48
- profile: "balanced",
49
- reasoning_effort: "medium",
50
- tool_budget: { discovery: 6, implementation: 10, verification: 6 },
51
- ...shared,
52
- unsafe_actions_requiring_explicit_user_ok: [
53
- "Destructive git history operations.",
54
- "Outside-repo read/write.",
55
- "Credential, keychain, or SSH material changes.",
56
- ],
57
- },
58
- aggressive: {
59
- profile: "aggressive",
60
- reasoning_effort: "low",
61
- tool_budget: { discovery: 10, implementation: 16, verification: 8 },
62
- stop_conditions: [
63
- "Requested action expands scope or risk beyond approved plan.",
64
- "Verification fails and remediation changes scope.",
65
- ],
66
- handoff_conditions: [
67
- "Role boundary reached (for example CODER -> TESTER/REVIEWER).",
68
- "Specialized agent is required.",
69
- ],
70
- unsafe_actions_requiring_explicit_user_ok: [
71
- "Destructive git history operations.",
72
- "Outside-repo read/write.",
73
- "Credential, keychain, or SSH material changes.",
74
- ],
75
- },
76
- };
77
- const resolved = structuredClone(byProfile[profile]);
78
- if (opts?.strictUnsafeConfirm === true) {
79
- const extra = "Network actions when approvals are disabled.";
80
- if (!resolved.unsafe_actions_requiring_explicit_user_ok.includes(extra)) {
81
- resolved.unsafe_actions_requiring_explicit_user_ok.push(extra);
82
- }
83
- }
84
- return resolved;
85
- }
86
21
  function parseBooleanValueForInit(flag, value) {
87
22
  const normalized = value.trim().toLowerCase();
88
23
  if (["1", "true", "yes", "y", "on"].includes(normalized))
@@ -410,7 +345,7 @@ async function cmdInit(opts) {
410
345
  force: flags.force === true,
411
346
  });
412
347
  await ensureAgentplaneDirs(resolved.agentplaneDir, backend);
413
- const execution = buildInitExecutionProfile(executionProfile, { strictUnsafeConfirm });
348
+ const execution = buildExecutionProfile(executionProfile, { strictUnsafeConfirm });
414
349
  await writeInitConfig({
415
350
  agentplaneDir: resolved.agentplaneDir,
416
351
  gitRoot: resolved.gitRoot,
@@ -432,6 +367,9 @@ async function cmdInit(opts) {
432
367
  configPathAbs: configPath,
433
368
  backendPathAbs: backendPath,
434
369
  });
370
+ if (backend === "redmine") {
371
+ installPaths.push(".env.example");
372
+ }
435
373
  await ensureInitGitignore({
436
374
  gitRoot: resolved.gitRoot,
437
375
  includeAgentPromptFiles: flags.gitignoreAgents === true,
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.ts"],"names":[],"mappings":"AAoWA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA0K5D"}
@@ -9,6 +9,7 @@ import { loadDotEnv } from "../shared/env.js";
9
9
  import { CliError, formatJsonError } from "../shared/errors.js";
10
10
  import { resolveContext } from "../usecases/context/resolve-context.js";
11
11
  import { getVersion } from "../meta/version.js";
12
+ import { getApprovalRequirements } from "../commands/shared/approval-requirements.js";
12
13
  import { parseCommandArgv } from "./spec/parse.js";
13
14
  import { helpSpec } from "./spec/help.js";
14
15
  import { usageError } from "./spec/errors.js";
@@ -375,7 +376,10 @@ export async function runCli(argv) {
375
376
  if (resolved && matched?.entry.needsConfig !== false) {
376
377
  try {
377
378
  const loaded = await getLoadedConfig("update-check");
378
- const requireNetwork = loaded.config.agents?.approvals.require_network === true;
379
+ const requireNetwork = getApprovalRequirements({
380
+ config: loaded.config,
381
+ action: "network_access",
382
+ }).required;
379
383
  const explicitlyApproved = globals.allowNetwork;
380
384
  skipUpdateCheckForPolicy = requireNetwork && !explicitlyApproved;
381
385
  }
@@ -1 +1 @@
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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"}
1
+ {"version":3,"file":"run-cli.test-helpers.d.ts","sourceRoot":"","sources":["../../src/cli/run-cli.test-helpers.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAkDpD,wBAAgB,sBAAsB,IAAI,IAAI,CA8C7C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,YAAY;;;;EAgC3B;AAED,wBAAgB,YAAY,IAAI,MAAM,IAAI,CAkBzC;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAOlE;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAMrD;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAIjD;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKpE;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAKhE;AAED,wBAAsB,mBAAmB,CAAC,IAAI,CAAC,EAAE;IAC/C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CA+FtE;AAED,wBAAsB,+BAA+B,CAAC,IAAI,EAAE;IAC1D,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4DlB;AA6DD,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;IAChF,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC,CAqDD;AAED,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7E;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlE;AAED,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAS/C;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOnE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYpF;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5E;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzE"}
@@ -6,11 +6,12 @@ import path from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { promisify } from "node:util";
8
8
  import { gzipSync } from "node:zlib";
9
- import { afterAll, beforeAll } from "vitest";
9
+ import { afterAll, afterEach, beforeAll } from "vitest";
10
10
  import { defaultConfig } from "@agentplaneorg/core";
11
11
  import { runCli } from "./run-cli.js";
12
12
  const execFileAsync = promisify(execFile);
13
13
  let agentplaneHome = null;
14
+ const testRoots = new Set();
14
15
  const originalAgentplaneHome = process.env.AGENTPLANE_HOME;
15
16
  const originalNoUpdateCheck = process.env.AGENTPLANE_NO_UPDATE_CHECK;
16
17
  const originalGitAuthorName = process.env.GIT_AUTHOR_NAME;
@@ -88,6 +89,14 @@ export function registerAgentplaneHome() {
88
89
  else
89
90
  process.env.GIT_COMMITTER_EMAIL = originalGitCommitterEmail;
90
91
  });
92
+ afterEach(async () => {
93
+ const roots = [...testRoots];
94
+ testRoots.clear();
95
+ await Promise.all(roots.map(async (root) => {
96
+ await rm(path.join(root, ".agentplane", ".upgrade"), { recursive: true, force: true });
97
+ await rm(path.join(root, ".agentplane", ".release"), { recursive: true, force: true });
98
+ }));
99
+ });
91
100
  }
92
101
  export function getAgentplaneHome() {
93
102
  return agentplaneHome;
@@ -154,10 +163,13 @@ export async function mkGitRepoRoot() {
154
163
  const template = await ensureGitTemplateRoot();
155
164
  const root = await mkdtemp(path.join(os.tmpdir(), "agentplane-cli-test-"));
156
165
  await copyDirContents(template, root);
166
+ testRoots.add(root);
157
167
  return root;
158
168
  }
159
169
  export async function mkTempDir() {
160
- return await mkdtemp(path.join(os.tmpdir(), "agentplane-cli-test-"));
170
+ const root = await mkdtemp(path.join(os.tmpdir(), "agentplane-cli-test-"));
171
+ testRoots.add(root);
172
+ return root;
161
173
  }
162
174
  export async function writeDefaultConfig(root) {
163
175
  const agentplaneDir = path.join(root, ".agentplane");
@@ -0,0 +1,3 @@
1
+ export declare function stripAnsi(text: string): string;
2
+ export declare function visibleLen(text: string): number;
3
+ //# sourceMappingURL=ansi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../../../src/cli/shared/ansi.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C"}