@frankzhang2026/opencode-android-orchestrator 0.9.0 → 0.10.0

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 (52) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +55 -12
  3. package/dist/config/commit-message-prefix.d.ts +31 -0
  4. package/dist/config/commit-message-prefix.d.ts.map +1 -0
  5. package/dist/config/commit-message-prefix.js +155 -0
  6. package/dist/config/commit-message-prefix.js.map +1 -0
  7. package/dist/config/verification-policy.d.ts +5 -3
  8. package/dist/config/verification-policy.d.ts.map +1 -1
  9. package/dist/config/verification-policy.js +32 -13
  10. package/dist/config/verification-policy.js.map +1 -1
  11. package/dist/doctor/installation.d.ts.map +1 -1
  12. package/dist/doctor/installation.js +78 -0
  13. package/dist/doctor/installation.js.map +1 -1
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +1 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/installer/adaptive-templates.d.ts +6 -2
  19. package/dist/installer/adaptive-templates.d.ts.map +1 -1
  20. package/dist/installer/adaptive-templates.js +8 -0
  21. package/dist/installer/adaptive-templates.js.map +1 -1
  22. package/dist/installer/index.d.ts +1 -0
  23. package/dist/installer/index.d.ts.map +1 -1
  24. package/dist/installer/index.js +1 -0
  25. package/dist/installer/index.js.map +1 -1
  26. package/dist/installer/init.d.ts +4 -1
  27. package/dist/installer/init.d.ts.map +1 -1
  28. package/dist/installer/init.js +60 -9
  29. package/dist/installer/init.js.map +1 -1
  30. package/dist/installer/opencode-config.d.ts +3 -3
  31. package/dist/installer/opencode-config.d.ts.map +1 -1
  32. package/dist/installer/opencode-config.js +1 -1
  33. package/dist/installer/opencode-config.js.map +1 -1
  34. package/dist/installer/upgrade.d.ts +5 -1
  35. package/dist/installer/upgrade.d.ts.map +1 -1
  36. package/dist/installer/upgrade.js +81 -10
  37. package/dist/installer/upgrade.js.map +1 -1
  38. package/docs/MIGRATION.md +27 -14
  39. package/docs/SECURITY.md +14 -5
  40. package/docs/TROUBLESHOOTING.md +13 -11
  41. package/package.json +1 -1
  42. package/templates/README.md +9 -1
  43. package/templates/automation/config.json +2 -1
  44. package/templates/automation/config.schema.json +7 -2
  45. package/templates/scripts/automation/abort-task.sh +2 -1
  46. package/templates/scripts/automation/accept-and-integrate.sh +4 -2
  47. package/templates/scripts/automation/approve-and-run.sh +1 -0
  48. package/templates/scripts/automation/lib.sh +93 -2
  49. package/templates/scripts/automation/orchestrate-task.sh +1 -0
  50. package/templates/scripts/automation/preflight.sh +11 -0
  51. package/templates/scripts/automation/show-acceptance-review.sh +3 -0
  52. package/templates/scripts/automation/tests/run-tests.sh +59 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.10.0 - 2026-09-11
4
+
5
+ - Add automation configuration schema v5 with
6
+ `commitMessagePrefixMode`, defaulting to `required`.
7
+ - Create and preserve the human-maintained
8
+ `automation/automation-commit-prefix` sidecar during init and upgrade without
9
+ adding it to the managed installation manifest.
10
+ - Block new orchestrated tasks until the required prefix file contains exactly
11
+ one valid non-comment line, while keeping init, upgrade, doctor, and shadow
12
+ verification usable with the initial comments-only template.
13
+ - Prefix both accepted task commits and abort recovery commits automatically,
14
+ read the latest value from the source worktree, and show the resulting message
15
+ in the human acceptance card without prompting on each commit.
16
+ - Exclude the prefix sidecar from task scope, evidence, cleanliness, automated
17
+ staging, and plugin-created commits, including isolated-worktree execution.
18
+
3
19
  ## 0.9.0 - 2026-09-09
4
20
 
5
21
  - Make Gradle's evaluated project model authoritative for Android module
package/README.md CHANGED
@@ -20,7 +20,9 @@ package, and removes the runtime GitHub/Superpowers plugin dependency. Version
20
20
  project-specific `AGENTS.md` content outside the managed marker block. Version
21
21
  `0.9.0` discovers Android modules from Gradle's evaluated runtime model, so
22
22
  dynamic settings logic and company convention plugins no longer leave modules
23
- or their focused-test tasks out of generated configuration.
23
+ or their focused-test tasks out of generated configuration. Version `0.10.0`
24
+ adds a user-maintained commit-message prefix that is read automatically for
25
+ each task commit and blocks task startup until the required value is filled.
24
26
 
25
27
  ## Documentation
26
28
 
@@ -55,8 +57,9 @@ project builds retain their configured cache behavior.
55
57
  ## Quick start
56
58
 
