@williambeto/ai-workflow 2.7.1 → 2.8.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.
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- BranchGate,
4
3
  COMPLETION_STATUS_TEXT,
5
4
  DelegationController,
6
5
  EvidenceLedger,
@@ -15,24 +14,357 @@ import {
15
14
  discoverPackageFiles,
16
15
  getFullAgentContent,
17
16
  getFullSkillFiles,
17
+ getPackageRoot,
18
18
  getPackageVersion,
19
19
  getWorkflowProfile,
20
20
  isRecoverableGateFailure,
21
21
  isTerminalFailure,
22
22
  readPackageFile,
23
23
  resolveWorkflowProfile
24
- } from "../chunk-W4RTQWVQ.js";
24
+ } from "../chunk-LI76KI7C.js";
25
+ import {
26
+ EvidenceValidator,
27
+ require_ajv,
28
+ require_codegen
29
+ } from "../chunk-FNT7DN3N.js";
25
30
  import {
26
31
  EvidenceCollector,
27
32
  QualityGuard,
28
33
  ValidationPlanner
29
- } from "../chunk-BDZPUAEX.js";
34
+ } from "../chunk-Y4RLP6ZM.js";
30
35
  import "../chunk-XW747GIG.js";
31
- import "../chunk-5WRI5ZAA.js";
36
+ import {
37
+ createManagedBackup,
38
+ createManagedPathBackup
39
+ } from "../chunk-AY33SA5W.js";
40
+ import {
41
+ BranchGate
42
+ } from "../chunk-AINIR25D.js";
43
+ import {
44
+ __commonJS,
45
+ __toESM
46
+ } from "../chunk-5WRI5ZAA.js";
47
+
48
+ // node_modules/ajv-formats/dist/formats.js
49
+ var require_formats = __commonJS({
50
+ "node_modules/ajv-formats/dist/formats.js"(exports) {
51
+ "use strict";
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.formatNames = exports.fastFormats = exports.fullFormats = void 0;
54
+ function fmtDef(validate, compare) {
55
+ return { validate, compare };
56
+ }
57
+ exports.fullFormats = {
58
+ // date: http://tools.ietf.org/html/rfc3339#section-5.6
59
+ date: fmtDef(date, compareDate),
60
+ // date-time: http://tools.ietf.org/html/rfc3339#section-5.6
61
+ time: fmtDef(getTime(true), compareTime),
62
+ "date-time": fmtDef(getDateTime(true), compareDateTime),
63
+ "iso-time": fmtDef(getTime(), compareIsoTime),
64
+ "iso-date-time": fmtDef(getDateTime(), compareIsoDateTime),
65
+ // duration: https://tools.ietf.org/html/rfc3339#appendix-A
66
+ duration: /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?|(\d+W)?)$/,
67
+ uri,
68
+ "uri-reference": /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,
69
+ // uri-template: https://tools.ietf.org/html/rfc6570
70
+ "uri-template": /^(?:(?:[^\x00-\x20"'<>%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,
71
+ // For the source: https://gist.github.com/dperini/729294
72
+ // For test cases: https://mathiasbynens.be/demo/url-regex
73
+ url: /^(?:https?|ftp):\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)(?:\.(?:[a-z0-9\u{00a1}-\u{ffff}]+-)*[a-z0-9\u{00a1}-\u{ffff}]+)*(?:\.(?:[a-z\u{00a1}-\u{ffff}]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/iu,
74
+ email: /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,
75
+ hostname: /^(?=.{1,253}\.?$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[-0-9a-z]{0,61}[0-9a-z])?)*\.?$/i,
76
+ // optimized https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9780596802837/ch07s16.html
77
+ ipv4: /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/,
78
+ ipv6: /^((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))$/i,
79
+ regex,
80
+ // uuid: http://tools.ietf.org/html/rfc4122
81
+ uuid: /^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,
82
+ // JSON-pointer: https://tools.ietf.org/html/rfc6901
83
+ // uri fragment: https://tools.ietf.org/html/rfc3986#appendix-A
84
+ "json-pointer": /^(?:\/(?:[^~/]|~0|~1)*)*$/,
85
+ "json-pointer-uri-fragment": /^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,
86
+ // relative JSON-pointer: http://tools.ietf.org/html/draft-luff-relative-json-pointer-00
87
+ "relative-json-pointer": /^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/,
88
+ // the following formats are used by the openapi specification: https://spec.openapis.org/oas/v3.0.0#data-types
89
+ // byte: https://github.com/miguelmota/is-base64
90
+ byte,
91
+ // signed 32 bit integer
92
+ int32: { type: "number", validate: validateInt32 },
93
+ // signed 64 bit integer
94
+ int64: { type: "number", validate: validateInt64 },
95
+ // C-type float
96
+ float: { type: "number", validate: validateNumber },
97
+ // C-type double
98
+ double: { type: "number", validate: validateNumber },
99
+ // hint to the UI to hide input strings
100
+ password: true,
101
+ // unchecked string payload
102
+ binary: true
103
+ };
104
+ exports.fastFormats = {
105
+ ...exports.fullFormats,
106
+ date: fmtDef(/^\d\d\d\d-[0-1]\d-[0-3]\d$/, compareDate),
107
+ time: fmtDef(/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i, compareTime),
108
+ "date-time": fmtDef(/^\d\d\d\d-[0-1]\d-[0-3]\dt(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)$/i, compareDateTime),
109
+ "iso-time": fmtDef(/^(?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i, compareIsoTime),
110
+ "iso-date-time": fmtDef(/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s](?:[0-2]\d:[0-5]\d:[0-5]\d|23:59:60)(?:\.\d+)?(?:z|[+-]\d\d(?::?\d\d)?)?$/i, compareIsoDateTime),
111
+ // uri: https://github.com/mafintosh/is-my-json-valid/blob/master/formats.js
112
+ uri: /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/)?[^\s]*$/i,
113
+ "uri-reference": /^(?:(?:[a-z][a-z0-9+\-.]*:)?\/?\/)?(?:[^\\\s#][^\s#]*)?(?:#[^\\\s]*)?$/i,
114
+ // email (sources from jsen validator):
115
+ // http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address#answer-8829363
116
+ // http://www.w3.org/TR/html5/forms.html#valid-e-mail-address (search for 'wilful violation')
117
+ email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i
118
+ };
119
+ exports.formatNames = Object.keys(exports.fullFormats);
120
+ function isLeapYear(year) {
121
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
122
+ }
123
+ var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
124
+ var DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
125
+ function date(str) {
126
+ const matches = DATE.exec(str);
127
+ if (!matches)
128
+ return false;
129
+ const year = +matches[1];
130
+ const month = +matches[2];
131
+ const day = +matches[3];
132
+ return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 && isLeapYear(year) ? 29 : DAYS[month]);
133
+ }
134
+ function compareDate(d1, d2) {
135
+ if (!(d1 && d2))
136
+ return void 0;
137
+ if (d1 > d2)
138
+ return 1;
139
+ if (d1 < d2)
140
+ return -1;
141
+ return 0;
142
+ }
143
+ var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
144
+ function getTime(strictTimeZone) {
145
+ return function time(str) {
146
+ const matches = TIME.exec(str);
147
+ if (!matches)
148
+ return false;
149
+ const hr = +matches[1];
150
+ const min = +matches[2];
151
+ const sec = +matches[3];
152
+ const tz = matches[4];
153
+ const tzSign = matches[5] === "-" ? -1 : 1;
154
+ const tzH = +(matches[6] || 0);
155
+ const tzM = +(matches[7] || 0);
156
+ if (tzH > 23 || tzM > 59 || strictTimeZone && !tz)
157
+ return false;
158
+ if (hr <= 23 && min <= 59 && sec < 60)
159
+ return true;
160
+ const utcMin = min - tzM * tzSign;
161
+ const utcHr = hr - tzH * tzSign - (utcMin < 0 ? 1 : 0);
162
+ return (utcHr === 23 || utcHr === -1) && (utcMin === 59 || utcMin === -1) && sec < 61;
163
+ };
164
+ }
165
+ function compareTime(s1, s2) {
166
+ if (!(s1 && s2))
167
+ return void 0;
168
+ const t1 = (/* @__PURE__ */ new Date("2020-01-01T" + s1)).valueOf();
169
+ const t2 = (/* @__PURE__ */ new Date("2020-01-01T" + s2)).valueOf();
170
+ if (!(t1 && t2))
171
+ return void 0;
172
+ return t1 - t2;
173
+ }
174
+ function compareIsoTime(t1, t2) {
175
+ if (!(t1 && t2))
176
+ return void 0;
177
+ const a1 = TIME.exec(t1);
178
+ const a2 = TIME.exec(t2);
179
+ if (!(a1 && a2))
180
+ return void 0;
181
+ t1 = a1[1] + a1[2] + a1[3];
182
+ t2 = a2[1] + a2[2] + a2[3];
183
+ if (t1 > t2)
184
+ return 1;
185
+ if (t1 < t2)
186
+ return -1;
187
+ return 0;
188
+ }
189
+ var DATE_TIME_SEPARATOR = /t|\s/i;
190
+ function getDateTime(strictTimeZone) {
191
+ const time = getTime(strictTimeZone);
192
+ return function date_time(str) {
193
+ const dateTime = str.split(DATE_TIME_SEPARATOR);
194
+ return dateTime.length === 2 && date(dateTime[0]) && time(dateTime[1]);
195
+ };
196
+ }
197
+ function compareDateTime(dt1, dt2) {
198
+ if (!(dt1 && dt2))
199
+ return void 0;
200
+ const d1 = new Date(dt1).valueOf();
201
+ const d2 = new Date(dt2).valueOf();
202
+ if (!(d1 && d2))
203
+ return void 0;
204
+ return d1 - d2;
205
+ }
206
+ function compareIsoDateTime(dt1, dt2) {
207
+ if (!(dt1 && dt2))
208
+ return void 0;
209
+ const [d1, t1] = dt1.split(DATE_TIME_SEPARATOR);
210
+ const [d2, t2] = dt2.split(DATE_TIME_SEPARATOR);
211
+ const res = compareDate(d1, d2);
212
+ if (res === void 0)
213
+ return void 0;
214
+ return res || compareTime(t1, t2);
215
+ }
216
+ var NOT_URI_FRAGMENT = /\/|:/;
217
+ var URI = /^(?:[a-z][a-z0-9+\-.]*:)(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'()*+,;=:@]|%[0-9a-f]{2})*)*)(?:\?(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i;
218
+ function uri(str) {
219
+ return NOT_URI_FRAGMENT.test(str) && URI.test(str);
220
+ }
221
+ var BYTE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/gm;
222
+ function byte(str) {
223
+ BYTE.lastIndex = 0;
224
+ return BYTE.test(str);
225
+ }
226
+ var MIN_INT32 = -(2 ** 31);
227
+ var MAX_INT32 = 2 ** 31 - 1;
228
+ function validateInt32(value) {
229
+ return Number.isInteger(value) && value <= MAX_INT32 && value >= MIN_INT32;
230
+ }
231
+ function validateInt64(value) {
232
+ return Number.isInteger(value);
233
+ }
234
+ function validateNumber() {
235
+ return true;
236
+ }
237
+ var Z_ANCHOR = /[^\\]\\Z/;
238
+ function regex(str) {
239
+ if (Z_ANCHOR.test(str))
240
+ return false;
241
+ try {
242
+ new RegExp(str);
243
+ return true;
244
+ } catch (e) {
245
+ return false;
246
+ }
247
+ }
248
+ }
249
+ });
250
+
251
+ // node_modules/ajv-formats/dist/limit.js
252
+ var require_limit = __commonJS({
253
+ "node_modules/ajv-formats/dist/limit.js"(exports) {
254
+ "use strict";
255
+ Object.defineProperty(exports, "__esModule", { value: true });
256
+ exports.formatLimitDefinition = void 0;
257
+ var ajv_1 = require_ajv();
258
+ var codegen_1 = require_codegen();
259
+ var ops = codegen_1.operators;
260
+ var KWDs = {
261
+ formatMaximum: { okStr: "<=", ok: ops.LTE, fail: ops.GT },
262
+ formatMinimum: { okStr: ">=", ok: ops.GTE, fail: ops.LT },
263
+ formatExclusiveMaximum: { okStr: "<", ok: ops.LT, fail: ops.GTE },
264
+ formatExclusiveMinimum: { okStr: ">", ok: ops.GT, fail: ops.LTE }
265
+ };
266
+ var error = {
267
+ message: ({ keyword, schemaCode }) => (0, codegen_1.str)`should be ${KWDs[keyword].okStr} ${schemaCode}`,
268
+ params: ({ keyword, schemaCode }) => (0, codegen_1._)`{comparison: ${KWDs[keyword].okStr}, limit: ${schemaCode}}`
269
+ };
270
+ exports.formatLimitDefinition = {
271
+ keyword: Object.keys(KWDs),
272
+ type: "string",
273
+ schemaType: "string",
274
+ $data: true,
275
+ error,
276
+ code(cxt) {
277
+ const { gen, data, schemaCode, keyword, it } = cxt;
278
+ const { opts, self } = it;
279
+ if (!opts.validateFormats)
280
+ return;
281
+ const fCxt = new ajv_1.KeywordCxt(it, self.RULES.all.format.definition, "format");
282
+ if (fCxt.$data)
283
+ validate$DataFormat();
284
+ else
285
+ validateFormat();
286
+ function validate$DataFormat() {
287
+ const fmts = gen.scopeValue("formats", {
288
+ ref: self.formats,
289
+ code: opts.code.formats
290
+ });
291
+ const fmt = gen.const("fmt", (0, codegen_1._)`${fmts}[${fCxt.schemaCode}]`);
292
+ cxt.fail$data((0, codegen_1.or)((0, codegen_1._)`typeof ${fmt} != "object"`, (0, codegen_1._)`${fmt} instanceof RegExp`, (0, codegen_1._)`typeof ${fmt}.compare != "function"`, compareCode(fmt)));
293
+ }
294
+ function validateFormat() {
295
+ const format = fCxt.schema;
296
+ const fmtDef = self.formats[format];
297
+ if (!fmtDef || fmtDef === true)
298
+ return;
299
+ if (typeof fmtDef != "object" || fmtDef instanceof RegExp || typeof fmtDef.compare != "function") {
300
+ throw new Error(`"${keyword}": format "${format}" does not define "compare" function`);
301
+ }
302
+ const fmt = gen.scopeValue("formats", {
303
+ key: format,
304
+ ref: fmtDef,
305
+ code: opts.code.formats ? (0, codegen_1._)`${opts.code.formats}${(0, codegen_1.getProperty)(format)}` : void 0
306
+ });
307
+ cxt.fail$data(compareCode(fmt));
308
+ }
309
+ function compareCode(fmt) {
310
+ return (0, codegen_1._)`${fmt}.compare(${data}, ${schemaCode}) ${KWDs[keyword].fail} 0`;
311
+ }
312
+ },
313
+ dependencies: ["format"]
314
+ };
315
+ var formatLimitPlugin = (ajv) => {
316
+ ajv.addKeyword(exports.formatLimitDefinition);
317
+ return ajv;
318
+ };
319
+ exports.default = formatLimitPlugin;
320
+ }
321
+ });
322
+
323
+ // node_modules/ajv-formats/dist/index.js
324
+ var require_dist = __commonJS({
325
+ "node_modules/ajv-formats/dist/index.js"(exports, module) {
326
+ "use strict";
327
+ Object.defineProperty(exports, "__esModule", { value: true });
328
+ var formats_1 = require_formats();
329
+ var limit_1 = require_limit();
330
+ var codegen_1 = require_codegen();
331
+ var fullName = new codegen_1.Name("fullFormats");
332
+ var fastName = new codegen_1.Name("fastFormats");
333
+ var formatsPlugin = (ajv, opts = { keywords: true }) => {
334
+ if (Array.isArray(opts)) {
335
+ addFormats2(ajv, opts, formats_1.fullFormats, fullName);
336
+ return ajv;
337
+ }
338
+ const [formats, exportName] = opts.mode === "fast" ? [formats_1.fastFormats, fastName] : [formats_1.fullFormats, fullName];
339
+ const list = opts.formats || formats_1.formatNames;
340
+ addFormats2(ajv, list, formats, exportName);
341
+ if (opts.keywords)
342
+ (0, limit_1.default)(ajv);
343
+ return ajv;
344
+ };
345
+ formatsPlugin.get = (name, mode = "full") => {
346
+ const formats = mode === "fast" ? formats_1.fastFormats : formats_1.fullFormats;
347
+ const f = formats[name];
348
+ if (!f)
349
+ throw new Error(`Unknown format "${name}"`);
350
+ return f;
351
+ };
352
+ function addFormats2(ajv, list, fs15, exportName) {
353
+ var _a;
354
+ var _b;
355
+ (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
356
+ for (const f of list)
357
+ ajv.addFormat(f, fs15[f]);
358
+ }
359
+ module.exports = exports = formatsPlugin;
360
+ Object.defineProperty(exports, "__esModule", { value: true });
361
+ exports.default = formatsPlugin;
362
+ }
363
+ });
32
364
 
33
365
  // src/cli/commands/init.ts
34
- import fs7 from "fs/promises";
35
- import path9 from "path";
366
+ import fs6 from "fs/promises";
367
+ import path8 from "path";
36
368
 
37
369
  // src/core/install-plan.ts
38
370
  import path from "path";
@@ -390,49 +722,8 @@ async function readJsonc(filePath) {
390
722
  return JSON.parse(stripTrailingCommas(stripJsonComments(content)));
391
723
  }
392
724
 
393
- // src/core/backup.ts
394
- import fs2 from "fs/promises";
395
- import path3 from "path";
396
- function escapeRelativePath(relativePath) {
397
- return relativePath.replace(/[\\/]/g, "__");
398
- }
399
- async function createManagedBackup(filePath, { cwd, backupRoot, maxPerFile = 20 }) {
400
- const relativePath = path3.relative(cwd, filePath);
401
- const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
402
- const backupName = `${escapeRelativePath(relativePath)}.${stamp}.bak`;
403
- const absoluteBackupRoot = path3.join(cwd, backupRoot);
404
- const backupPath = path3.join(absoluteBackupRoot, backupName);
405
- await fs2.mkdir(absoluteBackupRoot, { recursive: true });
406
- await fs2.copyFile(filePath, backupPath);
407
- const prefix = `${escapeRelativePath(relativePath)}.`;
408
- const entries = await fs2.readdir(absoluteBackupRoot);
409
- const matching = entries.filter((entry) => entry.startsWith(prefix) && entry.endsWith(".bak")).sort();
410
- if (matching.length > maxPerFile) {
411
- const excess = matching.slice(0, matching.length - maxPerFile);
412
- await Promise.all(excess.map((entry) => fs2.unlink(path3.join(absoluteBackupRoot, entry))));
413
- }
414
- return backupPath;
415
- }
416
- async function createManagedPathBackup(targetPath, { cwd, backupRoot, maxPerFile = 20 }) {
417
- const relativePath = path3.relative(cwd, targetPath);
418
- const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
419
- const backupName = `${escapeRelativePath(relativePath)}.${stamp}.bak`;
420
- const absoluteBackupRoot = path3.join(cwd, backupRoot);
421
- const backupPath = path3.join(absoluteBackupRoot, backupName);
422
- await fs2.mkdir(absoluteBackupRoot, { recursive: true });
423
- await fs2.rename(targetPath, backupPath);
424
- const prefix = `${escapeRelativePath(relativePath)}.`;
425
- const entries = await fs2.readdir(absoluteBackupRoot);
426
- const matching = entries.filter((entry) => entry.startsWith(prefix) && entry.endsWith(".bak")).sort();
427
- if (matching.length > maxPerFile) {
428
- const excess = matching.slice(0, matching.length - maxPerFile);
429
- await Promise.all(excess.map((entry) => fs2.rm(path3.join(absoluteBackupRoot, entry), { recursive: true, force: true })));
430
- }
431
- return backupPath;
432
- }
433
-
434
725
  // src/core/opencode-merge.ts
435
- import path4 from "path";
726
+ import path3 from "path";
436
727
  var LEGACY_MARKER = "_aiWorkflowManaged";
437
728
  var AGENTS = {
438
729
  Atlas: { description: "Router and workflow coordinator for AI Workflow Kit" },
@@ -515,7 +806,7 @@ function buildManagedConfig() {
515
806
  };
516
807
  }
517
808
  async function mergeOpencodeConfig(cwd, { force = false, backupRoot = ".ai-workflow-backups" } = {}) {
518
- const targetPath = path4.join(cwd, "opencode.jsonc");
809
+ const targetPath = path3.join(cwd, "opencode.jsonc");
519
810
  const managed = buildManagedConfig();
520
811
  if (!await exists(targetPath)) {
521
812
  await writeFileSafe(targetPath, `${JSON.stringify(managed, null, 2)}
@@ -567,10 +858,10 @@ async function mergeOpencodeConfig(cwd, { force = false, backupRoot = ".ai-workf
567
858
  }
568
859
 
569
860
  // src/core/symlink-layout.ts
570
- import fs3 from "fs/promises";
571
- import path5 from "path";
861
+ import fs2 from "fs/promises";
862
+ import path4 from "path";
572
863
  function normalize(p) {
573
- return p.split(path5.sep).join("/");
864
+ return p.split(path4.sep).join("/");
574
865
  }
575
866
  var LINKABLE_ROOTS = /* @__PURE__ */ new Set([
576
867
  "opencode",
@@ -598,38 +889,38 @@ function buildSymlinkEntries({ templateFiles, installRoot = ".ai-workflow" }) {
598
889
  }
599
890
  async function isSymlinkTo(absoluteLinkPath, absoluteTargetPath) {
600
891
  try {
601
- const stat = await fs3.lstat(absoluteLinkPath);
892
+ const stat = await fs2.lstat(absoluteLinkPath);
602
893
  if (!stat.isSymbolicLink()) return false;
603
- const currentTarget = await fs3.readlink(absoluteLinkPath);
604
- const resolved = path5.resolve(path5.dirname(absoluteLinkPath), currentTarget);
894
+ const currentTarget = await fs2.readlink(absoluteLinkPath);
895
+ const resolved = path4.resolve(path4.dirname(absoluteLinkPath), currentTarget);
605
896
  return resolved === absoluteTargetPath;
606
897
  } catch {
607
898
  return false;
608
899
  }
609
900
  }
610
901
  async function setupInternalSymlinks(cwd, installRoot = ".ai-workflow") {
611
- const skillsLink = path5.join(cwd, installRoot, "opencode/skills");
612
- const skillsTarget = path5.join(cwd, installRoot, ".agents/skills");
902
+ const skillsLink = path4.join(cwd, installRoot, "opencode/skills");
903
+ const skillsTarget = path4.join(cwd, installRoot, ".agents/skills");
613
904
  if (!await exists2(skillsTarget)) return;
614
905
  try {
615
- const stat = await fs3.lstat(skillsLink).catch(() => null);
906
+ const stat = await fs2.lstat(skillsLink).catch(() => null);
616
907
  if (stat) {
617
908
  if (stat.isSymbolicLink()) {
618
- const current = await fs3.readlink(skillsLink);
909
+ const current = await fs2.readlink(skillsLink);
619
910
  if (current === "../.agents/skills") return;
620
- await fs3.unlink(skillsLink);
911
+ await fs2.unlink(skillsLink);
621
912
  } else {
622
913
  return;
623
914
  }
624
915
  }
625
916
  const type = process.platform === "win32" ? "junction" : "dir";
626
- await fs3.symlink("../.agents/skills", skillsLink, type);
917
+ await fs2.symlink("../.agents/skills", skillsLink, type);
627
918
  } catch {
628
919
  }
629
920
  }
630
921
  async function exists2(p) {
631
922
  try {
632
- await fs3.access(p);
923
+ await fs2.access(p);
633
924
  return true;
634
925
  } catch {
635
926
  return false;
@@ -637,8 +928,8 @@ async function exists2(p) {
637
928
  }
638
929
 
639
930
  // src/adapters/platforms/claude.ts
640
- import fs4 from "fs/promises";
641
- import path6 from "path";
931
+ import fs3 from "fs/promises";
932
+ import path5 from "path";
642
933
  var ClaudeAdapter = class {
643
934
  cwd;
644
935
  constructor({ cwd }) {
@@ -648,8 +939,8 @@ var ClaudeAdapter = class {
648
939
  * Transforms an OpenCode agent or skill into a Claude rule with completion contract.
649
940
  */
650
941
  async transformToRule(filePath, type = "agent") {
651
- const content = await fs4.readFile(filePath, "utf8");
652
- const fileName = path6.basename(filePath, ".md") === "SKILL" ? path6.basename(path6.dirname(filePath)) : path6.basename(filePath, ".md");
942
+ const content = await fs3.readFile(filePath, "utf8");
943
+ const fileName = path5.basename(filePath, ".md") === "SKILL" ? path5.basename(path5.dirname(filePath)) : path5.basename(filePath, ".md");
653
944
  const ruleName = `${type}-${fileName.toLowerCase()}`;
654
945
  const hardenedContent = `---
655
946
  name: ${ruleName}
@@ -679,34 +970,34 @@ Every task completion MUST provide the following payload:
679
970
  * Deploys agents, skills, and root CLAUDE.md.
680
971
  */
681
972
  async deploy(installRoot = ".ai-workflow") {
682
- const rulesDir = path6.join(this.cwd, ".claude/rules");
683
- await fs4.mkdir(rulesDir, { recursive: true });
684
- const sourceAgentsDir = path6.join(this.cwd, installRoot, "opencode/agents");
685
- const sourceSkillsDir = path6.join(this.cwd, installRoot, "opencode/skills");
686
- const sourceCommandsDir = path6.join(this.cwd, installRoot, "opencode/commands");
687
- const agentFiles = await fs4.readdir(sourceAgentsDir).catch(() => []);
973
+ const rulesDir = path5.join(this.cwd, ".claude/rules");
974
+ await fs3.mkdir(rulesDir, { recursive: true });
975
+ const sourceAgentsDir = path5.join(this.cwd, installRoot, "opencode/agents");
976
+ const sourceSkillsDir = path5.join(this.cwd, installRoot, "opencode/skills");
977
+ const sourceCommandsDir = path5.join(this.cwd, installRoot, "opencode/commands");
978
+ const agentFiles = await fs3.readdir(sourceAgentsDir).catch(() => []);
688
979
  for (const file of agentFiles) {
689
980
  if (!file.endsWith(".md")) continue;
690
- const transformed = await this.transformToRule(path6.join(sourceAgentsDir, file), "agent");
691
- await fs4.writeFile(path6.join(rulesDir, `${transformed.name}.md`), transformed.content);
981
+ const transformed = await this.transformToRule(path5.join(sourceAgentsDir, file), "agent");
982
+ await fs3.writeFile(path5.join(rulesDir, `${transformed.name}.md`), transformed.content);
692
983
  }
693
- const skillFolders = await fs4.readdir(sourceSkillsDir).catch(() => []);
984
+ const skillFolders = await fs3.readdir(sourceSkillsDir).catch(() => []);
694
985
  for (const folder of skillFolders) {
695
- const skillSource = path6.join(sourceSkillsDir, folder, "SKILL.md");
986
+ const skillSource = path5.join(sourceSkillsDir, folder, "SKILL.md");
696
987
  if (await this.exists(skillSource)) {
697
988
  const transformed = await this.transformToRule(skillSource, "skill");
698
- await fs4.writeFile(path6.join(rulesDir, `${transformed.name}.md`), transformed.content);
989
+ await fs3.writeFile(path5.join(rulesDir, `${transformed.name}.md`), transformed.content);
699
990
  }
700
991
  }
701
992
  await this.deployRootClaudeMd(sourceCommandsDir);
702
993
  }
703
994
  async deployRootClaudeMd(sourceCommandsDir) {
704
- const targetPath = path6.join(this.cwd, "CLAUDE.md");
705
- const commandFiles = await fs4.readdir(sourceCommandsDir).catch(() => []);
995
+ const targetPath = path5.join(this.cwd, "CLAUDE.md");
996
+ const commandFiles = await fs3.readdir(sourceCommandsDir).catch(() => []);
706
997
  let commandsDoc = "";
707
998
  for (const file of commandFiles) {
708
999
  if (!file.endsWith(".md")) continue;
709
- const name = path6.basename(file, ".md");
1000
+ const name = path5.basename(file, ".md");
710
1001
  commandsDoc += `- \`ai-workflow run --spec-path=...\` (Target: ${name})
711
1002
  `;
712
1003
  }
@@ -730,11 +1021,11 @@ Adhere to the specific rules and personas defined in \`.claude/rules/\`.
730
1021
  ## Completion Contract
731
1022
  Every task completion MUST follow the payload format defined in the individual rule files.
732
1023
  `;
733
- await fs4.writeFile(targetPath, instructions);
1024
+ await fs3.writeFile(targetPath, instructions);
734
1025
  }
735
1026
  async exists(p) {
736
1027
  try {
737
- await fs4.access(p);
1028
+ await fs3.access(p);
738
1029
  return true;
739
1030
  } catch {
740
1031
  return false;
@@ -743,8 +1034,8 @@ Every task completion MUST follow the payload format defined in the individual r
743
1034
  };
744
1035
 
745
1036
  // src/adapters/platforms/codex.ts
746
- import fs5 from "fs/promises";
747
- import path7 from "path";
1037
+ import fs4 from "fs/promises";
1038
+ import path6 from "path";
748
1039
  var CodexAdapter = class {
749
1040
  cwd;
750
1041
  constructor({ cwd }) {
@@ -754,8 +1045,8 @@ var CodexAdapter = class {
754
1045
  * Transforms an OpenCode agent into a Codex prompt with completion contract.
755
1046
  */
756
1047
  async transformAgent(filePath) {
757
- const content = await fs5.readFile(filePath, "utf8");
758
- const fileName = path7.basename(filePath, ".md");
1048
+ const content = await fs4.readFile(filePath, "utf8");
1049
+ const fileName = path6.basename(filePath, ".md");
759
1050
  const hardenedContent = `${content}
760
1051
 
761
1052
  ## System Directives for Codex
@@ -787,55 +1078,55 @@ Every task completion MUST provide the following payload:
787
1078
  * - Commands -> .codex/prompts/
788
1079
  */
789
1080
  async deploy(installRoot = ".ai-workflow", force) {
790
- const sourceAgentsDir = path7.join(this.cwd, installRoot, "opencode/agents");
791
- const sourceSkillsDir = path7.join(this.cwd, installRoot, "opencode/skills");
792
- const sourceCommandsDir = path7.join(this.cwd, installRoot, "opencode/commands");
793
- const codexAgentsDir = path7.join(this.cwd, ".github/agents");
794
- await fs5.mkdir(codexAgentsDir, { recursive: true });
795
- const agentFiles = await fs5.readdir(sourceAgentsDir).catch(() => []);
1081
+ const sourceAgentsDir = path6.join(this.cwd, installRoot, "opencode/agents");
1082
+ const sourceSkillsDir = path6.join(this.cwd, installRoot, "opencode/skills");
1083
+ const sourceCommandsDir = path6.join(this.cwd, installRoot, "opencode/commands");
1084
+ const codexAgentsDir = path6.join(this.cwd, ".github/agents");
1085
+ await fs4.mkdir(codexAgentsDir, { recursive: true });
1086
+ const agentFiles = await fs4.readdir(sourceAgentsDir).catch(() => []);
796
1087
  for (const file of agentFiles) {
797
1088
  if (!file.endsWith(".md")) continue;
798
- const transformed = await this.transformAgent(path7.join(sourceAgentsDir, file));
799
- await fs5.writeFile(path7.join(codexAgentsDir, `${transformed.name}.md`), transformed.content);
1089
+ const transformed = await this.transformAgent(path6.join(sourceAgentsDir, file));
1090
+ await fs4.writeFile(path6.join(codexAgentsDir, `${transformed.name}.md`), transformed.content);
800
1091
  }
801
- const codexSkillsDir = path7.join(this.cwd, ".codex/skills");
802
- await fs5.mkdir(codexSkillsDir, { recursive: true });
803
- const skillFolders = await fs5.readdir(sourceSkillsDir).catch(() => []);
1092
+ const codexSkillsDir = path6.join(this.cwd, ".codex/skills");
1093
+ await fs4.mkdir(codexSkillsDir, { recursive: true });
1094
+ const skillFolders = await fs4.readdir(sourceSkillsDir).catch(() => []);
804
1095
  for (const folder of skillFolders) {
805
- const skillSource = path7.join(sourceSkillsDir, folder, "SKILL.md");
1096
+ const skillSource = path6.join(sourceSkillsDir, folder, "SKILL.md");
806
1097
  if (await this.exists(skillSource)) {
807
- const targetDir = path7.join(codexSkillsDir, folder);
808
- await fs5.mkdir(targetDir, { recursive: true });
809
- const content = await fs5.readFile(skillSource, "utf8");
810
- await fs5.writeFile(path7.join(targetDir, "SKILL.md"), content);
1098
+ const targetDir = path6.join(codexSkillsDir, folder);
1099
+ await fs4.mkdir(targetDir, { recursive: true });
1100
+ const content = await fs4.readFile(skillSource, "utf8");
1101
+ await fs4.writeFile(path6.join(targetDir, "SKILL.md"), content);
811
1102
  }
812
1103
  }
813
- const codexPromptsDir = path7.join(this.cwd, ".codex/prompts");
814
- await fs5.mkdir(codexPromptsDir, { recursive: true });
815
- const commandFiles = await fs5.readdir(sourceCommandsDir).catch(() => []);
1104
+ const codexPromptsDir = path6.join(this.cwd, ".codex/prompts");
1105
+ await fs4.mkdir(codexPromptsDir, { recursive: true });
1106
+ const commandFiles = await fs4.readdir(sourceCommandsDir).catch(() => []);
816
1107
  for (const file of commandFiles) {
817
1108
  if (!file.endsWith(".md") && !file.endsWith(".toml")) continue;
818
- const targetFileName = file.endsWith(".toml") ? `${path7.basename(file, ".toml")}.md` : file;
819
- const content = await fs5.readFile(path7.join(sourceCommandsDir, file), "utf8");
820
- await fs5.writeFile(path7.join(codexPromptsDir, targetFileName), content);
821
- }
822
- const codexPoliciesDir = path7.join(this.cwd, ".codex", "docs", "policies");
823
- await fs5.mkdir(codexPoliciesDir, { recursive: true });
824
- const sourcePoliciesDir = path7.join(this.cwd, installRoot, "opencode", "docs", "policies");
825
- const policyFiles = await fs5.readdir(sourcePoliciesDir).catch(() => []);
1109
+ const targetFileName = file.endsWith(".toml") ? `${path6.basename(file, ".toml")}.md` : file;
1110
+ const content = await fs4.readFile(path6.join(sourceCommandsDir, file), "utf8");
1111
+ await fs4.writeFile(path6.join(codexPromptsDir, targetFileName), content);
1112
+ }
1113
+ const codexPoliciesDir = path6.join(this.cwd, ".codex", "docs", "policies");
1114
+ await fs4.mkdir(codexPoliciesDir, { recursive: true });
1115
+ const sourcePoliciesDir = path6.join(this.cwd, installRoot, "opencode", "docs", "policies");
1116
+ const policyFiles = await fs4.readdir(sourcePoliciesDir).catch(() => []);
826
1117
  for (const file of policyFiles) {
827
1118
  if (!file.endsWith(".md")) continue;
828
- const policyContent = await fs5.readFile(path7.join(sourcePoliciesDir, file), "utf8");
829
- await fs5.writeFile(path7.join(codexPoliciesDir, file), policyContent);
1119
+ const policyContent = await fs4.readFile(path6.join(sourcePoliciesDir, file), "utf8");
1120
+ await fs4.writeFile(path6.join(codexPoliciesDir, file), policyContent);
830
1121
  }
831
1122
  await this.deployRootCopilotInstructions();
832
1123
  await this.deployRootCodexMd(force);
833
1124
  await this.deployRootAgentsMd(force);
834
1125
  }
835
1126
  async deployRootCopilotInstructions() {
836
- const githubDir = path7.join(this.cwd, ".github");
837
- await fs5.mkdir(githubDir, { recursive: true });
838
- const targetPath = path7.join(githubDir, "copilot-instructions.md");
1127
+ const githubDir = path6.join(this.cwd, ".github");
1128
+ await fs4.mkdir(githubDir, { recursive: true });
1129
+ const targetPath = path6.join(githubDir, "copilot-instructions.md");
839
1130
  const instructions = `# AI Workflow Kit Governance
840
1131
 
841
1132
  This repository uses the **AI Workflow Kit** (OpenCode-first) workflow.
@@ -857,15 +1148,15 @@ All architectural changes must align with the specifications issued by the **Spe
857
1148
  ## Completion Contract
858
1149
  Every task completion MUST follow the payload format defined in the individual agent files.
859
1150
  `;
860
- await fs5.writeFile(targetPath, instructions);
1151
+ await fs4.writeFile(targetPath, instructions);
861
1152
  }
862
1153
  async deployRootCodexMd(force) {
863
- const targetPath = path7.join(this.cwd, "CODEX.md");
1154
+ const targetPath = path6.join(this.cwd, "CODEX.md");
864
1155
  if (!force && await this.exists(targetPath)) return;
865
- const templatePath = path7.join(this.cwd, ".ai-workflow", "templates", "CODEX.md.template");
1156
+ const templatePath = path6.join(this.cwd, ".ai-workflow", "templates", "CODEX.md.template");
866
1157
  if (await this.exists(templatePath)) {
867
- const content = await fs5.readFile(templatePath, "utf8");
868
- await fs5.writeFile(targetPath, content);
1158
+ const content = await fs4.readFile(templatePath, "utf8");
1159
+ await fs4.writeFile(targetPath, content);
869
1160
  return;
870
1161
  }
871
1162
  const instructions = `# AI Workflow Kit Governance
@@ -889,23 +1180,23 @@ All architectural changes must align with the specifications issued by the **Spe
889
1180
  ## Completion Contract
890
1181
  Every task completion MUST follow the payload format defined in the individual agent files.
891
1182
  `;
892
- await fs5.writeFile(targetPath, instructions);
1183
+ await fs4.writeFile(targetPath, instructions);
893
1184
  }
894
1185
  async deployRootAgentsMd(force) {
895
- const targetPath = path7.join(this.cwd, "AGENTS.md");
1186
+ const targetPath = path6.join(this.cwd, "AGENTS.md");
896
1187
  if (!force && await this.exists(targetPath)) return;
897
- const templatePath = path7.join(this.cwd, ".ai-workflow", "AGENTS.md");
1188
+ const templatePath = path6.join(this.cwd, ".ai-workflow", "AGENTS.md");
898
1189
  if (await this.exists(templatePath)) {
899
- let content = await fs5.readFile(templatePath, "utf8");
1190
+ let content = await fs4.readFile(templatePath, "utf8");
900
1191
  content = content.replace(/\.agents\/skills/g, ".codex/skills");
901
1192
  content = content.replace(/opencode\/commands/g, ".codex/prompts");
902
1193
  content = content.replace(/opencode\/docs\/policies/g, ".codex/docs/policies");
903
- await fs5.writeFile(targetPath, content);
1194
+ await fs4.writeFile(targetPath, content);
904
1195
  }
905
1196
  }
906
1197
  async exists(p) {
907
1198
  try {
908
- await fs5.access(p);
1199
+ await fs4.access(p);
909
1200
  return true;
910
1201
  } catch {
911
1202
  return false;
@@ -914,8 +1205,8 @@ Every task completion MUST follow the payload format defined in the individual a
914
1205
  };
915
1206
 
916
1207
  // src/adapters/platforms/antigravity.ts
917
- import fs6 from "fs/promises";
918
- import path8 from "path";
1208
+ import fs5 from "fs/promises";
1209
+ import path7 from "path";
919
1210
  import { pathToFileURL } from "url";
920
1211
  var PERSONA_MAPPING = {
921
1212
  "atlas": "Atlas",
@@ -938,8 +1229,8 @@ var AntigravityAdapter = class {
938
1229
  * Transforms an OpenCode agent or specialized skill file to an Antigravity Skill.
939
1230
  */
940
1231
  async transform(filePath) {
941
- const content = await fs6.readFile(filePath, "utf8");
942
- const fileName = path8.basename(filePath, ".md") === "SKILL" ? path8.basename(path8.dirname(filePath)) : path8.basename(filePath, ".md");
1232
+ const content = await fs5.readFile(filePath, "utf8");
1233
+ const fileName = path7.basename(filePath, ".md") === "SKILL" ? path7.basename(path7.dirname(filePath)) : path7.basename(filePath, ".md");
943
1234
  const persona = PERSONA_MAPPING[fileName.toLowerCase()] || "Astra";
944
1235
  if (content.trim().startsWith("---")) {
945
1236
  return { content, name: fileName };
@@ -975,17 +1266,17 @@ Every task completion MUST provide the following payload:
975
1266
  * Also orchestrates the .antigravity/ native integration.
976
1267
  */
977
1268
  async deploy(transformedItems, installRoot = ".ai-workflow") {
978
- const agentsDir = path8.join(this.cwd, installRoot, "opencode/agents");
979
- const skillsDir = path8.join(this.cwd, installRoot, "opencode/skills");
980
- await fs6.mkdir(agentsDir, { recursive: true });
981
- await fs6.mkdir(skillsDir, { recursive: true });
1269
+ const agentsDir = path7.join(this.cwd, installRoot, "opencode/agents");
1270
+ const skillsDir = path7.join(this.cwd, installRoot, "opencode/skills");
1271
+ await fs5.mkdir(agentsDir, { recursive: true });
1272
+ await fs5.mkdir(skillsDir, { recursive: true });
982
1273
  for (const item of transformedItems) {
983
1274
  const isAgent = PERSONA_MAPPING[item.name.toLowerCase()];
984
- const targetDir = isAgent ? agentsDir : path8.join(skillsDir, item.name);
1275
+ const targetDir = isAgent ? agentsDir : path7.join(skillsDir, item.name);
985
1276
  const fileName = isAgent ? `${item.name}.md` : "SKILL.md";
986
1277
  const absoluteTargetDir = isAgent ? agentsDir : targetDir;
987
- await fs6.mkdir(absoluteTargetDir, { recursive: true });
988
- await fs6.writeFile(path8.join(absoluteTargetDir, fileName), item.content);
1278
+ await fs5.mkdir(absoluteTargetDir, { recursive: true });
1279
+ await fs5.writeFile(path7.join(absoluteTargetDir, fileName), item.content);
989
1280
  }
990
1281
  await this.deployNativeExtensions(installRoot);
991
1282
  await this.deployInstructions();
@@ -995,13 +1286,13 @@ Every task completion MUST provide the following payload:
995
1286
  * Using hard copies instead of symlinks ensures native discovery across all platforms.
996
1287
  */
997
1288
  async deployNativeExtensions(installRoot = ".ai-workflow") {
998
- const antigravityDir = path8.join(this.cwd, ".agents");
999
- const antigravityAgents = path8.join(antigravityDir, "agents");
1000
- const antigravitySkills = path8.join(antigravityDir, "skills");
1001
- const antigravityCommands = path8.join(antigravityDir, "commands");
1002
- await fs6.mkdir(antigravityAgents, { recursive: true });
1003
- await fs6.mkdir(antigravitySkills, { recursive: true });
1004
- await fs6.mkdir(antigravityCommands, { recursive: true });
1289
+ const antigravityDir = path7.join(this.cwd, ".agents");
1290
+ const antigravityAgents = path7.join(antigravityDir, "agents");
1291
+ const antigravitySkills = path7.join(antigravityDir, "skills");
1292
+ const antigravityCommands = path7.join(antigravityDir, "commands");
1293
+ await fs5.mkdir(antigravityAgents, { recursive: true });
1294
+ await fs5.mkdir(antigravitySkills, { recursive: true });
1295
+ await fs5.mkdir(antigravityCommands, { recursive: true });
1005
1296
  const getUrls = (targetPath) => {
1006
1297
  const linuxUrl = pathToFileURL(targetPath).href;
1007
1298
  const urls = [linuxUrl];
@@ -1043,8 +1334,8 @@ Every task completion MUST provide the following payload:
1043
1334
  "user_rules"
1044
1335
  ]
1045
1336
  };
1046
- const sourceAgentsDir = path8.join(this.cwd, installRoot, "opencode/agents");
1047
- const agentFiles = await fs6.readdir(sourceAgentsDir).catch(() => []);
1337
+ const sourceAgentsDir = path7.join(this.cwd, installRoot, "opencode/agents");
1338
+ const agentFiles = await fs5.readdir(sourceAgentsDir).catch(() => []);
1048
1339
  const AGENTS_INFO = {
1049
1340
  "atlas": { name: "Atlas", description: "Router and workflow coordinator for AI Workflow Kit" },
1050
1341
  "nexus": { name: "Nexus", description: "Discovery, requirement, scope, and specification owner" },
@@ -1055,14 +1346,14 @@ Every task completion MUST provide the following payload:
1055
1346
  };
1056
1347
  for (const file of agentFiles) {
1057
1348
  if (!file.endsWith(".md")) continue;
1058
- const lowercaseName = path8.basename(file, ".md").toLowerCase();
1349
+ const lowercaseName = path7.basename(file, ".md").toLowerCase();
1059
1350
  const info = AGENTS_INFO[lowercaseName];
1060
1351
  if (!info) continue;
1061
- const agentFolder = path8.join(antigravityAgents, lowercaseName);
1062
- await fs6.mkdir(agentFolder, { recursive: true });
1063
- const content = await fs6.readFile(path8.join(sourceAgentsDir, file), "utf8");
1064
- const mdTarget = path8.join(agentFolder, `${lowercaseName}.md`);
1065
- await fs6.writeFile(mdTarget, content);
1352
+ const agentFolder = path7.join(antigravityAgents, lowercaseName);
1353
+ await fs5.mkdir(agentFolder, { recursive: true });
1354
+ const content = await fs5.readFile(path7.join(sourceAgentsDir, file), "utf8");
1355
+ const mdTarget = path7.join(agentFolder, `${lowercaseName}.md`);
1356
+ await fs5.writeFile(mdTarget, content);
1066
1357
  const agentJson = {
1067
1358
  name: lowercaseName,
1068
1359
  description: info.description,
@@ -1083,7 +1374,7 @@ ${getUrls(mdTarget)}`
1083
1374
  }
1084
1375
  }
1085
1376
  };
1086
- await fs6.writeFile(path8.join(agentFolder, "agent.json"), JSON.stringify(agentJson, null, 2));
1377
+ await fs5.writeFile(path7.join(agentFolder, "agent.json"), JSON.stringify(agentJson, null, 2));
1087
1378
  }
1088
1379
  const SUBAGENTS_INFO = {
1089
1380
  "Architecture-Specialist": { description: "Select the simplest architecture that safely satisfies current requirements", skill: "architecture" },
@@ -1108,9 +1399,9 @@ ${getUrls(mdTarget)}`
1108
1399
  };
1109
1400
  for (const [name, subInfo] of Object.entries(SUBAGENTS_INFO)) {
1110
1401
  const lowercaseSubagentName = name.toLowerCase();
1111
- const subagentFolder = path8.join(antigravityAgents, lowercaseSubagentName);
1112
- await fs6.mkdir(subagentFolder, { recursive: true });
1113
- const skillPath = path8.join(antigravitySkills, subInfo.skill, "SKILL.md");
1402
+ const subagentFolder = path7.join(antigravityAgents, lowercaseSubagentName);
1403
+ await fs5.mkdir(subagentFolder, { recursive: true });
1404
+ const skillPath = path7.join(antigravitySkills, subInfo.skill, "SKILL.md");
1114
1405
  const subagentJson = {
1115
1406
  name: lowercaseSubagentName,
1116
1407
  description: subInfo.description,
@@ -1131,50 +1422,50 @@ ${getUrls(skillPath)}`
1131
1422
  }
1132
1423
  }
1133
1424
  };
1134
- await fs6.writeFile(path8.join(subagentFolder, "agent.json"), JSON.stringify(subagentJson, null, 2));
1425
+ await fs5.writeFile(path7.join(subagentFolder, "agent.json"), JSON.stringify(subagentJson, null, 2));
1135
1426
  }
1136
- const sourceSkillsDir = path8.join(this.cwd, installRoot, "opencode/skills");
1137
- const skillFolders = await fs6.readdir(sourceSkillsDir).catch(() => []);
1427
+ const sourceSkillsDir = path7.join(this.cwd, installRoot, "opencode/skills");
1428
+ const skillFolders = await fs5.readdir(sourceSkillsDir).catch(() => []);
1138
1429
  for (const folder of skillFolders) {
1139
- const skillSource = path8.join(sourceSkillsDir, folder, "SKILL.md");
1430
+ const skillSource = path7.join(sourceSkillsDir, folder, "SKILL.md");
1140
1431
  if (await this.exists(skillSource)) {
1141
- await fs6.mkdir(path8.join(antigravitySkills, folder), { recursive: true });
1142
- const content = await fs6.readFile(skillSource, "utf8");
1143
- await fs6.writeFile(path8.join(antigravitySkills, folder, "SKILL.md"), content);
1432
+ await fs5.mkdir(path7.join(antigravitySkills, folder), { recursive: true });
1433
+ const content = await fs5.readFile(skillSource, "utf8");
1434
+ await fs5.writeFile(path7.join(antigravitySkills, folder, "SKILL.md"), content);
1144
1435
  }
1145
1436
  }
1146
- const sourceCommandsDir = path8.join(this.cwd, installRoot, "opencode/commands");
1437
+ const sourceCommandsDir = path7.join(this.cwd, installRoot, "opencode/commands");
1147
1438
  if (await this.exists(sourceCommandsDir)) {
1148
- const commandFiles = await fs6.readdir(sourceCommandsDir).catch(() => []);
1439
+ const commandFiles = await fs5.readdir(sourceCommandsDir).catch(() => []);
1149
1440
  for (const file of commandFiles) {
1150
1441
  if (!file.endsWith(".md") && !file.endsWith(".toml")) continue;
1151
- const content = await fs6.readFile(path8.join(sourceCommandsDir, file), "utf8");
1152
- await fs6.writeFile(path8.join(antigravityCommands, file), content);
1442
+ const content = await fs5.readFile(path7.join(sourceCommandsDir, file), "utf8");
1443
+ await fs5.writeFile(path7.join(antigravityCommands, file), content);
1153
1444
  }
1154
1445
  }
1155
- const sourcePoliciesDir = path8.join(this.cwd, installRoot, "opencode", "docs", "policies");
1156
- const antigravityPolicies = path8.join(antigravityDir, "docs", "policies");
1446
+ const sourcePoliciesDir = path7.join(this.cwd, installRoot, "opencode", "docs", "policies");
1447
+ const antigravityPolicies = path7.join(antigravityDir, "docs", "policies");
1157
1448
  if (await this.exists(sourcePoliciesDir)) {
1158
- await fs6.mkdir(antigravityPolicies, { recursive: true });
1159
- const policyFiles = await fs6.readdir(sourcePoliciesDir).catch(() => []);
1449
+ await fs5.mkdir(antigravityPolicies, { recursive: true });
1450
+ const policyFiles = await fs5.readdir(sourcePoliciesDir).catch(() => []);
1160
1451
  for (const file of policyFiles) {
1161
1452
  if (!file.endsWith(".md")) continue;
1162
- const content = await fs6.readFile(path8.join(sourcePoliciesDir, file), "utf8");
1163
- await fs6.writeFile(path8.join(antigravityPolicies, file), content);
1453
+ const content = await fs5.readFile(path7.join(sourcePoliciesDir, file), "utf8");
1454
+ await fs5.writeFile(path7.join(antigravityPolicies, file), content);
1164
1455
  }
1165
1456
  }
1166
- const settingsPath = path8.join(antigravityDir, "settings.json");
1457
+ const settingsPath = path7.join(antigravityDir, "settings.json");
1167
1458
  if (!await this.exists(settingsPath)) {
1168
1459
  const settings = {
1169
1460
  model: { name: "auto" },
1170
1461
  ui: { theme: "Ayu" }
1171
1462
  };
1172
- await fs6.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1463
+ await fs5.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1173
1464
  }
1174
1465
  }
1175
1466
  async exists(p) {
1176
1467
  try {
1177
- await fs6.access(p);
1468
+ await fs5.access(p);
1178
1469
  return true;
1179
1470
  } catch {
1180
1471
  return false;
@@ -1184,10 +1475,10 @@ ${getUrls(skillPath)}`
1184
1475
  * Deploys the main ANTIGRAVITY.md and .antigravityignore instructions to the project root.
1185
1476
  */
1186
1477
  async deployInstructions() {
1187
- const targetPath = path8.join(this.cwd, "ANTIGRAVITY.md");
1188
- const ignorePath = path8.join(this.cwd, ".antigravityignore");
1478
+ const targetPath = path7.join(this.cwd, "ANTIGRAVITY.md");
1479
+ const ignorePath = path7.join(this.cwd, ".antigravityignore");
1189
1480
  try {
1190
- await fs6.access(targetPath);
1481
+ await fs5.access(targetPath);
1191
1482
  } catch {
1192
1483
  const instructions = `# AI Workflow Kit - Engineering Governance
1193
1484
 
@@ -1216,10 +1507,10 @@ All architectural changes must align with the specifications issued by the **Spe
1216
1507
  - **Native Discovery**: This project uses workspace-specific extensions in \`.agents/\`.
1217
1508
  - **Workflow Entry**: Use \`/atlas\` to begin any task.
1218
1509
  `;
1219
- await fs6.writeFile(targetPath, instructions);
1510
+ await fs5.writeFile(targetPath, instructions);
1220
1511
  }
1221
1512
  try {
1222
- await fs6.access(ignorePath);
1513
+ await fs5.access(ignorePath);
1223
1514
  } catch {
1224
1515
  const ignoreContent = `.ai-workflow/
1225
1516
  .ai-workflow-backups/
@@ -1232,7 +1523,7 @@ EVIDENCE.json
1232
1523
  .agents/tmp/
1233
1524
  .agents/history/
1234
1525
  `;
1235
- await fs6.writeFile(ignorePath, ignoreContent);
1526
+ await fs5.writeFile(ignorePath, ignoreContent);
1236
1527
  }
1237
1528
  }
1238
1529
  };
@@ -1266,7 +1557,7 @@ function buildGitignoreBlock(entries) {
1266
1557
  ].join("\n");
1267
1558
  }
1268
1559
  async function upsertGitignoreBlock(cwd, entries) {
1269
- const gitignorePath = path9.join(cwd, ".gitignore");
1560
+ const gitignorePath = path8.join(cwd, ".gitignore");
1270
1561
  const block = buildGitignoreBlock(entries);
1271
1562
  const beginMarker = "# BEGIN AI WORKFLOW KIT";
1272
1563
  const endMarker = "# END AI WORKFLOW KIT";
@@ -1276,7 +1567,7 @@ async function upsertGitignoreBlock(cwd, entries) {
1276
1567
  `);
1277
1568
  return "created";
1278
1569
  }
1279
- const current = await fs7.readFile(gitignorePath, "utf8");
1570
+ const current = await fs6.readFile(gitignorePath, "utf8");
1280
1571
  const beginIndex = current.indexOf(beginMarker);
1281
1572
  const endIndex = current.indexOf(endMarker);
1282
1573
  if (beginIndex >= 0 && endIndex > beginIndex) {
@@ -1297,7 +1588,7 @@ async function upsertGitignoreBlock(cwd, entries) {
1297
1588
  return "updated";
1298
1589
  }
1299
1590
  async function injectScripts(cwd) {
1300
- const pkgPath = path9.join(cwd, "package.json");
1591
+ const pkgPath = path8.join(cwd, "package.json");
1301
1592
  if (!await exists(pkgPath)) return false;
1302
1593
  try {
1303
1594
  const pkg = await readJson(pkgPath);
@@ -1315,7 +1606,7 @@ async function injectScripts(cwd) {
1315
1606
  async function verifySelfExecutionGuard(cwd, devMode) {
1316
1607
  if (!devMode) {
1317
1608
  try {
1318
- const pkgPath = path9.join(cwd, "package.json");
1609
+ const pkgPath = path8.join(cwd, "package.json");
1319
1610
  if (await exists(pkgPath)) {
1320
1611
  const pkg = await readJson(pkgPath);
1321
1612
  if (pkg.name === "@williambeto/ai-workflow") {
@@ -1363,8 +1654,8 @@ async function writeSymlinks(cwd, linkEntries, force, backupRoot = ".ai-workflow
1363
1654
  const linkBackups = [];
1364
1655
  const linkCreated = [];
1365
1656
  for (const { linkPath, targetPath } of linkEntries) {
1366
- const absoluteLinkPath = path9.join(cwd, linkPath);
1367
- const absoluteTargetPath = path9.join(cwd, targetPath);
1657
+ const absoluteLinkPath = path8.join(cwd, linkPath);
1658
+ const absoluteTargetPath = path8.join(cwd, targetPath);
1368
1659
  if (!await exists(absoluteTargetPath)) {
1369
1660
  throw new Error(`missing link target: ${targetPath}`);
1370
1661
  }
@@ -1383,14 +1674,14 @@ async function writeSymlinks(cwd, linkEntries, force, backupRoot = ".ai-workflow
1383
1674
  maxPerFile: 20
1384
1675
  });
1385
1676
  linkBackups.push(backupPath);
1386
- await fs7.rm(absoluteLinkPath, { recursive: true, force: true });
1677
+ await fs6.rm(absoluteLinkPath, { recursive: true, force: true });
1387
1678
  }
1388
- const stat = await fs7.lstat(absoluteTargetPath);
1679
+ const stat = await fs6.lstat(absoluteTargetPath);
1389
1680
  const type = process.platform === "win32" ? stat.isDirectory() ? "junction" : "file" : stat.isDirectory() ? "dir" : "file";
1390
- const linkTarget = process.platform === "win32" ? absoluteTargetPath : path9.relative(path9.dirname(absoluteLinkPath), absoluteTargetPath);
1681
+ const linkTarget = process.platform === "win32" ? absoluteTargetPath : path8.relative(path8.dirname(absoluteLinkPath), absoluteTargetPath);
1391
1682
  try {
1392
- await fs7.mkdir(path9.dirname(absoluteLinkPath), { recursive: true });
1393
- await fs7.symlink(linkTarget, absoluteLinkPath, type);
1683
+ await fs6.mkdir(path8.dirname(absoluteLinkPath), { recursive: true });
1684
+ await fs6.symlink(linkTarget, absoluteLinkPath, type);
1394
1685
  } catch (error) {
1395
1686
  throw new Error(
1396
1687
  `failed to create symlink '${linkPath}' -> '${targetPath}' (${error.message}). For Windows, enable Developer Mode or run terminal as Administrator. For Linux/macOS, verify write permissions in project root.`
@@ -1403,9 +1694,9 @@ async function writeSymlinks(cwd, linkEntries, force, backupRoot = ".ai-workflow
1403
1694
  async function executePlatformMigrations(cwd, installRoot, platforms, claude, codex, antigravity, force) {
1404
1695
  if (platforms.length === 0) return;
1405
1696
  console.log("ai-workflow: migrating to native platforms...");
1406
- const agentsDir = path9.join(cwd, installRoot, "opencode/agents");
1407
- const skillsDir = path9.join(cwd, installRoot, "opencode/skills");
1408
- const agentFiles = (await fs7.readdir(agentsDir).catch(() => [])).filter((f) => f.endsWith(".md")).map((f) => path9.join(agentsDir, f));
1697
+ const agentsDir = path8.join(cwd, installRoot, "opencode/agents");
1698
+ const skillsDir = path8.join(cwd, installRoot, "opencode/skills");
1699
+ const agentFiles = (await fs6.readdir(agentsDir).catch(() => [])).filter((f) => f.endsWith(".md")).map((f) => path8.join(agentsDir, f));
1409
1700
  if (claude) {
1410
1701
  const adapter = new ClaudeAdapter({ cwd });
1411
1702
  await adapter.deploy(installRoot);
@@ -1418,10 +1709,10 @@ async function executePlatformMigrations(cwd, installRoot, platforms, claude, co
1418
1709
  }
1419
1710
  if (antigravity) {
1420
1711
  const adapter = new AntigravityAdapter({ cwd });
1421
- const skillFolders = await fs7.readdir(skillsDir).catch(() => []);
1712
+ const skillFolders = await fs6.readdir(skillsDir).catch(() => []);
1422
1713
  const skillFiles = [];
1423
1714
  for (const folder of skillFolders) {
1424
- const skillPath = path9.join(skillsDir, folder, "SKILL.md");
1715
+ const skillPath = path8.join(skillsDir, folder, "SKILL.md");
1425
1716
  if (await exists(skillPath)) {
1426
1717
  skillFiles.push(skillPath);
1427
1718
  }
@@ -1553,15 +1844,15 @@ async function runInit({
1553
1844
  }
1554
1845
 
1555
1846
  // src/cli/commands/doctor.ts
1556
- import fs8 from "fs/promises";
1557
- import path10 from "path";
1847
+ import fs7 from "fs/promises";
1848
+ import path9 from "path";
1558
1849
  var REQUIRED_FILES = [
1559
1850
  ".ai-workflow",
1560
1851
  "opencode/README.md"
1561
1852
  ];
1562
1853
  async function isSymlink(filePath) {
1563
1854
  try {
1564
- const stat = await fs8.lstat(filePath);
1855
+ const stat = await fs7.lstat(filePath);
1565
1856
  return stat.isSymbolicLink();
1566
1857
  } catch {
1567
1858
  return false;
@@ -1587,7 +1878,7 @@ async function checkOpenCodeRuntime(cwd, state) {
1587
1878
  }
1588
1879
  async function checkRequiredFiles(cwd, state) {
1589
1880
  for (const relativePath of REQUIRED_FILES) {
1590
- const ok = await exists(path10.join(cwd, relativePath));
1881
+ const ok = await exists(path9.join(cwd, relativePath));
1591
1882
  if (ok) {
1592
1883
  console.log(`PASS ${relativePath}`);
1593
1884
  } else {
@@ -1597,8 +1888,8 @@ async function checkRequiredFiles(cwd, state) {
1597
1888
  }
1598
1889
  }
1599
1890
  async function checkAiWorkflowConfig(cwd, state) {
1600
- const configPathV2 = path10.join(cwd, ".ai-workflow/config.json");
1601
- const configPathLegacy = path10.join(cwd, ".ai-workflow.json");
1891
+ const configPathV2 = path9.join(cwd, ".ai-workflow/config.json");
1892
+ const configPathLegacy = path9.join(cwd, ".ai-workflow.json");
1602
1893
  let configPath = null;
1603
1894
  if (await exists(configPathV2)) {
1604
1895
  configPath = configPathV2;
@@ -1608,7 +1899,7 @@ async function checkAiWorkflowConfig(cwd, state) {
1608
1899
  if (!configPath) return;
1609
1900
  try {
1610
1901
  const config = await readJson(configPath);
1611
- const basename = path10.basename(configPath);
1902
+ const basename = path9.basename(configPath);
1612
1903
  if (config.installMode === "project-local" || config.mode === "standalone") {
1613
1904
  console.log("PASS install mode is project-local/standalone");
1614
1905
  } else {
@@ -1635,7 +1926,7 @@ async function checkAiWorkflowConfig(cwd, state) {
1635
1926
  }
1636
1927
  if (Array.isArray(config.managedFiles)) {
1637
1928
  for (const relativePath of config.managedFiles) {
1638
- const fileExists = await exists(path10.join(cwd, relativePath));
1929
+ const fileExists = await exists(path9.join(cwd, relativePath));
1639
1930
  if (!fileExists) {
1640
1931
  state.hasWarning = true;
1641
1932
  console.log(`WARN managed file missing: ${relativePath}`);
@@ -1644,7 +1935,7 @@ async function checkAiWorkflowConfig(cwd, state) {
1644
1935
  }
1645
1936
  if (Array.isArray(config.managedLinks)) {
1646
1937
  for (const relativePath of config.managedLinks) {
1647
- const absolutePath = path10.join(cwd, relativePath);
1938
+ const absolutePath = path9.join(cwd, relativePath);
1648
1939
  if (!await exists(absolutePath)) {
1649
1940
  state.hasWarning = true;
1650
1941
  console.log(`WARN managed link missing: ${relativePath}`);
@@ -1658,11 +1949,11 @@ async function checkAiWorkflowConfig(cwd, state) {
1658
1949
  }
1659
1950
  } catch {
1660
1951
  state.hasFailure = true;
1661
- console.log(`FAIL ${path10.basename(configPath)} is not valid JSON`);
1952
+ console.log(`FAIL ${path9.basename(configPath)} is not valid JSON`);
1662
1953
  }
1663
1954
  }
1664
1955
  async function checkOpencodeJson(cwd, state) {
1665
- const opencodePath = path10.join(cwd, "opencode.jsonc");
1956
+ const opencodePath = path9.join(cwd, "opencode.jsonc");
1666
1957
  if (!await exists(opencodePath)) {
1667
1958
  state.hasFailure = true;
1668
1959
  console.log("FAIL opencode.jsonc missing");
@@ -1708,7 +1999,7 @@ async function checkOpencodeJson(cwd, state) {
1708
1999
  }
1709
2000
  }
1710
2001
  async function checkPackageJson(cwd, state) {
1711
- const packageJsonPath = path10.join(cwd, "package.json");
2002
+ const packageJsonPath = path9.join(cwd, "package.json");
1712
2003
  if (await exists(packageJsonPath)) {
1713
2004
  try {
1714
2005
  const packageJson = await readJson(packageJsonPath);
@@ -1731,7 +2022,7 @@ async function checkCodexRuntime(cwd, state) {
1731
2022
  { name: ".codex policies detected", path: ".codex/docs/policies" }
1732
2023
  ];
1733
2024
  for (const check of checks) {
1734
- const ok = await exists(path10.join(cwd, check.path));
2025
+ const ok = await exists(path9.join(cwd, check.path));
1735
2026
  if (ok) {
1736
2027
  console.log(`PASS ${check.name}`);
1737
2028
  } else {
@@ -1739,7 +2030,7 @@ async function checkCodexRuntime(cwd, state) {
1739
2030
  console.log(`FAIL ${check.name}`);
1740
2031
  }
1741
2032
  }
1742
- const codexMdOk = await exists(path10.join(cwd, "CODEX.md"));
2033
+ const codexMdOk = await exists(path9.join(cwd, "CODEX.md"));
1743
2034
  if (codexMdOk) {
1744
2035
  console.log(`PASS root CODEX.md exists`);
1745
2036
  }
@@ -1822,7 +2113,8 @@ async function runCollectEvidence({
1822
2113
  userRequest = null,
1823
2114
  explicitApprovals = [],
1824
2115
  visualDist = null,
1825
- port = null
2116
+ port = null,
2117
+ workflowEvidence = null
1826
2118
  }) {
1827
2119
  const policies = resolvePoliciesFromLegacyMode(mode, evidencePolicy);
1828
2120
  const qualityGuard = new QualityGuard({ cwd, taskSlug, evidencePolicy: policies.evidencePolicy, riskLevel: policies.riskLevel });
@@ -1839,7 +2131,8 @@ async function runCollectEvidence({
1839
2131
  userRequest,
1840
2132
  explicitApprovals,
1841
2133
  visualDist,
1842
- port: port || 8080
2134
+ port: port || 8080,
2135
+ workflowEvidence
1843
2136
  });
1844
2137
  const evidence = await collector.collect(tasks, { writeArtifact: persist });
1845
2138
  const summary = buildDeliverySummary({ evidence });
@@ -1854,11 +2147,11 @@ async function runCollectEvidence({
1854
2147
 
1855
2148
  // src/core/healing/cli-remediation-executor.ts
1856
2149
  import { spawnSync, execSync as execSync2 } from "child_process";
1857
- import fs9 from "fs/promises";
1858
- import path11 from "path";
2150
+ import fs8 from "fs/promises";
2151
+ import path10 from "path";
1859
2152
  async function readScripts(cwd) {
1860
2153
  try {
1861
- const pkg = JSON.parse(await fs9.readFile(path11.join(cwd, "package.json"), "utf8"));
2154
+ const pkg = JSON.parse(await fs8.readFile(path10.join(cwd, "package.json"), "utf8"));
1862
2155
  return pkg.scripts || {};
1863
2156
  } catch {
1864
2157
  return {};
@@ -1948,8 +2241,170 @@ function createCliRemediationExecutor(cwd) {
1948
2241
  }
1949
2242
 
1950
2243
  // src/cli/commands/run.ts
1951
- import path12 from "path";
2244
+ import path14 from "path";
2245
+ import fs12 from "fs/promises";
2246
+
2247
+ // src/core/sdd/approval-receipt.ts
2248
+ var import_ajv = __toESM(require_ajv(), 1);
2249
+ var import_ajv_formats = __toESM(require_dist(), 1);
1952
2250
  import fs10 from "fs/promises";
2251
+ import path12 from "path";
2252
+
2253
+ // src/core/sdd/workflow-artifacts.ts
2254
+ import { createHash } from "crypto";
2255
+ import fs9 from "fs/promises";
2256
+ import path11 from "path";
2257
+ function sha256(content) {
2258
+ return createHash("sha256").update(content).digest("hex");
2259
+ }
2260
+ async function hashFile(filePath) {
2261
+ return sha256(await fs9.readFile(filePath));
2262
+ }
2263
+ async function writeFileAtomic(filePath, content) {
2264
+ await fs9.mkdir(path11.dirname(filePath), { recursive: true });
2265
+ const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
2266
+ try {
2267
+ await fs9.writeFile(temporaryPath, content, { encoding: "utf8", flag: "wx" });
2268
+ await fs9.rename(temporaryPath, filePath);
2269
+ } catch (error) {
2270
+ await fs9.rm(temporaryPath, { force: true }).catch(() => {
2271
+ });
2272
+ throw error;
2273
+ }
2274
+ }
2275
+ function stripMarkdownFence(content) {
2276
+ const trimmed = content.trim();
2277
+ const match = trimmed.match(/^```(?:markdown|md|json)?\s*\n([\s\S]*?)\n```$/i);
2278
+ return (match ? match[1] : trimmed).trim() + "\n";
2279
+ }
2280
+
2281
+ // src/core/sdd/approval-receipt.ts
2282
+ var ApprovalReceiptValidator = class {
2283
+ cwd;
2284
+ constructor({ cwd = process.cwd() } = {}) {
2285
+ this.cwd = path12.resolve(cwd);
2286
+ }
2287
+ async validate(receiptPath, specPath, expectedWorkflowId) {
2288
+ const absoluteReceiptPath = path12.resolve(this.cwd, receiptPath);
2289
+ if (absoluteReceiptPath !== this.cwd && !absoluteReceiptPath.startsWith(`${this.cwd}${path12.sep}`)) {
2290
+ return { valid: false, reason: "Approval receipt must be inside the repository." };
2291
+ }
2292
+ try {
2293
+ const stat = await fs10.lstat(absoluteReceiptPath);
2294
+ if (!stat.isFile() || stat.isSymbolicLink()) {
2295
+ return { valid: false, reason: "Approval receipt must be a regular, non-symlink file." };
2296
+ }
2297
+ } catch {
2298
+ return { valid: false, reason: `Approval receipt not found: ${receiptPath}` };
2299
+ }
2300
+ let receipt;
2301
+ try {
2302
+ receipt = JSON.parse(await fs10.readFile(absoluteReceiptPath, "utf8"));
2303
+ const root = getPackageRoot();
2304
+ const schema = JSON.parse(await fs10.readFile(path12.join(root, "dist-assets/schemas/approval-receipt.schema.json"), "utf8"));
2305
+ const ajv = new import_ajv.default({ allErrors: true });
2306
+ (0, import_ajv_formats.default)(ajv);
2307
+ const validateSchema = ajv.compile(schema);
2308
+ if (!validateSchema(receipt)) {
2309
+ const errors = (validateSchema.errors || []).map((error) => `${error.instancePath} ${error.message}`).join(", ");
2310
+ return { valid: false, reason: `Approval receipt schema violation: ${errors}` };
2311
+ }
2312
+ } catch (error) {
2313
+ return { valid: false, reason: `Approval receipt validation failed: ${error.message}` };
2314
+ }
2315
+ if (expectedWorkflowId && receipt.workflowId !== expectedWorkflowId) {
2316
+ return { valid: false, reason: `Approval receipt workflowId '${receipt.workflowId}' does not match '${expectedWorkflowId}'.` };
2317
+ }
2318
+ const approvedSpecHash = await hashFile(specPath);
2319
+ if (receipt.approvedSpecHash !== approvedSpecHash) {
2320
+ return { valid: false, reason: "Approval receipt hash does not match the approved specification bytes." };
2321
+ }
2322
+ return { valid: true, receipt, approvedSpecHash };
2323
+ }
2324
+ };
2325
+
2326
+ // src/core/sdd/technical-plan-validator.ts
2327
+ var import_ajv2 = __toESM(require_ajv(), 1);
2328
+ import fs11 from "fs/promises";
2329
+ import path13 from "path";
2330
+ function isContained(root, candidate) {
2331
+ return candidate === root || candidate.startsWith(`${root}${path13.sep}`);
2332
+ }
2333
+ var TechnicalPlanValidator = class {
2334
+ cwd;
2335
+ constructor({ cwd = process.cwd() } = {}) {
2336
+ this.cwd = path13.resolve(cwd);
2337
+ }
2338
+ async validateScopedPath(candidate, forbiddenPaths) {
2339
+ if (path13.isAbsolute(candidate)) return `Absolute path is not allowed: '${candidate}'.`;
2340
+ const normalized = candidate.replaceAll("\\", "/");
2341
+ if (!normalized || normalized.split("/").some((part) => part === "" || part === "." || part === "..")) {
2342
+ return `Path must be normalized without empty, '.' or '..' segments: '${candidate}'.`;
2343
+ }
2344
+ if (normalized === ".git" || normalized.startsWith(".git/") || normalized === ".ai-workflow" || normalized.startsWith(".ai-workflow/")) {
2345
+ return `Workflow control path is out of implementation scope: '${candidate}'.`;
2346
+ }
2347
+ const conflictsWithProtectedPath = [...forbiddenPaths].some(
2348
+ (protectedPath) => normalized === protectedPath || normalized.startsWith(`${protectedPath}/`) || protectedPath.startsWith(`${normalized}/`)
2349
+ );
2350
+ if (normalized === "EVIDENCE.json" || conflictsWithProtectedPath) {
2351
+ return `Protected workflow artifact is out of implementation scope: '${candidate}'.`;
2352
+ }
2353
+ const absolute = path13.resolve(this.cwd, normalized);
2354
+ if (!isContained(this.cwd, absolute)) return `Path escapes repository: '${candidate}'.`;
2355
+ let cursor = this.cwd;
2356
+ for (const part of normalized.split("/")) {
2357
+ cursor = path13.join(cursor, part);
2358
+ try {
2359
+ const stat = await fs11.lstat(cursor);
2360
+ if (cursor === absolute && stat.isDirectory()) {
2361
+ return `filesInScope must name explicit files, not a directory: '${candidate}'.`;
2362
+ }
2363
+ if (stat.isSymbolicLink()) {
2364
+ const resolved = await fs11.realpath(cursor);
2365
+ if (!isContained(this.cwd, resolved)) return `Symlink escapes repository: '${candidate}'.`;
2366
+ cursor = resolved;
2367
+ }
2368
+ } catch (error) {
2369
+ if (error.code !== "ENOENT") return `Cannot inspect scoped path '${candidate}': ${error.message}`;
2370
+ break;
2371
+ }
2372
+ }
2373
+ return null;
2374
+ }
2375
+ async validateOutput(output, protectedPaths = []) {
2376
+ let plan;
2377
+ try {
2378
+ plan = JSON.parse(stripMarkdownFence(output));
2379
+ } catch (error) {
2380
+ return { valid: false, reason: `Technical plan is not valid JSON: ${error.message}` };
2381
+ }
2382
+ try {
2383
+ const schema = JSON.parse(await fs11.readFile(path13.join(getPackageRoot(), "dist-assets/schemas/technical-plan.schema.json"), "utf8"));
2384
+ const validateSchema = new import_ajv2.default({ allErrors: true }).compile(schema);
2385
+ if (!validateSchema(plan)) {
2386
+ const errors = (validateSchema.errors || []).map((error) => `${error.instancePath} ${error.message}`).join(", ");
2387
+ return { valid: false, reason: `Technical plan schema violation: ${errors}` };
2388
+ }
2389
+ } catch (error) {
2390
+ return { valid: false, reason: `Technical plan schema validation failed: ${error.message}` };
2391
+ }
2392
+ if (plan.filesInScope.length === 0) {
2393
+ return { valid: false, reason: "Technical plan filesInScope must not be empty." };
2394
+ }
2395
+ const forbidden = new Set(protectedPaths.map((entry) => path13.relative(this.cwd, path13.resolve(this.cwd, entry)).replaceAll("\\", "/")));
2396
+ for (const entry of plan.filesInScope) {
2397
+ const reason = await this.validateScopedPath(entry.path, forbidden);
2398
+ if (reason) return { valid: false, reason };
2399
+ }
2400
+ const content = `${JSON.stringify(plan, null, 2)}
2401
+ `;
2402
+ return { valid: true, plan, content };
2403
+ }
2404
+ };
2405
+
2406
+ // src/cli/commands/run.ts
2407
+ import { execFileSync } from "child_process";
1953
2408
  function normalizeTaskSlugFromSpec(specPath) {
1954
2409
  const normalized = String(specPath).replaceAll("\\", "/");
1955
2410
  const marker = "/docs/workflows/";
@@ -1958,7 +2413,7 @@ function normalizeTaskSlugFromSpec(specPath) {
1958
2413
  const slug = normalized.slice(index).split("/")[0];
1959
2414
  if (slug) return slug;
1960
2415
  }
1961
- return path12.basename(specPath, path12.extname(specPath));
2416
+ return path14.basename(specPath, path14.extname(specPath));
1962
2417
  }
1963
2418
  function combineValidation(evidence, quality) {
1964
2419
  const statuses = [evidence.internalStatus, quality.overallStatus];
@@ -1970,27 +2425,194 @@ function combineValidation(evidence, quality) {
1970
2425
  else if (statuses.includes("PASS_WITH_NOTES")) overallStatus = "PASS_WITH_NOTES";
1971
2426
  return { overallStatus, evidence, quality };
1972
2427
  }
1973
- async function runMasterOrchestrator({ cwd, specPath, override, remediationExecutor = null }) {
2428
+ function repositoryRelative(cwd, candidate) {
2429
+ return path14.relative(cwd, path14.resolve(cwd, candidate)).replaceAll("\\", "/");
2430
+ }
2431
+ async function findCompatibleLedger(cwd, specRelativePath) {
2432
+ const historyDir = path14.join(cwd, ".ai-workflow/history");
2433
+ const matches = [];
2434
+ for (const file of await fs12.readdir(historyDir).catch(() => [])) {
2435
+ if (!file.endsWith("-ledger.json")) continue;
2436
+ try {
2437
+ const events = JSON.parse(await fs12.readFile(path14.join(historyDir, file), "utf8"));
2438
+ if (events.some((event) => event.eventType === "specification_complete" && event.data?.artifactPath === specRelativePath)) {
2439
+ matches.push(path14.join(historyDir, file));
2440
+ }
2441
+ } catch {
2442
+ }
2443
+ }
2444
+ return matches;
2445
+ }
2446
+ async function runDeepImplementation(cwd, absoluteSpecPath, specPath, approvalPath, specContent) {
2447
+ if (!approvalPath) throw new Error("[SDD BLOCKED] DEEP resume requires --approval-path.");
2448
+ const approvalValidator = new ApprovalReceiptValidator({ cwd });
2449
+ const approval = await approvalValidator.validate(approvalPath, absoluteSpecPath);
2450
+ if (!approval.valid || !approval.receipt || !approval.approvedSpecHash) {
2451
+ throw new Error(`[SDD BLOCKED] ${approval.reason || "Approval receipt is invalid."}`);
2452
+ }
2453
+ const workflowId = approval.receipt.workflowId;
2454
+ const ledgerPath = `.ai-workflow/history/${workflowId}-ledger.json`;
2455
+ const absoluteLedgerPath = path14.join(cwd, ledgerPath);
2456
+ const relativeSpecPath = repositoryRelative(cwd, specPath);
2457
+ const compatibleLedgers = await findCompatibleLedger(cwd, relativeSpecPath);
2458
+ if (compatibleLedgers.length > 1) {
2459
+ throw new Error("[SDD BLOCKED] Multiple ledgers claim the same approved specification.");
2460
+ }
2461
+ if (compatibleLedgers.length === 1 && path14.resolve(compatibleLedgers[0]) !== path14.resolve(absoluteLedgerPath)) {
2462
+ throw new Error("[SDD BLOCKED] Approval workflowId conflicts with the ledger that created the specification.");
2463
+ }
2464
+ const ledger = new EvidenceLedger({ cwd, workflowId });
2465
+ const loaded = await ledger.load(ledgerPath);
2466
+ if (!loaded) {
2467
+ ledger.logEvent({
2468
+ actor: "Atlas",
2469
+ actorType: "control-plane",
2470
+ observed: true,
2471
+ eventType: "workflow_attached",
2472
+ provenance: "sdd-control-plane",
2473
+ data: { specSource: "external", specPath: relativeSpecPath, status: "COMPLETED" }
2474
+ });
2475
+ }
2476
+ const events = ledger.getEvents();
2477
+ const approvalEvents = events.filter((event) => event.eventType === "spec_approval_verified");
2478
+ if (approvalEvents.length > 1) throw new Error("[SDD BLOCKED] Duplicate specification approval events in ledger.");
2479
+ if (approvalEvents.length === 1 && (approvalEvents[0].data?.approvedHash !== approval.approvedSpecHash || approvalEvents[0].data?.approvalPath !== repositoryRelative(cwd, approvalPath))) throw new Error("[SDD BLOCKED] Existing specification approval conflicts with the supplied receipt.");
2480
+ const nexusTerminals = events.filter((event) => event.eventType === "specification_complete");
2481
+ if (nexusTerminals.length > 1) throw new Error("[SDD BLOCKED] Duplicate Nexus terminal events in ledger.");
2482
+ if (nexusTerminals.length === 1 && nexusTerminals[0].data?.artifactPath !== relativeSpecPath) {
2483
+ throw new Error("[SDD BLOCKED] Ledger specification path does not match --spec-path.");
2484
+ }
2485
+ const draftHash = nexusTerminals[0]?.data?.artifactHash || null;
2486
+ const controller = new DelegationController({ cwd, ledger, adapter: new OpenCodeAdapter({ cwd }) });
2487
+ const absolutePlanPath = path14.join(cwd, "docs/workflows", workflowId, "technical-plan.json");
2488
+ const relativePlanPath = repositoryRelative(cwd, absolutePlanPath);
2489
+ if (await fs12.access(absolutePlanPath).then(() => true).catch(() => false)) {
2490
+ throw new Error(`[SDD BLOCKED] Refusing to overwrite existing technical plan: ${relativePlanPath}`);
2491
+ }
2492
+ const planValidator = new TechnicalPlanValidator({ cwd });
2493
+ const protectedPaths = [absoluteSpecPath, approvalPath, ledgerPath, absolutePlanPath, "EVIDENCE.json"];
2494
+ const planning = await controller.executePhase({
2495
+ phase: "planning",
2496
+ actor: "Orion",
2497
+ prompt: [
2498
+ "Return only a JSON technical plan conforming to dist-assets/schemas/technical-plan.schema.json.",
2499
+ "Use explicit repository-relative file paths in filesInScope. Do not edit files or implement.",
2500
+ "Approved specification:",
2501
+ specContent
2502
+ ].join("\n\n"),
2503
+ readOnly: true,
2504
+ requireExplicitActor: true,
2505
+ onOutput: async (output) => {
2506
+ const validation = await planValidator.validateOutput(output, protectedPaths);
2507
+ if (!validation.valid || !validation.content) throw new Error(validation.reason || "Technical plan is invalid.");
2508
+ await writeFileAtomic(absolutePlanPath, validation.content);
2509
+ return { artifactPath: relativePlanPath, artifactHash: sha256(validation.content) };
2510
+ }
2511
+ });
2512
+ await ledger.save(ledgerPath);
2513
+ if (!planning.success || !planning.artifact?.artifactHash) {
2514
+ throw new Error(`[WORKFLOW BLOCKED] Orion planning phase failed: ${planning.error || "unknown failure"}`);
2515
+ }
2516
+ if (approvalEvents.length === 0) {
2517
+ ledger.logEvent({
2518
+ actor: "Atlas",
2519
+ actorType: "control-plane",
2520
+ observed: true,
2521
+ eventType: "spec_approval_verified",
2522
+ provenance: "approval-receipt",
2523
+ data: {
2524
+ approvalPath: repositoryRelative(cwd, approvalPath),
2525
+ approvedHash: approval.approvedSpecHash,
2526
+ draftHash,
2527
+ authorizationSource: approval.receipt.authorizationSource,
2528
+ status: "COMPLETED"
2529
+ }
2530
+ });
2531
+ await ledger.save(ledgerPath);
2532
+ }
2533
+ const planContent = await fs12.readFile(absolutePlanPath, "utf8");
2534
+ const parsedPlan = JSON.parse(planContent);
2535
+ const approvedHash = approval.approvedSpecHash;
2536
+ const planHash = String(planning.artifact.artifactHash);
2537
+ const baseSha = (() => {
2538
+ try {
2539
+ return execFileSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8", stdio: "pipe" }).trim();
2540
+ } catch {
2541
+ return "unknown";
2542
+ }
2543
+ })();
2544
+ const finalizer = new Finalizer({ cwd, fastTrack: false });
2545
+ const beforeImplementation = await finalizer.snapshotManager.capture();
2546
+ const allowedFiles = new Set(parsedPlan.filesInScope.map((entry) => String(entry.path).replaceAll("\\", "/")));
2547
+ const implementation = await controller.executePhase({
2548
+ phase: "implementation",
2549
+ actor: "Astra",
2550
+ prompt: [
2551
+ "Implement the approved specification using the validated technical plan.",
2552
+ `You may modify only these files: ${[...allowedFiles].join(", ")}`,
2553
+ "Do not modify the specification, approval receipt, technical plan, ledger, or evidence artifacts.",
2554
+ "Approved specification:",
2555
+ specContent,
2556
+ "Validated technical plan:",
2557
+ planContent
2558
+ ].join("\n\n"),
2559
+ readOnly: false,
2560
+ requireExplicitActor: true,
2561
+ onOutput: async () => {
2562
+ if (await hashFile(absoluteSpecPath) !== approvedHash) throw new Error("Approved specification changed during Astra implementation.");
2563
+ if (await hashFile(absolutePlanPath) !== planHash) throw new Error("Technical plan changed during Astra implementation.");
2564
+ const integrity = await finalizer.verifyIntegrity(beforeImplementation);
2565
+ const workspaceStateMarkers = /* @__PURE__ */ new Set(["stagedDiff", "unstagedDiff", "untrackedFiles"]);
2566
+ const changed = [...integrity.changes.added, ...integrity.changes.modified, ...integrity.changes.deleted].filter((entry) => !workspaceStateMarkers.has(entry) && !/^(branch|head|indexTree):/.test(entry)).map((entry) => String(entry).replaceAll("\\", "/"));
2567
+ const outsideScope = changed.filter((entry) => !allowedFiles.has(entry));
2568
+ if (outsideScope.length > 0) throw new Error(`Astra modified files outside the technical plan: ${outsideScope.join(", ")}`);
2569
+ return { artifactPath: relativePlanPath, artifactHash: planHash };
2570
+ }
2571
+ });
2572
+ await ledger.save(ledgerPath);
2573
+ if (!implementation.success) {
2574
+ throw new Error(`[WORKFLOW BLOCKED] Astra implementation phase failed: ${implementation.error || "unknown failure"}`);
2575
+ }
2576
+ const phaseEvents = ledger.getEvents().filter(
2577
+ (event) => ["specification_complete", "planning_complete", "implementation_complete"].includes(event.eventType) && event.data?.success !== false
2578
+ );
2579
+ return {
2580
+ workflowId,
2581
+ baseSha,
2582
+ artifactHashes: { draft: draftHash, approved: approvedHash, technicalPlan: planHash },
2583
+ phaseOrder: phaseEvents.map((event) => event.data?.phase || event.eventType.replace("_complete", "")),
2584
+ confirmedActors: phaseEvents.filter((event) => event.data?.runtimeAgentApplied).map((event) => ({
2585
+ phase: event.data.phase || event.eventType.replace("_complete", ""),
2586
+ requested: event.data.runtimeAgentRequested,
2587
+ applied: event.data.runtimeAgentApplied
2588
+ })),
2589
+ ledger,
2590
+ ledgerPath,
2591
+ controller
2592
+ };
2593
+ }
2594
+ async function runMasterOrchestrator({ cwd, specPath, approvalPath, override, remediationExecutor = null }) {
1974
2595
  console.log("\n[AI WORKFLOW] Starting evidence-backed orchestration...\n");
1975
- const branchGate = new BranchGate({ memoryDir: path12.join(cwd, ".ai-workflow"), cwd });
2596
+ const branchGate = new BranchGate({ memoryDir: path14.join(cwd, ".ai-workflow"), cwd });
1976
2597
  const taskSlug = specPath ? normalizeTaskSlugFromSpec(specPath) : "implementation";
1977
2598
  const gateResult = branchGate.check(override, { taskSlug });
1978
2599
  if (gateResult.blocked) throw new Error(`[GATE BLOCKED] ${gateResult.reason}`);
1979
2600
  console.log(`[PASS] Branch Gate: ${gateResult.recovered ? `${gateResult.branchBefore} -> ${gateResult.branch}` : `${gateResult.branch} is authorized`}.`);
1980
2601
  if (!specPath) throw new Error("[SDD BLOCKED] Missing --spec-path. An approved specification is required.");
1981
2602
  const validator = new SpecValidator();
1982
- const absoluteSpecPath = path12.isAbsolute(specPath) ? specPath : path12.join(cwd, specPath);
2603
+ const absoluteSpecPath = path14.isAbsolute(specPath) ? specPath : path14.join(cwd, specPath);
1983
2604
  const validation = await validator.validate(absoluteSpecPath);
1984
2605
  if (!validation.valid) throw new Error(`[SDD BLOCKED] Specification is not ready: ${validation.reason}`);
1985
2606
  const specTier = validation.tier || "standard";
1986
2607
  const riskLevel = specTier === "deep" ? "high" : specTier === "tiny" ? "low" : "medium";
1987
2608
  const evidencePolicy = specTier === "deep" ? "required" : "optional";
1988
2609
  const remediationLimit = specTier === "deep" ? 3 : specTier === "tiny" ? 1 : 2;
1989
- const specContent = await fs10.readFile(absoluteSpecPath, "utf8");
2610
+ const specContent = await fs12.readFile(absoluteSpecPath, "utf8");
1990
2611
  const workflowProfile = resolveWorkflowProfile({ request: specContent });
1991
2612
  const profileDefinition = getWorkflowProfile(workflowProfile);
1992
2613
  console.log(`[PASS] Specification: ${specTier.toUpperCase()} spec is APPROVED.`);
1993
2614
  console.log(`[PROFILE] ${workflowProfile} -> ${profileDefinition.owner}; skills: ${profileDefinition.skills.join(", ") || "none"}.`);
2615
+ const deepContext = specTier === "deep" ? await runDeepImplementation(cwd, absoluteSpecPath, specPath, approvalPath, specContent) : null;
1994
2616
  const validateWorkflow = async () => {
1995
2617
  const evidence = await runCollectEvidence({
1996
2618
  cwd,
@@ -1998,18 +2620,36 @@ async function runMasterOrchestrator({ cwd, specPath, override, remediationExecu
1998
2620
  taskSlug,
1999
2621
  evidencePolicy,
2000
2622
  profile: workflowProfile,
2001
- branchRecovery: gateResult.recovered ? `${gateResult.branchBefore} -> ${gateResult.branch}` : "NOT_REQUIRED"
2623
+ branchRecovery: gateResult.recovered ? `${gateResult.branchBefore} -> ${gateResult.branch}` : "NOT_REQUIRED",
2624
+ workflowEvidence: deepContext ? {
2625
+ workflowId: deepContext.workflowId,
2626
+ baseSha: deepContext.baseSha,
2627
+ artifactHashes: deepContext.artifactHashes,
2628
+ phaseOrder: deepContext.phaseOrder,
2629
+ confirmedActors: deepContext.confirmedActors
2630
+ } : null
2002
2631
  });
2003
2632
  const quality = await new QualityGuard({ cwd, taskSlug, evidencePolicy, riskLevel }).verify();
2004
- return combineValidation(evidence, quality);
2633
+ const combined = combineValidation(evidence, quality);
2634
+ if (deepContext) {
2635
+ const workflowEvidence = await new EvidenceValidator({ cwd, requireWorkflowEvidence: true }).validate();
2636
+ if (!workflowEvidence.valid) {
2637
+ combined.overallStatus = "FAIL_QUALITY_GATE";
2638
+ combined.reason = workflowEvidence.reason;
2639
+ }
2640
+ }
2641
+ return combined;
2005
2642
  };
2006
- let result = await validateWorkflow();
2643
+ const observedValidate = async () => deepContext ? await deepContext.controller.validate(taskSlug, workflowProfile, validateWorkflow, evidencePolicy) : await validateWorkflow();
2644
+ let result = await observedValidate();
2645
+ if (deepContext) await deepContext.ledger.save(deepContext.ledgerPath);
2007
2646
  if (isRecoverableGateFailure(result.overallStatus)) {
2008
2647
  console.log(`
2009
2648
  [REMEDIATION REQUIRED] ${result.overallStatus}. Starting bounded remediation (limit: ${remediationLimit}).`);
2010
2649
  const executor = typeof remediationExecutor === "function" ? remediationExecutor : createCliRemediationExecutor(cwd);
2011
2650
  const healer = new HealerEngine({ cwd, remediationLimit, taskSlug });
2012
- result = await healer.run({ initialResult: result, validate: validateWorkflow, remediate: executor });
2651
+ result = await healer.run({ initialResult: result, validate: observedValidate, remediate: executor });
2652
+ if (deepContext) await deepContext.ledger.save(deepContext.ledgerPath);
2013
2653
  }
2014
2654
  if (isTerminalFailure(result.overallStatus)) {
2015
2655
  throw new Error(`[WORKFLOW BLOCKED] ${result.overallStatus}: ${result.reason || "Validation could not be resolved safely."}`);
@@ -2020,7 +2660,7 @@ async function runMasterOrchestrator({ cwd, specPath, override, remediationExecu
2020
2660
  console.log("\n--- Final Handoff ---");
2021
2661
  const handoffEngine = new HandoffEngine({ cwd });
2022
2662
  const handoffPath = await handoffEngine.generate({
2023
- taskId: path12.basename(specPath, ".md"),
2663
+ taskId: path14.basename(specPath, ".md"),
2024
2664
  status: result.overallStatus,
2025
2665
  specPaths: [specPath],
2026
2666
  evidence: result.evidence,
@@ -2029,14 +2669,14 @@ async function runMasterOrchestrator({ cwd, specPath, override, remediationExecu
2029
2669
  console.log(`
2030
2670
  [AI WORKFLOW COMPLETE] ${result.overallStatus}`);
2031
2671
  if (result.remediation?.attempts) console.log(`Remediation attempts: ${result.remediation.attempts}`);
2032
- console.log(`Handoff Packet: ${path12.relative(cwd, handoffPath)}
2672
+ console.log(`Handoff Packet: ${path14.relative(cwd, handoffPath)}
2033
2673
  `);
2034
- return { ...result, workflowProfile };
2674
+ return { ...result, workflowProfile, workflowId: deepContext?.workflowId || null };
2035
2675
  }
2036
2676
 
2037
2677
  // src/core/healing/runtime-remediation-executor.ts
2038
- import fs11 from "fs/promises";
2039
- import path13 from "path";
2678
+ import fs13 from "fs/promises";
2679
+ import path15 from "path";
2040
2680
  import { execSync as execSync3 } from "child_process";
2041
2681
  function createRuntimeRemediationExecutor(cwd, ledger = null) {
2042
2682
  const adapter = new OpenCodeAdapter({ cwd });
@@ -2076,14 +2716,14 @@ function createRuntimeRemediationExecutor(cwd, ledger = null) {
2076
2716
  }
2077
2717
  let requestContent = {};
2078
2718
  try {
2079
- requestContent = JSON.parse(await fs11.readFile(requestPath, "utf8"));
2719
+ requestContent = JSON.parse(await fs13.readFile(requestPath, "utf8"));
2080
2720
  } catch {
2081
2721
  }
2082
2722
  const filesBefore = getChangedFiles2();
2083
2723
  const fileContentsBefore = {};
2084
2724
  for (const file of filesBefore) {
2085
2725
  try {
2086
- fileContentsBefore[file] = await fs11.readFile(path13.join(cwd, file), "utf8");
2726
+ fileContentsBefore[file] = await fs13.readFile(path15.join(cwd, file), "utf8");
2087
2727
  } catch {
2088
2728
  fileContentsBefore[file] = null;
2089
2729
  }
@@ -2121,7 +2761,7 @@ Please inspect the code, identify the root cause of these failures (e.g. failing
2121
2761
  changedFiles.push(file);
2122
2762
  } else {
2123
2763
  try {
2124
- const contentAfter = await fs11.readFile(path13.join(cwd, file), "utf8");
2764
+ const contentAfter = await fs13.readFile(path15.join(cwd, file), "utf8");
2125
2765
  if (contentAfter !== fileContentsBefore[file]) {
2126
2766
  changedFiles.push(file);
2127
2767
  }
@@ -2158,8 +2798,8 @@ Please inspect the code, identify the root cause of these failures (e.g. failing
2158
2798
  }
2159
2799
 
2160
2800
  // src/cli/commands/execute.ts
2161
- import fs12 from "fs/promises";
2162
- import path14 from "path";
2801
+ import fs14 from "fs/promises";
2802
+ import path16 from "path";
2163
2803
  import { execSync as execSync4 } from "child_process";
2164
2804
  async function captureReadOnlyState(cwd, fastTrack = false) {
2165
2805
  const finalizer = new Finalizer({ cwd, fastTrack });
@@ -2265,12 +2905,12 @@ function runBranchGate(plan, taskSlug, cwd, stateMachine, branchGate) {
2265
2905
  }
2266
2906
  async function createSpecIfRequired(plan, classification, taskSlug, cwd) {
2267
2907
  if (plan.specPath) {
2268
- const fullSpecPath = path14.join(cwd, plan.specPath);
2269
- const specExists = await fs12.access(fullSpecPath).then(() => true).catch(() => false);
2908
+ const fullSpecPath = path16.join(cwd, plan.specPath);
2909
+ const specExists = await fs14.access(fullSpecPath).then(() => true).catch(() => false);
2270
2910
  if (!specExists) {
2271
- await fs12.mkdir(path14.dirname(fullSpecPath), { recursive: true });
2272
- const specTemplatePath = path14.join(cwd, ".ai-workflow/templates/specs/standard.md");
2273
- const templateContent = await fs12.readFile(specTemplatePath, "utf8").catch(() => {
2911
+ await fs14.mkdir(path16.dirname(fullSpecPath), { recursive: true });
2912
+ const specTemplatePath = path16.join(cwd, ".ai-workflow/templates/specs/standard.md");
2913
+ const templateContent = await fs14.readFile(specTemplatePath, "utf8").catch(() => {
2274
2914
  return `# [STANDARD] Specification: ${classification.request}
2275
2915
 
2276
2916
  ## Metadata
@@ -2298,11 +2938,87 @@ async function createSpecIfRequired(plan, classification, taskSlug, cwd) {
2298
2938
 
2299
2939
  - [ ] Behavior tests pass`;
2300
2940
  });
2301
- await fs12.writeFile(fullSpecPath, templateContent);
2941
+ await fs14.writeFile(fullSpecPath, templateContent);
2302
2942
  console.log(`[EXECUTE] Created DRAFT specification template at: ${plan.specPath}`);
2303
2943
  }
2304
2944
  }
2305
2945
  }
2946
+ async function runDeepSpecificationCheckpoint(plan, classification, taskSlug, cwd, delegationController, stateMachine) {
2947
+ if (!plan.specPath) throw new Error("[SDD BLOCKED] Required specification path was not planned.");
2948
+ const absoluteSpecPath = path16.resolve(cwd, plan.specPath);
2949
+ const relativeSpecPath = path16.relative(cwd, absoluteSpecPath).replaceAll("\\", "/");
2950
+ if (relativeSpecPath.startsWith("../") || path16.isAbsolute(relativeSpecPath)) {
2951
+ throw new Error("[SDD BLOCKED] Planned specification path escapes the repository.");
2952
+ }
2953
+ if (await fs14.access(absoluteSpecPath).then(() => true).catch(() => false)) {
2954
+ throw new Error(`[SDD BLOCKED] Refusing to overwrite existing specification: ${relativeSpecPath}`);
2955
+ }
2956
+ const approvalPath = `.ai-workflow/approvals/${taskSlug}.json`;
2957
+ const validator = new SpecValidator();
2958
+ stateMachine.transitionTo("DELEGATED");
2959
+ const prompt = [
2960
+ "Produce only the complete Markdown for a [DEEP] specification.",
2961
+ "The Metadata Status must be exactly DRAFT. Include concrete acceptance criteria as unchecked checkboxes.",
2962
+ "Do not approve the specification, create a receipt, edit files, or implement code.",
2963
+ `Workflow ID: ${taskSlug}`,
2964
+ `Request: ${classification.request}`
2965
+ ].join("\n");
2966
+ const phaseResult = await delegationController.executePhase({
2967
+ phase: "specification",
2968
+ actor: "Nexus",
2969
+ prompt,
2970
+ readOnly: true,
2971
+ requireExplicitActor: true,
2972
+ onOutput: async (output) => {
2973
+ const content = stripMarkdownFence(output);
2974
+ const validation = validator.validateDraftContent(content);
2975
+ if (!validation.valid) throw new Error(`Nexus DRAFT rejected: ${validation.reason}`);
2976
+ await writeFileAtomic(absoluteSpecPath, content);
2977
+ return { artifactPath: relativeSpecPath, artifactHash: sha256(content), draftHash: sha256(content) };
2978
+ }
2979
+ });
2980
+ if (!phaseResult.success) {
2981
+ stateMachine.transitionTo("BLOCKED");
2982
+ throw new Error(`[SDD BLOCKED] Nexus specification phase failed: ${phaseResult.error || "unknown failure"}`);
2983
+ }
2984
+ const draftHash = String(phaseResult.artifact?.artifactHash || "");
2985
+ delegationController.ledger?.logEvent({
2986
+ actor: "Atlas",
2987
+ actorType: "control-plane",
2988
+ observed: true,
2989
+ eventType: "approval_checkpoint",
2990
+ provenance: "sdd-control-plane",
2991
+ data: {
2992
+ specSource: "nexus",
2993
+ specPath: relativeSpecPath,
2994
+ approvalPath,
2995
+ draftHash,
2996
+ approvedHash: null,
2997
+ planHash: null,
2998
+ status: "BLOCKED",
2999
+ reason: "SDD APPROVAL REQUIRED"
3000
+ }
3001
+ });
3002
+ stateMachine.transitionTo("BLOCKED");
3003
+ const resumeCommand = `aw run --spec-path=${relativeSpecPath} --approval-path=${approvalPath}`;
3004
+ console.log(`
3005
+ [BLOCKED] SDD APPROVAL REQUIRED`);
3006
+ console.log(`Specification: ${relativeSpecPath}`);
3007
+ console.log(`Resume: ${resumeCommand}
3008
+ `);
3009
+ return {
3010
+ overallStatus: "BLOCKED",
3011
+ reason: "SDD APPROVAL REQUIRED",
3012
+ checkpoint: "approval",
3013
+ exitCode: 2,
3014
+ workflowId: taskSlug,
3015
+ specPath: relativeSpecPath,
3016
+ approvalPath,
3017
+ draftHash,
3018
+ resumeCommand,
3019
+ stateHistory: stateMachine.getHistory()
3020
+ };
3021
+ }
2306
3022
  async function runImplementation(plan, classification, delegationController, stateMachine, fastTrack = false) {
2307
3023
  stateMachine.transitionTo("DELEGATED");
2308
3024
  stateMachine.transitionTo("IMPLEMENTING");
@@ -2415,7 +3131,7 @@ async function generateFinalHandoff(plan, taskSlug, cwd, finalState, evidence) {
2415
3131
  });
2416
3132
  console.log(`
2417
3133
  [AI WORKFLOW COMPLETE] ${finalState}`);
2418
- console.log(`Handoff Packet: ${path14.relative(cwd, handoffPath)}
3134
+ console.log(`Handoff Packet: ${path16.relative(cwd, handoffPath)}
2419
3135
  `);
2420
3136
  return handoffPath;
2421
3137
  }
@@ -2425,12 +3141,12 @@ async function runFastTrackValidation(cwd, result, checkBranchSafety) {
2425
3141
  checkBranchSafety();
2426
3142
  const changedFiles = result.evidence?.changedFiles || [];
2427
3143
  console.log(`[FAST-TRACK] Changed files detected:`, changedFiles);
2428
- const evidencePath = path14.join(cwd, "EVIDENCE.json");
2429
- const hasEvidence = await fs12.access(evidencePath).then(() => true).catch(() => false);
3144
+ const evidencePath = path16.join(cwd, "EVIDENCE.json");
3145
+ const hasEvidence = await fs14.access(evidencePath).then(() => true).catch(() => false);
2430
3146
  if (hasEvidence) {
2431
- const { EvidenceValidator } = await import("../evidence-validator-76ZQQYDU.js");
3147
+ const { EvidenceValidator: EvidenceValidator2 } = await import("../evidence-validator-HS3NTWAB.js");
2432
3148
  const isTest = process.env.NODE_ENV === "test" || process.env.VITEST === "true";
2433
- const evidenceValidator = new EvidenceValidator({ cwd, skipFileCheck: isTest, skipGitCheck: isTest });
3149
+ const evidenceValidator = new EvidenceValidator2({ cwd, skipFileCheck: isTest, skipGitCheck: isTest });
2434
3150
  const valResult = await evidenceValidator.validate();
2435
3151
  if (!valResult.valid) {
2436
3152
  console.error(`
@@ -2500,7 +3216,7 @@ async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2500
3216
  const { plan: planObj, classification } = await classifyAndPlanExecution(naturalRequest, cwd, taskSlug, delegationController, stateMachine);
2501
3217
  plan = planObj;
2502
3218
  const fastTrack = plan.riskLevel === "low" && (!plan.branchNeeded || plan.evidencePolicy === "optional");
2503
- const branchGate = new BranchGate({ memoryDir: path14.join(cwd, ".ai-workflow"), cwd });
3219
+ const branchGate = new BranchGate({ memoryDir: path16.join(cwd, ".ai-workflow"), cwd });
2504
3220
  const gateResult = runBranchGate(plan, taskSlug, cwd, stateMachine, branchGate);
2505
3221
  const checkBranchSafety = () => {
2506
3222
  if (!planObj.branchNeeded) return;
@@ -2510,6 +3226,9 @@ async function runExecute({ cwd, naturalRequest, taskSlug: taskSlugOverride }) {
2510
3226
  throw new Error(`[WORKFLOW BLOCKED] Security violation: current branch is protected '${currentBranch}'!`);
2511
3227
  }
2512
3228
  };
3229
+ if (classification.specPolicy === "required") {
3230
+ return await runDeepSpecificationCheckpoint(plan, classification, taskSlug, cwd, delegationController, stateMachine);
3231
+ }
2513
3232
  await createSpecIfRequired(plan, classification, taskSlug, cwd);
2514
3233
  let readOnlyStateBefore = null;
2515
3234
  if (!plan.branchNeeded) {
@@ -2585,6 +3304,7 @@ ${JSON.stringify(ledger.getEvents(), null, 2)}
2585
3304
  try {
2586
3305
  await ledger.save(`.ai-workflow/history/${taskSlug}-ledger.json`);
2587
3306
  } catch (err) {
3307
+ if (plan?.riskLevel === "high") throw err;
2588
3308
  }
2589
3309
  }
2590
3310
  }
@@ -2621,7 +3341,7 @@ async function runClean({ cwd, yes = false, dryRun = false, purgeAgents = false
2621
3341
  "opencode"
2622
3342
  ];
2623
3343
  const hasAgents = existsSync(join(cwd, ".agents"));
2624
- const existingTargets = targets.map((name) => join(cwd, name)).filter((path15) => existsSync(path15) || isSymlink2(path15));
3344
+ const existingTargets = targets.map((name) => join(cwd, name)).filter((path17) => existsSync(path17) || isSymlink2(path17));
2625
3345
  if (existingTargets.length === 0 && (!hasAgents || !purgeAgents)) {
2626
3346
  console.log("No AI Workflow configuration or files found in the current project.");
2627
3347
  return;
@@ -2630,7 +3350,7 @@ async function runClean({ cwd, yes = false, dryRun = false, purgeAgents = false
2630
3350
  console.log("===============================");
2631
3351
  if (dryRun) {
2632
3352
  console.log("[DRY RUN] The following items would be deleted:");
2633
- existingTargets.forEach((path15) => console.log(` - ${path15}`));
3353
+ existingTargets.forEach((path17) => console.log(` - ${path17}`));
2634
3354
  if (hasAgents && purgeAgents) {
2635
3355
  console.log(` - ${join(cwd, ".agents")} (customizations folder)`);
2636
3356
  } else if (hasAgents) {
@@ -2684,12 +3404,14 @@ function printHelp() {
2684
3404
 
2685
3405
  Usage:
2686
3406
  ai-workflow execute "<request>" [--task=<slug>] [--request="<request>"]
2687
- ai-workflow run --spec-path=<path>
3407
+ ai-workflow run --spec-path=<path> [--approval-path=<path>]
2688
3408
  ai-workflow init [--yes] [--force] [--dry-run] [--no-install] [--no-overwrite] [--claude] [--codex] [--antigravity] [--profile=<profile>]
2689
3409
  ai-workflow validate [--a11y] [--visual-dist=<path>] [--port=<port>]
2690
3410
  ai-workflow collect-evidence [--task=<slug>] [--evidence-policy=<optional|required>] [--mode=<quick|standard|full>] [--dry-run] [--visual-dist=<path>] [--port=<port>]
2691
3411
  ai-workflow doctor
2692
3412
  ai-workflow clean [--yes] [--dry-run] [--purge-agents]
3413
+ ai-workflow lint skills
3414
+ ai-workflow skill create <name> [--description="<desc>"] [--dry-run] [--force]
2693
3415
 
2694
3416
  Commands:
2695
3417
  execute Orchestrate execution of a natural request through the state machine
@@ -2698,10 +3420,13 @@ Commands:
2698
3420
  collect-evidence Run observed project validation; persists EVIDENCE.json under required evidence policy
2699
3421
  doctor Verify local ai-workflow installation
2700
3422
  clean De-initialize and remove AI Workflow files and symlinks from the project
3423
+ lint Run specialized linters (e.g. lint skills)
3424
+ skill Manage AI workflow skills (e.g. create)
2701
3425
  `);
2702
3426
  }
2703
3427
  function parseFlags(args) {
2704
3428
  const specPathArg = args.find((arg) => arg.startsWith("--spec-path="));
3429
+ const approvalPathArg = args.find((arg) => arg.startsWith("--approval-path="));
2705
3430
  const profileEqArg = args.find((arg) => arg.startsWith("--profile="));
2706
3431
  const taskArg = args.find((arg) => arg.startsWith("--task="));
2707
3432
  const modeArg = args.find((arg) => arg.startsWith("--mode="));
@@ -2722,6 +3447,7 @@ function parseFlags(args) {
2722
3447
  antigravity: args.includes("--antigravity"),
2723
3448
  "dev-mode": args.includes("--dev-mode"),
2724
3449
  specPath: specPathArg ? specPathArg.replace("--spec-path=", "") : void 0,
3450
+ approvalPath: approvalPathArg ? approvalPathArg.replace("--approval-path=", "") : void 0,
2725
3451
  profile: profileVal || void 0,
2726
3452
  taskSlug: taskArg ? taskArg.replace("--task=", "") : void 0,
2727
3453
  mode: modeArg ? modeArg.replace("--mode=", "") : void 0,
@@ -2743,7 +3469,7 @@ var commandMap = {
2743
3469
  taskSlug: flags.taskSlug
2744
3470
  });
2745
3471
  if (result && (result.overallStatus === "FAIL_QUALITY_GATE" || result.overallStatus === "BLOCKED" || result.overallStatus === "FAIL")) {
2746
- process.exit(1);
3472
+ process.exitCode = result.exitCode === 2 ? 2 : 1;
2747
3473
  }
2748
3474
  },
2749
3475
  run: async (_, flags) => {
@@ -2773,7 +3499,7 @@ var commandMap = {
2773
3499
  });
2774
3500
  },
2775
3501
  validate: async (_, flags) => {
2776
- const { runValidate } = await import("../validate-A46WUBVZ.js");
3502
+ const { runValidate } = await import("../validate-IEHLAVZ6.js");
2777
3503
  await runValidate({
2778
3504
  cwd: process.cwd(),
2779
3505
  taskSlug: flags.taskSlug,
@@ -2790,6 +3516,38 @@ var commandMap = {
2790
3516
  cwd: process.cwd(),
2791
3517
  ...flags
2792
3518
  });
3519
+ },
3520
+ lint: async (args) => {
3521
+ if (args[0] === "skills") {
3522
+ const { runLinter } = await import("../skill-frontmatter-linter-FMJADOK4.js");
3523
+ const { errors, filesScanned } = runLinter(process.cwd());
3524
+ console.log(`Scanned ${filesScanned} skill files.`);
3525
+ if (errors.length > 0) {
3526
+ console.error(`\\nFound ${errors.length} frontmatter issues:`);
3527
+ for (const err of errors) {
3528
+ console.error(`- ${err.filePath}: ${err.message}`);
3529
+ }
3530
+ process.exit(1);
3531
+ } else {
3532
+ console.log("All skills passed frontmatter linting.");
3533
+ }
3534
+ } else {
3535
+ console.error("Unknown lint target. Supported: skills");
3536
+ process.exit(1);
3537
+ }
3538
+ },
3539
+ skill: async (args) => {
3540
+ if (args[0] === "create") {
3541
+ const { parseSkillCreateArgs, runSkillCreate } = await import("../skill-4MEGJ3DO.js");
3542
+ const createOptions = parseSkillCreateArgs(args.slice(1));
3543
+ await runSkillCreate({
3544
+ cwd: process.cwd(),
3545
+ ...createOptions
3546
+ });
3547
+ } else {
3548
+ console.error("Unknown skill command. Supported: create");
3549
+ process.exit(1);
3550
+ }
2793
3551
  }
2794
3552
  };
2795
3553
  async function runCli(args) {