agent-work-loop 0.0.0 → 0.6.22
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.
- package/README.md +272 -12
- package/dist/brief-Z3JKXEUP.js +181 -0
- package/dist/changelog-R7BNBF2C.js +62 -0
- package/dist/chunk-4OCSYHYB.js +274 -0
- package/dist/chunk-6E7XEQOH.js +27 -0
- package/dist/chunk-7SYRDDTX.js +516 -0
- package/dist/chunk-BUWGQVHT.js +1243 -0
- package/dist/chunk-C7TN3LM3.js +448 -0
- package/dist/chunk-CCMG377E.js +771 -0
- package/dist/chunk-D5OINC3G.js +52 -0
- package/dist/chunk-F5LHXBH7.js +209 -0
- package/dist/chunk-FBEUJR2P.js +446 -0
- package/dist/chunk-I77CXOEX.js +693 -0
- package/dist/chunk-LMWAVN7B.js +904 -0
- package/dist/chunk-O7GRZZPJ.js +347 -0
- package/dist/chunk-TKPHC32G.js +96 -0
- package/dist/chunk-UOPWVM2H.js +727 -0
- package/dist/chunk-VU6IPRRM.js +166 -0
- package/dist/chunk-X5LMP5J7.js +307 -0
- package/dist/chunk-ZLTOL3D3.js +286 -0
- package/dist/cli.js +373 -11
- package/dist/commit-APXIVOSD.js +411 -0
- package/dist/config-TFMW7O4T.js +34 -0
- package/dist/doctor-BU6HWXE4.js +29 -0
- package/dist/evolve-NNQX2A43.js +38 -0
- package/dist/feedback-KAXNFMUY.js +125 -0
- package/dist/gotchas-CW4KZDEF.js +43 -0
- package/dist/hold-recheck-SLI7NDLU.js +133 -0
- package/dist/init-UDM5AXKI.js +79 -0
- package/dist/lane-MIVLTDEU.js +41 -0
- package/dist/loop-summary-XAI6KOGB.js +361 -0
- package/dist/metrics-WLRZZRTK.js +25 -0
- package/dist/record-UKDIUJ5T.js +68 -0
- package/dist/review-NTZ3HY3N.js +118 -0
- package/dist/rules-4VDP5LZW.js +33 -0
- package/dist/state-XM7NZ2HA.js +37 -0
- package/dist/status-I3MQOCQM.js +40 -0
- package/dist/uninstall-MOHJDMQH.js +545 -0
- package/dist/update-AYTBYAHI.js +61 -0
- package/dist/verify-6YF5FXWM.js +37 -0
- package/dist/version-check-G27JYMTZ.js +14 -0
- package/dist/work-6MMIQMUC.js +50 -0
- package/engine/skills/claude/awl-loop/SKILL.md +292 -0
- package/engine/skills/claude/awl-loop/reference.md +131 -0
- package/engine/skills/claude/awl-pipeline/SKILL.md +83 -0
- package/engine/skills/claude/awl-pipeline-exec/SKILL.md +200 -0
- package/engine/skills/claude/awl-pipeline-plan/SKILL.md +71 -0
- package/engine/skills/claude/awl-pipeline-review/SKILL.md +149 -0
- package/engine/skills/codex/AGENTS.awl.md +117 -0
- package/engine/templates/block-publish.mjs +9 -0
- package/engine/templates/pre-push.sample +7 -0
- package/engine/templates/related-cmd-examples.md +37 -0
- package/engine/version.json +2 -2
- package/package.json +9 -3
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveProjectRoot
|
|
3
|
+
} from "./chunk-UOPWVM2H.js";
|
|
4
|
+
import {
|
|
5
|
+
caps,
|
|
6
|
+
card,
|
|
7
|
+
makeColors
|
|
8
|
+
} from "./chunk-7SYRDDTX.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/state.ts
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import path from "path";
|
|
13
|
+
function statePath(projectRoot) {
|
|
14
|
+
return path.join(projectRoot, ".awl", "state.json");
|
|
15
|
+
}
|
|
16
|
+
function migrateState(raw) {
|
|
17
|
+
if ("workitems" in raw) {
|
|
18
|
+
return raw;
|
|
19
|
+
}
|
|
20
|
+
return { ...raw, workitems: {} };
|
|
21
|
+
}
|
|
22
|
+
function loadState(projectRoot) {
|
|
23
|
+
try {
|
|
24
|
+
const raw = JSON.parse(fs.readFileSync(statePath(projectRoot), "utf8"));
|
|
25
|
+
return migrateState(raw);
|
|
26
|
+
} catch {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function mergeState(current, patch) {
|
|
31
|
+
const merged = { ...current, ...patch };
|
|
32
|
+
if (Array.isArray(patch.criteria)) {
|
|
33
|
+
let acc = { ...current };
|
|
34
|
+
for (const c of patch.criteria) {
|
|
35
|
+
if (c && typeof c.id === "string") {
|
|
36
|
+
acc = setCriterion(acc, c.id, c);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
merged.criteria = acc.criteria;
|
|
40
|
+
}
|
|
41
|
+
return merged;
|
|
42
|
+
}
|
|
43
|
+
function getCriterion(state, id) {
|
|
44
|
+
const criteria = Array.isArray(state.criteria) ? state.criteria : [];
|
|
45
|
+
return criteria.find((c) => c.id === id);
|
|
46
|
+
}
|
|
47
|
+
function setCriterion(state, id, patch) {
|
|
48
|
+
const criteria = Array.isArray(state.criteria) ? [...state.criteria] : [];
|
|
49
|
+
const idx = criteria.findIndex((c) => c.id === id);
|
|
50
|
+
if (idx >= 0) {
|
|
51
|
+
criteria[idx] = { ...criteria[idx], ...patch };
|
|
52
|
+
} else {
|
|
53
|
+
criteria.push({ id, ...patch });
|
|
54
|
+
}
|
|
55
|
+
return { ...state, criteria };
|
|
56
|
+
}
|
|
57
|
+
function writeState(projectRoot, state) {
|
|
58
|
+
const p = statePath(projectRoot);
|
|
59
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
60
|
+
const tmp = `${p}.${process.pid}.tmp`;
|
|
61
|
+
fs.writeFileSync(tmp, `${JSON.stringify(state, null, 2)}
|
|
62
|
+
`);
|
|
63
|
+
fs.renameSync(tmp, p);
|
|
64
|
+
}
|
|
65
|
+
var STATE_LOCK_STALE_MS = 1e4;
|
|
66
|
+
function stateLockFile(projectRoot) {
|
|
67
|
+
return path.join(projectRoot, ".awl", "state.lock");
|
|
68
|
+
}
|
|
69
|
+
function sessionToken() {
|
|
70
|
+
return `proc-${process.pid}`;
|
|
71
|
+
}
|
|
72
|
+
function lockAgeAt(p) {
|
|
73
|
+
try {
|
|
74
|
+
const raw = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
75
|
+
const at = typeof raw.at === "string" ? Date.parse(raw.at) : Number.NaN;
|
|
76
|
+
if (!Number.isNaN(at)) {
|
|
77
|
+
return at;
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
return fs.statSync(p).mtimeMs;
|
|
83
|
+
} catch {
|
|
84
|
+
return Date.now();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function acquireStateLock(projectRoot, token) {
|
|
88
|
+
const p = stateLockFile(projectRoot);
|
|
89
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
90
|
+
const tryCreate = () => {
|
|
91
|
+
const tmp = `${p}.${process.pid}.acq`;
|
|
92
|
+
try {
|
|
93
|
+
fs.writeFileSync(tmp, JSON.stringify({ token, at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
94
|
+
fs.linkSync(tmp, p);
|
|
95
|
+
return true;
|
|
96
|
+
} catch (e) {
|
|
97
|
+
if (e.code === "EEXIST") {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
throw e;
|
|
101
|
+
} finally {
|
|
102
|
+
try {
|
|
103
|
+
fs.unlinkSync(tmp);
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
if (tryCreate()) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (Date.now() - lockAgeAt(p) > STATE_LOCK_STALE_MS) {
|
|
112
|
+
const claimed = `${p}.${process.pid}.steal`;
|
|
113
|
+
try {
|
|
114
|
+
fs.renameSync(p, claimed);
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
try {
|
|
119
|
+
fs.unlinkSync(claimed);
|
|
120
|
+
} catch {
|
|
121
|
+
}
|
|
122
|
+
return tryCreate();
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
function releaseStateLock(projectRoot, token) {
|
|
127
|
+
const p = stateLockFile(projectRoot);
|
|
128
|
+
if (token !== void 0) {
|
|
129
|
+
const held = readRawLockToken(p);
|
|
130
|
+
if (held !== null && held !== token) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
fs.unlinkSync(p);
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function readRawLockToken(p) {
|
|
140
|
+
try {
|
|
141
|
+
const raw = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
142
|
+
return typeof raw.token === "string" ? raw.token : null;
|
|
143
|
+
} catch {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function readStateLock(projectRoot) {
|
|
148
|
+
try {
|
|
149
|
+
const raw = JSON.parse(fs.readFileSync(stateLockFile(projectRoot), "utf8"));
|
|
150
|
+
const at = typeof raw.at === "string" ? raw.at : "";
|
|
151
|
+
const atMs = at ? Date.parse(at) : Number.NaN;
|
|
152
|
+
if (Number.isNaN(atMs) || Date.now() - atMs > STATE_LOCK_STALE_MS) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
return { token: typeof raw.token === "string" ? raw.token : "", at };
|
|
156
|
+
} catch {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function applyVerificationAttempts(state, passed) {
|
|
161
|
+
const criteria = Array.isArray(state.criteria) ? state.criteria : [];
|
|
162
|
+
const focus = typeof state.currentFocus === "string" ? state.currentFocus : void 0;
|
|
163
|
+
const targets = focus ? criteria.filter((c) => c.id === focus) : criteria.filter((c) => c.status === "in_progress");
|
|
164
|
+
if (targets.length === 0) return { state, blocked: [] };
|
|
165
|
+
const blocked = [];
|
|
166
|
+
const next = criteria.map((criterion) => {
|
|
167
|
+
if (!targets.includes(criterion)) return criterion;
|
|
168
|
+
if (passed) return { ...criterion, attempts: 0 };
|
|
169
|
+
const attempts = typeof criterion.attempts === "number" ? criterion.attempts + 1 : 1;
|
|
170
|
+
if (attempts >= 3) {
|
|
171
|
+
blocked.push(String(criterion.id));
|
|
172
|
+
return { ...criterion, attempts, status: "blocked", autoBlocked: true };
|
|
173
|
+
}
|
|
174
|
+
return { ...criterion, attempts };
|
|
175
|
+
});
|
|
176
|
+
return {
|
|
177
|
+
state: blocked.length ? { ...state, criteria: next, phase: "blocked", loop: "blocked" } : { ...state, criteria: next },
|
|
178
|
+
blocked
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function requireRoot() {
|
|
182
|
+
const root = resolveProjectRoot();
|
|
183
|
+
if (!root) {
|
|
184
|
+
process.stderr.write("\n \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. awl init \uC744 \uC2E4\uD589\uD558\uC138\uC694.\n");
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
return root;
|
|
188
|
+
}
|
|
189
|
+
function renderState(state, c) {
|
|
190
|
+
const color = makeColors(c.color);
|
|
191
|
+
if (Object.keys(state).length === 0) {
|
|
192
|
+
return card("\uD604\uC7AC \uC0C1\uD0DC", ["\uC0C1\uD0DC\uAC00 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4."], c);
|
|
193
|
+
}
|
|
194
|
+
const out = [];
|
|
195
|
+
for (const [k, v] of Object.entries(state)) {
|
|
196
|
+
const val = typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
197
|
+
out.push(`${k.padEnd(14, " ")}${color.dim(val)}`);
|
|
198
|
+
}
|
|
199
|
+
return card("\uD604\uC7AC \uC0C1\uD0DC", out, c);
|
|
200
|
+
}
|
|
201
|
+
function runStateGet(opts) {
|
|
202
|
+
const state = loadState(requireRoot());
|
|
203
|
+
if (opts.json) {
|
|
204
|
+
process.stdout.write(`${JSON.stringify(state, null, 2)}
|
|
205
|
+
`);
|
|
206
|
+
} else {
|
|
207
|
+
process.stdout.write(`${renderState(state, caps())}
|
|
208
|
+
`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function runStateSet(jsonPatch, opts = {}) {
|
|
212
|
+
const root = requireRoot();
|
|
213
|
+
let patch;
|
|
214
|
+
try {
|
|
215
|
+
patch = JSON.parse(jsonPatch);
|
|
216
|
+
} catch (e) {
|
|
217
|
+
process.stderr.write(`
|
|
218
|
+
\uAC31\uC2E0 JSON \uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4: ${String(e)}
|
|
219
|
+
`);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
if (typeof patch !== "object" || patch === null || Array.isArray(patch)) {
|
|
223
|
+
process.stderr.write("\n \uAC31\uC2E0\uC740 JSON \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4.\n");
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
const p = patch;
|
|
227
|
+
const token = sessionToken();
|
|
228
|
+
if (!acquireStateLock(root, token)) {
|
|
229
|
+
process.stderr.write(
|
|
230
|
+
"\n \uB2E4\uB978 \uC138\uC158\uC774 \uC9C0\uAE08 state \uB97C \uC4F0\uB294 \uC911\uC785\uB2C8\uB2E4(.awl/state.lock). \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.\n"
|
|
231
|
+
);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
let gateRejected = false;
|
|
235
|
+
try {
|
|
236
|
+
const current = loadState(root);
|
|
237
|
+
if (p.phase === "loop" && opts.requireGateForLoop) {
|
|
238
|
+
const workitem = typeof current.workitem === "string" ? current.workitem : void 0;
|
|
239
|
+
gateRejected = !opts.requireGateForLoop(workitem);
|
|
240
|
+
}
|
|
241
|
+
if (!gateRejected) {
|
|
242
|
+
const merged = mergeState(current, p);
|
|
243
|
+
writeState(root, merged);
|
|
244
|
+
process.stdout.write(`${JSON.stringify(merged, null, 2)}
|
|
245
|
+
`);
|
|
246
|
+
}
|
|
247
|
+
} finally {
|
|
248
|
+
releaseStateLock(root, token);
|
|
249
|
+
}
|
|
250
|
+
if (gateRejected) {
|
|
251
|
+
process.stderr.write(
|
|
252
|
+
"\n \uAC8C\uC774\uD2B8 1 \uC2B9\uC778 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. awl record gate \uB85C \uACC4\uD68D\uC744 \uC2B9\uC778(approved)\uD55C \uB4A4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.\n"
|
|
253
|
+
);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export {
|
|
259
|
+
statePath,
|
|
260
|
+
migrateState,
|
|
261
|
+
loadState,
|
|
262
|
+
mergeState,
|
|
263
|
+
getCriterion,
|
|
264
|
+
setCriterion,
|
|
265
|
+
writeState,
|
|
266
|
+
stateLockFile,
|
|
267
|
+
sessionToken,
|
|
268
|
+
acquireStateLock,
|
|
269
|
+
releaseStateLock,
|
|
270
|
+
readStateLock,
|
|
271
|
+
applyVerificationAttempts,
|
|
272
|
+
runStateGet,
|
|
273
|
+
runStateSet
|
|
274
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
run
|
|
3
|
+
} from "./chunk-UOPWVM2H.js";
|
|
4
|
+
|
|
5
|
+
// src/core/protected-files.ts
|
|
6
|
+
async function changedProtectedFiles(projectRoot, protectedFiles) {
|
|
7
|
+
if (!protectedFiles || protectedFiles.length === 0) return [];
|
|
8
|
+
const result = await run({
|
|
9
|
+
cmd: "git",
|
|
10
|
+
args: ["diff", "--name-only", "HEAD"],
|
|
11
|
+
cwd: projectRoot,
|
|
12
|
+
timeoutMs: 15e3
|
|
13
|
+
});
|
|
14
|
+
const changed = new Set(
|
|
15
|
+
result.stdout.split("\n").map((p) => p.trim()).filter(Boolean)
|
|
16
|
+
);
|
|
17
|
+
return protectedFiles.filter((file) => changed.has(file));
|
|
18
|
+
}
|
|
19
|
+
async function protectedFilesMessage(projectRoot, protectedFiles) {
|
|
20
|
+
const changed = await changedProtectedFiles(projectRoot, protectedFiles);
|
|
21
|
+
return changed.length ? `\uBCF4\uD638 \uD30C\uC77C\uC774 \uBCC0\uACBD\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${changed.join(", ")}
|
|
22
|
+
\uC0AC\uB78C\uC774 \uD655\uC778\uD55C \uACBD\uC6B0\uC5D0\uB9CC --force \uB85C \uBCF4\uD638 \uD30C\uC77C \uAC80\uC0AC\uB97C \uC6B0\uD68C\uD558\uC138\uC694.` : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
protectedFilesMessage
|
|
27
|
+
};
|