57
59
  ```sh
58
- npx @frankzhang2026/opencode-android-orchestrator@0.9.0 init .
59
- npx @frankzhang2026/opencode-android-orchestrator@0.9.0 doctor .
60
+ npx @frankzhang2026/opencode-android-orchestrator@0.10.0 init .
61
+ $EDITOR automation/automation-commit-prefix
62
+ npx @frankzhang2026/opencode-android-orchestrator@0.10.0 doctor .
60
63
  opencode --agent scheduled-planner .
61
64
  ```
62
65
 
@@ -66,7 +69,7 @@ a task contract without selecting a primary module. To intentionally restrict
66
69
  generated contracts to one module, opt into primary-module scope:
67
70
 
68
71
  ```sh
69
- npx @frankzhang2026/opencode-android-orchestrator@0.9.0 init . \
72
+ npx @frankzhang2026/opencode-android-orchestrator@0.10.0 init . \
70
73
  --module-scope primary \
71
74
  --primary-module :mobile
72
75
  ```
@@ -94,14 +97,14 @@ For an existing manifest-managed installation whose generated module/task
94
97
  lists are incomplete, refresh all derived Gradle data in one upgrade:
95
98
 
96
99
  ```sh
97
- npx @frankzhang2026/opencode-android-orchestrator@0.9.0 upgrade . \
100
+ npx @frankzhang2026/opencode-android-orchestrator@0.10.0 upgrade . \
98
101
  --refresh-gradle-discovery
99
102
  ```
100
103
 
101
104
  The refresh updates `androidProject.modules`, production/test paths, protected
102
105
  build files, and all five Gradle task groups together. Without the flag,
103
106
  upgrade preserves an intentionally customized task matrix. The explicit
104
- refresh is also allowed on an already installed `0.9.0` when the evaluated
107
+ refresh is also allowed on an already installed `0.10.0` when the evaluated
105
108
  Gradle model has changed; an unchanged refresh remains byte-idempotent.
106
109
 
107
110
  ### Bundled workflow skills
@@ -146,13 +149,47 @@ unchanged. Android lint is disabled by default; setting `lintEnabled` to `true`
146
149
  runs the discovered `lintTasks` in those gates. Assemble, scope, evidence, and
147
150
  required device-test checks are unaffected by either flag.
148
151
 
149
- These two booleans are the operator-editable exceptions in the otherwise
150
- managed configuration. Change their values in place and commit the file before
152
+ These two booleans and `commitMessagePrefixMode` are the operator-editable
153
+ exceptions in the otherwise managed configuration. Change their values in
154
+ place and commit the file before
151
155
  starting orchestration. Doctor accepts these policy changes and a later
152
156
  upgrade preserves them. Do not reformat or edit unrelated generated fields.
153
157
  Legacy installations without the fields receive `true` for unit tests and
154
158
  `false` for lint during upgrade.
155
159
 
160
+ ### Automatic commit-message prefix
161
+
162
+ Automation configuration schema V5 adds this repository policy:
163
+
164
+ ```json
165
+ {
166
+ "commitMessagePrefixMode": "required"
167
+ }
168
+ ```
169
+
170
+ `required` is the default. During `init` or `upgrade`, the plugin creates
171
+ `automation/automation-commit-prefix` only when it does not already exist. The
172
+ initial file contains comments but no value, so installation or upgrade still
173
+ succeeds while new task startup remains blocked. Edit it once and put the
174
+ current company text on exactly one non-comment line, for example:
175
+
176
+ ```text
177
+ 本周研发批次
178
+ ```
179
+
180
+ The plugin reads that file automatically; it never asks for the value on each
181
+ commit. A successful task commit becomes, for example,
182
+ `本周研发批次 Implement Add profile validation (TASK-123)`, and an abort
183
+ recovery commit receives the same current prefix. Change the one line whenever
184
+ the company text changes; the next plugin-created commit uses the new value.
185
+
186
+ The prefix file is human-owned, excluded from the 47 managed-file hashes and
187
+ from task diffs, evidence, automated staging, and plugin-created commits, and
188
+ preserved by upgrade and uninstall. Set `commitMessagePrefixMode` to `disabled`
189
+ only when repository policy explicitly does not require a prefix. This setting
190
+ governs commits made by the orchestrator; use a repository Git hook if manually
191
+ created commits must also be enforced.
192
+
156
193
  ### Managed long-command timeout
157
194
 
158
195
  The plugin raises direct managed lifecycle commands such as `claim-task.sh`,
@@ -220,7 +257,10 @@ The install transaction manages 47 project-local paths:
220
257
  | Android automation config and task example | 2 | Generate from detected modules. |
221
258
  | `AGENTS.md` and OpenCode JSON/JSONC | 2 | Merge bounded content without replacing unrelated settings. |
222
259
 
