agent-work-loop 0.0.0 → 0.6.23
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-46HZN6UB.js +446 -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-C7BR2DCS.js +96 -0
- package/dist/chunk-D5OINC3G.js +52 -0
- package/dist/chunk-DP4O5ME2.js +307 -0
- package/dist/chunk-F5LHXBH7.js +209 -0
- package/dist/chunk-G5LAJ5TV.js +453 -0
- package/dist/chunk-I77CXOEX.js +693 -0
- package/dist/chunk-IMB46O6S.js +286 -0
- package/dist/chunk-IXMAFR4Y.js +771 -0
- package/dist/chunk-QE2CLNBG.js +347 -0
- package/dist/chunk-UOPWVM2H.js +727 -0
- package/dist/chunk-YTAHVR4P.js +166 -0
- package/dist/chunk-ZE6HXOYG.js +904 -0
- package/dist/cli.js +374 -13
- package/dist/commit-APXIVOSD.js +411 -0
- package/dist/config-TFMW7O4T.js +34 -0
- package/dist/doctor-SSKNLPGH.js +29 -0
- package/dist/evolve-QPD7TWGO.js +38 -0
- package/dist/feedback-KAXNFMUY.js +125 -0
- package/dist/gotchas-MCA5Y76R.js +43 -0
- package/dist/hold-recheck-WN5EG7HD.js +133 -0
- package/dist/init-UDM5AXKI.js +79 -0
- package/dist/lane-DAZISODH.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-ZTHDJ47V.js +118 -0
- package/dist/rules-R2UZPIVW.js +33 -0
- package/dist/state-XM7NZ2HA.js +37 -0
- package/dist/status-L6U5KO6T.js +40 -0
- package/dist/uninstall-5DFEOFL5.js +545 -0
- package/dist/update-AYTBYAHI.js +61 -0
- package/dist/verify-L7ARTK42.js +37 -0
- package/dist/version-check-LKGU2DNF.js +14 -0
- package/dist/work-KEPTGZ6H.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 +89 -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 +10 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pipelineLanes
|
|
3
|
+
} from "./chunk-46HZN6UB.js";
|
|
4
|
+
import "./chunk-DP4O5ME2.js";
|
|
5
|
+
import "./chunk-ZE6HXOYG.js";
|
|
6
|
+
import "./chunk-D5OINC3G.js";
|
|
7
|
+
import "./chunk-QE2CLNBG.js";
|
|
8
|
+
import "./chunk-6E7XEQOH.js";
|
|
9
|
+
import "./chunk-IXMAFR4Y.js";
|
|
10
|
+
import "./chunk-C7BR2DCS.js";
|
|
11
|
+
import "./chunk-YTAHVR4P.js";
|
|
12
|
+
import "./chunk-IMB46O6S.js";
|
|
13
|
+
import "./chunk-G5LAJ5TV.js";
|
|
14
|
+
import "./chunk-F5LHXBH7.js";
|
|
15
|
+
import "./chunk-I77CXOEX.js";
|
|
16
|
+
import "./chunk-4OCSYHYB.js";
|
|
17
|
+
import {
|
|
18
|
+
resolveProjectRoot
|
|
19
|
+
} from "./chunk-UOPWVM2H.js";
|
|
20
|
+
import "./chunk-BUWGQVHT.js";
|
|
21
|
+
import {
|
|
22
|
+
caps,
|
|
23
|
+
card,
|
|
24
|
+
makeColors,
|
|
25
|
+
signal
|
|
26
|
+
} from "./chunk-7SYRDDTX.js";
|
|
27
|
+
|
|
28
|
+
// src/commands/hold-recheck.ts
|
|
29
|
+
import fs from "fs";
|
|
30
|
+
import path from "path";
|
|
31
|
+
var HOLD_SUFFIX = ".hold.md";
|
|
32
|
+
var CONDITION_MARKER_RE = /un-hold\s*조건/i;
|
|
33
|
+
var DEP_ID_RE = /[a-z][a-z0-9]*(?:-[a-z0-9]+)+/g;
|
|
34
|
+
function parseHoldDependencies(content) {
|
|
35
|
+
const marker = CONDITION_MARKER_RE.exec(content);
|
|
36
|
+
if (!marker) {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const afterMarker = content.slice(marker.index + marker[0].length);
|
|
40
|
+
let clause = "";
|
|
41
|
+
for (const rawLine of afterMarker.split("\n")) {
|
|
42
|
+
const line = rawLine.replace(/^[*#\s::]+/, "").trim();
|
|
43
|
+
if (line.length > 0) {
|
|
44
|
+
clause = line;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (!clause) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const ids = clause.match(DEP_ID_RE) ?? [];
|
|
52
|
+
return [...new Set(ids)];
|
|
53
|
+
}
|
|
54
|
+
function readDirNames(dir) {
|
|
55
|
+
try {
|
|
56
|
+
return fs.readdirSync(dir);
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function recheckHolds(root) {
|
|
62
|
+
const planDir = path.join(root, ".tasks", "plan");
|
|
63
|
+
const execDir = path.join(root, ".tasks", "exec");
|
|
64
|
+
const reviewDir = path.join(root, ".tasks", "review");
|
|
65
|
+
const planFiles = readDirNames(planDir);
|
|
66
|
+
const execFiles = readDirNames(execDir);
|
|
67
|
+
const reviewFiles = readDirNames(reviewDir);
|
|
68
|
+
const lanes = pipelineLanes(planFiles, execFiles, reviewFiles);
|
|
69
|
+
const landed = (id) => lanes.find((l) => l.name === id)?.status === "complete";
|
|
70
|
+
const unheld = [];
|
|
71
|
+
const kept = [];
|
|
72
|
+
for (const file of planFiles) {
|
|
73
|
+
if (!file.endsWith(HOLD_SUFFIX)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const name = file.slice(0, -HOLD_SUFFIX.length);
|
|
77
|
+
const fullPath = path.join(planDir, file);
|
|
78
|
+
const content = fs.readFileSync(fullPath, "utf8");
|
|
79
|
+
const deps = parseHoldDependencies(content);
|
|
80
|
+
if (deps.length === 0) {
|
|
81
|
+
kept.push({ name, reason: "no-condition" });
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const waitingOn = deps.filter((d) => !landed(d));
|
|
85
|
+
if (waitingOn.length > 0) {
|
|
86
|
+
kept.push({ name, reason: "unsatisfied", waitingOn });
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
fs.renameSync(fullPath, path.join(planDir, `${name}.md`));
|
|
90
|
+
unheld.push(name);
|
|
91
|
+
}
|
|
92
|
+
unheld.sort();
|
|
93
|
+
return { unheld, kept };
|
|
94
|
+
}
|
|
95
|
+
async function runHoldRecheck(opts) {
|
|
96
|
+
const root = resolveProjectRoot();
|
|
97
|
+
if (!root) {
|
|
98
|
+
const cc = caps();
|
|
99
|
+
process.stderr.write(
|
|
100
|
+
`
|
|
101
|
+
${signal(cc, "error")} \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.
|
|
102
|
+
awl init \uC744 \uC2E4\uD589\uD558\uC138\uC694.
|
|
103
|
+
`
|
|
104
|
+
);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
const result = recheckHolds(root);
|
|
108
|
+
if (opts.json) {
|
|
109
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
110
|
+
`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const c = caps();
|
|
114
|
+
const color = makeColors(c.color);
|
|
115
|
+
const lines = [];
|
|
116
|
+
if (result.unheld.length === 0 && result.kept.length === 0) {
|
|
117
|
+
lines.push("\uC7AC\uC810\uAC80\uD560 hold \uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
118
|
+
}
|
|
119
|
+
for (const name of result.unheld) {
|
|
120
|
+
lines.push(`${signal(c, "ok")} ${color.bold(name)} un-hold (\uC758\uC874 \uCC29\uC9C0+\uD569\uACA9)`);
|
|
121
|
+
}
|
|
122
|
+
for (const k of result.kept) {
|
|
123
|
+
const why = k.reason === "no-condition" ? "\uD328\uD134 \uC5C6\uC74C(\uC804\uB7B5\uBB38\uC11C \uB4F1)" : `\uB300\uAE30: ${(k.waitingOn ?? []).join(", ")}`;
|
|
124
|
+
lines.push(`${signal(c, "warn")} ${color.dim(k.name)} hold \uC720\uC9C0 ${color.dim(`(${why})`)}`);
|
|
125
|
+
}
|
|
126
|
+
process.stdout.write(`${card("hold \uC7AC\uC810\uAC80", lines, c)}
|
|
127
|
+
`);
|
|
128
|
+
}
|
|
129
|
+
export {
|
|
130
|
+
parseHoldDependencies,
|
|
131
|
+
recheckHolds,
|
|
132
|
+
runHoldRecheck
|
|
133
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LANG_OPTIONS,
|
|
3
|
+
LANG_VALUES,
|
|
4
|
+
applyInit,
|
|
5
|
+
applyVerifyCwd,
|
|
6
|
+
ask,
|
|
7
|
+
buildConfig,
|
|
8
|
+
buildScreens,
|
|
9
|
+
claudeSkillLabel,
|
|
10
|
+
detectAgents,
|
|
11
|
+
detectLanguage,
|
|
12
|
+
detectVerify,
|
|
13
|
+
detectWorkspacePackages,
|
|
14
|
+
ensureGitignore,
|
|
15
|
+
installClaudeSkill,
|
|
16
|
+
installCodexSkill,
|
|
17
|
+
installSafetyHook,
|
|
18
|
+
isGlobalInstalled,
|
|
19
|
+
nonInteractiveInputs,
|
|
20
|
+
packageEngineDir,
|
|
21
|
+
promptNumber,
|
|
22
|
+
promptVerifyLocation,
|
|
23
|
+
registerProject,
|
|
24
|
+
renderNonTtyNotice,
|
|
25
|
+
renderResult,
|
|
26
|
+
resolveProjectChoice,
|
|
27
|
+
runInit,
|
|
28
|
+
scaffoldGlobal,
|
|
29
|
+
scanGitProjects,
|
|
30
|
+
selectMulti,
|
|
31
|
+
selectSingle,
|
|
32
|
+
skillsVersionPath,
|
|
33
|
+
splitEnv,
|
|
34
|
+
syncExistingInstall,
|
|
35
|
+
verifyStepLines,
|
|
36
|
+
writeConfig,
|
|
37
|
+
writeSkillsVersionStamp,
|
|
38
|
+
writeState
|
|
39
|
+
} from "./chunk-BUWGQVHT.js";
|
|
40
|
+
import "./chunk-7SYRDDTX.js";
|
|
41
|
+
export {
|
|
42
|
+
LANG_OPTIONS,
|
|
43
|
+
LANG_VALUES,
|
|
44
|
+
applyInit,
|
|
45
|
+
applyVerifyCwd,
|
|
46
|
+
ask,
|
|
47
|
+
buildConfig,
|
|
48
|
+
buildScreens,
|
|
49
|
+
claudeSkillLabel,
|
|
50
|
+
detectAgents,
|
|
51
|
+
detectLanguage,
|
|
52
|
+
detectVerify,
|
|
53
|
+
detectWorkspacePackages,
|
|
54
|
+
ensureGitignore,
|
|
55
|
+
installClaudeSkill,
|
|
56
|
+
installCodexSkill,
|
|
57
|
+
installSafetyHook,
|
|
58
|
+
isGlobalInstalled,
|
|
59
|
+
nonInteractiveInputs,
|
|
60
|
+
packageEngineDir,
|
|
61
|
+
promptNumber,
|
|
62
|
+
promptVerifyLocation,
|
|
63
|
+
registerProject,
|
|
64
|
+
renderNonTtyNotice,
|
|
65
|
+
renderResult,
|
|
66
|
+
resolveProjectChoice,
|
|
67
|
+
runInit,
|
|
68
|
+
scaffoldGlobal,
|
|
69
|
+
scanGitProjects,
|
|
70
|
+
selectMulti,
|
|
71
|
+
selectSingle,
|
|
72
|
+
skillsVersionPath,
|
|
73
|
+
splitEnv,
|
|
74
|
+
syncExistingInstall,
|
|
75
|
+
verifyStepLines,
|
|
76
|
+
writeConfig,
|
|
77
|
+
writeSkillsVersionStamp,
|
|
78
|
+
writeState
|
|
79
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WORKTREES_DIR,
|
|
3
|
+
branchOf,
|
|
4
|
+
collectLanes,
|
|
5
|
+
laneBranchMap,
|
|
6
|
+
parseWorktreeBranches,
|
|
7
|
+
renderLaneList,
|
|
8
|
+
runLaneList,
|
|
9
|
+
runLaneNew,
|
|
10
|
+
runLaneRemove,
|
|
11
|
+
unmergedCommitCount,
|
|
12
|
+
worktreeUntracked
|
|
13
|
+
} from "./chunk-DP4O5ME2.js";
|
|
14
|
+
import "./chunk-ZE6HXOYG.js";
|
|
15
|
+
import "./chunk-D5OINC3G.js";
|
|
16
|
+
import "./chunk-QE2CLNBG.js";
|
|
17
|
+
import "./chunk-6E7XEQOH.js";
|
|
18
|
+
import "./chunk-IXMAFR4Y.js";
|
|
19
|
+
import "./chunk-C7BR2DCS.js";
|
|
20
|
+
import "./chunk-YTAHVR4P.js";
|
|
21
|
+
import "./chunk-IMB46O6S.js";
|
|
22
|
+
import "./chunk-G5LAJ5TV.js";
|
|
23
|
+
import "./chunk-F5LHXBH7.js";
|
|
24
|
+
import "./chunk-I77CXOEX.js";
|
|
25
|
+
import "./chunk-4OCSYHYB.js";
|
|
26
|
+
import "./chunk-UOPWVM2H.js";
|
|
27
|
+
import "./chunk-BUWGQVHT.js";
|
|
28
|
+
import "./chunk-7SYRDDTX.js";
|
|
29
|
+
export {
|
|
30
|
+
WORKTREES_DIR,
|
|
31
|
+
branchOf,
|
|
32
|
+
collectLanes,
|
|
33
|
+
laneBranchMap,
|
|
34
|
+
parseWorktreeBranches,
|
|
35
|
+
renderLaneList,
|
|
36
|
+
runLaneList,
|
|
37
|
+
runLaneNew,
|
|
38
|
+
runLaneRemove,
|
|
39
|
+
unmergedCommitCount,
|
|
40
|
+
worktreeUntracked
|
|
41
|
+
};
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeCostDelta,
|
|
3
|
+
readCostSnapshot
|
|
4
|
+
} from "./chunk-D5OINC3G.js";
|
|
5
|
+
import {
|
|
6
|
+
computeDurationMs,
|
|
7
|
+
fmtDuration,
|
|
8
|
+
loadGenerations
|
|
9
|
+
} from "./chunk-F5LHXBH7.js";
|
|
10
|
+
import {
|
|
11
|
+
collectDeferred,
|
|
12
|
+
readRecords
|
|
13
|
+
} from "./chunk-I77CXOEX.js";
|
|
14
|
+
import {
|
|
15
|
+
loadState
|
|
16
|
+
} from "./chunk-4OCSYHYB.js";
|
|
17
|
+
import {
|
|
18
|
+
requireConfig
|
|
19
|
+
} from "./chunk-UOPWVM2H.js";
|
|
20
|
+
import "./chunk-BUWGQVHT.js";
|
|
21
|
+
import {
|
|
22
|
+
caps,
|
|
23
|
+
card,
|
|
24
|
+
makeColors,
|
|
25
|
+
padEndDisplay
|
|
26
|
+
} from "./chunk-7SYRDDTX.js";
|
|
27
|
+
|
|
28
|
+
// src/commands/loop-summary.ts
|
|
29
|
+
function gateAuto(rec) {
|
|
30
|
+
return typeof rec.auto === "boolean" ? rec.auto : void 0;
|
|
31
|
+
}
|
|
32
|
+
function computeInterventionLens(records) {
|
|
33
|
+
const gates = records.filter((r) => r.type === "gate");
|
|
34
|
+
const autonomous = gates.filter((r) => gateAuto(r) === true).length;
|
|
35
|
+
const humanGateCount = gates.length - autonomous;
|
|
36
|
+
const deferCount = collectDeferred(records).length;
|
|
37
|
+
const humanInterventions = humanGateCount + deferCount;
|
|
38
|
+
const total = autonomous + humanInterventions;
|
|
39
|
+
const unmannedRate = total > 0 ? Math.round(autonomous / total * 100) : void 0;
|
|
40
|
+
return { autonomous, humanInterventions, humanGateCount, deferCount, unmannedRate };
|
|
41
|
+
}
|
|
42
|
+
function computeQualityLens(records, criteria) {
|
|
43
|
+
const reviews = records.filter((r) => r.type === "review");
|
|
44
|
+
const reviewRejects = reviews.filter(
|
|
45
|
+
(r) => Array.isArray(r.findings) && r.findings.length > 0
|
|
46
|
+
).length;
|
|
47
|
+
const blocked = records.filter((r) => r.type === "blocked").length;
|
|
48
|
+
const num = (v) => typeof v === "number" ? v : 0;
|
|
49
|
+
const total = criteria.length;
|
|
50
|
+
const implementationFailures = criteria.reduce((s, c) => s + num(c.attempts), 0);
|
|
51
|
+
const proceduralErrors = criteria.reduce((s, c) => s + num(c.proceduralErrors), 0);
|
|
52
|
+
const avgAttempts = total > 0 ? Math.round(implementationFailures / total * 100) / 100 : 0;
|
|
53
|
+
return {
|
|
54
|
+
reviewCount: reviews.length,
|
|
55
|
+
reviewRejects,
|
|
56
|
+
blocked,
|
|
57
|
+
avgAttempts,
|
|
58
|
+
implementationFailures,
|
|
59
|
+
proceduralErrors
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function computeEfficiencyLens(records, costDelta) {
|
|
63
|
+
const ats = records.map((r) => typeof r.at === "string" ? r.at : "").filter((s) => s !== "").sort();
|
|
64
|
+
const gate1 = records.find((r) => r.type === "gate" && r.gate === 1);
|
|
65
|
+
const start = gate1 && typeof gate1.at === "string" ? gate1.at : ats[0];
|
|
66
|
+
const end = ats.length > 0 ? ats[ats.length - 1] : void 0;
|
|
67
|
+
const durationMs = start !== void 0 && end !== void 0 ? computeDurationMs(start, end) : void 0;
|
|
68
|
+
return { durationMs, costDelta };
|
|
69
|
+
}
|
|
70
|
+
function computeOutputLens(records, criteria) {
|
|
71
|
+
const passedCriteria = criteria.filter((c) => c.status === "passed").length;
|
|
72
|
+
const commitHashes = new Set(
|
|
73
|
+
criteria.map((c) => c.commit).filter((h) => typeof h === "string" && h.length > 0)
|
|
74
|
+
);
|
|
75
|
+
const gotchaApplied = records.filter((r) => r.type === "gotcha-applied").length;
|
|
76
|
+
const gotchaMissed = records.filter((r) => r.type === "gotcha-missed").length;
|
|
77
|
+
const gate1 = records.find((r) => r.type === "gate" && r.gate === 1);
|
|
78
|
+
const exclusions = gate1 && Array.isArray(gate1.presentedExclusions) ? gate1.presentedExclusions.length : 0;
|
|
79
|
+
return {
|
|
80
|
+
passedCriteria,
|
|
81
|
+
totalCriteria: criteria.length,
|
|
82
|
+
commits: commitHashes.size,
|
|
83
|
+
gotchaApplied,
|
|
84
|
+
gotchaMissed,
|
|
85
|
+
exclusions
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function assembleLoopSummary(workitem, records, criteria, costDelta) {
|
|
89
|
+
return {
|
|
90
|
+
workitem,
|
|
91
|
+
hasRecords: records.length > 0,
|
|
92
|
+
intervention: computeInterventionLens(records),
|
|
93
|
+
quality: computeQualityLens(records, criteria),
|
|
94
|
+
efficiency: computeEfficiencyLens(records, costDelta),
|
|
95
|
+
output: computeOutputLens(records, criteria)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
var LABEL_WIDTH = 7;
|
|
99
|
+
function buildSummaryLines(summary) {
|
|
100
|
+
if (!summary.hasRecords) {
|
|
101
|
+
return ["\uAE30\uB85D \uC5C6\uC74C \u2014 record-trail-guard \uCC38\uC870", "\uBE48 0 \uD1B5\uACC4\uB85C \uC624\uB3C4\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."];
|
|
102
|
+
}
|
|
103
|
+
const iv = summary.intervention;
|
|
104
|
+
const rate = iv.unmannedRate !== void 0 ? ` (\uBB34\uC778\uC728 ${iv.unmannedRate}%)` : "";
|
|
105
|
+
const lines = [`\uC0AC\uB78C \uAC1C\uC785 ${iv.humanInterventions} \xB7 \uC790\uC728 ${iv.autonomous}${rate}`];
|
|
106
|
+
lines.push(` \uAC8C\uC774\uD2B8 \uC790\uC728 ${iv.autonomous} \xB7 \uC0AC\uB78C ${iv.humanGateCount} \xB7 defer ${iv.deferCount}`);
|
|
107
|
+
lines.push("");
|
|
108
|
+
const q = summary.quality;
|
|
109
|
+
lines.push(
|
|
110
|
+
`${padEndDisplay("\uD488\uC9C8", LABEL_WIDTH)}\uB9AC\uBDF0 ${q.reviewCount}(\uBC18\uB824 ${q.reviewRejects}) \xB7 blocked ${q.blocked} \xB7 \uD3C9\uADE0\uC2DC\uB3C4/AC ${q.avgAttempts}`
|
|
111
|
+
);
|
|
112
|
+
lines.push(
|
|
113
|
+
`${padEndDisplay("", LABEL_WIDTH)}\uC2E4\uD328 \uC6D0\uC778 \uAD6C\uD604 ${q.implementationFailures} \xB7 \uC808\uCC28 ${q.proceduralErrors} (\uD658\uACBD \uBBF8\uAE30\uB85D)`
|
|
114
|
+
);
|
|
115
|
+
const e = summary.efficiency;
|
|
116
|
+
const eff = [];
|
|
117
|
+
if (e.durationMs !== void 0) {
|
|
118
|
+
eff.push(`\uC18C\uC694 ${fmtDuration(e.durationMs)}`);
|
|
119
|
+
}
|
|
120
|
+
if (e.costDelta !== void 0) {
|
|
121
|
+
eff.push(`\uBE44\uC6A9 ~$${e.costDelta}`);
|
|
122
|
+
}
|
|
123
|
+
lines.push(
|
|
124
|
+
`${padEndDisplay("\uD6A8\uC728", LABEL_WIDTH)}${eff.length > 0 ? eff.join(" \xB7 ") : "\uC2DC\uAC04\xB7\uBE44\uC6A9 \uC18C\uC2A4 \uBD80\uC7AC\uB85C \uC0DD\uB7B5"}`
|
|
125
|
+
);
|
|
126
|
+
const o = summary.output;
|
|
127
|
+
lines.push(
|
|
128
|
+
`${padEndDisplay("\uC0B0\uCD9C", LABEL_WIDTH)}\uC644\uB8CC AC ${o.passedCriteria}/${o.totalCriteria} \xB7 \uACA9\uB9AC\uCEE4\uBC0B ${o.commits} \xB7 gotcha \uC801\uC6A9 ${o.gotchaApplied}/\uB204\uB77D ${o.gotchaMissed} \xB7 \uBC94\uC704\uBC30\uC81C ${o.exclusions}`
|
|
129
|
+
);
|
|
130
|
+
return lines;
|
|
131
|
+
}
|
|
132
|
+
function renderLoopSummary(summary, c) {
|
|
133
|
+
const color = makeColors(c.color);
|
|
134
|
+
const lines = buildSummaryLines(summary);
|
|
135
|
+
const styled = lines.map((ln, i) => {
|
|
136
|
+
if (i === 0) {
|
|
137
|
+
return color.bold(ln);
|
|
138
|
+
}
|
|
139
|
+
if (ln.startsWith(" ")) {
|
|
140
|
+
return color.dim(ln);
|
|
141
|
+
}
|
|
142
|
+
return ln;
|
|
143
|
+
});
|
|
144
|
+
const title = summary.workitem ? `\uC791\uC5C5 \uC644\uB8CC \uC694\uC57D \xB7 ${summary.workitem}` : "\uC791\uC5C5 \uC644\uB8CC \uC694\uC57D";
|
|
145
|
+
return card(title, styled, c);
|
|
146
|
+
}
|
|
147
|
+
function summaryToJson(summary) {
|
|
148
|
+
if (!summary.hasRecords) {
|
|
149
|
+
return {
|
|
150
|
+
workitem: summary.workitem,
|
|
151
|
+
hasRecords: false,
|
|
152
|
+
note: "\uAE30\uB85D \uC5C6\uC74C \u2014 record-trail-guard \uCC38\uC870"
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return summary;
|
|
156
|
+
}
|
|
157
|
+
var round2 = (n) => Math.round(n * 100) / 100;
|
|
158
|
+
var round0 = (n) => Math.round(n);
|
|
159
|
+
function avgDefined(values, round) {
|
|
160
|
+
const defined = values.filter((v) => typeof v === "number");
|
|
161
|
+
return defined.length > 0 ? round(defined.reduce((s, v) => s + v, 0) / defined.length) : void 0;
|
|
162
|
+
}
|
|
163
|
+
function aggregateLoopSummaries(summaries) {
|
|
164
|
+
const n = summaries.length;
|
|
165
|
+
const sum = (f) => summaries.reduce((s, x) => s + f(x), 0);
|
|
166
|
+
const avg = (f) => n > 0 ? round2(sum(f) / n) : 0;
|
|
167
|
+
return {
|
|
168
|
+
count: n,
|
|
169
|
+
intervention: {
|
|
170
|
+
autonomous: sum((s) => s.intervention.autonomous),
|
|
171
|
+
humanInterventions: sum((s) => s.intervention.humanInterventions),
|
|
172
|
+
humanGateCount: sum((s) => s.intervention.humanGateCount),
|
|
173
|
+
deferCount: sum((s) => s.intervention.deferCount),
|
|
174
|
+
unmannedRate: avgDefined(
|
|
175
|
+
summaries.map((s) => s.intervention.unmannedRate),
|
|
176
|
+
round0
|
|
177
|
+
)
|
|
178
|
+
},
|
|
179
|
+
quality: {
|
|
180
|
+
reviewCount: sum((s) => s.quality.reviewCount),
|
|
181
|
+
reviewRejects: sum((s) => s.quality.reviewRejects),
|
|
182
|
+
blocked: sum((s) => s.quality.blocked),
|
|
183
|
+
avgAttempts: avg((s) => s.quality.avgAttempts),
|
|
184
|
+
implementationFailures: sum((s) => s.quality.implementationFailures),
|
|
185
|
+
proceduralErrors: sum((s) => s.quality.proceduralErrors)
|
|
186
|
+
},
|
|
187
|
+
efficiency: {
|
|
188
|
+
durationMs: avgDefined(
|
|
189
|
+
summaries.map((s) => s.efficiency.durationMs),
|
|
190
|
+
round0
|
|
191
|
+
),
|
|
192
|
+
costDelta: avgDefined(
|
|
193
|
+
summaries.map((s) => s.efficiency.costDelta),
|
|
194
|
+
round2
|
|
195
|
+
)
|
|
196
|
+
},
|
|
197
|
+
output: {
|
|
198
|
+
passedCriteria: sum((s) => s.output.passedCriteria),
|
|
199
|
+
totalCriteria: sum((s) => s.output.totalCriteria),
|
|
200
|
+
commits: sum((s) => s.output.commits),
|
|
201
|
+
gotchaApplied: sum((s) => s.output.gotchaApplied),
|
|
202
|
+
gotchaMissed: sum((s) => s.output.gotchaMissed),
|
|
203
|
+
exclusions: sum((s) => s.output.exclusions)
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function buildAggregateLines(agg) {
|
|
208
|
+
const iv = agg.intervention;
|
|
209
|
+
const rate = iv.unmannedRate !== void 0 ? ` (\uBB34\uC778\uC728 \uD3C9\uADE0 ${iv.unmannedRate}%)` : "";
|
|
210
|
+
const lines = [
|
|
211
|
+
`\uC0AC\uB78C \uAC1C\uC785 \uD569 ${iv.humanInterventions} \xB7 \uC790\uC728 \uD569 ${iv.autonomous}${rate}`
|
|
212
|
+
];
|
|
213
|
+
lines.push(` \uAC8C\uC774\uD2B8 \uC790\uC728 ${iv.autonomous} \xB7 \uC0AC\uB78C ${iv.humanGateCount} \xB7 defer ${iv.deferCount}`);
|
|
214
|
+
lines.push("");
|
|
215
|
+
const q = agg.quality;
|
|
216
|
+
lines.push(
|
|
217
|
+
`${padEndDisplay("\uD488\uC9C8", LABEL_WIDTH)}\uB9AC\uBDF0 ${q.reviewCount}(\uBC18\uB824 ${q.reviewRejects}) \xB7 blocked ${q.blocked} \xB7 \uD3C9\uADE0\uC2DC\uB3C4/AC \uD3C9\uADE0 ${q.avgAttempts}`
|
|
218
|
+
);
|
|
219
|
+
lines.push(
|
|
220
|
+
`${padEndDisplay("", LABEL_WIDTH)}\uC2E4\uD328 \uC6D0\uC778 \uD569 \uAD6C\uD604 ${q.implementationFailures} \xB7 \uC808\uCC28 ${q.proceduralErrors}`
|
|
221
|
+
);
|
|
222
|
+
const e = agg.efficiency;
|
|
223
|
+
const eff = [];
|
|
224
|
+
if (e.durationMs !== void 0) {
|
|
225
|
+
eff.push(`\uC18C\uC694 \uD3C9\uADE0 ${fmtDuration(e.durationMs)}`);
|
|
226
|
+
}
|
|
227
|
+
if (e.costDelta !== void 0) {
|
|
228
|
+
eff.push(`\uBE44\uC6A9 \uD3C9\uADE0 ~$${e.costDelta}`);
|
|
229
|
+
}
|
|
230
|
+
lines.push(
|
|
231
|
+
`${padEndDisplay("\uD6A8\uC728", LABEL_WIDTH)}${eff.length > 0 ? eff.join(" \xB7 ") : "\uC2DC\uAC04\xB7\uBE44\uC6A9 \uC18C\uC2A4 \uBD80\uC7AC\uB85C \uC0DD\uB7B5"} (\uCC38\uACE0\uC6A9 \u2014 wall-clock \uC544\uB2D8)`
|
|
232
|
+
);
|
|
233
|
+
const o = agg.output;
|
|
234
|
+
lines.push(
|
|
235
|
+
`${padEndDisplay("\uC0B0\uCD9C", LABEL_WIDTH)}\uC644\uB8CC AC \uD569 ${o.passedCriteria}/${o.totalCriteria} \xB7 \uACA9\uB9AC\uCEE4\uBC0B \uD569 ${o.commits} \xB7 gotcha \uC801\uC6A9 \uD569 ${o.gotchaApplied}/\uB204\uB77D \uD569 ${o.gotchaMissed} \xB7 \uBC94\uC704\uBC30\uC81C \uD569 ${o.exclusions}`
|
|
236
|
+
);
|
|
237
|
+
return lines;
|
|
238
|
+
}
|
|
239
|
+
function renderAggregateLoopSummary(agg, c) {
|
|
240
|
+
const color = makeColors(c.color);
|
|
241
|
+
const lines = buildAggregateLines(agg);
|
|
242
|
+
const styled = lines.map((ln, i) => {
|
|
243
|
+
if (i === 0) {
|
|
244
|
+
return color.bold(ln);
|
|
245
|
+
}
|
|
246
|
+
if (ln.startsWith(" ")) {
|
|
247
|
+
return color.dim(ln);
|
|
248
|
+
}
|
|
249
|
+
return ln;
|
|
250
|
+
});
|
|
251
|
+
return card(`\uC804\uCCB4 \uC9D1\uACC4 \xB7 \uC6CC\uD06C\uC544\uC774\uD15C ${agg.count}\uAC1C`, styled, c);
|
|
252
|
+
}
|
|
253
|
+
function resolveBatchWorkitems(opts, generations) {
|
|
254
|
+
if (opts.workitems && opts.workitems.length > 0) {
|
|
255
|
+
return opts.workitems;
|
|
256
|
+
}
|
|
257
|
+
if (opts.since !== void 0) {
|
|
258
|
+
const sinceMs = Date.parse(opts.since);
|
|
259
|
+
if (Number.isNaN(sinceMs)) {
|
|
260
|
+
return [];
|
|
261
|
+
}
|
|
262
|
+
return generations.filter((g) => {
|
|
263
|
+
const t = Date.parse(g.at);
|
|
264
|
+
return !Number.isNaN(t) && t >= sinceMs;
|
|
265
|
+
}).map((g) => g.workitem);
|
|
266
|
+
}
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
269
|
+
function criteriaFor(state, workitem, current) {
|
|
270
|
+
if (workitem !== null && workitem === current && Array.isArray(state.criteria)) {
|
|
271
|
+
return state.criteria;
|
|
272
|
+
}
|
|
273
|
+
const reg = state.workitems && typeof state.workitems === "object" && !Array.isArray(state.workitems) ? state.workitems : {};
|
|
274
|
+
const entry = workitem !== null ? reg[workitem] : void 0;
|
|
275
|
+
if (entry && Array.isArray(entry.criteria)) {
|
|
276
|
+
return entry.criteria;
|
|
277
|
+
}
|
|
278
|
+
return [];
|
|
279
|
+
}
|
|
280
|
+
function startCostOf(state, workitem, current) {
|
|
281
|
+
if (workitem === null || workitem !== current) {
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
const c = state.costAtStart;
|
|
285
|
+
return c && typeof c === "object" && !Array.isArray(c) ? c : void 0;
|
|
286
|
+
}
|
|
287
|
+
function buildBatchSummaries(ids, state, current, usagePath) {
|
|
288
|
+
const nowSnapshot = readCostSnapshot(usagePath);
|
|
289
|
+
return ids.map((id) => {
|
|
290
|
+
const records = readRecords({ workitem: id });
|
|
291
|
+
const criteria = criteriaFor(state, id, current);
|
|
292
|
+
const costDelta = computeCostDelta(startCostOf(state, id, current), nowSnapshot);
|
|
293
|
+
return assembleLoopSummary(id, records, criteria, costDelta);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
function runLoopSummaryBatch(opts) {
|
|
297
|
+
const { config, projectRoot } = requireConfig();
|
|
298
|
+
const state = loadState(projectRoot);
|
|
299
|
+
const current = typeof state.workitem === "string" ? state.workitem : null;
|
|
300
|
+
const generations = opts.since !== void 0 ? loadGenerations(config.project) : [];
|
|
301
|
+
const ids = resolveBatchWorkitems({ workitems: opts.workitems, since: opts.since }, generations);
|
|
302
|
+
const summaries = buildBatchSummaries(ids, state, current, opts.usagePath);
|
|
303
|
+
const aggregate = aggregateLoopSummaries(summaries);
|
|
304
|
+
if (opts.json) {
|
|
305
|
+
process.stdout.write(
|
|
306
|
+
`${JSON.stringify({ summaries: summaries.map(summaryToJson), aggregate }, null, 2)}
|
|
307
|
+
`
|
|
308
|
+
);
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (summaries.length === 0) {
|
|
312
|
+
process.stdout.write(
|
|
313
|
+
"\uBC30\uCE58 \uB300\uC0C1 \uC6CC\uD06C\uC544\uC774\uD15C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 --workitems \uB610\uB294 --since \uB97C \uD655\uC778\uD558\uC138\uC694.\n"
|
|
314
|
+
);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const c = caps();
|
|
318
|
+
const blocks = summaries.map((s) => renderLoopSummary(s, c)).join("\n");
|
|
319
|
+
process.stdout.write(`${blocks}
|
|
320
|
+
${renderAggregateLoopSummary(aggregate, c)}
|
|
321
|
+
`);
|
|
322
|
+
}
|
|
323
|
+
function runLoopSummary(opts) {
|
|
324
|
+
if (opts.workitems && opts.workitems.length > 0 || opts.since !== void 0) {
|
|
325
|
+
runLoopSummaryBatch(opts);
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const { projectRoot } = requireConfig();
|
|
329
|
+
const state = loadState(projectRoot);
|
|
330
|
+
const current = typeof state.workitem === "string" ? state.workitem : null;
|
|
331
|
+
const workitem = opts.workitem ?? current;
|
|
332
|
+
const records = workitem ? readRecords({ workitem }) : [];
|
|
333
|
+
const criteria = criteriaFor(state, workitem, current);
|
|
334
|
+
const costDelta = computeCostDelta(
|
|
335
|
+
startCostOf(state, workitem, current),
|
|
336
|
+
readCostSnapshot(opts.usagePath)
|
|
337
|
+
);
|
|
338
|
+
const summary = assembleLoopSummary(workitem, records, criteria, costDelta);
|
|
339
|
+
if (opts.json) {
|
|
340
|
+
process.stdout.write(`${JSON.stringify(summaryToJson(summary), null, 2)}
|
|
341
|
+
`);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
process.stdout.write(`${renderLoopSummary(summary, caps())}
|
|
345
|
+
`);
|
|
346
|
+
}
|
|
347
|
+
export {
|
|
348
|
+
aggregateLoopSummaries,
|
|
349
|
+
assembleLoopSummary,
|
|
350
|
+
buildAggregateLines,
|
|
351
|
+
buildSummaryLines,
|
|
352
|
+
computeEfficiencyLens,
|
|
353
|
+
computeInterventionLens,
|
|
354
|
+
computeOutputLens,
|
|
355
|
+
computeQualityLens,
|
|
356
|
+
renderAggregateLoopSummary,
|
|
357
|
+
renderLoopSummary,
|
|
358
|
+
resolveBatchWorkitems,
|
|
359
|
+
runLoopSummary,
|
|
360
|
+
summaryToJson
|
|
361
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeDurationMs,
|
|
3
|
+
experimentKey,
|
|
4
|
+
fmtDuration,
|
|
5
|
+
groupByExperiment,
|
|
6
|
+
loadGenerations,
|
|
7
|
+
renderCompare,
|
|
8
|
+
renderMetrics,
|
|
9
|
+
renderMetricsCaveat,
|
|
10
|
+
runMetrics
|
|
11
|
+
} from "./chunk-F5LHXBH7.js";
|
|
12
|
+
import "./chunk-UOPWVM2H.js";
|
|
13
|
+
import "./chunk-BUWGQVHT.js";
|
|
14
|
+
import "./chunk-7SYRDDTX.js";
|
|
15
|
+
export {
|
|
16
|
+
computeDurationMs,
|
|
17
|
+
experimentKey,
|
|
18
|
+
fmtDuration,
|
|
19
|
+
groupByExperiment,
|
|
20
|
+
loadGenerations,
|
|
21
|
+
renderCompare,
|
|
22
|
+
renderMetrics,
|
|
23
|
+
renderMetricsCaveat,
|
|
24
|
+
runMetrics
|
|
25
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AWL_FEEDBACK_AREAS,
|
|
3
|
+
AWL_FEEDBACK_SEVERITIES,
|
|
4
|
+
BANNED_QUALITATIVE_WORDS,
|
|
5
|
+
DEFER_SEVERITIES,
|
|
6
|
+
GATE1_DECISIONS,
|
|
7
|
+
GATE2_DECISIONS,
|
|
8
|
+
NARRATIVE_KINDS,
|
|
9
|
+
RECORD_TYPES,
|
|
10
|
+
REFACTOR_KINDS,
|
|
11
|
+
SCHEMAS,
|
|
12
|
+
appendRecord,
|
|
13
|
+
buildRecord,
|
|
14
|
+
captureDiff,
|
|
15
|
+
collectDeferred,
|
|
16
|
+
computeCoverage,
|
|
17
|
+
detailTierFor,
|
|
18
|
+
hasApprovedGate1,
|
|
19
|
+
loadProjectName,
|
|
20
|
+
measureDiffSize,
|
|
21
|
+
monthFile,
|
|
22
|
+
newRecordId,
|
|
23
|
+
readRecords,
|
|
24
|
+
renderDeferSummary,
|
|
25
|
+
renderRecords,
|
|
26
|
+
resolveBlockedBaseline,
|
|
27
|
+
runDeferSummary,
|
|
28
|
+
runRecord,
|
|
29
|
+
runRecords,
|
|
30
|
+
selectMonthFiles,
|
|
31
|
+
shouldDefer
|
|
32
|
+
} from "./chunk-I77CXOEX.js";
|
|
33
|
+
import "./chunk-4OCSYHYB.js";
|
|
34
|
+
import "./chunk-UOPWVM2H.js";
|
|
35
|
+
import "./chunk-BUWGQVHT.js";
|
|
36
|
+
import "./chunk-7SYRDDTX.js";
|
|
37
|
+
export {
|
|
38
|
+
AWL_FEEDBACK_AREAS,
|
|
39
|
+
AWL_FEEDBACK_SEVERITIES,
|
|
40
|
+
BANNED_QUALITATIVE_WORDS,
|
|
41
|
+
DEFER_SEVERITIES,
|
|
42
|
+
GATE1_DECISIONS,
|
|
43
|
+
GATE2_DECISIONS,
|
|
44
|
+
NARRATIVE_KINDS,
|
|
45
|
+
RECORD_TYPES,
|
|
46
|
+
REFACTOR_KINDS,
|
|
47
|
+
SCHEMAS,
|
|
48
|
+
appendRecord,
|
|
49
|
+
buildRecord,
|
|
50
|
+
captureDiff,
|
|
51
|
+
collectDeferred,
|
|
52
|
+
computeCoverage,
|
|
53
|
+
detailTierFor,
|
|
54
|
+
hasApprovedGate1,
|
|
55
|
+
loadProjectName,
|
|
56
|
+
measureDiffSize,
|
|
57
|
+
monthFile,
|
|
58
|
+
newRecordId,
|
|
59
|
+
readRecords,
|
|
60
|
+
renderDeferSummary,
|
|
61
|
+
renderRecords,
|
|
62
|
+
resolveBlockedBaseline,
|
|
63
|
+
runDeferSummary,
|
|
64
|
+
runRecord,
|
|
65
|
+
runRecords,
|
|
66
|
+
selectMonthFiles,
|
|
67
|
+
shouldDefer
|
|
68
|
+
};
|