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,166 @@
|
|
|
1
|
+
import {
|
|
2
|
+
npmVersionCachePath
|
|
3
|
+
} from "./chunk-7SYRDDTX.js";
|
|
4
|
+
|
|
5
|
+
// package.json
|
|
6
|
+
var name = "agent-work-loop";
|
|
7
|
+
var version = "0.6.22";
|
|
8
|
+
|
|
9
|
+
// src/core/npm-registry.ts
|
|
10
|
+
import fs from "fs";
|
|
11
|
+
import path from "path";
|
|
12
|
+
var REGISTRY_URL = "https://registry.npmjs.org";
|
|
13
|
+
var FETCH_TIMEOUT_MS = 2e3;
|
|
14
|
+
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
15
|
+
async function fetchLatestVersion(packageName, fetchImpl = fetch) {
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
18
|
+
try {
|
|
19
|
+
const res = await fetchImpl(`${REGISTRY_URL}/${packageName}/latest`, {
|
|
20
|
+
signal: controller.signal
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const body = await res.json();
|
|
26
|
+
if (body && typeof body === "object") {
|
|
27
|
+
const v = body.version;
|
|
28
|
+
if (typeof v === "string") {
|
|
29
|
+
return v;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
} finally {
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function readCache() {
|
|
40
|
+
try {
|
|
41
|
+
const raw = JSON.parse(fs.readFileSync(npmVersionCachePath(), "utf8"));
|
|
42
|
+
if (raw && typeof raw === "object") {
|
|
43
|
+
const checkedAt = raw.checkedAt;
|
|
44
|
+
const latestVersion = raw.latestVersion;
|
|
45
|
+
if (typeof checkedAt === "string" && (typeof latestVersion === "string" || latestVersion === null)) {
|
|
46
|
+
return { checkedAt, latestVersion };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
function writeCache(cache) {
|
|
54
|
+
const p = npmVersionCachePath();
|
|
55
|
+
const tmp = `${p}.${process.pid}.tmp`;
|
|
56
|
+
try {
|
|
57
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
58
|
+
fs.writeFileSync(tmp, JSON.stringify(cache));
|
|
59
|
+
fs.renameSync(tmp, p);
|
|
60
|
+
} catch {
|
|
61
|
+
try {
|
|
62
|
+
fs.unlinkSync(tmp);
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function getLatestVersionCached(packageName, opts = {}) {
|
|
68
|
+
const now = opts.now ?? (() => Date.now());
|
|
69
|
+
const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
70
|
+
const cached = readCache();
|
|
71
|
+
if (cached && now() - new Date(cached.checkedAt).getTime() < ttlMs) {
|
|
72
|
+
return cached.latestVersion;
|
|
73
|
+
}
|
|
74
|
+
const latestVersion = await fetchLatestVersion(packageName, opts.fetchImpl ?? fetch);
|
|
75
|
+
writeCache({ checkedAt: new Date(now()).toISOString(), latestVersion });
|
|
76
|
+
return latestVersion;
|
|
77
|
+
}
|
|
78
|
+
function readCachedLatestVersion() {
|
|
79
|
+
return readCache()?.latestVersion ?? null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/core/versions.ts
|
|
83
|
+
var UPDATE_HINT = "npm i -g agent-work-loop@latest \uB85C \uAC31\uC2E0\uD558\uC138\uC694.";
|
|
84
|
+
function parseSemver(version2) {
|
|
85
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(version2);
|
|
86
|
+
if (!m) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
90
|
+
}
|
|
91
|
+
function isNewerSemver(a, b) {
|
|
92
|
+
if (a[0] !== b[0]) return a[0] > b[0];
|
|
93
|
+
if (a[1] !== b[1]) return a[1] > b[1];
|
|
94
|
+
if (a[2] !== b[2]) return a[2] > b[2];
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
function computeUpdateAvailable(current, npmLatestVersion) {
|
|
98
|
+
if (npmLatestVersion === null) {
|
|
99
|
+
return void 0;
|
|
100
|
+
}
|
|
101
|
+
const latestParsed = parseSemver(npmLatestVersion);
|
|
102
|
+
const currentParsed = parseSemver(current);
|
|
103
|
+
if (latestParsed === null || currentParsed === null) {
|
|
104
|
+
return void 0;
|
|
105
|
+
}
|
|
106
|
+
if (!isNewerSemver(latestParsed, currentParsed)) {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
return { current, latest: npmLatestVersion, hint: UPDATE_HINT };
|
|
110
|
+
}
|
|
111
|
+
var SKILL_LABELS = {
|
|
112
|
+
claude: "Claude",
|
|
113
|
+
codex: "Codex"
|
|
114
|
+
};
|
|
115
|
+
function checkVersions(inputs) {
|
|
116
|
+
const mismatches = [];
|
|
117
|
+
if (inputs.engineSourceVersion !== null && inputs.engineSourceVersion !== inputs.packageVersion) {
|
|
118
|
+
mismatches.push({
|
|
119
|
+
kind: "build",
|
|
120
|
+
a: inputs.packageVersion,
|
|
121
|
+
b: inputs.engineSourceVersion,
|
|
122
|
+
hint: "package.json \uACFC engine/version.json \uBC84\uC804\uC774 \uB2E4\uB985\uB2C8\uB2E4 \u2014 \uC124\uCE58\uAC00 \uC190\uC0C1\uB410\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uC7AC\uC124\uCE58\uD558\uC138\uC694."
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (inputs.installedEngineVersion !== null && inputs.installedEngineVersion !== inputs.packageVersion) {
|
|
126
|
+
mismatches.push({
|
|
127
|
+
kind: "binary-vs-engine",
|
|
128
|
+
a: inputs.packageVersion,
|
|
129
|
+
b: inputs.installedEngineVersion,
|
|
130
|
+
hint: "\uC124\uCE58\uB41C \uC5D4\uC9C4(~/.awl/engine)\uC774 \uC2E4\uD589 \uBC14\uC774\uB108\uB9AC\uC640 \uB2E4\uB985\uB2C8\uB2E4. awl update \uB85C \uC5D4\uC9C4\uC744 \uAC31\uC2E0\uD558\uC138\uC694."
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (inputs.projectEngineVersion !== null && inputs.installedEngineVersion !== null && inputs.projectEngineVersion !== inputs.installedEngineVersion) {
|
|
134
|
+
mismatches.push({
|
|
135
|
+
kind: "project-vs-engine",
|
|
136
|
+
a: inputs.projectEngineVersion,
|
|
137
|
+
b: inputs.installedEngineVersion,
|
|
138
|
+
hint: `\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 ${inputs.projectEngineVersion} \uAE30\uC900\uC73C\uB85C \uC124\uC815\uB410\uC73C\uB098 \uC5D4\uC9C4\uC740 ${inputs.installedEngineVersion}\uC785\uB2C8\uB2E4. awl init --yes \uB85C \uD504\uB85C\uC81D\uD2B8\xB7\uC2A4\uD0AC \uBC84\uC804\uC744 \uC5D4\uC9C4\uC5D0 \uB9DE\uCDB0 \uB3D9\uAE30\uD654\uD558\uC138\uC694.`
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
for (const skill of ["claude", "codex"]) {
|
|
142
|
+
const skillVersion = inputs.installedSkillVersions[skill];
|
|
143
|
+
if (skillVersion !== null && inputs.installedEngineVersion !== null && skillVersion !== inputs.installedEngineVersion) {
|
|
144
|
+
mismatches.push({
|
|
145
|
+
kind: `${skill}-skill-vs-engine`,
|
|
146
|
+
a: skillVersion,
|
|
147
|
+
b: inputs.installedEngineVersion,
|
|
148
|
+
hint: `\uC124\uCE58\uB41C ${SKILL_LABELS[skill]} \uC2A4\uD0AC\uC774 ${skillVersion} \uAE30\uC900\uC785\uB2C8\uB2E4. \uC5D4\uC9C4\uC740 ${inputs.installedEngineVersion}\uC785\uB2C8\uB2E4. awl init --yes \uB85C \uC2A4\uD0AC\uC744 \uC7AC\uC124\uCE58\xB7\uB3D9\uAE30\uD654\uD558\uC138\uC694.`
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
ok: mismatches.length === 0,
|
|
154
|
+
mismatches,
|
|
155
|
+
updateAvailable: computeUpdateAvailable(inputs.packageVersion, inputs.npmLatestVersion)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export {
|
|
160
|
+
name,
|
|
161
|
+
version,
|
|
162
|
+
getLatestVersionCached,
|
|
163
|
+
readCachedLatestVersion,
|
|
164
|
+
computeUpdateAvailable,
|
|
165
|
+
checkVersions
|
|
166
|
+
};
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import {
|
|
2
|
+
mergeIsolatedHome,
|
|
3
|
+
removeGitWorktree,
|
|
4
|
+
removeWorkitemFromState,
|
|
5
|
+
runWorkNew,
|
|
6
|
+
sanitizeForGit,
|
|
7
|
+
worktreeDirtyTracked
|
|
8
|
+
} from "./chunk-LMWAVN7B.js";
|
|
9
|
+
import {
|
|
10
|
+
loadState,
|
|
11
|
+
writeState
|
|
12
|
+
} from "./chunk-4OCSYHYB.js";
|
|
13
|
+
import {
|
|
14
|
+
resolveProjectRoot,
|
|
15
|
+
run
|
|
16
|
+
} from "./chunk-UOPWVM2H.js";
|
|
17
|
+
import {
|
|
18
|
+
caps,
|
|
19
|
+
card,
|
|
20
|
+
feedback,
|
|
21
|
+
makeColors,
|
|
22
|
+
signal
|
|
23
|
+
} from "./chunk-7SYRDDTX.js";
|
|
24
|
+
|
|
25
|
+
// src/commands/lane.ts
|
|
26
|
+
import fs from "fs";
|
|
27
|
+
import path from "path";
|
|
28
|
+
var WORKTREES_DIR = ".awl-worktrees";
|
|
29
|
+
var PIPELINE_TRIGGERS = ["/awl-pipeline-plan", "/awl-pipeline-exec", "/awl-pipeline-review"];
|
|
30
|
+
function requireRoot() {
|
|
31
|
+
const root = resolveProjectRoot();
|
|
32
|
+
if (!root) {
|
|
33
|
+
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");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
return root;
|
|
37
|
+
}
|
|
38
|
+
async function isGitWorkTree(root) {
|
|
39
|
+
const r = await run({
|
|
40
|
+
cmd: "git",
|
|
41
|
+
args: ["rev-parse", "--is-inside-work-tree"],
|
|
42
|
+
cwd: root,
|
|
43
|
+
timeoutMs: 1e4
|
|
44
|
+
});
|
|
45
|
+
return r.exitCode === 0 && r.stdout.trim() === "true";
|
|
46
|
+
}
|
|
47
|
+
async function runLaneNew(name, description) {
|
|
48
|
+
const root = requireRoot();
|
|
49
|
+
const c = caps();
|
|
50
|
+
const color = makeColors(c.color);
|
|
51
|
+
if (!await isGitWorkTree(root)) {
|
|
52
|
+
process.stderr.write(
|
|
53
|
+
`
|
|
54
|
+
${feedback(c, "error", "\uB808\uC778\uC744 \uB9CC\uB4E4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4", "\uD604\uC7AC \uC704\uCE58\uAC00 git \uC800\uC7A5\uC18C\uAC00 \uC544\uB2D9\uB2C8\uB2E4 \u2014 awl lane \uC740 git worktree \uB97C \uC501\uB2C8\uB2E4")}
|
|
55
|
+
`
|
|
56
|
+
);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const laneName = sanitizeForGit(name);
|
|
60
|
+
if (!laneName) {
|
|
61
|
+
process.stderr.write(`
|
|
62
|
+
${feedback(c, "error", "\uB808\uC778 \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694")}
|
|
63
|
+
`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const lanePath = path.join(root, WORKTREES_DIR, laneName);
|
|
67
|
+
if (fs.existsSync(lanePath)) {
|
|
68
|
+
process.stderr.write(
|
|
69
|
+
`
|
|
70
|
+
${feedback(c, "error", `\uC774\uBBF8 \uC874\uC7AC\uD558\uB294 \uB808\uC778\uC785\uB2C8\uB2E4: ${laneName}`, `awl lane rm ${laneName} \uB85C \uBA3C\uC800 \uC815\uB9AC\uD558\uC138\uC694`)}
|
|
71
|
+
`
|
|
72
|
+
);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
await runWorkNew(name, description, { worktree: true, isolated: true });
|
|
76
|
+
process.stdout.write(`
|
|
77
|
+
${feedback(c, "ok", `\uB808\uC778 \uC900\uBE44 ${color.bold(laneName)}`)}
|
|
78
|
+
`);
|
|
79
|
+
process.stdout.write(` ${color.dim("\uC774 \uB808\uC778\uC758 \uC5ED\uD560 \uC138\uC158\uC5D0\uC11C \uC2A4\uD0AC \uD2B8\uB9AC\uAC70\uB97C \uC2E4\uD589\uD558\uC138\uC694:")}
|
|
80
|
+
`);
|
|
81
|
+
for (const t of PIPELINE_TRIGGERS) {
|
|
82
|
+
process.stdout.write(` ${color.dim(t)}
|
|
83
|
+
`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function parseWorktreeBranches(porcelain) {
|
|
87
|
+
const map = /* @__PURE__ */ new Map();
|
|
88
|
+
let current = null;
|
|
89
|
+
for (const raw of porcelain.split("\n")) {
|
|
90
|
+
const line = raw.trim();
|
|
91
|
+
if (line.startsWith("worktree ")) {
|
|
92
|
+
current = line.slice("worktree ".length);
|
|
93
|
+
} else if (line.startsWith("branch ") && current) {
|
|
94
|
+
map.set(current, line.slice("branch ".length).replace(/^refs\/heads\//, ""));
|
|
95
|
+
} else if (line === "") {
|
|
96
|
+
current = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return map;
|
|
100
|
+
}
|
|
101
|
+
async function laneBranchMap(root) {
|
|
102
|
+
const r = await run({
|
|
103
|
+
cmd: "git",
|
|
104
|
+
args: ["worktree", "list", "--porcelain"],
|
|
105
|
+
cwd: root,
|
|
106
|
+
timeoutMs: 1e4
|
|
107
|
+
});
|
|
108
|
+
if (r.exitCode !== 0) {
|
|
109
|
+
return /* @__PURE__ */ new Map();
|
|
110
|
+
}
|
|
111
|
+
return parseWorktreeBranches(r.stdout);
|
|
112
|
+
}
|
|
113
|
+
async function unmergedCommitCount(root, branch) {
|
|
114
|
+
const r = await run({
|
|
115
|
+
cmd: "git",
|
|
116
|
+
args: ["rev-list", "--count", `HEAD..${branch}`],
|
|
117
|
+
cwd: root,
|
|
118
|
+
timeoutMs: 1e4
|
|
119
|
+
});
|
|
120
|
+
if (r.exitCode !== 0) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const n = Number.parseInt(r.stdout.trim(), 10);
|
|
124
|
+
return Number.isNaN(n) ? null : n;
|
|
125
|
+
}
|
|
126
|
+
var AWL_INTERNAL_DIRS = /* @__PURE__ */ new Set([".awl", ".awl-worktrees", ".claude"]);
|
|
127
|
+
async function worktreeUntracked(root, targetPath) {
|
|
128
|
+
const r = await run({
|
|
129
|
+
cmd: "git",
|
|
130
|
+
args: ["-C", targetPath, "ls-files", "--others", "--exclude-standard"],
|
|
131
|
+
cwd: root,
|
|
132
|
+
timeoutMs: 1e4
|
|
133
|
+
});
|
|
134
|
+
const files = r.stdout.split("\n").map((l) => l.trim()).filter(Boolean).filter((f) => !AWL_INTERNAL_DIRS.has(f.split("/")[0] ?? ""));
|
|
135
|
+
return { untracked: files.length > 0, count: files.length, first: files[0] };
|
|
136
|
+
}
|
|
137
|
+
function branchOf(branches, lanePath) {
|
|
138
|
+
const direct = branches.get(lanePath);
|
|
139
|
+
if (direct) {
|
|
140
|
+
return direct;
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
return branches.get(fs.realpathSync(lanePath));
|
|
144
|
+
} catch {
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function collectLanes(root) {
|
|
149
|
+
const base = path.join(root, WORKTREES_DIR);
|
|
150
|
+
let entries;
|
|
151
|
+
try {
|
|
152
|
+
entries = fs.readdirSync(base, { withFileTypes: true });
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
const branches = await laneBranchMap(root);
|
|
157
|
+
const lanes = [];
|
|
158
|
+
for (const e of entries) {
|
|
159
|
+
if (!e.isDirectory()) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const p = path.join(base, e.name);
|
|
163
|
+
lanes.push({ name: e.name, path: p, branch: branchOf(branches, p) ?? "(detached)" });
|
|
164
|
+
}
|
|
165
|
+
lanes.sort((a, b) => a.name.localeCompare(b.name));
|
|
166
|
+
return lanes;
|
|
167
|
+
}
|
|
168
|
+
function renderLaneList(lanes, c) {
|
|
169
|
+
const color = makeColors(c.color);
|
|
170
|
+
if (lanes.length === 0) {
|
|
171
|
+
return card(
|
|
172
|
+
"\uB808\uC778",
|
|
173
|
+
[
|
|
174
|
+
`${signal(c, "info")} \uB808\uC778\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.`,
|
|
175
|
+
"",
|
|
176
|
+
color.dim("awl lane new <name> \uB85C \uACA9\uB9AC \uB808\uC778\uC744 \uB9CC\uB4DC\uC138\uC694.")
|
|
177
|
+
],
|
|
178
|
+
c
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const nameWidth = Math.max(...lanes.map((l) => l.name.length), 4) + 2;
|
|
182
|
+
const out = [];
|
|
183
|
+
for (const l of lanes) {
|
|
184
|
+
out.push(`${color.bold(l.name.padEnd(nameWidth, " "))}${color.dim(l.branch)}`);
|
|
185
|
+
out.push(` ${color.dim(l.path)}`);
|
|
186
|
+
}
|
|
187
|
+
return card("\uB808\uC778", out, c);
|
|
188
|
+
}
|
|
189
|
+
async function runLaneList(opts) {
|
|
190
|
+
const root = requireRoot();
|
|
191
|
+
const lanes = await collectLanes(root);
|
|
192
|
+
if (opts.json) {
|
|
193
|
+
process.stdout.write(`${JSON.stringify(lanes, null, 2)}
|
|
194
|
+
`);
|
|
195
|
+
} else {
|
|
196
|
+
process.stdout.write(`${renderLaneList(lanes, caps())}
|
|
197
|
+
`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async function runLaneRemove(name, opts = {}) {
|
|
201
|
+
const root = requireRoot();
|
|
202
|
+
const c = caps();
|
|
203
|
+
const color = makeColors(c.color);
|
|
204
|
+
const laneName = sanitizeForGit(name);
|
|
205
|
+
if (!laneName) {
|
|
206
|
+
process.stderr.write(`
|
|
207
|
+
${feedback(c, "error", "\uB808\uC778 \uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694")}
|
|
208
|
+
`);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
const lanePath = path.join(root, WORKTREES_DIR, laneName);
|
|
212
|
+
if (!fs.existsSync(lanePath)) {
|
|
213
|
+
process.stderr.write(
|
|
214
|
+
`
|
|
215
|
+
${feedback(c, "error", `\uB808\uC778\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${laneName}`, "awl lane ls \uB85C \uD604\uC874 \uB808\uC778\uC744 \uD655\uC778\uD558\uC138\uC694")}
|
|
216
|
+
`
|
|
217
|
+
);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const branches = await laneBranchMap(root);
|
|
221
|
+
const branch = branchOf(branches, lanePath) ?? `work/${laneName}`;
|
|
222
|
+
if (!opts.force) {
|
|
223
|
+
const d = await worktreeDirtyTracked(root, lanePath);
|
|
224
|
+
if (d.dirty) {
|
|
225
|
+
process.stderr.write(
|
|
226
|
+
`
|
|
227
|
+
${feedback(c, "error", `\uB808\uC778\uC5D0 \uCEE4\uBC0B\uB418\uC9C0 \uC54A\uC740 \uBCC0\uACBD ${d.count}\uAC74 (\uC608: ${d.first})`, "--force \uB85C \uAC15\uC81C \uC81C\uAC70\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4")}
|
|
228
|
+
`
|
|
229
|
+
);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
const u = await worktreeUntracked(root, lanePath);
|
|
233
|
+
if (u.untracked) {
|
|
234
|
+
process.stderr.write(
|
|
235
|
+
`
|
|
236
|
+
${feedback(c, "error", `\uB808\uC778\uC5D0 \uCEE4\uBC0B\uB418\uC9C0 \uC54A\uC740 \uC0C8 \uD30C\uC77C ${u.count}\uAC74 (\uC608: ${u.first})`, "git add\xB7\uCEE4\uBC0B\uD558\uAC70\uB098 --force \uB85C \uAC15\uC81C \uC81C\uAC70\uD558\uC138\uC694")}
|
|
237
|
+
`
|
|
238
|
+
);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
const unmerged = await unmergedCommitCount(root, branch);
|
|
242
|
+
if (unmerged === null) {
|
|
243
|
+
process.stderr.write(
|
|
244
|
+
`
|
|
245
|
+
${feedback(c, "error", `\uB808\uC778 \uBE0C\uB79C\uCE58 ${branch} \uC758 \uBBF8\uBA38\uC9C0 \uCEE4\uBC0B \uC218\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 (rm \uD558\uBA74 \uCEE4\uBC0B\uC774 \uD30C\uAE30\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4)`, "\uBA3C\uC800 \uBE0C\uB79C\uCE58\uB97C \uD655\uC778\uD558\uAC70\uB098 --force \uB85C \uAC15\uC81C \uC81C\uAC70\uD558\uC138\uC694")}
|
|
246
|
+
`
|
|
247
|
+
);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
if (unmerged > 0) {
|
|
251
|
+
process.stderr.write(
|
|
252
|
+
`
|
|
253
|
+
${feedback(c, "error", `\uB808\uC778 \uBE0C\uB79C\uCE58 ${branch} \uC5D0 \uBCD1\uD569\uB418\uC9C0 \uC54A\uC740 \uCEE4\uBC0B ${unmerged}\uAC1C (rm \uD558\uBA74 \uD30C\uAE30\uB429\uB2C8\uB2E4)`, "\uBA3C\uC800 \uBCD1\uD569\xB7\uD478\uC2DC\uD558\uAC70\uB098 --force \uB85C \uAC15\uC81C \uC81C\uAC70\uD558\uC138\uC694")}
|
|
254
|
+
`
|
|
255
|
+
);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
let merged = null;
|
|
260
|
+
try {
|
|
261
|
+
merged = mergeIsolatedHome(path.join(lanePath, ".awl", "home"));
|
|
262
|
+
} catch (e) {
|
|
263
|
+
process.stderr.write(
|
|
264
|
+
`
|
|
265
|
+
${feedback(c, "error", "\uACA9\uB9AC \uD559\uC2B5 \uC804\uC5ED \uBCD1\uD569 \uC2E4\uD328 \u2014 \uB808\uC778\uC744 \uBCF4\uC874\uD569\uB2C8\uB2E4", e instanceof Error ? e.message : String(e))}
|
|
266
|
+
`
|
|
267
|
+
);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
const removed = await removeGitWorktree(root, lanePath, branch);
|
|
271
|
+
if (!removed.ok) {
|
|
272
|
+
process.stderr.write(`
|
|
273
|
+
${feedback(c, "error", "\uB808\uC778 \uC81C\uAC70 \uC2E4\uD328", removed.error ?? "")}
|
|
274
|
+
`);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
if (fs.existsSync(lanePath)) {
|
|
278
|
+
fs.rmSync(lanePath, { recursive: true, force: true });
|
|
279
|
+
}
|
|
280
|
+
const cleaned = removeWorkitemFromState(loadState(root), [name.trim(), laneName]);
|
|
281
|
+
if (cleaned.removed) {
|
|
282
|
+
writeState(root, cleaned.state);
|
|
283
|
+
}
|
|
284
|
+
process.stdout.write(`
|
|
285
|
+
${feedback(c, "ok", `\uB808\uC778 \uC81C\uAC70 ${color.bold(laneName)}`, branch)}
|
|
286
|
+
`);
|
|
287
|
+
if (merged && (merged.gotchasAdded > 0 || merged.rulesAdded > 0 || merged.generationsAdded > 0)) {
|
|
288
|
+
process.stdout.write(
|
|
289
|
+
` ${color.dim(`\uD559\uC2B5 \uC804\uC5ED \uBCD1\uD569 gotcha ${merged.gotchasAdded} \xB7 rule ${merged.rulesAdded} \xB7 generation ${merged.generationsAdded}`)}
|
|
290
|
+
`
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export {
|
|
296
|
+
WORKTREES_DIR,
|
|
297
|
+
runLaneNew,
|
|
298
|
+
parseWorktreeBranches,
|
|
299
|
+
laneBranchMap,
|
|
300
|
+
unmergedCommitCount,
|
|
301
|
+
worktreeUntracked,
|
|
302
|
+
branchOf,
|
|
303
|
+
collectLanes,
|
|
304
|
+
renderLaneList,
|
|
305
|
+
runLaneList,
|
|
306
|
+
runLaneRemove
|
|
307
|
+
};
|