agentplane 0.2.24 → 0.2.25

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":"block.spec.d.ts","sourceRoot":"","sources":["../../src/commands/block.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKvD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,WAAW,CA0H9C,CAAC"}
1
+ {"version":3,"file":"block.spec.d.ts","sourceRoot":"","sources":["../../src/commands/block.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,WAAW,CA8I9C,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { usageError } from "../cli/spec/errors.js";
2
+ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../shared/allow-prefix-policy.js";
2
3
  import { toStringList } from "../cli/spec/parse-utils.js";
3
4
  export const blockSpec = {
4
5
  id: ["block"],
@@ -44,13 +45,14 @@ export const blockSpec = {
44
45
  name: "commit-allow",
45
46
  valueHint: "<path-prefix>",
46
47
  repeatable: true,
47
- description: "Repeatable. Allowlist path prefixes to stage for the status commit (used with --commit-from-comment).",
48
+ description: "Repeatable. Allowlist path prefixes to stage for the status commit (used with --commit-from-comment). Use minimal prefixes; '.' is rejected.",
48
49
  },
49
50
  {
50
51
  kind: "boolean",
51
52
  name: "commit-auto-allow",
52
53
  default: false,
53
- description: "Auto-allow inferred allowlist paths if none are provided (used with --commit-from-comment).",
54
+ description: "Deprecated. Disabled for safety; pass explicit --commit-allow prefixes.",
55
+ deprecated: "disabled",
54
56
  },
55
57
  {
56
58
  kind: "boolean",
@@ -99,10 +101,29 @@ export const blockSpec = {
99
101
  validateRaw: (raw) => {
100
102
  const author = typeof raw.opts.author === "string" ? raw.opts.author.trim() : "";
101
103
  const body = typeof raw.opts.body === "string" ? raw.opts.body.trim() : "";
104
+ const commitAllow = toStringList(raw.opts["commit-allow"]);
102
105
  if (!author)
103
106
  throw usageError({ spec: blockSpec, message: "Invalid value for --author: empty." });
104
107
  if (!body)
105
108
  throw usageError({ spec: blockSpec, message: "Invalid value for --body: empty." });
109
+ if (findRepoWideAllowPrefixes(commitAllow).length > 0) {
110
+ throw usageError({
111
+ spec: blockSpec,
112
+ message: repoWideAllowPrefixMessage("--commit-allow"),
113
+ });
114
+ }
115
+ if (raw.opts["commit-auto-allow"] === true) {
116
+ throw usageError({
117
+ spec: blockSpec,
118
+ message: "--commit-auto-allow is disabled; pass explicit --commit-allow <path-prefix>.",
119
+ });
120
+ }
121
+ if (raw.opts["commit-from-comment"] === true && commitAllow.length === 0) {
122
+ throw usageError({
123
+ spec: blockSpec,
124
+ message: "--commit-from-comment requires --commit-allow <path-prefix> (tip: `agentplane guard suggest-allow --format args`).",
125
+ });
126
+ }
106
127
  },
107
128
  parse: (raw) => ({
108
129
  taskId: typeof raw.args["task-id"] === "string" ? raw.args["task-id"] : "",
@@ -1 +1 @@
1
- {"version":3,"file":"commit.spec.d.ts","sourceRoot":"","sources":["../../src/commands/commit.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAmJhD,CAAC"}
1
+ {"version":3,"file":"commit.spec.d.ts","sourceRoot":"","sources":["../../src/commands/commit.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAOvD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CA8JhD,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { usageError } from "../cli/spec/errors.js";
2
+ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../shared/allow-prefix-policy.js";
2
3
  export const commitSpec = {
3
4
  id: ["commit"],
4
5
  group: "Guard",
@@ -35,13 +36,14 @@ export const commitSpec = {
35
36
  name: "allow",
36
37
  valueHint: "<path-prefix>",
37
38
  repeatable: true,
38
- description: "Repeatable. Allowed path prefix (git-path).",
39
+ description: "Repeatable. Allowed path prefix (git-path). Use minimal prefixes; repo-wide '.' is rejected (tip: `agentplane guard suggest-allow --format args`).",
39
40
  },
40
41
  {
41
42
  kind: "boolean",
42
43
  name: "auto-allow",
43
44
  default: false,
44
- description: "Infer --allow prefixes from staged paths (only when no explicit --allow is provided).",
45
+ description: "Deprecated. Disabled for safety; pass explicit --allow prefixes.",
46
+ deprecated: "disabled",
45
47
  },
46
48
  {
47
49
  kind: "boolean",
@@ -77,10 +79,6 @@ export const commitSpec = {
77
79
  cmd: 'agentplane commit 202602030608-F1Q8AB -m "✨ F1Q8AB task: implement allowlist guard" --allow packages/agentplane',
78
80
  why: "Create a commit after validating allowlist and subject policy.",
79
81
  },
80
- {
81
- cmd: 'agentplane commit 202602030608-F1Q8AB -m "✨ F1Q8AB task: implement allowlist guard" --auto-allow',
82
- why: "Infer allowlist prefixes from staged paths.",
83
- },
84
82
  {
85
83
  cmd: "agentplane commit 202602030608-F1Q8AB --close",
86
84
  why: "Create a close commit for the task README using a deterministic message builder.",
@@ -120,6 +118,20 @@ export const commitSpec = {
120
118
  if (Array.isArray(allow) && allow.some((s) => typeof s === "string" && s.trim() === "")) {
121
119
  throw usageError({ spec: commitSpec, message: "Invalid value for --allow: empty." });
122
120
  }
121
+ const allowList = Array.isArray(allow)
122
+ ? allow
123
+ : typeof allow === "string"
124
+ ? [allow]
125
+ : [];
126
+ if (findRepoWideAllowPrefixes(allowList).length > 0) {
127
+ throw usageError({ spec: commitSpec, message: repoWideAllowPrefixMessage("--allow") });
128
+ }
129
+ if (raw.opts["auto-allow"] === true) {
130
+ throw usageError({
131
+ spec: commitSpec,
132
+ message: "--auto-allow is disabled; pass explicit --allow <path-prefix>.",
133
+ });
134
+ }
123
135
  },
124
136
  parse: (raw) => ({
125
137
  taskId: String(raw.args["task-id"]),
@@ -1 +1 @@
1
- {"version":3,"file":"finish.spec.d.ts","sourceRoot":"","sources":["../../src/commands/finish.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKvD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAqPhD,CAAC"}
1
+ {"version":3,"file":"finish.spec.d.ts","sourceRoot":"","sources":["../../src/commands/finish.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAsShD,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { usageError } from "../cli/spec/errors.js";
2
2
  import { toStringList } from "../cli/spec/parse-utils.js";
3
+ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../shared/allow-prefix-policy.js";
3
4
  export const finishSpec = {
4
5
  id: ["finish"],
5
6
  group: "Lifecycle",
@@ -77,13 +78,14 @@ export const finishSpec = {
77
78
  name: "commit-allow",
78
79
  valueHint: "<path-prefix>",
79
80
  repeatable: true,
80
- description: "Repeatable. Allowlist path prefixes to stage for the commit (used with --commit-from-comment).",
81
+ description: "Repeatable. Allowlist path prefixes to stage for the commit (used with --commit-from-comment). Use minimal prefixes; '.' is rejected.",
81
82
  },
82
83
  {
83
84
  kind: "boolean",
84
85
  name: "commit-auto-allow",
85
86
  default: false,
86
- description: "Auto-allow inferred allowlist paths if none are provided (used with --commit-from-comment).",
87
+ description: "Deprecated. Disabled for safety; pass explicit --commit-allow prefixes.",
88
+ deprecated: "disabled",
87
89
  },
88
90
  {
89
91
  kind: "boolean",
@@ -116,13 +118,14 @@ export const finishSpec = {
116
118
  name: "status-commit-allow",
117
119
  valueHint: "<path-prefix>",
118
120
  repeatable: true,
119
- description: "Repeatable. Allowlist path prefixes to stage for the status commit (used with --status-commit).",
121
+ description: "Repeatable. Allowlist path prefixes to stage for the status commit (used with --status-commit). Use minimal prefixes; '.' is rejected.",
120
122
  },
121
123
  {
122
124
  kind: "boolean",
123
125
  name: "status-commit-auto-allow",
124
126
  default: false,
125
- description: "Auto-allow inferred allowlist paths if none are provided (used with --status-commit).",
127
+ description: "Deprecated. Disabled for safety; pass explicit --status-commit-allow prefixes.",
128
+ deprecated: "disabled",
126
129
  },
127
130
  {
128
131
  kind: "boolean",
@@ -165,6 +168,38 @@ export const finishSpec = {
165
168
  const taskIds = Array.isArray(ids) ? ids : [];
166
169
  const commitFromComment = raw.opts["commit-from-comment"] === true;
167
170
  const statusCommit = raw.opts["status-commit"] === true;
171
+ const commitAllow = toStringList(raw.opts["commit-allow"]);
172
+ const statusCommitAllow = toStringList(raw.opts["status-commit-allow"]);
173
+ const commitAutoAllow = raw.opts["commit-auto-allow"] === true;
174
+ const statusCommitAutoAllow = raw.opts["status-commit-auto-allow"] === true;
175
+ if (findRepoWideAllowPrefixes(commitAllow).length > 0) {
176
+ throw usageError({
177
+ spec: finishSpec,
178
+ command: "finish",
179
+ message: repoWideAllowPrefixMessage("--commit-allow"),
180
+ });
181
+ }
182
+ if (findRepoWideAllowPrefixes(statusCommitAllow).length > 0) {
183
+ throw usageError({
184
+ spec: finishSpec,
185
+ command: "finish",
186
+ message: repoWideAllowPrefixMessage("--status-commit-allow"),
187
+ });
188
+ }
189
+ if (commitAutoAllow) {
190
+ throw usageError({
191
+ spec: finishSpec,
192
+ command: "finish",
193
+ message: "--commit-auto-allow is disabled; pass explicit --commit-allow <path-prefix>.",
194
+ });
195
+ }
196
+ if (statusCommitAutoAllow) {
197
+ throw usageError({
198
+ spec: finishSpec,
199
+ command: "finish",
200
+ message: "--status-commit-auto-allow is disabled; pass explicit --status-commit-allow <path-prefix>.",
201
+ });
202
+ }
168
203
  if ((commitFromComment || statusCommit) && taskIds.length !== 1) {
169
204
  throw usageError({
170
205
  spec: finishSpec,
@@ -172,6 +207,20 @@ export const finishSpec = {
172
207
  message: "--commit-from-comment/--status-commit requires exactly one task id",
173
208
  });
174
209
  }
210
+ if (commitFromComment && commitAllow.length === 0) {
211
+ throw usageError({
212
+ spec: finishSpec,
213
+ command: "finish",
214
+ message: "--commit-from-comment requires --commit-allow <path-prefix> (tip: `agentplane guard suggest-allow --format args`).",
215
+ });
216
+ }
217
+ if (statusCommit && statusCommitAllow.length === 0) {
218
+ throw usageError({
219
+ spec: finishSpec,
220
+ command: "finish",
221
+ message: "--status-commit requires --status-commit-allow <path-prefix> (tip: `agentplane guard suggest-allow --format args`).",
222
+ });
223
+ }
175
224
  if (raw.opts["close-commit"] === true && taskIds.length !== 1) {
176
225
  throw usageError({
177
226
  spec: finishSpec,
@@ -1 +1 @@
1
- {"version":3,"file":"commit.command.d.ts","sourceRoot":"","sources":["../../../src/commands/guard/commit.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,iBAAiB,CA+F1D,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC1E,KAAK,UAAU,EAAE,GAAG,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,CAkCtE"}
1
+ {"version":3,"file":"commit.command.d.ts","sourceRoot":"","sources":["../../../src/commands/guard/commit.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAOtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,iBAAiB,CA0G1D,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC1E,KAAK,UAAU,EAAE,GAAG,iBAAiB,KAAG,OAAO,CAAC,MAAM,CAAC,CA2BtE"}
@@ -1,6 +1,7 @@
1
1
  import { usageError } from "../../cli/spec/errors.js";
2
2
  import { CliError } from "../../shared/errors.js";
3
- import { cmdGuardCommit, suggestAllowPrefixes } from "./index.js";
3
+ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../../shared/allow-prefix-policy.js";
4
+ import { cmdGuardCommit } from "./index.js";
4
5
  export const guardCommitSpec = {
5
6
  id: ["guard", "commit"],
6
7
  group: "Guard",
@@ -20,13 +21,14 @@ export const guardCommitSpec = {
20
21
  name: "allow",
21
22
  valueHint: "<path-prefix>",
22
23
  repeatable: true,
23
- description: "Repeatable. Allowed path prefix (git-path).",
24
+ description: "Repeatable. Allowed path prefix (git-path). Use minimal prefixes; repo-wide '.' is rejected (tip: `agentplane guard suggest-allow --format args`).",
24
25
  },
25
26
  {
26
27
  kind: "boolean",
27
28
  name: "auto-allow",
28
29
  default: false,
29
- description: "Infer --allow prefixes from staged paths (only when no explicit --allow is provided).",
30
+ description: "Deprecated. Disabled for safety; pass explicit --allow prefixes.",
31
+ deprecated: "disabled",
30
32
  },
31
33
  {
32
34
  kind: "boolean",
@@ -62,10 +64,6 @@ export const guardCommitSpec = {
62
64
  cmd: 'agentplane guard commit 202602030608-F1Q8AB -m "✨ F1Q8AB task: implement allowlist guard" --allow packages/agentplane',
63
65
  why: "Validate staged changes are covered by allowlist and policy.",
64
66
  },
65
- {
66
- cmd: 'agentplane guard commit 202602030608-F1Q8AB -m "✨ F1Q8AB task: implement allowlist guard" --auto-allow',
67
- why: "Infer allowlist prefixes from staged paths.",
68
- },
69
67
  ],
70
68
  validateRaw: (raw) => {
71
69
  const msg = typeof raw.opts.message === "string" ? raw.opts.message.trim() : "";
@@ -76,6 +74,20 @@ export const guardCommitSpec = {
76
74
  if (Array.isArray(allow) && allow.some((s) => typeof s === "string" && s.trim() === "")) {
77
75
  throw usageError({ spec: guardCommitSpec, message: "Invalid value for --allow: empty." });
78
76
  }
77
+ const allowList = Array.isArray(allow)
78
+ ? allow
79
+ : typeof allow === "string"
80
+ ? [allow]
81
+ : [];
82
+ if (findRepoWideAllowPrefixes(allowList).length > 0) {
83
+ throw usageError({ spec: guardCommitSpec, message: repoWideAllowPrefixMessage("--allow") });
84
+ }
85
+ if (raw.opts["auto-allow"] === true) {
86
+ throw usageError({
87
+ spec: guardCommitSpec,
88
+ message: "--auto-allow is disabled; pass explicit --allow <path-prefix>.",
89
+ });
90
+ }
79
91
  },
80
92
  parse: (raw) => ({
81
93
  taskId: String(raw.args["task-id"]),
@@ -99,18 +111,12 @@ export const guardCommitSpec = {
99
111
  export function makeRunGuardCommitHandler(getCtx) {
100
112
  return async (ctx, p) => {
101
113
  const cmdCtx = await getCtx("guard commit");
102
- let allow = p.allow;
103
- if (p.autoAllow && allow.length === 0) {
104
- const staged = await cmdCtx.git.statusStagedPaths();
105
- const prefixes = suggestAllowPrefixes(staged);
106
- if (prefixes.length === 0) {
107
- throw new CliError({
108
- exitCode: 5,
109
- code: "E_GIT",
110
- message: "No staged files (git index empty)",
111
- });
112
- }
113
- allow = prefixes;
114
+ if (p.autoAllow) {
115
+ throw new CliError({
116
+ exitCode: 2,
117
+ code: "E_USAGE",
118
+ message: "--auto-allow is disabled; pass explicit --allow <path-prefix>.",
119
+ });
114
120
  }
115
121
  return await cmdGuardCommit({
116
122
  ctx: cmdCtx,
@@ -118,7 +124,7 @@ export function makeRunGuardCommitHandler(getCtx) {
118
124
  rootOverride: ctx.rootOverride,
119
125
  taskId: p.taskId,
120
126
  message: p.message,
121
- allow,
127
+ allow: p.allow,
122
128
  allowBase: p.allowBase,
123
129
  allowTasks: p.allowTasks,
124
130
  allowPolicy: p.allowPolicy,
@@ -1 +1 @@
1
- {"version":3,"file":"allow.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/allow.ts"],"names":[],"mappings":"AAMA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAkBvF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAe9D;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOpB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,cAAc,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA2CpB"}
1
+ {"version":3,"file":"allow.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/allow.ts"],"names":[],"mappings":"AAMA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAkBvF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAe9D;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOpB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,EAAE,cAAc,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkDpB"}
@@ -82,6 +82,13 @@ export async function stageAllowlist(opts) {
82
82
  message: "Provide at least one allowed prefix",
83
83
  });
84
84
  }
85
+ if (allow.includes(".")) {
86
+ throw new CliError({
87
+ exitCode: 2,
88
+ code: "E_USAGE",
89
+ message: "Repo-wide allowlist ('.') is not allowed; choose minimal prefixes (tip: `agentplane guard suggest-allow --format args`).",
90
+ });
91
+ }
85
92
  const denied = new Set();
86
93
  if (!opts.allowTasks)
87
94
  denied.add(opts.tasksPath);
@@ -98,7 +105,7 @@ export async function stageAllowlist(opts) {
98
105
  throw new CliError({
99
106
  exitCode: 2,
100
107
  code: "E_USAGE",
101
- message: "No changes matched allowed prefixes (use --commit-auto-allow or update --commit-allow)",
108
+ message: "No changes matched allowed prefixes (update --commit-allow)",
102
109
  });
103
110
  }
104
111
  // `git add <pathspec>` is not reliable for staging deletes/renames across versions/configs.
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commands.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAOvF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAyDxE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAS9E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyJlB"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/commands.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAOvF,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAyDxE,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBlB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAS9E;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgJlB"}
@@ -201,20 +201,12 @@ export async function cmdCommit(opts) {
201
201
  }
202
202
  return 0;
203
203
  }
204
- let allow = opts.allow;
205
- if (opts.autoAllow && allow.length === 0) {
206
- const ctx = opts.ctx ??
207
- (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
208
- const staged = await ctx.git.statusStagedPaths();
209
- const prefixes = suggestAllowPrefixes(staged);
210
- if (prefixes.length === 0) {
211
- throw new CliError({
212
- exitCode: 5,
213
- code: "E_GIT",
214
- message: "No staged files (git index empty)",
215
- });
216
- }
217
- allow = prefixes;
204
+ if (opts.autoAllow) {
205
+ throw new CliError({
206
+ exitCode: 2,
207
+ code: "E_USAGE",
208
+ message: "--auto-allow is disabled; pass explicit --allow <path-prefix>.",
209
+ });
218
210
  }
219
211
  await guardCommitCheck({
220
212
  ctx: opts.ctx,
@@ -222,7 +214,7 @@ export async function cmdCommit(opts) {
222
214
  rootOverride: opts.rootOverride,
223
215
  taskId: opts.taskId,
224
216
  message: opts.message,
225
- allow,
217
+ allow: opts.allow,
226
218
  allowBase: opts.allowBase,
227
219
  allowTasks: opts.allowTasks,
228
220
  allowPolicy: opts.allowPolicy,
@@ -1 +1 @@
1
- {"version":3,"file":"comment-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/comment-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAS/E,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAiEvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA+F/D"}
1
+ {"version":3,"file":"comment-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/comment-commit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAQ/E,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAiEvF,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAyF/D"}
@@ -2,10 +2,9 @@ import { extractTaskSuffix } from "@agentplaneorg/core";
2
2
  import { invalidValueMessage, successMessage } from "../../../cli/output.js";
3
3
  import { CliError } from "../../../shared/errors.js";
4
4
  import { formatCommentBodyForCommit, normalizeCommentBodyForCommit, } from "../../../shared/comment-format.js";
5
- import { protectedPathKindForFile } from "../../../shared/protected-paths.js";
6
5
  import { loadCommandContext } from "../../shared/task-backend.js";
7
6
  import { buildGitCommitEnv } from "./env.js";
8
- import { stageAllowlist, suggestAllowPrefixes } from "./allow.js";
7
+ import { stageAllowlist } from "./allow.js";
9
8
  import { guardCommitCheck } from "./policy.js";
10
9
  function deriveCommitMessageFromComment(opts) {
11
10
  const prefix = opts.emoji.trim();
@@ -49,27 +48,19 @@ function deriveCommitBodyFromComment(opts) {
49
48
  export async function commitFromComment(opts) {
50
49
  const ctx = opts.ctx ??
51
50
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
52
- let allowPrefixes = opts.allow.map((prefix) => prefix.trim()).filter(Boolean);
53
- if (opts.autoAllow && allowPrefixes.length === 0) {
54
- const changed = await ctx.git.statusChangedPaths();
55
- const tasksPath = opts.config.paths.tasks_path;
56
- // Auto-allow is for ergonomic status commits. It must never silently
57
- // broaden into policy/config/CI changes (those require explicit intent).
58
- const eligible = changed.filter((filePath) => {
59
- const kind = protectedPathKindForFile({ filePath, tasksPath });
60
- if (!kind)
61
- return true;
62
- if (kind === "tasks")
63
- return opts.allowTasks;
64
- return false;
51
+ if (opts.autoAllow) {
52
+ throw new CliError({
53
+ exitCode: 2,
54
+ code: "E_USAGE",
55
+ message: "--commit-auto-allow is disabled; pass explicit --commit-allow <path-prefix>.",
65
56
  });
66
- allowPrefixes = suggestAllowPrefixes(eligible);
67
57
  }
58
+ let allowPrefixes = opts.allow.map((prefix) => prefix.trim()).filter(Boolean);
68
59
  if (allowPrefixes.length === 0) {
69
60
  throw new CliError({
70
61
  exitCode: 2,
71
62
  code: "E_USAGE",
72
- message: "Provide at least one --commit-allow prefix or enable --commit-auto-allow",
63
+ message: "Provide at least one --commit-allow prefix",
73
64
  });
74
65
  }
75
66
  const staged = await stageAllowlist({
@@ -1 +1 @@
1
- {"version":3,"file":"start.spec.d.ts","sourceRoot":"","sources":["../../src/commands/start.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKvD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,WAAW,CA0H9C,CAAC"}
1
+ {"version":3,"file":"start.spec.d.ts","sourceRoot":"","sources":["../../src/commands/start.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,WAAW,CA8I9C,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { usageError } from "../cli/spec/errors.js";
2
+ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../shared/allow-prefix-policy.js";
2
3
  import { toStringList } from "../cli/spec/parse-utils.js";
3
4
  export const startSpec = {
4
5
  id: ["start"],
@@ -44,13 +45,14 @@ export const startSpec = {
44
45
  name: "commit-allow",
45
46
  valueHint: "<path-prefix>",
46
47
  repeatable: true,
47
- description: "Repeatable. Allowlist path prefixes to stage for the status commit (used with --commit-from-comment).",
48
+ description: "Repeatable. Allowlist path prefixes to stage for the status commit (used with --commit-from-comment). Use minimal prefixes; '.' is rejected.",
48
49
  },
49
50
  {
50
51
  kind: "boolean",
51
52
  name: "commit-auto-allow",
52
53
  default: false,
53
- description: "Auto-allow inferred allowlist paths if none are provided (used with --commit-from-comment).",
54
+ description: "Deprecated. Disabled for safety; pass explicit --commit-allow prefixes.",
55
+ deprecated: "disabled",
54
56
  },
55
57
  {
56
58
  kind: "boolean",
@@ -99,10 +101,29 @@ export const startSpec = {
99
101
  validateRaw: (raw) => {
100
102
  const author = typeof raw.opts.author === "string" ? raw.opts.author.trim() : "";
101
103
  const body = typeof raw.opts.body === "string" ? raw.opts.body.trim() : "";
104
+ const commitAllow = toStringList(raw.opts["commit-allow"]);
102
105
  if (!author)
103
106
  throw usageError({ spec: startSpec, message: "Invalid value for --author: empty." });
104
107
  if (!body)
105
108
  throw usageError({ spec: startSpec, message: "Invalid value for --body: empty." });
109
+ if (findRepoWideAllowPrefixes(commitAllow).length > 0) {
110
+ throw usageError({
111
+ spec: startSpec,
112
+ message: repoWideAllowPrefixMessage("--commit-allow"),
113
+ });
114
+ }
115
+ if (raw.opts["commit-auto-allow"] === true) {
116
+ throw usageError({
117
+ spec: startSpec,
118
+ message: "--commit-auto-allow is disabled; pass explicit --commit-allow <path-prefix>.",
119
+ });
120
+ }
121
+ if (raw.opts["commit-from-comment"] === true && commitAllow.length === 0) {
122
+ throw usageError({
123
+ spec: startSpec,
124
+ message: "--commit-from-comment requires --commit-allow <path-prefix> (tip: `agentplane guard suggest-allow --format args`).",
125
+ });
126
+ }
106
127
  },
107
128
  parse: (raw) => ({
108
129
  taskId: typeof raw.args["task-id"] === "string" ? raw.args["task-id"] : "",
@@ -1 +1 @@
1
- {"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAmCnC,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqUlB"}
1
+ {"version":3,"file":"finish.d.ts","sourceRoot":"","sources":["../../../src/commands/task/finish.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAmCnC,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2VlB"}
@@ -40,13 +40,7 @@ export async function cmdFinish(opts) {
40
40
  }
41
41
  const { prefix, min_chars: minChars } = ctx.config.tasks.comments.verified;
42
42
  requireStructuredComment(opts.body, prefix, minChars);
43
- const autoStatusCommit = (ctx.config.finish_auto_status_commit === true ||
44
- ctx.config.commit_automation === "finish_only") &&
45
- !opts.commitFromComment &&
46
- !opts.statusCommit &&
47
- opts.closeCommit !== true &&
48
- opts.taskIds.length === 1;
49
- const statusCommitRequested = opts.statusCommit || autoStatusCommit;
43
+ const statusCommitRequested = opts.statusCommit;
50
44
  if ((opts.commitFromComment || statusCommitRequested) && opts.taskIds.length !== 1) {
51
45
  throw new CliError({
52
46
  exitCode: 2,
@@ -76,6 +70,34 @@ export async function cmdFinish(opts) {
76
70
  message: "--commit-from-comment/--status-commit requires exactly one task id",
77
71
  });
78
72
  }
73
+ if (opts.commitAutoAllow) {
74
+ throw new CliError({
75
+ exitCode: 2,
76
+ code: "E_USAGE",
77
+ message: "--commit-auto-allow is disabled; pass explicit --commit-allow <path-prefix>.",
78
+ });
79
+ }
80
+ if (opts.statusCommitAutoAllow) {
81
+ throw new CliError({
82
+ exitCode: 2,
83
+ code: "E_USAGE",
84
+ message: "--status-commit-auto-allow is disabled; pass explicit --status-commit-allow <path-prefix>.",
85
+ });
86
+ }
87
+ if (opts.commitFromComment && opts.commitAllow.length === 0) {
88
+ throw new CliError({
89
+ exitCode: 2,
90
+ code: "E_USAGE",
91
+ message: "--commit-from-comment requires --commit-allow <path-prefix>",
92
+ });
93
+ }
94
+ if (statusCommitRequested && opts.statusCommitAllow.length === 0) {
95
+ throw new CliError({
96
+ exitCode: 2,
97
+ code: "E_USAGE",
98
+ message: "--status-commit requires --status-commit-allow <path-prefix>",
99
+ });
100
+ }
79
101
  const gitRoot = ctx.resolvedProject.gitRoot;
80
102
  const commitInfo = opts.commit
81
103
  ? await readCommitInfo(gitRoot, opts.commit)
@@ -168,7 +190,7 @@ export async function cmdFinish(opts) {
168
190
  enforceStatusCommitPolicy({
169
191
  policy: ctx.config.status_commit_policy,
170
192
  action: "finish",
171
- confirmed: opts.confirmStatusCommit || autoStatusCommit,
193
+ confirmed: opts.confirmStatusCommit,
172
194
  quiet: opts.quiet,
173
195
  statusFrom: primaryStatusFrom ?? "UNKNOWN",
174
196
  statusTo: "DONE",
@@ -208,7 +230,7 @@ export async function cmdFinish(opts) {
208
230
  formattedComment: formatCommentBodyForCommit(opts.body, ctx.config),
209
231
  emoji: opts.commitEmoji ?? defaultCommitEmojiForStatus("DONE"),
210
232
  allow: opts.commitAllow,
211
- autoAllow: opts.commitAutoAllow || opts.commitAllow.length === 0,
233
+ autoAllow: false,
212
234
  allowTasks: opts.commitAllowTasks,
213
235
  requireClean: opts.commitRequireClean,
214
236
  quiet: opts.quiet,
@@ -269,7 +291,7 @@ export async function cmdFinish(opts) {
269
291
  formattedComment: formatCommentBodyForCommit(opts.body, ctx.config),
270
292
  emoji: opts.statusCommitEmoji ?? defaultCommitEmojiForStatus("DONE"),
271
293
  allow: opts.statusCommitAllow,
272
- autoAllow: opts.statusCommitAutoAllow || opts.statusCommitAllow.length === 0,
294
+ autoAllow: false,
273
295
  allowTasks: true,
274
296
  requireClean: opts.statusCommitRequireClean,
275
297
  quiet: opts.quiet,
@@ -1 +1 @@
1
- {"version":3,"file":"set-status.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAoJ9D,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC5E,KAAK,UAAU,EAAE,GAAG,mBAAmB,KAAG,OAAO,CAAC,MAAM,CAAC,CAsBxE"}
1
+ {"version":3,"file":"set-status.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/set-status.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAOtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAyK9D,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC5E,KAAK,UAAU,EAAE,GAAG,mBAAmB,KAAG,OAAO,CAAC,MAAM,CAAC,CAsBxE"}
@@ -1,5 +1,6 @@
1
1
  import { usageError } from "../../cli/spec/errors.js";
2
2
  import { toStringList } from "../../cli/spec/parse-utils.js";
3
+ import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../../shared/allow-prefix-policy.js";
3
4
  import { cmdTaskSetStatus } from "./set-status.js";
4
5
  export const taskSetStatusSpec = {
5
6
  id: ["task", "set-status"],
@@ -57,13 +58,14 @@ export const taskSetStatusSpec = {
57
58
  name: "commit-allow",
58
59
  valueHint: "<path-prefix>",
59
60
  repeatable: true,
60
- description: "Repeatable. Allowlist prefix for commit-from-comment staging.",
61
+ description: "Repeatable. Allowlist prefix for commit-from-comment staging. Use minimal prefixes; '.' is rejected.",
61
62
  },
62
63
  {
63
64
  kind: "boolean",
64
65
  name: "commit-auto-allow",
65
66
  default: false,
66
- description: "Auto-derive allowlist prefixes from staged paths (commit-from-comment).",
67
+ description: "Deprecated. Disabled for safety; pass explicit --commit-allow prefixes.",
68
+ deprecated: "disabled",
67
69
  },
68
70
  {
69
71
  kind: "boolean",
@@ -125,6 +127,24 @@ export const taskSetStatusSpec = {
125
127
  message: "Invalid value for --commit-allow: empty.",
126
128
  });
127
129
  }
130
+ if (findRepoWideAllowPrefixes(allow).length > 0) {
131
+ throw usageError({
132
+ spec: taskSetStatusSpec,
133
+ message: repoWideAllowPrefixMessage("--commit-allow"),
134
+ });
135
+ }
136
+ if (raw.opts["commit-auto-allow"] === true) {
137
+ throw usageError({
138
+ spec: taskSetStatusSpec,
139
+ message: "--commit-auto-allow is disabled; pass explicit --commit-allow <path-prefix>.",
140
+ });
141
+ }
142
+ if (raw.opts["commit-from-comment"] === true && allow.length === 0) {
143
+ throw usageError({
144
+ spec: taskSetStatusSpec,
145
+ message: "--commit-from-comment requires --commit-allow <path-prefix> (tip: `agentplane guard suggest-allow --format args`).",
146
+ });
147
+ }
128
148
  },
129
149
  parse: (raw) => {
130
150
  const commitAllow = toStringList(raw.opts["commit-allow"]);
@@ -1 +1 @@
1
- {"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../../../src/policy/rules/allowlist.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,CA+B9D"}
1
+ {"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../../../src/policy/rules/allowlist.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE/D,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,CA0C9D"}
@@ -17,6 +17,15 @@ export function allowlistRule(ctx) {
17
17
  };
18
18
  }
19
19
  const allow = allowRaw.map((p) => normalizeGitPathPrefix(p));
20
+ if (allow.includes(".")) {
21
+ return {
22
+ ok: false,
23
+ errors: [
24
+ gitError("Repo-wide allowlist ('.') is not allowed; choose minimal prefixes (tip: `agentplane guard suggest-allow --format args`)."),
25
+ ],
26
+ warnings: [],
27
+ };
28
+ }
20
29
  const errors = [];
21
30
  for (const filePath of staged) {
22
31
  if (!allow.some((prefix) => gitPathIsUnderPrefix(filePath, prefix))) {
@@ -0,0 +1,3 @@
1
+ export declare function findRepoWideAllowPrefixes(prefixes: string[]): string[];
2
+ export declare function repoWideAllowPrefixMessage(flagName: string): string;
3
+ //# sourceMappingURL=allow-prefix-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allow-prefix-policy.d.ts","sourceRoot":"","sources":["../../src/shared/allow-prefix-policy.ts"],"names":[],"mappings":"AAEA,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEtE;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKnE"}
@@ -0,0 +1,8 @@
1
+ import { normalizeGitPathPrefix } from "./git-path.js";
2
+ export function findRepoWideAllowPrefixes(prefixes) {
3
+ return prefixes.filter((prefix) => normalizeGitPathPrefix(prefix) === ".");
4
+ }
5
+ export function repoWideAllowPrefixMessage(flagName) {
6
+ return (`${flagName} cannot be repo-wide ('.'). ` +
7
+ "Choose minimal path prefixes; tip: `agentplane guard suggest-allow --format args`.");
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentplane",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "description": "Agent Plane CLI for task workflows, recipes, and project automation.",
5
5
  "keywords": [
6
6
  "agentplane",
@@ -55,7 +55,7 @@
55
55
  "prepublishOnly": "node ../../scripts/enforce-github-publish.mjs && npm run prepack"
56
56
  },
57
57
  "dependencies": {
58
- "@agentplaneorg/core": "0.2.24",
58
+ "@agentplaneorg/core": "0.2.25",
59
59
  "yauzl": "^2.10.0"
60
60
  },
61
61
  "devDependencies": {