223
- After installation, start the `scheduled-planner` and use its interactive flow.
260
+ After installation or upgrade, fill the required commit-prefix file before
261
+ starting `scheduled-planner`; preflight rejects a missing, comments-only,
262
+ multi-value, oversized, or symbolic-link prefix file. Then use the planner's
263
+ interactive flow.
224
264
  The `/acceptance <TASK-ID>`, `/resume-task <TASK-ID>`,
225
265
  `/resume-review <TASK-ID>`, and `/abort-task <TASK-ID>` commands are
226
266
  recovery/re-entry points; they do not replace the required fresh approval
@@ -240,6 +280,8 @@ Cache setting, `0.6.1` adds configurable long-command timeouts plus bounded
240
280
  baseline-interruption recovery, and `0.7.0` makes unit-test and lint gates
241
281
  repository-configurable. Version `0.8.0` moves the five required workflow
242
282
  skills into the npm package and removes their external plugin dependency.
283
+ Version `0.9.0` makes Gradle's evaluated module model authoritative, and
284
+ `0.10.0` adds the required user-maintained commit prefix and task-start gate.
243
285
 
244
286
  The cross-version plugin entry, OpenCode version doctor, Android/Gradle project
245
287
  discovery, audited V4 OpenCode/configuration resources, and all deterministic
@@ -304,7 +346,7 @@ Implemented checks include:
304
346
  Shell executable modes, merges OpenCode JSON/JSONC and one bounded AGENTS
305
347
  block, bootstraps the optional human-owned worktree allowlist when missing,
306
348
  and is byte-idempotent for an unchanged installed version
307
- - write-before-complete verification using the 44-case automation suite and a
349
+ - write-before-complete verification using the 46-case automation suite and a
308
350
  read-only shadow run; any failure restores original files before reporting
309
351
  the error
310
352
  - an installation-aware, read-only doctor that authenticates the 47-file
@@ -382,7 +424,8 @@ preparation alone as resource installation;
382
424
  ## Init
383
425
 
384
426
  ```sh
385
- npx @frankzhang2026/opencode-android-orchestrator@0.9.0 init .
427
+ npx @frankzhang2026/opencode-android-orchestrator@0.10.0 init .
428
+ $EDITOR automation/automation-commit-prefix
386
429
  opencode --agent scheduled-planner .
387
430
  ```
388
431
 
@@ -503,7 +546,7 @@ the immediately preceding `question` result and bind at least the approval
503
546
  kind, task ID, session, message, relevant sealed SHA/branch, timestamp, and
504
547
  nonce. It must also retain fixed-script authentication, strict state
505
548
  preconditions, project/worktree bounds, abort propagation that terminates child
506
- processes, bounded structured output, exact per-agent permissions, the 44-case
549
+ processes, bounded structured output, exact per-agent permissions, the 46-case
507
550
  transaction suite, and real `1.14.22`/`1.15.13` integration tests. Internal
508
551
  Coder/Reviewer transition scripts remain private orchestration details rather
509
552
  than public tools.
@@ -0,0 +1,31 @@
1
+ export declare const COMMIT_MESSAGE_PREFIX_RELATIVE_PATH = "automation/automation-commit-prefix";
2
+ export declare const INITIAL_COMMIT_MESSAGE_PREFIX_CONTENT: string;
3
+ export declare const COMMIT_MESSAGE_PREFIX_FILE_MAX_BYTES = 4096;
4
+ export declare const COMMIT_MESSAGE_PREFIX_MAX_BYTES = 256;
5
+ export type CommitMessagePrefixMode = "required" | "disabled";
6
+ export declare const DEFAULT_COMMIT_MESSAGE_PREFIX_MODE: CommitMessagePrefixMode;
7
+ export declare function isCommitMessagePrefixMode(value: unknown): value is CommitMessagePrefixMode;
8
+ export type CommitMessagePrefixInspectionStatus = "disabled" | "missing" | "unconfigured" | "configured" | "invalid";
9
+ export interface CommitMessagePrefixInspection {
10
+ path: string;
11
+ mode: CommitMessagePrefixMode;
12
+ status: CommitMessagePrefixInspectionStatus;
13
+ prefix: string | null;
14
+ details: readonly string[];
15
+ }
16
+ export type CommitMessagePrefixInitializationStatus = "disabled" | "created-unconfigured" | "existing-unconfigured" | "existing-configured";
17
+ export interface CommitMessagePrefixInitialization {
18
+ path: string;
19
+ mode: CommitMessagePrefixMode;
20
+ status: CommitMessagePrefixInitializationStatus;
21
+ }
22
+ export type CommitMessagePrefixErrorCode = "COMMIT_MESSAGE_PREFIX_INVALID" | "COMMIT_MESSAGE_PREFIX_ROLLBACK_FAILED" | "COMMIT_MESSAGE_PREFIX_WRITE_FAILED";
23
+ export declare class CommitMessagePrefixError extends Error {
24
+ readonly code: CommitMessagePrefixErrorCode;
25
+ readonly details: readonly string[];
26
+ constructor(code: CommitMessagePrefixErrorCode, message: string, details?: readonly string[]);
27
+ }
28
+ export declare function inspectCommitMessagePrefix(targetDirectory: string, mode: CommitMessagePrefixMode): CommitMessagePrefixInspection;
29
+ export declare function initializeCommitMessagePrefix(targetDirectory: string, mode: CommitMessagePrefixMode): CommitMessagePrefixInitialization;
30
+ export declare function rollbackCommitMessagePrefixInitialization(initialization: CommitMessagePrefixInitialization): void;
31
+ //# sourceMappingURL=commit-message-prefix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-message-prefix.d.ts","sourceRoot":"","sources":["../../src/config/commit-message-prefix.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mCAAmC,wCACT,CAAC;AACxC,eAAO,MAAM,qCAAqC,QAItC,CAAC;AACb,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAC1D,eAAO,MAAM,+BAA+B,MAAM,CAAC;AAEnD,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,UAAU,CAAC;AAE9D,eAAO,MAAM,kCAAkC,EAAE,uBACrC,CAAC;AAEb,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,uBAAuB,CAElC;AAED,MAAM,MAAM,mCAAmC,GAC3C,UAAU,GACV,SAAS,GACT,cAAc,GACd,YAAY,GACZ,SAAS,CAAC;AAEd,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,EAAE,mCAAmC,CAAC;IAC5C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,MAAM,uCAAuC,GAC/C,UAAU,GACV,sBAAsB,GACtB,uBAAuB,GACvB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,iCAAiC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,EAAE,uCAAuC,CAAC;CACjD;AAED,MAAM,MAAM,4BAA4B,GACpC,+BAA+B,GAC/B,uCAAuC,GACvC,oCAAoC,CAAC;AAEzC,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,4BAA4B,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;gBAGlC,IAAI,EAAE,4BAA4B,EAClC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,SAAS,MAAM,EAAO;CAOlC;AA4BD,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,uBAAuB,GAC5B,6BAA6B,CAqF/B;AAcD,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE,uBAAuB,GAC5B,iCAAiC,CAoCnC;AAED,wBAAgB,yCAAyC,CACvD,cAAc,EAAE,iCAAiC,GAChD,IAAI,CA8BN"}
@@ -0,0 +1,155 @@
1
+ import { lstatSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { TextDecoder } from "node:util";
4
+ export const COMMIT_MESSAGE_PREFIX_RELATIVE_PATH = "automation/automation-commit-prefix";
5
+ export const INITIAL_COMMIT_MESSAGE_PREFIX_CONTENT = [
6
+ "# 必填:请在下一行填写当前 Git 提交文案前缀",
7
+ "# 示例:XXX",
8
+ "",
9
+ ].join("\n");
10
+ export const COMMIT_MESSAGE_PREFIX_FILE_MAX_BYTES = 4_096;
11
+ export const COMMIT_MESSAGE_PREFIX_MAX_BYTES = 256;
12
+ export const DEFAULT_COMMIT_MESSAGE_PREFIX_MODE = "required";
13
+ export function isCommitMessagePrefixMode(value) {
14
+ return value === "required" || value === "disabled";
15
+ }
16
+ export class CommitMessagePrefixError extends Error {
17
+ code;
18
+ details;
19
+ constructor(code, message, details = []) {
20
+ super(message);
21
+ this.name = "CommitMessagePrefixError";
22
+ this.code = code;
23
+ this.details = details;
24
+ }
25
+ }
26
+ function filesystemErrorCode(error) {
27
+ if (typeof error === "object" &&
28
+ error !== null &&
29
+ "code" in error &&
30
+ typeof error.code === "string") {
31
+ return error.code;
32
+ }
33
+ return null;
34
+ }
35
+ function invalidInspection(path, mode, detail) {
36
+ return {
37
+ path,
38
+ mode,
39
+ status: "invalid",
40
+ prefix: null,
41
+ details: [detail],
42
+ };
43
+ }
44
+ export function inspectCommitMessagePrefix(targetDirectory, mode) {
45
+ const path = join(targetDirectory, ...COMMIT_MESSAGE_PREFIX_RELATIVE_PATH.split("/"));
46
+ if (mode === "disabled") {
47
+ return { path, mode, status: "disabled", prefix: null, details: [] };
48
+ }
49
+ let stats;
50
+ try {
51
+ stats = lstatSync(path);
52
+ }
53
+ catch (error) {
54
+ if (filesystemErrorCode(error) === "ENOENT") {
55
+ return { path, mode, status: "missing", prefix: null, details: [] };
56
+ }
57
+ return invalidInspection(path, mode, error instanceof Error ? error.message : String(error));
58
+ }
59
+ if (stats.isSymbolicLink() || !stats.isFile()) {
60
+ return invalidInspection(path, mode, "The commit-message prefix must be a regular file, not a symlink or directory.");
61
+ }
62
+ if (stats.size > COMMIT_MESSAGE_PREFIX_FILE_MAX_BYTES) {
63
+ return invalidInspection(path, mode, `The commit-message prefix file exceeds ${String(COMMIT_MESSAGE_PREFIX_FILE_MAX_BYTES)} bytes.`);
64
+ }
65
+ let content;
66
+ try {
67
+ content = new TextDecoder("utf-8", { fatal: true }).decode(readFileSync(path));
68
+ }
69
+ catch (error) {
70
+ return invalidInspection(path, mode, `The commit-message prefix file is unreadable or is not valid UTF-8: ${error instanceof Error ? error.message : String(error)}`);
71
+ }
72
+ const activeLines = content
73
+ .split(/\r?\n/)
74
+ .filter((line) => line.trim().length > 0 && !line.trimStart().startsWith("#"));
75
+ if (activeLines.length === 0) {
76
+ return { path, mode, status: "unconfigured", prefix: null, details: [] };
77
+ }
78
+ if (activeLines.length !== 1) {
79
+ return invalidInspection(path, mode, "The commit-message prefix file must contain exactly one non-comment line.");
80
+ }
81
+ const prefix = activeLines[0];
82
+ if (prefix !== prefix.trim()) {
83
+ return invalidInspection(path, mode, "The commit-message prefix must not have leading or trailing whitespace.");
84
+ }
85
+ if (/[\u0000-\u001f\u007f]/u.test(prefix)) {
86
+ return invalidInspection(path, mode, "The commit-message prefix must not contain control characters.");
87
+ }
88
+ if (Buffer.byteLength(prefix, "utf8") > COMMIT_MESSAGE_PREFIX_MAX_BYTES) {
89
+ return invalidInspection(path, mode, `The commit-message prefix exceeds ${String(COMMIT_MESSAGE_PREFIX_MAX_BYTES)} UTF-8 bytes.`);
90
+ }
91
+ return { path, mode, status: "configured", prefix, details: [] };
92
+ }
93
+ function assertUsableInspection(inspection) {
94
+ if (inspection.status === "invalid") {
95
+ throw new CommitMessagePrefixError("COMMIT_MESSAGE_PREFIX_INVALID", "The commit-message prefix file is invalid.", [inspection.path, ...inspection.details]);
96
+ }
97
+ }
98
+ export function initializeCommitMessagePrefix(targetDirectory, mode) {
99
+ const initial = inspectCommitMessagePrefix(targetDirectory, mode);
100
+ assertUsableInspection(initial);
101
+ if (initial.status === "disabled") {
102
+ return { path: initial.path, mode, status: "disabled" };
103
+ }
104
+ if (initial.status === "configured") {
105
+ return { path: initial.path, mode, status: "existing-configured" };
106
+ }
107
+ if (initial.status === "unconfigured") {
108
+ return { path: initial.path, mode, status: "existing-unconfigured" };
109
+ }
110
+ try {
111
+ writeFileSync(initial.path, INITIAL_COMMIT_MESSAGE_PREFIX_CONTENT, {
112
+ flag: "wx",
113
+ mode: 0o644,
114
+ });
115
+ return { path: initial.path, mode, status: "created-unconfigured" };
116
+ }
117
+ catch (error) {
118
+ if (filesystemErrorCode(error) === "EEXIST") {
119
+ const concurrent = inspectCommitMessagePrefix(targetDirectory, mode);
120
+ assertUsableInspection(concurrent);
121
+ if (concurrent.status === "configured") {
122
+ return { path: concurrent.path, mode, status: "existing-configured" };
123
+ }
124
+ if (concurrent.status === "unconfigured") {
125
+ return { path: concurrent.path, mode, status: "existing-unconfigured" };
126
+ }
127
+ }
128
+ throw new CommitMessagePrefixError("COMMIT_MESSAGE_PREFIX_WRITE_FAILED", `Unable to create the commit-message prefix file: ${initial.path}`, [error instanceof Error ? error.message : String(error)]);
129
+ }
130
+ }
131
+ export function rollbackCommitMessagePrefixInitialization(initialization) {
132
+ if (initialization.status !== "created-unconfigured") {
133
+ return;
134
+ }
135
+ try {
136
+ const stats = lstatSync(initialization.path);
137
+ const content = readFileSync(initialization.path, "utf8");
138
+ if (stats.isSymbolicLink() ||
139
+ !stats.isFile() ||
140
+ content !== INITIAL_COMMIT_MESSAGE_PREFIX_CONTENT) {
141
+ throw new Error("The automatically created prefix file changed and was preserved.");
142
+ }
143
+ unlinkSync(initialization.path);
144
+ }
145
+ catch (error) {
146
+ if (filesystemErrorCode(error) === "ENOENT") {
147
+ return;
148
+ }
149
+ throw new CommitMessagePrefixError("COMMIT_MESSAGE_PREFIX_ROLLBACK_FAILED", "The automatically created commit-message prefix file could not be rolled back safely.", [
150
+ error instanceof Error ? error.message : String(error),
151
+ `Preserved path: ${initialization.path}`,
152
+ ]);
153
+ }
154
+ }
155
+ //# sourceMappingURL=commit-message-prefix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-message-prefix.js","sourceRoot":"","sources":["../../src/config/commit-message-prefix.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
+ import { type CommitMessagePrefixMode } from "./commit-message-prefix.js";
1
2
  export declare const AUTOMATION_CONFIG_RELATIVE_PATH = "automation/config.json";
2
3
  export declare const DEFAULT_LINT_ENABLED = false;
3
4
  export declare const DEFAULT_UNIT_TESTS_ENABLED = true;
4
5
  export interface VerificationPolicy {
6
+ commitMessagePrefixMode: CommitMessagePrefixMode;
5
7
  lintEnabled: boolean;
6
8
  unitTestsEnabled: boolean;
7
9
  }
@@ -11,9 +13,9 @@ interface ContentFingerprint {
11
13
  }
12
14
  /**
13
15
  * Accept an otherwise byte-identical generated configuration when an operator
14
- * changed only the two supported verification-policy booleans. Enumerating the
15
- * previous boolean states lets upgrades authenticate the remaining managed
16
- * content against the installed manifest without storing another file copy.
16
+ * changed only supported operator policy fields. Enumerating prior states lets
17
+ * upgrades authenticate the remaining managed content against the installed
18
+ * manifest without storing another file copy.
17
19
  */
18
20
  export declare function matchesManifestModuloVerificationPolicy(content: Uint8Array, expected: ContentFingerprint): boolean;
19
21
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"verification-policy.d.ts","sourceRoot":"","sources":["../../src/config/verification-policy.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,+BAA+B,2BAA2B,CAAC;AACxE,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAC1C,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAsBD;;;;;GAKG;AACH,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAwCT"}
1
+ {"version":3,"file":"verification-policy.d.ts","sourceRoot":"","sources":["../../src/config/verification-policy.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,4BAA4B,CAAC;AAEpC,eAAO,MAAM,+BAA+B,2BAA2B,CAAC;AACxE,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAC1C,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,uBAAuB,EAAE,uBAAuB,CAAC;IACjD,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAiCD;;;;;GAKG;AACH,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAkDT"}
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { DEFAULT_COMMIT_MESSAGE_PREFIX_MODE, isCommitMessagePrefixMode, } from "./commit-message-prefix.js";
2
3
  export const AUTOMATION_CONFIG_RELATIVE_PATH = "automation/config.json";
3
4
  export const DEFAULT_LINT_ENABLED = false;
4
5
  export const DEFAULT_UNIT_TESTS_ENABLED = true;
@@ -16,11 +17,19 @@ function setOptionalBoolean(value, key, configured) {
16
17
  value[key] = configured;
17
18
  }
18
19
  }
20
+ function setOptionalCommitMessagePrefixMode(value, configured) {
21
+ if (configured === undefined) {
22
+ delete value.commitMessagePrefixMode;
23
+ }
24
+ else {
25
+ value.commitMessagePrefixMode = configured;
26
+ }
27
+ }
19
28
  /**
20
29
  * Accept an otherwise byte-identical generated configuration when an operator
21
- * changed only the two supported verification-policy booleans. Enumerating the
22
- * previous boolean states lets upgrades authenticate the remaining managed
23
- * content against the installed manifest without storing another file copy.
30
+ * changed only supported operator policy fields. Enumerating prior states lets
31
+ * upgrades authenticate the remaining managed content against the installed
32
+ * manifest without storing another file copy.
24
33
  */
25
34
  export function matchesManifestModuloVerificationPolicy(content, expected) {
26
35
  if (content.byteLength === expected.size &&
@@ -38,19 +47,29 @@ export function matchesManifestModuloVerificationPolicy(content, expected) {
38
47
  return false;
39
48
  }
40
49
  if (typeof parsed.lintEnabled !== "boolean" ||
41
- typeof parsed.unitTestsEnabled !== "boolean") {
50
+ typeof parsed.unitTestsEnabled !== "boolean" ||
51
+ (parsed.commitMessagePrefixMode !== undefined &&
52
+ !isCommitMessagePrefixMode(parsed.commitMessagePrefixMode))) {
42
53
  return false;
43
54
  }
44
55
  const states = [undefined, false, true];
45
- for (const unitTestsEnabled of states) {
46
- for (const lintEnabled of states) {
47
- const candidate = { ...parsed };
48
- setOptionalBoolean(candidate, "unitTestsEnabled", unitTestsEnabled);
49
- setOptionalBoolean(candidate, "lintEnabled", lintEnabled);
50
- const rendered = Buffer.from(`${JSON.stringify(candidate, null, 2)}\n`);
51
- if (rendered.byteLength === expected.size &&
52
- sha256(rendered) === expected.sha256) {
53
- return true;
56
+ const prefixModes = [
57
+ undefined,
58
+ DEFAULT_COMMIT_MESSAGE_PREFIX_MODE,
59
+ "disabled",
60
+ ];
61
+ for (const commitMessagePrefixMode of prefixModes) {
62
+ for (const unitTestsEnabled of states) {
63
+ for (const lintEnabled of states) {
64
+ const candidate = { ...parsed };
65
+ setOptionalCommitMessagePrefixMode(candidate, commitMessagePrefixMode);
66
+ setOptionalBoolean(candidate, "unitTestsEnabled", unitTestsEnabled);
67
+ setOptionalBoolean(candidate, "lintEnabled", lintEnabled);
68
+ const rendered = Buffer.from(`${JSON.stringify(candidate, null, 2)}\n`);
69
+ if (rendered.byteLength === expected.size &&
70
+ sha256(rendered) === expected.sha256) {
71
+ return true;
72
+ }
54
73
  }
55
74
  }
56
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"verification-policy.js","sourceRoot":"","sources":["../../src/config/verification-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,CAAC,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAC1C,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAY/C,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,MAAM,CAAC,OAAmB;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,kBAAkB,CACzB,KAA8B,EAC9B,GAA6B,EAC7B,UAA+B;IAE/B,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uCAAuC,CACrD,OAAmB,EACnB,QAA4B;IAE5B,IACE,OAAO,CAAC,UAAU,KAAK,QAAQ,CAAC,IAAI;QACpC,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,MAAM,EACnC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAY,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IACE,OAAO,MAAM,CAAC,WAAW,KAAK,SAAS;QACvC,OAAO,MAAM,CAAC,gBAAgB,KAAK,SAAS,EAC5C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAqC,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1E,KAAK,MAAM,gBAAgB,IAAI,MAAM,EAAE,CAAC;QACtC,KAAK,MAAM,WAAW,IAAI,MAAM,EAAE,CAAC;YACjC,MAAM,SAAS,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;YAChC,kBAAkB,CAAC,SAAS,EAAE,kBAAkB,EAAE,gBAAgB,CAAC,CAAC;YACpE,kBAAkB,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC;YAC1D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACxE,IACE,QAAQ,CAAC,UAAU,KAAK,QAAQ,CAAC,IAAI;gBACrC,MAAM,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,MAAM,EACpC,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"verification-policy.js","sourceRoot":"","sources":["../../src/config/verification-policy.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"installation.d.ts","sourceRoot":"","sources":["../../src/doctor/installation.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,2BAA2B,KAAK,CAAC;AA+mB9C,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,MAAM,GACtB,SAAS,WAAW,EAAE,CA4DxB"}
1
+ {"version":3,"file":"installation.d.ts","sourceRoot":"","sources":["../../src/doctor/installation.ts"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAusB9C,wBAAgB,wBAAwB,CACtC,eAAe,EAAE,MAAM,GACtB,SAAS,WAAW,EAAE,CA6DxB"}
@@ -3,6 +3,7 @@ import { lstatSync, readFileSync, } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { DEFAULT_LONG_COMMAND_TIMEOUT_MS } from "../config/long-command-timeout.js";
6
+ import { COMMIT_MESSAGE_PREFIX_RELATIVE_PATH, DEFAULT_COMMIT_MESSAGE_PREFIX_MODE, inspectCommitMessagePrefix, isCommitMessagePrefixMode, } from "../config/commit-message-prefix.js";
6
7
  import { AUTOMATION_CONFIG_RELATIVE_PATH, DEFAULT_LINT_ENABLED, DEFAULT_UNIT_TESTS_ENABLED, matchesManifestModuloVerificationPolicy, } from "../config/verification-policy.js";
7
8
  import { isModuleScope, planAdaptiveProjectTemplates, } from "../installer/adaptive-templates.js";
8
9
  import { planAgentsConfigMerge } from "../installer/agents-config.js";
@@ -257,6 +258,7 @@ function blockedInstallationChecks(reason) {
257
258
  blockedCheck("managed-permissions", "Managed permissions", reason),
258
259
  blockedCheck("installation-backups", "Installation backups", reason),
259
260
  blockedCheck("managed-configuration", "Managed configuration", reason),
261
+ blockedCheck("commit-message-prefix", "Commit-message prefix", reason),
260
262
  ];
261
263
  }
262
264
  function managedResourceCheck(manifest, inspections) {
@@ -445,6 +447,17 @@ function managedConfigurationCheck(targetDirectory, manifest, inspections) {
445
447
  unitTestsEnabled,
446
448
  };
447
449
  }
450
+ const commitMessagePrefixMode = automationConfig.commitMessagePrefixMode ??
451
+ DEFAULT_COMMIT_MESSAGE_PREFIX_MODE;
452
+ if (!isCommitMessagePrefixMode(commitMessagePrefixMode)) {
453
+ throw new Error("commitMessagePrefixMode must be either required or disabled");
454
+ }
455
+ if (automationConfig.commitMessagePrefixMode === undefined) {
456
+ comparableAutomationConfig = {
457
+ ...comparableAutomationConfig,
458
+ commitMessagePrefixMode,
459
+ };
460
+ }
448
461
  const longCommandTimeoutMs = automationConfig.longCommandTimeoutMs ?? DEFAULT_LONG_COMMAND_TIMEOUT_MS;
449
462
  if (typeof longCommandTimeoutMs !== "number") {
450
463
  throw new Error("longCommandTimeoutMs must be a number");
@@ -461,6 +474,7 @@ function managedConfigurationCheck(targetDirectory, manifest, inspections) {
461
474
  gradleVerification: automationConfig.gradleVerification,
462
475
  lintEnabled,
463
476
  unitTestsEnabled,
477
+ commitMessagePrefixMode,
464
478
  longCommandTimeoutMs,
465
479
  });
466
480
  if (!jsonMatches(comparableAutomationConfig, expected.automationConfig)) {
@@ -471,6 +485,7 @@ function managedConfigurationCheck(targetDirectory, manifest, inspections) {
471
485
  details.push(`Automation default module: ${primaryModule}`);
472
486
  details.push(`Unit-test verification: ${unitTestsEnabled ? "enabled" : "disabled"}`);
473
487
  details.push(`Android lint verification: ${lintEnabled ? "enabled" : "disabled"}`);
488
+ details.push(`Commit-message prefix mode: ${commitMessagePrefixMode}`);
474
489
  }
475
490
  const taskExample = JSON.parse(inspectedText("automation/tasks/TASK-TEMPLATE.json.example", inspections));
476
491
  if (!jsonMatches(taskExample, expected.taskContractExample)) {
@@ -490,6 +505,68 @@ function managedConfigurationCheck(targetDirectory, manifest, inspections) {
490
505
  details: failures.length === 0 ? details : failures,
491
506
  };
492
507
  }
508
+ function commitMessagePrefixCheck(targetDirectory, inspections) {
509
+ let mode;
510
+ try {
511
+ const automationConfig = JSON.parse(inspectedText(AUTOMATION_CONFIG_RELATIVE_PATH, inspections));
512
+ if (!isRecord(automationConfig)) {
513
+ throw new Error("automation config must be a JSON object");
514
+ }
515
+ const configuredMode = automationConfig.commitMessagePrefixMode ??
516
+ DEFAULT_COMMIT_MESSAGE_PREFIX_MODE;
517
+ if (!isCommitMessagePrefixMode(configuredMode)) {
518
+ throw new Error("commitMessagePrefixMode must be either required or disabled");
519
+ }
520
+ mode = configuredMode;
521
+ }
522
+ catch (error) {
523
+ return {
524
+ id: "commit-message-prefix",
525
+ label: "Commit-message prefix",
526
+ status: "fail",
527
+ summary: "Commit-message prefix policy could not be inspected.",
528
+ details: errorDetails(error),
529
+ };
530
+ }
531
+ const inspection = inspectCommitMessagePrefix(targetDirectory, mode);
532
+ if (inspection.status === "disabled") {
533
+ return {
534
+ id: "commit-message-prefix",
535
+ label: "Commit-message prefix",
536
+ status: "pass",
537
+ summary: "Commit-message prefixing is disabled by automation configuration.",
538
+ details: [],
539
+ };
540
+ }
541
+ if (inspection.status === "configured") {
542
+ return {
543
+ id: "commit-message-prefix",
544
+ label: "Commit-message prefix",
545
+ status: "pass",
546
+ summary: "The required user-maintained commit-message prefix is configured.",
547
+ details: [inspection.path],
548
+ };
549
+ }
550
+ if (inspection.status === "missing" || inspection.status === "unconfigured") {
551
+ return {
552
+ id: "commit-message-prefix",
553
+ label: "Commit-message prefix",
554
+ status: "warn",
555
+ summary: "New automation tasks are blocked until the commit-message prefix is filled.",
556
+ details: [
557
+ inspection.path,
558
+ `Put exactly one non-comment prefix line in ${COMMIT_MESSAGE_PREFIX_RELATIVE_PATH}.`,
559
+ ],
560
+ };
561
+ }
562
+ return {
563
+ id: "commit-message-prefix",
564
+ label: "Commit-message prefix",
565
+ status: "fail",
566
+ summary: "The required commit-message prefix file is invalid.",
567
+ details: [inspection.path, ...inspection.details],
568
+ };
569
+ }
493
570
  export function installationDoctorChecks(targetDirectory) {
494
571
  let manifest;
495
572
  try {
@@ -537,6 +614,7 @@ export function installationDoctorChecks(targetDirectory) {
537
614
  managedPermissionCheck(manifest, inspections),
538
615
  installationBackupCheck(targetDirectory, manifest),
539
616
  managedConfigurationCheck(targetDirectory, manifest, inspections),
617
+ commitMessagePrefixCheck(targetDirectory, inspections),
540
618
  ];
541
619
  }
542
620
  //# sourceMappingURL=installation.js.map