@andyqiu/codeforge 0.5.19 → 0.5.20
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/codeforge.json +9 -9
- package/dist/index.js +736 -430
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1069,17 +1069,17 @@ var require_visit = __commonJS((exports) => {
|
|
|
1069
1069
|
visit.BREAK = BREAK;
|
|
1070
1070
|
visit.SKIP = SKIP;
|
|
1071
1071
|
visit.REMOVE = REMOVE;
|
|
1072
|
-
function visit_(key, node, visitor,
|
|
1073
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
1072
|
+
function visit_(key, node, visitor, path19) {
|
|
1073
|
+
const ctrl = callVisitor(key, node, visitor, path19);
|
|
1074
1074
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
1075
|
-
replaceNode(key,
|
|
1076
|
-
return visit_(key, ctrl, visitor,
|
|
1075
|
+
replaceNode(key, path19, ctrl);
|
|
1076
|
+
return visit_(key, ctrl, visitor, path19);
|
|
1077
1077
|
}
|
|
1078
1078
|
if (typeof ctrl !== "symbol") {
|
|
1079
1079
|
if (identity.isCollection(node)) {
|
|
1080
|
-
|
|
1080
|
+
path19 = Object.freeze(path19.concat(node));
|
|
1081
1081
|
for (let i = 0;i < node.items.length; ++i) {
|
|
1082
|
-
const ci = visit_(i, node.items[i], visitor,
|
|
1082
|
+
const ci = visit_(i, node.items[i], visitor, path19);
|
|
1083
1083
|
if (typeof ci === "number")
|
|
1084
1084
|
i = ci - 1;
|
|
1085
1085
|
else if (ci === BREAK)
|
|
@@ -1090,13 +1090,13 @@ var require_visit = __commonJS((exports) => {
|
|
|
1090
1090
|
}
|
|
1091
1091
|
}
|
|
1092
1092
|
} else if (identity.isPair(node)) {
|
|
1093
|
-
|
|
1094
|
-
const ck = visit_("key", node.key, visitor,
|
|
1093
|
+
path19 = Object.freeze(path19.concat(node));
|
|
1094
|
+
const ck = visit_("key", node.key, visitor, path19);
|
|
1095
1095
|
if (ck === BREAK)
|
|
1096
1096
|
return BREAK;
|
|
1097
1097
|
else if (ck === REMOVE)
|
|
1098
1098
|
node.key = null;
|
|
1099
|
-
const cv = visit_("value", node.value, visitor,
|
|
1099
|
+
const cv = visit_("value", node.value, visitor, path19);
|
|
1100
1100
|
if (cv === BREAK)
|
|
1101
1101
|
return BREAK;
|
|
1102
1102
|
else if (cv === REMOVE)
|
|
@@ -1117,17 +1117,17 @@ var require_visit = __commonJS((exports) => {
|
|
|
1117
1117
|
visitAsync.BREAK = BREAK;
|
|
1118
1118
|
visitAsync.SKIP = SKIP;
|
|
1119
1119
|
visitAsync.REMOVE = REMOVE;
|
|
1120
|
-
async function visitAsync_(key, node, visitor,
|
|
1121
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
1120
|
+
async function visitAsync_(key, node, visitor, path19) {
|
|
1121
|
+
const ctrl = await callVisitor(key, node, visitor, path19);
|
|
1122
1122
|
if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
|
|
1123
|
-
replaceNode(key,
|
|
1124
|
-
return visitAsync_(key, ctrl, visitor,
|
|
1123
|
+
replaceNode(key, path19, ctrl);
|
|
1124
|
+
return visitAsync_(key, ctrl, visitor, path19);
|
|
1125
1125
|
}
|
|
1126
1126
|
if (typeof ctrl !== "symbol") {
|
|
1127
1127
|
if (identity.isCollection(node)) {
|
|
1128
|
-
|
|
1128
|
+
path19 = Object.freeze(path19.concat(node));
|
|
1129
1129
|
for (let i = 0;i < node.items.length; ++i) {
|
|
1130
|
-
const ci = await visitAsync_(i, node.items[i], visitor,
|
|
1130
|
+
const ci = await visitAsync_(i, node.items[i], visitor, path19);
|
|
1131
1131
|
if (typeof ci === "number")
|
|
1132
1132
|
i = ci - 1;
|
|
1133
1133
|
else if (ci === BREAK)
|
|
@@ -1138,13 +1138,13 @@ var require_visit = __commonJS((exports) => {
|
|
|
1138
1138
|
}
|
|
1139
1139
|
}
|
|
1140
1140
|
} else if (identity.isPair(node)) {
|
|
1141
|
-
|
|
1142
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
1141
|
+
path19 = Object.freeze(path19.concat(node));
|
|
1142
|
+
const ck = await visitAsync_("key", node.key, visitor, path19);
|
|
1143
1143
|
if (ck === BREAK)
|
|
1144
1144
|
return BREAK;
|
|
1145
1145
|
else if (ck === REMOVE)
|
|
1146
1146
|
node.key = null;
|
|
1147
|
-
const cv = await visitAsync_("value", node.value, visitor,
|
|
1147
|
+
const cv = await visitAsync_("value", node.value, visitor, path19);
|
|
1148
1148
|
if (cv === BREAK)
|
|
1149
1149
|
return BREAK;
|
|
1150
1150
|
else if (cv === REMOVE)
|
|
@@ -1171,23 +1171,23 @@ var require_visit = __commonJS((exports) => {
|
|
|
1171
1171
|
}
|
|
1172
1172
|
return visitor;
|
|
1173
1173
|
}
|
|
1174
|
-
function callVisitor(key, node, visitor,
|
|
1174
|
+
function callVisitor(key, node, visitor, path19) {
|
|
1175
1175
|
if (typeof visitor === "function")
|
|
1176
|
-
return visitor(key, node,
|
|
1176
|
+
return visitor(key, node, path19);
|
|
1177
1177
|
if (identity.isMap(node))
|
|
1178
|
-
return visitor.Map?.(key, node,
|
|
1178
|
+
return visitor.Map?.(key, node, path19);
|
|
1179
1179
|
if (identity.isSeq(node))
|
|
1180
|
-
return visitor.Seq?.(key, node,
|
|
1180
|
+
return visitor.Seq?.(key, node, path19);
|
|
1181
1181
|
if (identity.isPair(node))
|
|
1182
|
-
return visitor.Pair?.(key, node,
|
|
1182
|
+
return visitor.Pair?.(key, node, path19);
|
|
1183
1183
|
if (identity.isScalar(node))
|
|
1184
|
-
return visitor.Scalar?.(key, node,
|
|
1184
|
+
return visitor.Scalar?.(key, node, path19);
|
|
1185
1185
|
if (identity.isAlias(node))
|
|
1186
|
-
return visitor.Alias?.(key, node,
|
|
1186
|
+
return visitor.Alias?.(key, node, path19);
|
|
1187
1187
|
return;
|
|
1188
1188
|
}
|
|
1189
|
-
function replaceNode(key,
|
|
1190
|
-
const parent =
|
|
1189
|
+
function replaceNode(key, path19, node) {
|
|
1190
|
+
const parent = path19[path19.length - 1];
|
|
1191
1191
|
if (identity.isCollection(parent)) {
|
|
1192
1192
|
parent.items[key] = node;
|
|
1193
1193
|
} else if (identity.isPair(parent)) {
|
|
@@ -1746,10 +1746,10 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1746
1746
|
var createNode = require_createNode();
|
|
1747
1747
|
var identity = require_identity();
|
|
1748
1748
|
var Node = require_Node();
|
|
1749
|
-
function collectionFromPath(schema,
|
|
1749
|
+
function collectionFromPath(schema, path19, value) {
|
|
1750
1750
|
let v = value;
|
|
1751
|
-
for (let i =
|
|
1752
|
-
const k =
|
|
1751
|
+
for (let i = path19.length - 1;i >= 0; --i) {
|
|
1752
|
+
const k = path19[i];
|
|
1753
1753
|
if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
|
|
1754
1754
|
const a = [];
|
|
1755
1755
|
a[k] = v;
|
|
@@ -1768,7 +1768,7 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1768
1768
|
sourceObjects: new Map
|
|
1769
1769
|
});
|
|
1770
1770
|
}
|
|
1771
|
-
var isEmptyPath = (
|
|
1771
|
+
var isEmptyPath = (path19) => path19 == null || typeof path19 === "object" && !!path19[Symbol.iterator]().next().done;
|
|
1772
1772
|
|
|
1773
1773
|
class Collection extends Node.NodeBase {
|
|
1774
1774
|
constructor(type, schema) {
|
|
@@ -1789,11 +1789,11 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1789
1789
|
copy.range = this.range.slice();
|
|
1790
1790
|
return copy;
|
|
1791
1791
|
}
|
|
1792
|
-
addIn(
|
|
1793
|
-
if (isEmptyPath(
|
|
1792
|
+
addIn(path19, value) {
|
|
1793
|
+
if (isEmptyPath(path19))
|
|
1794
1794
|
this.add(value);
|
|
1795
1795
|
else {
|
|
1796
|
-
const [key, ...rest] =
|
|
1796
|
+
const [key, ...rest] = path19;
|
|
1797
1797
|
const node = this.get(key, true);
|
|
1798
1798
|
if (identity.isCollection(node))
|
|
1799
1799
|
node.addIn(rest, value);
|
|
@@ -1803,8 +1803,8 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1803
1803
|
throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
1804
1804
|
}
|
|
1805
1805
|
}
|
|
1806
|
-
deleteIn(
|
|
1807
|
-
const [key, ...rest] =
|
|
1806
|
+
deleteIn(path19) {
|
|
1807
|
+
const [key, ...rest] = path19;
|
|
1808
1808
|
if (rest.length === 0)
|
|
1809
1809
|
return this.delete(key);
|
|
1810
1810
|
const node = this.get(key, true);
|
|
@@ -1813,8 +1813,8 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1813
1813
|
else
|
|
1814
1814
|
throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
|
|
1815
1815
|
}
|
|
1816
|
-
getIn(
|
|
1817
|
-
const [key, ...rest] =
|
|
1816
|
+
getIn(path19, keepScalar) {
|
|
1817
|
+
const [key, ...rest] = path19;
|
|
1818
1818
|
const node = this.get(key, true);
|
|
1819
1819
|
if (rest.length === 0)
|
|
1820
1820
|
return !keepScalar && identity.isScalar(node) ? node.value : node;
|
|
@@ -1829,15 +1829,15 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1829
1829
|
return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
|
|
1830
1830
|
});
|
|
1831
1831
|
}
|
|
1832
|
-
hasIn(
|
|
1833
|
-
const [key, ...rest] =
|
|
1832
|
+
hasIn(path19) {
|
|
1833
|
+
const [key, ...rest] = path19;
|
|
1834
1834
|
if (rest.length === 0)
|
|
1835
1835
|
return this.has(key);
|
|
1836
1836
|
const node = this.get(key, true);
|
|
1837
1837
|
return identity.isCollection(node) ? node.hasIn(rest) : false;
|
|
1838
1838
|
}
|
|
1839
|
-
setIn(
|
|
1840
|
-
const [key, ...rest] =
|
|
1839
|
+
setIn(path19, value) {
|
|
1840
|
+
const [key, ...rest] = path19;
|
|
1841
1841
|
if (rest.length === 0) {
|
|
1842
1842
|
this.set(key, value);
|
|
1843
1843
|
} else {
|
|
@@ -4230,9 +4230,9 @@ var require_Document = __commonJS((exports) => {
|
|
|
4230
4230
|
if (assertCollection(this.contents))
|
|
4231
4231
|
this.contents.add(value);
|
|
4232
4232
|
}
|
|
4233
|
-
addIn(
|
|
4233
|
+
addIn(path19, value) {
|
|
4234
4234
|
if (assertCollection(this.contents))
|
|
4235
|
-
this.contents.addIn(
|
|
4235
|
+
this.contents.addIn(path19, value);
|
|
4236
4236
|
}
|
|
4237
4237
|
createAlias(node, name) {
|
|
4238
4238
|
if (!node.anchor) {
|
|
@@ -4281,30 +4281,30 @@ var require_Document = __commonJS((exports) => {
|
|
|
4281
4281
|
delete(key) {
|
|
4282
4282
|
return assertCollection(this.contents) ? this.contents.delete(key) : false;
|
|
4283
4283
|
}
|
|
4284
|
-
deleteIn(
|
|
4285
|
-
if (Collection.isEmptyPath(
|
|
4284
|
+
deleteIn(path19) {
|
|
4285
|
+
if (Collection.isEmptyPath(path19)) {
|
|
4286
4286
|
if (this.contents == null)
|
|
4287
4287
|
return false;
|
|
4288
4288
|
this.contents = null;
|
|
4289
4289
|
return true;
|
|
4290
4290
|
}
|
|
4291
|
-
return assertCollection(this.contents) ? this.contents.deleteIn(
|
|
4291
|
+
return assertCollection(this.contents) ? this.contents.deleteIn(path19) : false;
|
|
4292
4292
|
}
|
|
4293
4293
|
get(key, keepScalar) {
|
|
4294
4294
|
return identity.isCollection(this.contents) ? this.contents.get(key, keepScalar) : undefined;
|
|
4295
4295
|
}
|
|
4296
|
-
getIn(
|
|
4297
|
-
if (Collection.isEmptyPath(
|
|
4296
|
+
getIn(path19, keepScalar) {
|
|
4297
|
+
if (Collection.isEmptyPath(path19))
|
|
4298
4298
|
return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
|
|
4299
|
-
return identity.isCollection(this.contents) ? this.contents.getIn(
|
|
4299
|
+
return identity.isCollection(this.contents) ? this.contents.getIn(path19, keepScalar) : undefined;
|
|
4300
4300
|
}
|
|
4301
4301
|
has(key) {
|
|
4302
4302
|
return identity.isCollection(this.contents) ? this.contents.has(key) : false;
|
|
4303
4303
|
}
|
|
4304
|
-
hasIn(
|
|
4305
|
-
if (Collection.isEmptyPath(
|
|
4304
|
+
hasIn(path19) {
|
|
4305
|
+
if (Collection.isEmptyPath(path19))
|
|
4306
4306
|
return this.contents !== undefined;
|
|
4307
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
4307
|
+
return identity.isCollection(this.contents) ? this.contents.hasIn(path19) : false;
|
|
4308
4308
|
}
|
|
4309
4309
|
set(key, value) {
|
|
4310
4310
|
if (this.contents == null) {
|
|
@@ -4313,13 +4313,13 @@ var require_Document = __commonJS((exports) => {
|
|
|
4313
4313
|
this.contents.set(key, value);
|
|
4314
4314
|
}
|
|
4315
4315
|
}
|
|
4316
|
-
setIn(
|
|
4317
|
-
if (Collection.isEmptyPath(
|
|
4316
|
+
setIn(path19, value) {
|
|
4317
|
+
if (Collection.isEmptyPath(path19)) {
|
|
4318
4318
|
this.contents = value;
|
|
4319
4319
|
} else if (this.contents == null) {
|
|
4320
|
-
this.contents = Collection.collectionFromPath(this.schema, Array.from(
|
|
4320
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path19), value);
|
|
4321
4321
|
} else if (assertCollection(this.contents)) {
|
|
4322
|
-
this.contents.setIn(
|
|
4322
|
+
this.contents.setIn(path19, value);
|
|
4323
4323
|
}
|
|
4324
4324
|
}
|
|
4325
4325
|
setSchema(version, options = {}) {
|
|
@@ -6214,9 +6214,9 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
6214
6214
|
visit.BREAK = BREAK;
|
|
6215
6215
|
visit.SKIP = SKIP;
|
|
6216
6216
|
visit.REMOVE = REMOVE;
|
|
6217
|
-
visit.itemAtPath = (cst,
|
|
6217
|
+
visit.itemAtPath = (cst, path19) => {
|
|
6218
6218
|
let item = cst;
|
|
6219
|
-
for (const [field, index] of
|
|
6219
|
+
for (const [field, index] of path19) {
|
|
6220
6220
|
const tok = item?.[field];
|
|
6221
6221
|
if (tok && "items" in tok) {
|
|
6222
6222
|
item = tok.items[index];
|
|
@@ -6225,23 +6225,23 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
6225
6225
|
}
|
|
6226
6226
|
return item;
|
|
6227
6227
|
};
|
|
6228
|
-
visit.parentCollection = (cst,
|
|
6229
|
-
const parent = visit.itemAtPath(cst,
|
|
6230
|
-
const field =
|
|
6228
|
+
visit.parentCollection = (cst, path19) => {
|
|
6229
|
+
const parent = visit.itemAtPath(cst, path19.slice(0, -1));
|
|
6230
|
+
const field = path19[path19.length - 1][0];
|
|
6231
6231
|
const coll = parent?.[field];
|
|
6232
6232
|
if (coll && "items" in coll)
|
|
6233
6233
|
return coll;
|
|
6234
6234
|
throw new Error("Parent collection not found");
|
|
6235
6235
|
};
|
|
6236
|
-
function _visit(
|
|
6237
|
-
let ctrl = visitor(item,
|
|
6236
|
+
function _visit(path19, item, visitor) {
|
|
6237
|
+
let ctrl = visitor(item, path19);
|
|
6238
6238
|
if (typeof ctrl === "symbol")
|
|
6239
6239
|
return ctrl;
|
|
6240
6240
|
for (const field of ["key", "value"]) {
|
|
6241
6241
|
const token = item[field];
|
|
6242
6242
|
if (token && "items" in token) {
|
|
6243
6243
|
for (let i = 0;i < token.items.length; ++i) {
|
|
6244
|
-
const ci = _visit(Object.freeze(
|
|
6244
|
+
const ci = _visit(Object.freeze(path19.concat([[field, i]])), token.items[i], visitor);
|
|
6245
6245
|
if (typeof ci === "number")
|
|
6246
6246
|
i = ci - 1;
|
|
6247
6247
|
else if (ci === BREAK)
|
|
@@ -6252,10 +6252,10 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
6252
6252
|
}
|
|
6253
6253
|
}
|
|
6254
6254
|
if (typeof ctrl === "function" && field === "key")
|
|
6255
|
-
ctrl = ctrl(item,
|
|
6255
|
+
ctrl = ctrl(item, path19);
|
|
6256
6256
|
}
|
|
6257
6257
|
}
|
|
6258
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
6258
|
+
return typeof ctrl === "function" ? ctrl(item, path19) : ctrl;
|
|
6259
6259
|
}
|
|
6260
6260
|
exports.visit = visit;
|
|
6261
6261
|
});
|
|
@@ -8011,11 +8011,11 @@ function shouldStopByStuck(history, cfg) {
|
|
|
8011
8011
|
async function withTimeout4(p, timeoutMs) {
|
|
8012
8012
|
if (timeoutMs <= 0)
|
|
8013
8013
|
return await p;
|
|
8014
|
-
return await new Promise((
|
|
8014
|
+
return await new Promise((resolve17, reject) => {
|
|
8015
8015
|
const timer = setTimeout(() => reject(new Error(`timeout after ${timeoutMs}ms`)), timeoutMs);
|
|
8016
8016
|
Promise.resolve(p).then((v) => {
|
|
8017
8017
|
clearTimeout(timer);
|
|
8018
|
-
|
|
8018
|
+
resolve17(v);
|
|
8019
8019
|
}, (err) => {
|
|
8020
8020
|
clearTimeout(timer);
|
|
8021
8021
|
reject(err);
|
|
@@ -14575,6 +14575,292 @@ async function execute28(input) {
|
|
|
14575
14575
|
};
|
|
14576
14576
|
}
|
|
14577
14577
|
}
|
|
14578
|
+
// tools/adr-init.ts
|
|
14579
|
+
import { z as z30 } from "zod";
|
|
14580
|
+
|
|
14581
|
+
// lib/adr-init.ts
|
|
14582
|
+
import { spawnSync } from "node:child_process";
|
|
14583
|
+
import { existsSync as existsSync4, promises as fsp } from "node:fs";
|
|
14584
|
+
import * as path16 from "node:path";
|
|
14585
|
+
import * as url from "node:url";
|
|
14586
|
+
function resolveAssetsRoot() {
|
|
14587
|
+
const here = path16.dirname(url.fileURLToPath(import.meta.url));
|
|
14588
|
+
let dir = here;
|
|
14589
|
+
for (let i = 0;i < 6; i++) {
|
|
14590
|
+
if (existsSync4(path16.join(dir, "package.json")) && existsSync4(path16.join(dir, "assets", "adr-init"))) {
|
|
14591
|
+
return path16.join(dir, "assets", "adr-init");
|
|
14592
|
+
}
|
|
14593
|
+
const parent = path16.dirname(dir);
|
|
14594
|
+
if (parent === dir)
|
|
14595
|
+
break;
|
|
14596
|
+
dir = parent;
|
|
14597
|
+
}
|
|
14598
|
+
throw new Error(`assets/adr-init/ 未找到(从 ${here} 上溯 6 层);` + `如果是 npm 安装请检查 package.json "files" 字段是否包含 "assets/"`);
|
|
14599
|
+
}
|
|
14600
|
+
function isGitRepo2(cwd) {
|
|
14601
|
+
try {
|
|
14602
|
+
const r = spawnSync("git", ["rev-parse", "--show-toplevel"], {
|
|
14603
|
+
cwd,
|
|
14604
|
+
stdio: "pipe",
|
|
14605
|
+
encoding: "utf8"
|
|
14606
|
+
});
|
|
14607
|
+
return r.status === 0;
|
|
14608
|
+
} catch {
|
|
14609
|
+
return false;
|
|
14610
|
+
}
|
|
14611
|
+
}
|
|
14612
|
+
function runGitConfigHooksPath(cwd) {
|
|
14613
|
+
try {
|
|
14614
|
+
const r = spawnSync("git", ["config", "core.hooksPath", ".githooks"], {
|
|
14615
|
+
cwd,
|
|
14616
|
+
stdio: "pipe",
|
|
14617
|
+
encoding: "utf8"
|
|
14618
|
+
});
|
|
14619
|
+
if (r.status === 0)
|
|
14620
|
+
return { ok: true };
|
|
14621
|
+
return { ok: false, error: (r.stderr ?? "").trim() || `exit=${r.status}` };
|
|
14622
|
+
} catch (e) {
|
|
14623
|
+
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
14624
|
+
}
|
|
14625
|
+
}
|
|
14626
|
+
async function runAdrInit(opts = {}) {
|
|
14627
|
+
const cwd = path16.resolve(opts.cwd ?? process.cwd());
|
|
14628
|
+
const force = !!opts.force;
|
|
14629
|
+
const dryRun = !!opts.dryRun;
|
|
14630
|
+
const writePrepare = !!opts.writePrepare;
|
|
14631
|
+
const installPrePush = opts.installPrePush !== false;
|
|
14632
|
+
const result = {
|
|
14633
|
+
ok: true,
|
|
14634
|
+
wrote: [],
|
|
14635
|
+
skipped: [],
|
|
14636
|
+
backedUp: [],
|
|
14637
|
+
suggestions: [],
|
|
14638
|
+
warnings: [],
|
|
14639
|
+
dryRun
|
|
14640
|
+
};
|
|
14641
|
+
if (!isGitRepo2(cwd)) {
|
|
14642
|
+
result.ok = false;
|
|
14643
|
+
result.reason = "not_git_repo";
|
|
14644
|
+
result.warnings.push(`${cwd} 不是 git 仓库;adr-init 需要 git 才能下发 hooks`);
|
|
14645
|
+
return result;
|
|
14646
|
+
}
|
|
14647
|
+
let assetsRoot;
|
|
14648
|
+
try {
|
|
14649
|
+
assetsRoot = resolveAssetsRoot();
|
|
14650
|
+
} catch (e) {
|
|
14651
|
+
result.ok = false;
|
|
14652
|
+
result.reason = "assets_not_found";
|
|
14653
|
+
result.warnings.push(e instanceof Error ? e.message : String(e));
|
|
14654
|
+
return result;
|
|
14655
|
+
}
|
|
14656
|
+
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
14657
|
+
const plan = [
|
|
14658
|
+
{ src: "scripts/adr-check.mjs", dst: "scripts/adr-check.mjs" },
|
|
14659
|
+
{ src: "scripts/adr-index-sync.mjs", dst: "scripts/adr-index-sync.mjs" },
|
|
14660
|
+
{ src: "docs/adr/README.md", dst: "docs/adr/README.md" },
|
|
14661
|
+
{ src: "docs/adr/template.md", dst: "docs/adr/template.md" },
|
|
14662
|
+
{
|
|
14663
|
+
src: ".github/pull_request_template.md",
|
|
14664
|
+
dst: ".github/pull_request_template.md"
|
|
14665
|
+
},
|
|
14666
|
+
{ src: "githooks/pre-commit.sh", dst: ".githooks/pre-commit", chmod: 493 }
|
|
14667
|
+
];
|
|
14668
|
+
if (installPrePush) {
|
|
14669
|
+
plan.push({
|
|
14670
|
+
src: "githooks/pre-push.sh",
|
|
14671
|
+
dst: ".githooks/pre-push",
|
|
14672
|
+
chmod: 493
|
|
14673
|
+
});
|
|
14674
|
+
}
|
|
14675
|
+
for (const item of plan) {
|
|
14676
|
+
const srcAbs = path16.join(assetsRoot, item.src);
|
|
14677
|
+
const dstAbs = path16.join(cwd, item.dst);
|
|
14678
|
+
if (!existsSync4(srcAbs)) {
|
|
14679
|
+
result.warnings.push(`资产缺失:${item.src}(跳过 ${item.dst})`);
|
|
14680
|
+
continue;
|
|
14681
|
+
}
|
|
14682
|
+
if (existsSync4(dstAbs)) {
|
|
14683
|
+
if (!force) {
|
|
14684
|
+
result.skipped.push(item.dst);
|
|
14685
|
+
continue;
|
|
14686
|
+
}
|
|
14687
|
+
const bakRel = `${item.dst}.bak.${ts}`;
|
|
14688
|
+
if (!dryRun) {
|
|
14689
|
+
try {
|
|
14690
|
+
await fsp.copyFile(dstAbs, path16.join(cwd, bakRel));
|
|
14691
|
+
} catch (e) {
|
|
14692
|
+
result.ok = false;
|
|
14693
|
+
result.reason = "io_error";
|
|
14694
|
+
result.warnings.push(`备份 ${item.dst} 失败:${e instanceof Error ? e.message : String(e)}`);
|
|
14695
|
+
return result;
|
|
14696
|
+
}
|
|
14697
|
+
}
|
|
14698
|
+
result.backedUp.push(bakRel);
|
|
14699
|
+
}
|
|
14700
|
+
if (!dryRun) {
|
|
14701
|
+
try {
|
|
14702
|
+
await fsp.mkdir(path16.dirname(dstAbs), { recursive: true });
|
|
14703
|
+
await fsp.copyFile(srcAbs, dstAbs);
|
|
14704
|
+
if (item.chmod !== undefined) {
|
|
14705
|
+
try {
|
|
14706
|
+
await fsp.chmod(dstAbs, item.chmod);
|
|
14707
|
+
} catch (e) {
|
|
14708
|
+
if (process.platform !== "win32") {
|
|
14709
|
+
result.warnings.push(`chmod ${item.dst} 失败:${e instanceof Error ? e.message : String(e)}`);
|
|
14710
|
+
}
|
|
14711
|
+
}
|
|
14712
|
+
}
|
|
14713
|
+
} catch (e) {
|
|
14714
|
+
result.ok = false;
|
|
14715
|
+
result.reason = "io_error";
|
|
14716
|
+
result.warnings.push(`写入 ${item.dst} 失败:${e instanceof Error ? e.message : String(e)}`);
|
|
14717
|
+
return result;
|
|
14718
|
+
}
|
|
14719
|
+
}
|
|
14720
|
+
result.wrote.push(item.dst);
|
|
14721
|
+
}
|
|
14722
|
+
if (!dryRun) {
|
|
14723
|
+
const r = runGitConfigHooksPath(cwd);
|
|
14724
|
+
if (r.ok) {
|
|
14725
|
+
result.suggestions.push("已运行:git config core.hooksPath .githooks(hooks 已启用)");
|
|
14726
|
+
} else {
|
|
14727
|
+
result.warnings.push(`自动启用 hooks 失败:${r.error ?? "未知错误"};请手动执行 git config core.hooksPath .githooks`);
|
|
14728
|
+
}
|
|
14729
|
+
} else {
|
|
14730
|
+
result.suggestions.push("[dry-run] 将运行:git config core.hooksPath .githooks");
|
|
14731
|
+
}
|
|
14732
|
+
const pkgPath = path16.join(cwd, "package.json");
|
|
14733
|
+
const isNpm = existsSync4(pkgPath);
|
|
14734
|
+
if (isNpm) {
|
|
14735
|
+
if (writePrepare) {
|
|
14736
|
+
try {
|
|
14737
|
+
const raw = await fsp.readFile(pkgPath, "utf8");
|
|
14738
|
+
const pkg = JSON.parse(raw);
|
|
14739
|
+
const existing = (pkg.scripts && typeof pkg.scripts.prepare === "string" ? pkg.scripts.prepare : "") ?? "";
|
|
14740
|
+
const target = "git config core.hooksPath .githooks";
|
|
14741
|
+
if (existing.includes(target)) {
|
|
14742
|
+
result.suggestions.push(`package.json scripts.prepare 已含目标命令,无需改动`);
|
|
14743
|
+
} else {
|
|
14744
|
+
const bakRel = `package.json.bak.${ts}`;
|
|
14745
|
+
if (!dryRun) {
|
|
14746
|
+
try {
|
|
14747
|
+
await fsp.copyFile(pkgPath, path16.join(cwd, bakRel));
|
|
14748
|
+
} catch (e) {
|
|
14749
|
+
result.warnings.push(`备份 package.json 失败:${e instanceof Error ? e.message : String(e)}`);
|
|
14750
|
+
}
|
|
14751
|
+
}
|
|
14752
|
+
result.backedUp.push(bakRel);
|
|
14753
|
+
if (existing.includes("husky")) {
|
|
14754
|
+
result.warnings.push(`package.json scripts.prepare 已含 husky,仍合并写入;如有问题可回滚 ${bakRel}`);
|
|
14755
|
+
}
|
|
14756
|
+
const merged = existing ? `${existing} && ${target}` : target;
|
|
14757
|
+
pkg.scripts = { ...pkg.scripts ?? {}, prepare: merged };
|
|
14758
|
+
if (!dryRun) {
|
|
14759
|
+
try {
|
|
14760
|
+
await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + `
|
|
14761
|
+
`, "utf8");
|
|
14762
|
+
} catch (e) {
|
|
14763
|
+
result.ok = false;
|
|
14764
|
+
result.reason = "io_error";
|
|
14765
|
+
result.warnings.push(`写入 package.json 失败:${e instanceof Error ? e.message : String(e)}`);
|
|
14766
|
+
return result;
|
|
14767
|
+
}
|
|
14768
|
+
}
|
|
14769
|
+
result.wrote.push("package.json");
|
|
14770
|
+
}
|
|
14771
|
+
} catch (e) {
|
|
14772
|
+
result.warnings.push(`读取 package.json 失败:${e instanceof Error ? e.message : String(e)}`);
|
|
14773
|
+
}
|
|
14774
|
+
} else {
|
|
14775
|
+
result.suggestions.push(`(可选) 在 package.json scripts.prepare 追加:"git config core.hooksPath .githooks",` + `或下次跑 codeforge adr-init --write-prepare 自动合并(写前自动 backup package.json)`);
|
|
14776
|
+
}
|
|
14777
|
+
} else {
|
|
14778
|
+
result.suggestions.push("非 npm 项目:请在 README / AGENTS.md 提醒首次 clone 后跑 git config core.hooksPath .githooks");
|
|
14779
|
+
}
|
|
14780
|
+
return result;
|
|
14781
|
+
}
|
|
14782
|
+
|
|
14783
|
+
// tools/adr-init.ts
|
|
14784
|
+
var description29 = [
|
|
14785
|
+
"把 CodeForge 的 ADR 体系(adr-check / adr-index-sync / pre-commit / pre-push / docs/adr 模板 / PR 模板)一键下发到当前 git 项目。",
|
|
14786
|
+
"**何时调用**:",
|
|
14787
|
+
"- 用户说「给这个项目加 ADR / 装一下 ADR 检查 / 同步一下 ADR 模板」",
|
|
14788
|
+
"- 新项目 init 流程中希望把决策记录体系一起带上",
|
|
14789
|
+
"**特点**:零 npm 依赖(用 git config core.hooksPath 而非 husky);跟仓库走(提交 .githooks/ 进 git);幂等(默认 skip 已存在文件,--force 自动 .bak.<ts> 备份)",
|
|
14790
|
+
"**何时不需要**:当前项目已有完整的 ADR + hooks(默认 skip 行为会保护,但调用本身浪费一次 IO)"
|
|
14791
|
+
].join(`
|
|
14792
|
+
`);
|
|
14793
|
+
var ArgsSchema29 = z30.object({
|
|
14794
|
+
cwd: z30.string().optional().describe("目标项目根目录,默认 process.cwd();通常无需传"),
|
|
14795
|
+
force: z30.boolean().optional().describe("已存在文件覆盖;覆盖前自动 .bak.<ts> 备份"),
|
|
14796
|
+
dryRun: z30.boolean().optional().describe("只输出将要执行的写入计划,不实际写盘"),
|
|
14797
|
+
writePrepare: z30.boolean().optional().describe("(npm 项目)自动合并 git config core.hooksPath 到 package.json scripts.prepare;写前自动 backup package.json;默认只建议不写"),
|
|
14798
|
+
installPrePush: z30.boolean().optional().describe("是否同时生成 .githooks/pre-push hook,默认 true")
|
|
14799
|
+
});
|
|
14800
|
+
function summarize(r) {
|
|
14801
|
+
const lines = [];
|
|
14802
|
+
lines.push(`# adr-init 执行结果${r.dryRun ? "(dry-run)" : ""}`);
|
|
14803
|
+
if (r.wrote.length > 0) {
|
|
14804
|
+
lines.push(`
|
|
14805
|
+
## 写入(${r.wrote.length})`);
|
|
14806
|
+
for (const f of r.wrote)
|
|
14807
|
+
lines.push(`- ${f}`);
|
|
14808
|
+
}
|
|
14809
|
+
if (r.skipped.length > 0) {
|
|
14810
|
+
lines.push(`
|
|
14811
|
+
## 跳过 / 已存在(${r.skipped.length}) — 加 --force 覆盖`);
|
|
14812
|
+
for (const f of r.skipped)
|
|
14813
|
+
lines.push(`- ${f}`);
|
|
14814
|
+
}
|
|
14815
|
+
if (r.backedUp.length > 0) {
|
|
14816
|
+
lines.push(`
|
|
14817
|
+
## 备份(${r.backedUp.length})`);
|
|
14818
|
+
for (const f of r.backedUp)
|
|
14819
|
+
lines.push(`- ${f}`);
|
|
14820
|
+
}
|
|
14821
|
+
if (r.suggestions.length > 0) {
|
|
14822
|
+
lines.push(`
|
|
14823
|
+
## 建议`);
|
|
14824
|
+
for (const s of r.suggestions)
|
|
14825
|
+
lines.push(`- ${s}`);
|
|
14826
|
+
}
|
|
14827
|
+
if (r.warnings.length > 0) {
|
|
14828
|
+
lines.push(`
|
|
14829
|
+
## 警告`);
|
|
14830
|
+
for (const w of r.warnings)
|
|
14831
|
+
lines.push(`- ${w}`);
|
|
14832
|
+
}
|
|
14833
|
+
return lines.join(`
|
|
14834
|
+
`);
|
|
14835
|
+
}
|
|
14836
|
+
async function execute29(input) {
|
|
14837
|
+
const parsed = ArgsSchema29.safeParse(input);
|
|
14838
|
+
if (!parsed.success) {
|
|
14839
|
+
return {
|
|
14840
|
+
ok: false,
|
|
14841
|
+
reason: "invalid_input",
|
|
14842
|
+
message: parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")
|
|
14843
|
+
};
|
|
14844
|
+
}
|
|
14845
|
+
try {
|
|
14846
|
+
const result = await runAdrInit(parsed.data);
|
|
14847
|
+
if (!result.ok) {
|
|
14848
|
+
return {
|
|
14849
|
+
ok: false,
|
|
14850
|
+
reason: result.reason ?? "io_error",
|
|
14851
|
+
message: result.warnings.join("; ") || "adr-init 执行失败",
|
|
14852
|
+
result
|
|
14853
|
+
};
|
|
14854
|
+
}
|
|
14855
|
+
return { ok: true, result, summary: summarize(result) };
|
|
14856
|
+
} catch (e) {
|
|
14857
|
+
return {
|
|
14858
|
+
ok: false,
|
|
14859
|
+
reason: "io_error",
|
|
14860
|
+
message: e instanceof Error ? e.message : String(e)
|
|
14861
|
+
};
|
|
14862
|
+
}
|
|
14863
|
+
}
|
|
14578
14864
|
// lib/opencode-runner.ts
|
|
14579
14865
|
function makeOpencodeRunner(opts) {
|
|
14580
14866
|
const log4 = opts.log ?? (() => {});
|
|
@@ -14732,20 +15018,20 @@ async function withTimeout3(p, ms, signal) {
|
|
|
14732
15018
|
throw err;
|
|
14733
15019
|
}
|
|
14734
15020
|
}
|
|
14735
|
-
return await new Promise((
|
|
15021
|
+
return await new Promise((resolve14, reject) => {
|
|
14736
15022
|
let settled = false;
|
|
14737
15023
|
const timer = setTimeout(() => {
|
|
14738
15024
|
if (settled)
|
|
14739
15025
|
return;
|
|
14740
15026
|
settled = true;
|
|
14741
|
-
|
|
15027
|
+
resolve14({ kind: "timeout" });
|
|
14742
15028
|
}, ms);
|
|
14743
15029
|
const onAbort = () => {
|
|
14744
15030
|
if (settled)
|
|
14745
15031
|
return;
|
|
14746
15032
|
settled = true;
|
|
14747
15033
|
clearTimeout(timer);
|
|
14748
|
-
|
|
15034
|
+
resolve14({ kind: "aborted" });
|
|
14749
15035
|
};
|
|
14750
15036
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
14751
15037
|
p.then((value) => {
|
|
@@ -14754,7 +15040,7 @@ async function withTimeout3(p, ms, signal) {
|
|
|
14754
15040
|
settled = true;
|
|
14755
15041
|
clearTimeout(timer);
|
|
14756
15042
|
signal?.removeEventListener("abort", onAbort);
|
|
14757
|
-
|
|
15043
|
+
resolve14({ kind: "ok", value });
|
|
14758
15044
|
}, (err) => {
|
|
14759
15045
|
if (settled)
|
|
14760
15046
|
return;
|
|
@@ -14837,18 +15123,18 @@ init_decision_parser();
|
|
|
14837
15123
|
// lib/parent-map-store.ts
|
|
14838
15124
|
init_runtime_paths();
|
|
14839
15125
|
import { promises as fs13 } from "node:fs";
|
|
14840
|
-
import * as
|
|
15126
|
+
import * as path17 from "node:path";
|
|
14841
15127
|
var PARENT_MAP_VERSION = 1;
|
|
14842
15128
|
var PARENT_MAP_LOCK_TIMEOUT_MS = 2000;
|
|
14843
15129
|
var PARENT_MAP_MAX_ENTRIES = 256;
|
|
14844
15130
|
function parentMapDir(mainRoot) {
|
|
14845
|
-
return
|
|
15131
|
+
return path17.join(runtimeDir(path17.resolve(mainRoot), { ensure: false }), "session-worktrees");
|
|
14846
15132
|
}
|
|
14847
15133
|
function parentMapPath(mainRoot) {
|
|
14848
|
-
return
|
|
15134
|
+
return path17.join(parentMapDir(mainRoot), "parent-map.json");
|
|
14849
15135
|
}
|
|
14850
15136
|
function parentMapLockPath(mainRoot) {
|
|
14851
|
-
return
|
|
15137
|
+
return path17.join(parentMapDir(mainRoot), "parent-map.lock");
|
|
14852
15138
|
}
|
|
14853
15139
|
async function readParentMapFile(mainRoot) {
|
|
14854
15140
|
const file = parentMapPath(mainRoot);
|
|
@@ -14868,7 +15154,7 @@ async function readParentMapFile(mainRoot) {
|
|
|
14868
15154
|
}
|
|
14869
15155
|
async function writeParentMapFile(mainRoot, payload) {
|
|
14870
15156
|
const file = parentMapPath(mainRoot);
|
|
14871
|
-
await fs13.mkdir(
|
|
15157
|
+
await fs13.mkdir(path17.dirname(file), { recursive: true });
|
|
14872
15158
|
const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
14873
15159
|
await fs13.writeFile(tmp, JSON.stringify(payload, null, 2), "utf8");
|
|
14874
15160
|
await fs13.rename(tmp, file);
|
|
@@ -14903,7 +15189,7 @@ async function loadParentMap(mainRoot) {
|
|
|
14903
15189
|
}
|
|
14904
15190
|
async function mutateParentMap(mainRoot, mutator, opts = {}) {
|
|
14905
15191
|
const lockPath = parentMapLockPath(mainRoot);
|
|
14906
|
-
await fs13.mkdir(
|
|
15192
|
+
await fs13.mkdir(path17.dirname(lockPath), { recursive: true });
|
|
14907
15193
|
const lockOpts = {
|
|
14908
15194
|
timeoutMs: opts.timeoutMs ?? PARENT_MAP_LOCK_TIMEOUT_MS,
|
|
14909
15195
|
...opts
|
|
@@ -14922,7 +15208,7 @@ async function appendParentEntry(mainRoot, childID, parentID, ts, opts = {}) {
|
|
|
14922
15208
|
if (!childID || !parentID)
|
|
14923
15209
|
return;
|
|
14924
15210
|
const lockPath = parentMapLockPath(mainRoot);
|
|
14925
|
-
await fs13.mkdir(
|
|
15211
|
+
await fs13.mkdir(path17.dirname(lockPath), { recursive: true });
|
|
14926
15212
|
const lockOpts = {
|
|
14927
15213
|
timeoutMs: opts.timeoutMs ?? PARENT_MAP_LOCK_TIMEOUT_MS,
|
|
14928
15214
|
...opts
|
|
@@ -15170,7 +15456,7 @@ async function raceAbortTimeout(p, signal, timeoutMs, label) {
|
|
|
15170
15456
|
e.name = "AbortError";
|
|
15171
15457
|
throw e;
|
|
15172
15458
|
}
|
|
15173
|
-
return await new Promise((
|
|
15459
|
+
return await new Promise((resolve15, reject) => {
|
|
15174
15460
|
let settled = false;
|
|
15175
15461
|
const timer = setTimeout(() => {
|
|
15176
15462
|
if (settled)
|
|
@@ -15195,7 +15481,7 @@ async function raceAbortTimeout(p, signal, timeoutMs, label) {
|
|
|
15195
15481
|
settled = true;
|
|
15196
15482
|
clearTimeout(timer);
|
|
15197
15483
|
signal?.removeEventListener("abort", onAbort);
|
|
15198
|
-
|
|
15484
|
+
resolve15(v);
|
|
15199
15485
|
}, (e) => {
|
|
15200
15486
|
if (settled)
|
|
15201
15487
|
return;
|
|
@@ -15256,7 +15542,7 @@ function clip4(s, max) {
|
|
|
15256
15542
|
|
|
15257
15543
|
// lib/codeforge-runtime.ts
|
|
15258
15544
|
import { promises as fs14 } from "node:fs";
|
|
15259
|
-
import * as
|
|
15545
|
+
import * as path18 from "node:path";
|
|
15260
15546
|
var DEFAULT_RUNTIME = {
|
|
15261
15547
|
autonomy: {
|
|
15262
15548
|
downgrade_on_risky: true
|
|
@@ -15299,7 +15585,7 @@ function loadRuntimeSync(opts = {}) {
|
|
|
15299
15585
|
}
|
|
15300
15586
|
async function loadRuntime(opts = {}) {
|
|
15301
15587
|
const root = opts.root ?? process.cwd();
|
|
15302
|
-
const abs =
|
|
15588
|
+
const abs = path18.resolve(root, opts.file ?? CONFIG_FILE);
|
|
15303
15589
|
let raw;
|
|
15304
15590
|
try {
|
|
15305
15591
|
raw = await fs14.readFile(abs, "utf8");
|
|
@@ -15583,7 +15869,7 @@ var toolHeartbeatServer = async (ctx) => {
|
|
|
15583
15869
|
var handler7 = toolHeartbeatServer;
|
|
15584
15870
|
|
|
15585
15871
|
// plugins/codeforge-tools.ts
|
|
15586
|
-
var
|
|
15872
|
+
var z31 = tool.schema;
|
|
15587
15873
|
var PLUGIN_NAME8 = "codeforge-tools";
|
|
15588
15874
|
logLifecycle(PLUGIN_NAME8, "import");
|
|
15589
15875
|
function wrap(output, metadata) {
|
|
@@ -15630,15 +15916,15 @@ function buildKhWriteTools() {
|
|
|
15630
15916
|
add_knowledge: tool({
|
|
15631
15917
|
description: description3,
|
|
15632
15918
|
args: {
|
|
15633
|
-
title:
|
|
15634
|
-
content:
|
|
15635
|
-
category:
|
|
15636
|
-
tags:
|
|
15637
|
-
relatedFiles:
|
|
15638
|
-
relatedCommit:
|
|
15639
|
-
relatedPR:
|
|
15640
|
-
scope:
|
|
15641
|
-
preConfirmed:
|
|
15919
|
+
title: z31.string().min(2).max(60).describe("简短标题(2-60 字)"),
|
|
15920
|
+
content: z31.string().min(10).describe("详细内容(Markdown,独立可理解)"),
|
|
15921
|
+
category: z31.string().optional().describe("分类(可选,自动推断)"),
|
|
15922
|
+
tags: z31.array(z31.string()).optional(),
|
|
15923
|
+
relatedFiles: z31.array(z31.string()).optional(),
|
|
15924
|
+
relatedCommit: z31.string().optional(),
|
|
15925
|
+
relatedPR: z31.string().optional(),
|
|
15926
|
+
scope: z31.string().optional(),
|
|
15927
|
+
preConfirmed: z31.boolean().optional()
|
|
15642
15928
|
},
|
|
15643
15929
|
async execute(args) {
|
|
15644
15930
|
return await runSafe("add_knowledge", async () => {
|
|
@@ -15653,18 +15939,18 @@ function buildKhWriteTools() {
|
|
|
15653
15939
|
upload_document: tool({
|
|
15654
15940
|
description: description4,
|
|
15655
15941
|
args: {
|
|
15656
|
-
name:
|
|
15657
|
-
content:
|
|
15658
|
-
encoding:
|
|
15659
|
-
chunk_strategy:
|
|
15660
|
-
chunk_size:
|
|
15661
|
-
chunk_overlap:
|
|
15662
|
-
separator:
|
|
15663
|
-
distill:
|
|
15664
|
-
category:
|
|
15665
|
-
tags:
|
|
15666
|
-
scope:
|
|
15667
|
-
pre_confirmed:
|
|
15942
|
+
name: z31.string().min(1).describe("文件名(含扩展名)"),
|
|
15943
|
+
content: z31.string().min(1).describe("文件完整内容"),
|
|
15944
|
+
encoding: z31.enum(["utf8", "base64"]).optional(),
|
|
15945
|
+
chunk_strategy: z31.enum(["auto", "heading", "fixed", "paragraph", "separator"]).optional(),
|
|
15946
|
+
chunk_size: z31.number().int().optional(),
|
|
15947
|
+
chunk_overlap: z31.number().int().optional(),
|
|
15948
|
+
separator: z31.string().optional(),
|
|
15949
|
+
distill: z31.boolean().optional(),
|
|
15950
|
+
category: z31.string().optional(),
|
|
15951
|
+
tags: z31.array(z31.string()).optional(),
|
|
15952
|
+
scope: z31.string().optional(),
|
|
15953
|
+
pre_confirmed: z31.boolean().optional()
|
|
15668
15954
|
},
|
|
15669
15955
|
async execute(args) {
|
|
15670
15956
|
return await runSafeTracked("upload_document", async () => {
|
|
@@ -15679,16 +15965,16 @@ function buildKhWriteTools() {
|
|
|
15679
15965
|
upload_document_from_url: tool({
|
|
15680
15966
|
description: description5,
|
|
15681
15967
|
args: {
|
|
15682
|
-
url:
|
|
15683
|
-
chunk_strategy:
|
|
15684
|
-
chunk_size:
|
|
15685
|
-
chunk_overlap:
|
|
15686
|
-
separator:
|
|
15687
|
-
distill:
|
|
15688
|
-
category:
|
|
15689
|
-
tags:
|
|
15690
|
-
scope:
|
|
15691
|
-
pre_confirmed:
|
|
15968
|
+
url: z31.string().min(1).describe("HTTP(s) URL"),
|
|
15969
|
+
chunk_strategy: z31.enum(["auto", "heading", "fixed", "paragraph", "separator"]).optional(),
|
|
15970
|
+
chunk_size: z31.number().int().optional(),
|
|
15971
|
+
chunk_overlap: z31.number().int().optional(),
|
|
15972
|
+
separator: z31.string().optional(),
|
|
15973
|
+
distill: z31.boolean().optional(),
|
|
15974
|
+
category: z31.string().optional(),
|
|
15975
|
+
tags: z31.array(z31.string()).optional(),
|
|
15976
|
+
scope: z31.string().optional(),
|
|
15977
|
+
pre_confirmed: z31.boolean().optional()
|
|
15692
15978
|
},
|
|
15693
15979
|
async execute(args) {
|
|
15694
15980
|
return await runSafeTracked("upload_document_from_url", async () => {
|
|
@@ -15703,11 +15989,11 @@ function buildKhWriteTools() {
|
|
|
15703
15989
|
update_knowledge: tool({
|
|
15704
15990
|
description: description6,
|
|
15705
15991
|
args: {
|
|
15706
|
-
knowledgeId:
|
|
15707
|
-
appendContent:
|
|
15708
|
-
replaceContent:
|
|
15709
|
-
additionalTags:
|
|
15710
|
-
category:
|
|
15992
|
+
knowledgeId: z31.string().min(1).describe("知识 ID(从 smart_search 获取)"),
|
|
15993
|
+
appendContent: z31.string().optional(),
|
|
15994
|
+
replaceContent: z31.string().optional(),
|
|
15995
|
+
additionalTags: z31.array(z31.string()).optional(),
|
|
15996
|
+
category: z31.string().optional()
|
|
15711
15997
|
},
|
|
15712
15998
|
async execute(args) {
|
|
15713
15999
|
return await runSafe("update_knowledge", async () => {
|
|
@@ -15722,8 +16008,8 @@ function buildKhWriteTools() {
|
|
|
15722
16008
|
flag_outdated: tool({
|
|
15723
16009
|
description: description7,
|
|
15724
16010
|
args: {
|
|
15725
|
-
knowledgeId:
|
|
15726
|
-
reason:
|
|
16011
|
+
knowledgeId: z31.string().min(1).describe("知识 ID"),
|
|
16012
|
+
reason: z31.string().min(5).max(500).describe("过时原因简述")
|
|
15727
16013
|
},
|
|
15728
16014
|
async execute(args) {
|
|
15729
16015
|
return await runSafe("flag_outdated", async () => {
|
|
@@ -15738,8 +16024,8 @@ function buildKhWriteTools() {
|
|
|
15738
16024
|
delete_knowledge: tool({
|
|
15739
16025
|
description: description8,
|
|
15740
16026
|
args: {
|
|
15741
|
-
knowledgeId:
|
|
15742
|
-
reason:
|
|
16027
|
+
knowledgeId: z31.string().min(1).describe("知识 ID"),
|
|
16028
|
+
reason: z31.string().min(3).max(300).describe("删除原因(写入审计日志)")
|
|
15743
16029
|
},
|
|
15744
16030
|
async execute(args) {
|
|
15745
16031
|
return await runSafe("delete_knowledge", async () => {
|
|
@@ -15754,9 +16040,9 @@ function buildKhWriteTools() {
|
|
|
15754
16040
|
list_recent: tool({
|
|
15755
16041
|
description: description9,
|
|
15756
16042
|
args: {
|
|
15757
|
-
days:
|
|
15758
|
-
limit:
|
|
15759
|
-
category:
|
|
16043
|
+
days: z31.number().int().min(1).max(90).optional().describe("最近几天(默认 7)"),
|
|
16044
|
+
limit: z31.number().int().min(1).max(50).optional().describe("返回条数(默认 10)"),
|
|
16045
|
+
category: z31.string().optional()
|
|
15760
16046
|
},
|
|
15761
16047
|
async execute(args) {
|
|
15762
16048
|
return await runSafe("list_recent", async () => {
|
|
@@ -15771,12 +16057,12 @@ function buildKhWriteTools() {
|
|
|
15771
16057
|
update_working_memory: tool({
|
|
15772
16058
|
description: description10,
|
|
15773
16059
|
args: {
|
|
15774
|
-
section:
|
|
15775
|
-
items:
|
|
15776
|
-
content:
|
|
15777
|
-
priority:
|
|
16060
|
+
section: z31.string().min(1).describe("分区名(constraints / in_progress / topic:xxx 等)"),
|
|
16061
|
+
items: z31.array(z31.object({
|
|
16062
|
+
content: z31.string().min(1),
|
|
16063
|
+
priority: z31.number().optional()
|
|
15778
16064
|
})),
|
|
15779
|
-
replace:
|
|
16065
|
+
replace: z31.boolean().optional().describe("是否替换分区全部内容(默认 false=追加)")
|
|
15780
16066
|
},
|
|
15781
16067
|
async execute(args) {
|
|
15782
16068
|
return await runSafe("update_working_memory", async () => {
|
|
@@ -15791,7 +16077,7 @@ function buildKhWriteTools() {
|
|
|
15791
16077
|
get_working_memory: tool({
|
|
15792
16078
|
description: description11,
|
|
15793
16079
|
args: {
|
|
15794
|
-
section:
|
|
16080
|
+
section: z31.string().optional().describe("分区名;不传则返回全部")
|
|
15795
16081
|
},
|
|
15796
16082
|
async execute(args) {
|
|
15797
16083
|
return await runSafe("get_working_memory", async () => {
|
|
@@ -15806,9 +16092,9 @@ function buildKhWriteTools() {
|
|
|
15806
16092
|
update_user_preference: tool({
|
|
15807
16093
|
description: description12,
|
|
15808
16094
|
args: {
|
|
15809
|
-
key:
|
|
15810
|
-
value:
|
|
15811
|
-
action:
|
|
16095
|
+
key: z31.string().min(1).max(64).describe("偏好键名(language / coding_style / signature 等)"),
|
|
16096
|
+
value: z31.string().min(1).max(500).describe("偏好值"),
|
|
16097
|
+
action: z31.enum(["set", "delete"]).optional()
|
|
15812
16098
|
},
|
|
15813
16099
|
async execute(args) {
|
|
15814
16100
|
return await runSafe("update_user_preference", async () => {
|
|
@@ -15823,9 +16109,9 @@ function buildKhWriteTools() {
|
|
|
15823
16109
|
web_search: tool({
|
|
15824
16110
|
description: description13,
|
|
15825
16111
|
args: {
|
|
15826
|
-
query:
|
|
15827
|
-
limit:
|
|
15828
|
-
time_range:
|
|
16112
|
+
query: z31.string().min(1).describe("搜索词"),
|
|
16113
|
+
limit: z31.number().int().min(1).max(10).optional(),
|
|
16114
|
+
time_range: z31.enum(["", "day", "week", "month", "year"]).optional()
|
|
15829
16115
|
},
|
|
15830
16116
|
async execute(args) {
|
|
15831
16117
|
return await runSafeTracked("web_search", async () => {
|
|
@@ -15840,11 +16126,11 @@ function buildKhWriteTools() {
|
|
|
15840
16126
|
generate_image: tool({
|
|
15841
16127
|
description: description14,
|
|
15842
16128
|
args: {
|
|
15843
|
-
prompt:
|
|
15844
|
-
n:
|
|
15845
|
-
size:
|
|
15846
|
-
transparent:
|
|
15847
|
-
alt:
|
|
16129
|
+
prompt: z31.string().min(4).max(4000).describe("画面描述"),
|
|
16130
|
+
n: z31.number().int().min(1).max(3).optional(),
|
|
16131
|
+
size: z31.string().optional(),
|
|
16132
|
+
transparent: z31.boolean().optional(),
|
|
16133
|
+
alt: z31.string().optional()
|
|
15848
16134
|
},
|
|
15849
16135
|
async execute(args) {
|
|
15850
16136
|
return await runSafeTracked("generate_image", async () => {
|
|
@@ -15863,7 +16149,7 @@ function buildBrowserTools() {
|
|
|
15863
16149
|
browser_navigate: tool({
|
|
15864
16150
|
description: description19,
|
|
15865
16151
|
args: {
|
|
15866
|
-
url:
|
|
16152
|
+
url: z31.string().min(1).describe("要打开的 URL;必须是 http(s)")
|
|
15867
16153
|
},
|
|
15868
16154
|
async execute(args) {
|
|
15869
16155
|
return await runSafe("browser_navigate", async () => {
|
|
@@ -15878,7 +16164,7 @@ function buildBrowserTools() {
|
|
|
15878
16164
|
browser_click: tool({
|
|
15879
16165
|
description: description20,
|
|
15880
16166
|
args: {
|
|
15881
|
-
selector:
|
|
16167
|
+
selector: z31.string().min(1).describe("CSS / Playwright locator,必须能唯一定位")
|
|
15882
16168
|
},
|
|
15883
16169
|
async execute(args) {
|
|
15884
16170
|
return await runSafe("browser_click", async () => {
|
|
@@ -15893,8 +16179,8 @@ function buildBrowserTools() {
|
|
|
15893
16179
|
browser_fill: tool({
|
|
15894
16180
|
description: description21,
|
|
15895
16181
|
args: {
|
|
15896
|
-
selector:
|
|
15897
|
-
value:
|
|
16182
|
+
selector: z31.string().min(1).describe("CSS / Playwright locator"),
|
|
16183
|
+
value: z31.string().describe("要填入的文本;原样写入不转义")
|
|
15898
16184
|
},
|
|
15899
16185
|
async execute(args) {
|
|
15900
16186
|
return await runSafe("browser_fill", async () => {
|
|
@@ -15909,8 +16195,8 @@ function buildBrowserTools() {
|
|
|
15909
16195
|
browser_screenshot: tool({
|
|
15910
16196
|
description: description22,
|
|
15911
16197
|
args: {
|
|
15912
|
-
fullPage:
|
|
15913
|
-
selector:
|
|
16198
|
+
fullPage: z31.boolean().optional().describe("是否截全长页面(默认仅可视区)"),
|
|
16199
|
+
selector: z31.string().optional().describe("CSS 选择器;指定时只截该元素")
|
|
15914
16200
|
},
|
|
15915
16201
|
async execute(args) {
|
|
15916
16202
|
return await runSafe("browser_screenshot", async () => {
|
|
@@ -15925,8 +16211,8 @@ function buildBrowserTools() {
|
|
|
15925
16211
|
browser_console: tool({
|
|
15926
16212
|
description: description23,
|
|
15927
16213
|
args: {
|
|
15928
|
-
level:
|
|
15929
|
-
sinceTs:
|
|
16214
|
+
level: z31.enum(["log", "info", "warn", "error", "debug"]).optional().describe("过滤级别"),
|
|
16215
|
+
sinceTs: z31.number().optional().describe("timestamp >= sinceTs 的条目")
|
|
15930
16216
|
},
|
|
15931
16217
|
async execute(args) {
|
|
15932
16218
|
return await runSafe("browser_console", async () => {
|
|
@@ -15941,8 +16227,8 @@ function buildBrowserTools() {
|
|
|
15941
16227
|
browser_network: tool({
|
|
15942
16228
|
description: description24,
|
|
15943
16229
|
args: {
|
|
15944
|
-
method:
|
|
15945
|
-
sinceTs:
|
|
16230
|
+
method: z31.string().optional().describe("HTTP 方法过滤(GET/POST/...)"),
|
|
16231
|
+
sinceTs: z31.number().optional().describe("start_ts >= sinceTs 的请求")
|
|
15946
16232
|
},
|
|
15947
16233
|
async execute(args) {
|
|
15948
16234
|
return await runSafe("browser_network", async () => {
|
|
@@ -15978,7 +16264,8 @@ var CORE_TOOL_NAMES = [
|
|
|
15978
16264
|
"model_chain",
|
|
15979
16265
|
"session_merge",
|
|
15980
16266
|
"plan_write",
|
|
15981
|
-
"plan_read"
|
|
16267
|
+
"plan_read",
|
|
16268
|
+
"adr_init"
|
|
15982
16269
|
];
|
|
15983
16270
|
var BROWSER_TOOL_NAMES = [
|
|
15984
16271
|
"browser_navigate",
|
|
@@ -16022,9 +16309,9 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16022
16309
|
smart_search: tool({
|
|
16023
16310
|
description,
|
|
16024
16311
|
args: {
|
|
16025
|
-
query:
|
|
16026
|
-
limit:
|
|
16027
|
-
prefer:
|
|
16312
|
+
query: z31.string().min(1).describe("自然语言查询词,例如「登录限流方案」「dev 服务器部署流程」"),
|
|
16313
|
+
limit: z31.number().int().min(1).max(15).optional().describe("返回条数,默认 5;超过 15 会被 KH 截断"),
|
|
16314
|
+
prefer: z31.array(z31.string()).optional().describe("偏好分类(best-effort);常用 architecture / anti_pattern / convention")
|
|
16028
16315
|
},
|
|
16029
16316
|
async execute(args) {
|
|
16030
16317
|
return await runSafe("smart_search", async () => {
|
|
@@ -16043,8 +16330,8 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16043
16330
|
save_chat_insight: tool({
|
|
16044
16331
|
description: description2,
|
|
16045
16332
|
args: {
|
|
16046
|
-
insight:
|
|
16047
|
-
category:
|
|
16333
|
+
insight: z31.string().min(20).max(5000).describe("完整知识条目(Markdown)。推荐三段式:## 问题 / ## 原因 / ## 解决"),
|
|
16334
|
+
category: z31.enum([
|
|
16048
16335
|
"convention",
|
|
16049
16336
|
"anti_pattern",
|
|
16050
16337
|
"architecture",
|
|
@@ -16054,7 +16341,7 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16054
16341
|
"tooling",
|
|
16055
16342
|
"decision"
|
|
16056
16343
|
]).describe("分类"),
|
|
16057
|
-
tags:
|
|
16344
|
+
tags: z31.array(z31.string().min(1)).optional().describe("标签数组,建议 `tech:xxx` / `platform:xxx`")
|
|
16058
16345
|
},
|
|
16059
16346
|
async execute(args) {
|
|
16060
16347
|
return await runSafe("save_chat_insight", async () => {
|
|
@@ -16077,25 +16364,25 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16077
16364
|
ast_edit: tool({
|
|
16078
16365
|
description: description15,
|
|
16079
16366
|
args: {
|
|
16080
|
-
action:
|
|
16367
|
+
action: z31.enum([
|
|
16081
16368
|
"replace_anchor",
|
|
16082
16369
|
"insert_after_anchor",
|
|
16083
16370
|
"insert_before_anchor",
|
|
16084
16371
|
"delete_range",
|
|
16085
16372
|
"rename_symbol"
|
|
16086
16373
|
]).describe("编辑类型;不同 action 需要的字段不同"),
|
|
16087
|
-
target:
|
|
16088
|
-
before_hash:
|
|
16089
|
-
auto_stage:
|
|
16090
|
-
description:
|
|
16091
|
-
anchor:
|
|
16092
|
-
regex:
|
|
16093
|
-
occurrence:
|
|
16094
|
-
payload:
|
|
16095
|
-
start:
|
|
16096
|
-
end:
|
|
16097
|
-
old_name:
|
|
16098
|
-
new_name:
|
|
16374
|
+
target: z31.string().min(1).describe("目标文件路径(相对 cwd 或绝对)"),
|
|
16375
|
+
before_hash: z31.string().optional().describe("操作前的 sha256 hex(强烈建议传,新文件传 null/省略)"),
|
|
16376
|
+
auto_stage: z31.boolean().optional().describe("已废弃(保留兼容字段):Phase 5 后 ast_edit 直接写入 session worktree,无需独立 stage"),
|
|
16377
|
+
description: z31.string().optional().describe("可选变更说明(写入 audit log)"),
|
|
16378
|
+
anchor: z31.string().optional().describe("anchor 类用:anchor 文本或 regex 源"),
|
|
16379
|
+
regex: z31.boolean().optional().describe("anchor 是否按 RegExp 解释,默认 false"),
|
|
16380
|
+
occurrence: z31.number().int().min(1).optional().describe("第几次匹配(1-based),默认 1"),
|
|
16381
|
+
payload: z31.string().optional().describe("anchor 类用:要写入的内容"),
|
|
16382
|
+
start: z31.number().int().min(1).optional().describe("delete_range 用:起始行(1-based)"),
|
|
16383
|
+
end: z31.number().int().min(1).optional().describe("delete_range 用:结束行(1-based)"),
|
|
16384
|
+
old_name: z31.string().optional().describe("rename_symbol 用:旧标识符"),
|
|
16385
|
+
new_name: z31.string().optional().describe("rename_symbol 用:新标识符")
|
|
16099
16386
|
},
|
|
16100
16387
|
async execute(args) {
|
|
16101
16388
|
return await runSafeTracked("ast_edit", async () => {
|
|
@@ -16118,10 +16405,10 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16118
16405
|
repo_map: tool({
|
|
16119
16406
|
description: description16,
|
|
16120
16407
|
args: {
|
|
16121
|
-
root:
|
|
16122
|
-
top:
|
|
16123
|
-
focus:
|
|
16124
|
-
max_files:
|
|
16408
|
+
root: z31.string().optional().describe("扫描根目录,默认 cwd"),
|
|
16409
|
+
top: z31.number().int().min(1).max(100).optional().describe("展示 top N 文件,默认 20"),
|
|
16410
|
+
focus: z31.string().optional().describe("聚焦文件(POSIX 相对路径)"),
|
|
16411
|
+
max_files: z31.number().int().min(10).max(5000).optional().describe("扫描上限,默认 500")
|
|
16125
16412
|
},
|
|
16126
16413
|
async execute(args) {
|
|
16127
16414
|
return await runSafeTracked("repo_map", async () => {
|
|
@@ -16142,14 +16429,14 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16142
16429
|
rules_debug: tool({
|
|
16143
16430
|
description: description17,
|
|
16144
16431
|
args: {
|
|
16145
|
-
current_agent:
|
|
16146
|
-
root:
|
|
16147
|
-
home_dir:
|
|
16148
|
-
project_dir:
|
|
16149
|
-
skip_personal:
|
|
16150
|
-
skip_project:
|
|
16151
|
-
skip_agent:
|
|
16152
|
-
markdown:
|
|
16432
|
+
current_agent: z31.string().optional().describe("当前 agent 名"),
|
|
16433
|
+
root: z31.string().optional().describe("项目根目录"),
|
|
16434
|
+
home_dir: z31.string().optional().describe("覆盖个人规则目录"),
|
|
16435
|
+
project_dir: z31.string().optional().describe("覆盖项目规则目录"),
|
|
16436
|
+
skip_personal: z31.boolean().optional(),
|
|
16437
|
+
skip_project: z31.boolean().optional(),
|
|
16438
|
+
skip_agent: z31.boolean().optional(),
|
|
16439
|
+
markdown: z31.boolean().optional().describe("默认 true:渲染 markdown 摘要")
|
|
16153
16440
|
},
|
|
16154
16441
|
async execute(args) {
|
|
16155
16442
|
return await runSafe("rules_debug", async () => {
|
|
@@ -16164,14 +16451,14 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16164
16451
|
review_approval: tool({
|
|
16165
16452
|
description: description18,
|
|
16166
16453
|
args: {
|
|
16167
|
-
verdict:
|
|
16168
|
-
pendingIds:
|
|
16169
|
-
notes:
|
|
16170
|
-
decisionLine:
|
|
16171
|
-
source:
|
|
16172
|
-
reviewerAgent:
|
|
16173
|
-
sessionId:
|
|
16174
|
-
model:
|
|
16454
|
+
verdict: z31.enum(["APPROVE", "APPROVE_WITH_NOTES"]).describe("审批裁决;REQUEST_CHANGES / BLOCK 不应调本工具"),
|
|
16455
|
+
pendingIds: z31.array(z31.string().min(1)).min(1).describe("本次 APPROVE 覆盖的 pending change id 列表"),
|
|
16456
|
+
notes: z31.string().min(1).max(2000).describe("审阅意见摘要(建议 ≤ 500 字)"),
|
|
16457
|
+
decisionLine: z31.string().optional().describe("`## Decision` 节首行原文(默认 verdict 字面量,机审证据)"),
|
|
16458
|
+
source: z31.enum(["reviewer", "codeforge-fallback"]).optional().describe("写入来源;默认 'reviewer',codeforge 补写时传 'codeforge-fallback'"),
|
|
16459
|
+
reviewerAgent: z31.string().optional().describe("写入 agent name(默认 'reviewer';fallback 时为 'codeforge')"),
|
|
16460
|
+
sessionId: z31.string().optional().describe("reviewer 子 session id(boomerang 溯源用,可选)"),
|
|
16461
|
+
model: z31.string().optional().describe("审批模型 id(审计用,可选)")
|
|
16175
16462
|
},
|
|
16176
16463
|
async execute(args) {
|
|
16177
16464
|
return await runSafe("review_approval", async () => {
|
|
@@ -16192,10 +16479,10 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16192
16479
|
model_chain: tool({
|
|
16193
16480
|
description: description25,
|
|
16194
16481
|
args: {
|
|
16195
|
-
agent:
|
|
16196
|
-
current:
|
|
16197
|
-
root:
|
|
16198
|
-
config_file:
|
|
16482
|
+
agent: z31.string().optional().describe("查指定 agent;不传 → 列出全部"),
|
|
16483
|
+
current: z31.string().optional().describe("当前已用过的模型(<provider>/<id>),用于算下一档"),
|
|
16484
|
+
root: z31.string().optional().describe("项目根目录,默认 cwd"),
|
|
16485
|
+
config_file: z31.string().optional().describe("配置文件名;默认 codeforge.json")
|
|
16199
16486
|
},
|
|
16200
16487
|
async execute(args) {
|
|
16201
16488
|
return await runSafe("model_chain", async () => {
|
|
@@ -16216,11 +16503,11 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16216
16503
|
session_merge: tool({
|
|
16217
16504
|
description: description26,
|
|
16218
16505
|
args: {
|
|
16219
|
-
action:
|
|
16220
|
-
session_id:
|
|
16221
|
-
plan_id:
|
|
16222
|
-
force:
|
|
16223
|
-
stat:
|
|
16506
|
+
action: z31.enum(["merge", "status", "discard", "diff"]).describe("操作类型:merge=合并到主仓(orchestrator 专用)/ status=查询状态 / discard=放弃 / diff=查看 worktree 改动"),
|
|
16507
|
+
session_id: z31.string().optional().describe("目标 session id;不传则用当前 session"),
|
|
16508
|
+
plan_id: z31.string().optional().describe("关联的 plan_id(reviewer 校验时用),格式 plan-YYYYMMDD-HHmmss-NNN"),
|
|
16509
|
+
force: z31.boolean().optional().describe("action=merge 时跳过 review 直接 squash merge(写审计)"),
|
|
16510
|
+
stat: z31.boolean().optional().describe("action=diff 时:true=只显示文件列表+统计,false=完整 diff(默认 false)")
|
|
16224
16511
|
},
|
|
16225
16512
|
async execute(args, input) {
|
|
16226
16513
|
return await runSafe("session_merge", async () => {
|
|
@@ -16256,9 +16543,9 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16256
16543
|
plan_write: tool({
|
|
16257
16544
|
description: description27,
|
|
16258
16545
|
args: {
|
|
16259
|
-
title:
|
|
16260
|
-
content:
|
|
16261
|
-
tags:
|
|
16546
|
+
title: z31.string().min(2).max(80).describe('方案简短标题(2-80 字),如 "实现 worktree session 隔离 Phase 1"'),
|
|
16547
|
+
content: z31.string().min(10).describe("方案 markdown 全文,建议 ≥ 50 行"),
|
|
16548
|
+
tags: z31.array(z31.string().min(1)).optional().describe('标签(可选),如 ["phase:1", "arch:worktree"]')
|
|
16262
16549
|
},
|
|
16263
16550
|
async execute(args) {
|
|
16264
16551
|
return await runSafeTracked("plan_write", async () => {
|
|
@@ -16277,8 +16564,8 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16277
16564
|
plan_read: tool({
|
|
16278
16565
|
description: description28,
|
|
16279
16566
|
args: {
|
|
16280
|
-
plan_id:
|
|
16281
|
-
path:
|
|
16567
|
+
plan_id: z31.string().optional().describe("方案 ID(推荐),格式 plan-YYYYMMDD-HHmmss-NNN"),
|
|
16568
|
+
path: z31.string().optional().describe("方案绝对路径(兜底用,没有 plan_id 元数据时退而求其次)")
|
|
16282
16569
|
},
|
|
16283
16570
|
async execute(args) {
|
|
16284
16571
|
return await runSafe("plan_read", async () => {
|
|
@@ -16297,6 +16584,25 @@ var codeforgeToolsServer = async (ctx) => {
|
|
|
16297
16584
|
return wrap(result, meta);
|
|
16298
16585
|
});
|
|
16299
16586
|
}
|
|
16587
|
+
}),
|
|
16588
|
+
adr_init: tool({
|
|
16589
|
+
description: description29,
|
|
16590
|
+
args: {
|
|
16591
|
+
cwd: z31.string().optional().describe("目标项目根目录,默认 process.cwd();通常无需传"),
|
|
16592
|
+
force: z31.boolean().optional().describe("已存在文件覆盖;覆盖前自动 .bak.<ts> 备份"),
|
|
16593
|
+
dryRun: z31.boolean().optional().describe("只输出将要执行的写入计划,不实际写盘"),
|
|
16594
|
+
writePrepare: z31.boolean().optional().describe("(npm 项目)自动合并 git config core.hooksPath 到 package.json scripts.prepare;写前自动 backup"),
|
|
16595
|
+
installPrePush: z31.boolean().optional().describe("是否同时生成 .githooks/pre-push hook,默认 true")
|
|
16596
|
+
},
|
|
16597
|
+
async execute(args) {
|
|
16598
|
+
return await runSafe("adr_init", async () => {
|
|
16599
|
+
const v = projectValidate("adr_init", ArgsSchema29, args);
|
|
16600
|
+
if (!v.ok)
|
|
16601
|
+
return wrap(JSON.parse(v.output));
|
|
16602
|
+
const result = await execute29(v.data);
|
|
16603
|
+
return wrap(result, { title: "adr_init" });
|
|
16604
|
+
});
|
|
16605
|
+
}
|
|
16300
16606
|
})
|
|
16301
16607
|
}
|
|
16302
16608
|
};
|
|
@@ -16305,10 +16611,10 @@ var handler8 = codeforgeToolsServer;
|
|
|
16305
16611
|
|
|
16306
16612
|
// plugins/discover-spec-suggest.ts
|
|
16307
16613
|
import { readFileSync as readFileSync3, readdirSync, statSync as statSync3 } from "node:fs";
|
|
16308
|
-
import { join as
|
|
16614
|
+
import { join as join15 } from "node:path";
|
|
16309
16615
|
|
|
16310
16616
|
// lib/handoff-schema.ts
|
|
16311
|
-
import { z as
|
|
16617
|
+
import { z as z32 } from "zod";
|
|
16312
16618
|
|
|
16313
16619
|
// node_modules/yaml/dist/index.js
|
|
16314
16620
|
var composer = require_composer();
|
|
@@ -16361,92 +16667,92 @@ var MAX_HANDOFF_SIZE = 100 * 1024;
|
|
|
16361
16667
|
var SLUG_REGEX = /^[a-z0-9][a-z0-9-]{0,49}$/;
|
|
16362
16668
|
var SCORE_DIMENSIONS = ["functional", "ux", "technical", "constraints", "edge_cases"];
|
|
16363
16669
|
var COMBO_VALUES = ["A", "B", "C", "D"];
|
|
16364
|
-
var NeedSchema =
|
|
16365
|
-
id:
|
|
16366
|
-
type:
|
|
16367
|
-
statement:
|
|
16368
|
-
rationale:
|
|
16369
|
-
acceptance:
|
|
16670
|
+
var NeedSchema = z32.object({
|
|
16671
|
+
id: z32.string().min(1),
|
|
16672
|
+
type: z32.enum(["must", "should", "nice-to-have"]),
|
|
16673
|
+
statement: z32.string().min(1),
|
|
16674
|
+
rationale: z32.string().optional(),
|
|
16675
|
+
acceptance: z32.array(z32.string()).optional()
|
|
16370
16676
|
});
|
|
16371
|
-
var BoundarySchema =
|
|
16372
|
-
excluded:
|
|
16373
|
-
reason:
|
|
16677
|
+
var BoundarySchema = z32.object({
|
|
16678
|
+
excluded: z32.string().min(1),
|
|
16679
|
+
reason: z32.string().min(1)
|
|
16374
16680
|
});
|
|
16375
|
-
var AssumptionSchema =
|
|
16376
|
-
statement:
|
|
16377
|
-
confidence:
|
|
16378
|
-
needs_validation_by:
|
|
16681
|
+
var AssumptionSchema = z32.object({
|
|
16682
|
+
statement: z32.string().min(1),
|
|
16683
|
+
confidence: z32.enum(["verified", "speculation", "high-risk-unknown"]),
|
|
16684
|
+
needs_validation_by: z32.enum(["plan", "coder", "runtime"]).optional()
|
|
16379
16685
|
});
|
|
16380
|
-
var OpenIssueSchema =
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
id:
|
|
16384
|
-
question:
|
|
16385
|
-
blocking:
|
|
16686
|
+
var OpenIssueSchema = z32.union([
|
|
16687
|
+
z32.string().min(1),
|
|
16688
|
+
z32.object({
|
|
16689
|
+
id: z32.string().optional(),
|
|
16690
|
+
question: z32.string().min(1),
|
|
16691
|
+
blocking: z32.boolean().optional()
|
|
16386
16692
|
})
|
|
16387
16693
|
]);
|
|
16388
|
-
var RedFlagsSchema =
|
|
16389
|
-
raised:
|
|
16390
|
-
combos:
|
|
16391
|
-
reasons:
|
|
16392
|
-
user_persisted_rounds:
|
|
16393
|
-
downstream_advisory:
|
|
16694
|
+
var RedFlagsSchema = z32.object({
|
|
16695
|
+
raised: z32.boolean(),
|
|
16696
|
+
combos: z32.array(z32.enum(COMBO_VALUES)).default([]),
|
|
16697
|
+
reasons: z32.array(z32.string()).default([]),
|
|
16698
|
+
user_persisted_rounds: z32.number().int().nonnegative().default(0),
|
|
16699
|
+
downstream_advisory: z32.string().nullable().optional()
|
|
16394
16700
|
}).superRefine((rf, ctx) => {
|
|
16395
16701
|
if (rf.raised) {
|
|
16396
16702
|
if (rf.combos.length === 0) {
|
|
16397
16703
|
ctx.addIssue({
|
|
16398
|
-
code:
|
|
16704
|
+
code: z32.ZodIssueCode.custom,
|
|
16399
16705
|
message: "red_flags.raised=true 时 combos 必须 >=1",
|
|
16400
16706
|
path: ["combos"]
|
|
16401
16707
|
});
|
|
16402
16708
|
}
|
|
16403
16709
|
if (rf.reasons.length === 0) {
|
|
16404
16710
|
ctx.addIssue({
|
|
16405
|
-
code:
|
|
16711
|
+
code: z32.ZodIssueCode.custom,
|
|
16406
16712
|
message: "red_flags.raised=true 时 reasons 必须 >=1",
|
|
16407
16713
|
path: ["reasons"]
|
|
16408
16714
|
});
|
|
16409
16715
|
}
|
|
16410
16716
|
}
|
|
16411
16717
|
});
|
|
16412
|
-
var ScoresSchema =
|
|
16413
|
-
var PreCodingBlockerSchema =
|
|
16414
|
-
id:
|
|
16415
|
-
blocker:
|
|
16416
|
-
source:
|
|
16417
|
-
must_resolve_by:
|
|
16718
|
+
var ScoresSchema = z32.object(Object.fromEntries(SCORE_DIMENSIONS.map((d) => [d, z32.number().min(0).max(1)])));
|
|
16719
|
+
var PreCodingBlockerSchema = z32.object({
|
|
16720
|
+
id: z32.string().regex(/^PRE-\d+$/, "id 必须形如 PRE-1 / PRE-2"),
|
|
16721
|
+
blocker: z32.string().min(1),
|
|
16722
|
+
source: z32.enum(["assumption", "red_flag", "open_issue"]),
|
|
16723
|
+
must_resolve_by: z32.enum(["user", "codeforge"])
|
|
16418
16724
|
});
|
|
16419
|
-
var KhRefSchema =
|
|
16420
|
-
kh_id:
|
|
16421
|
-
title:
|
|
16422
|
-
relevance:
|
|
16725
|
+
var KhRefSchema = z32.object({
|
|
16726
|
+
kh_id: z32.string(),
|
|
16727
|
+
title: z32.string(),
|
|
16728
|
+
relevance: z32.enum(["positive", "negative", "neutral"]).optional()
|
|
16423
16729
|
});
|
|
16424
|
-
var HandoffSchema =
|
|
16425
|
-
schema_version:
|
|
16426
|
-
slug:
|
|
16427
|
-
title:
|
|
16428
|
-
created_at:
|
|
16429
|
-
discover_session_id:
|
|
16430
|
-
weighted_score:
|
|
16730
|
+
var HandoffSchema = z32.object({
|
|
16731
|
+
schema_version: z32.string().regex(/^\d+\.\d+\.\d+$/, "schema_version 必须形如 1.1.0 / 1.2.0"),
|
|
16732
|
+
slug: z32.string().regex(SLUG_REGEX, "slug 仅允许 [a-z0-9-],长度 1-50,首字符为字母数字"),
|
|
16733
|
+
title: z32.string().min(1).max(200),
|
|
16734
|
+
created_at: z32.string().optional(),
|
|
16735
|
+
discover_session_id: z32.string().optional(),
|
|
16736
|
+
weighted_score: z32.number().min(0).max(1),
|
|
16431
16737
|
scores: ScoresSchema,
|
|
16432
|
-
needs:
|
|
16433
|
-
boundaries:
|
|
16434
|
-
assumptions:
|
|
16435
|
-
open_issues:
|
|
16436
|
-
rejected_alternatives:
|
|
16437
|
-
acceptance_criteria:
|
|
16438
|
-
id:
|
|
16439
|
-
description:
|
|
16440
|
-
measurable:
|
|
16441
|
-
metric:
|
|
16738
|
+
needs: z32.array(NeedSchema).min(1, "needs 必须 >=1"),
|
|
16739
|
+
boundaries: z32.array(BoundarySchema).min(1, "boundaries 必须 >=1"),
|
|
16740
|
+
assumptions: z32.array(AssumptionSchema),
|
|
16741
|
+
open_issues: z32.array(OpenIssueSchema).default([]),
|
|
16742
|
+
rejected_alternatives: z32.array(z32.object({ option: z32.string(), reason: z32.string() })).default([]),
|
|
16743
|
+
acceptance_criteria: z32.array(z32.object({
|
|
16744
|
+
id: z32.string().regex(/^AC-/, "AC id 必须以 AC- 开头"),
|
|
16745
|
+
description: z32.string().min(1),
|
|
16746
|
+
measurable: z32.boolean().optional(),
|
|
16747
|
+
metric: z32.string().optional()
|
|
16442
16748
|
})).default([]),
|
|
16443
16749
|
red_flags: RedFlagsSchema,
|
|
16444
|
-
pre_coding_blockers:
|
|
16445
|
-
kh_references:
|
|
16446
|
-
adr_refs:
|
|
16447
|
-
related_artifacts:
|
|
16448
|
-
prd:
|
|
16449
|
-
transcript:
|
|
16750
|
+
pre_coding_blockers: z32.array(PreCodingBlockerSchema).default([]),
|
|
16751
|
+
kh_references: z32.array(KhRefSchema).default([]),
|
|
16752
|
+
adr_refs: z32.array(z32.string()).default([]),
|
|
16753
|
+
related_artifacts: z32.object({
|
|
16754
|
+
prd: z32.string().optional(),
|
|
16755
|
+
transcript: z32.string().optional()
|
|
16450
16756
|
}).optional()
|
|
16451
16757
|
});
|
|
16452
16758
|
function validateHandoff(rawYaml, fileSize) {
|
|
@@ -16472,9 +16778,9 @@ function validateHandoff(rawYaml, fileSize) {
|
|
|
16472
16778
|
const result = HandoffSchema.safeParse(parsed);
|
|
16473
16779
|
if (!result.success) {
|
|
16474
16780
|
const first = result.error.issues[0];
|
|
16475
|
-
const
|
|
16781
|
+
const path19 = first?.path?.join(".") ?? "(root)";
|
|
16476
16782
|
const msg = first?.message ?? "unknown";
|
|
16477
|
-
return { ok: false, reason: `schema 校验失败:${
|
|
16783
|
+
return { ok: false, reason: `schema 校验失败:${path19}: ${msg}` };
|
|
16478
16784
|
}
|
|
16479
16785
|
return { ok: true, data: result.data, schemaVersion: result.data.schema_version };
|
|
16480
16786
|
}
|
|
@@ -16491,7 +16797,7 @@ var SESSION_TTL_MS2 = 24 * 60 * 60 * 1000;
|
|
|
16491
16797
|
var MATCH_THRESHOLD = 0.15;
|
|
16492
16798
|
var MAX_CANDIDATES = 3;
|
|
16493
16799
|
var NUDGE_MAX_LEN = 1500;
|
|
16494
|
-
var SPECS_REL_DIR =
|
|
16800
|
+
var SPECS_REL_DIR = join15(".codeforge", "specs");
|
|
16495
16801
|
var sessionMap = new Map;
|
|
16496
16802
|
function pruneIfOversize2() {
|
|
16497
16803
|
while (sessionMap.size > SESSION_CAP2) {
|
|
@@ -16598,7 +16904,7 @@ function loadSpecs(rootDir, opts = {}) {
|
|
|
16598
16904
|
const dirExists = opts.dirExists ?? defaultDirExists;
|
|
16599
16905
|
const statReader = opts.statReader ?? defaultStatReader;
|
|
16600
16906
|
const log6 = makePluginLogger(PLUGIN_NAME9);
|
|
16601
|
-
const specsRoot =
|
|
16907
|
+
const specsRoot = join15(rootDir, SPECS_REL_DIR);
|
|
16602
16908
|
const records = [];
|
|
16603
16909
|
if (!dirExists(specsRoot)) {
|
|
16604
16910
|
log6.info(`specs 目录不存在,plugin 将 no-op`, { specsRoot });
|
|
@@ -16619,7 +16925,7 @@ function loadSpecs(rootDir, opts = {}) {
|
|
|
16619
16925
|
log6.info(`跳过非合法 slug 命名的条目`, { entry });
|
|
16620
16926
|
continue;
|
|
16621
16927
|
}
|
|
16622
|
-
const specDir =
|
|
16928
|
+
const specDir = join15(specsRoot, entry);
|
|
16623
16929
|
let dirStat;
|
|
16624
16930
|
try {
|
|
16625
16931
|
dirStat = statReader(specDir);
|
|
@@ -16632,7 +16938,7 @@ function loadSpecs(rootDir, opts = {}) {
|
|
|
16632
16938
|
}
|
|
16633
16939
|
if (!dirStat.isDirectory)
|
|
16634
16940
|
continue;
|
|
16635
|
-
const handoffPath =
|
|
16941
|
+
const handoffPath = join15(specDir, "handoff.yaml");
|
|
16636
16942
|
let fileStat;
|
|
16637
16943
|
try {
|
|
16638
16944
|
fileStat = statReader(handoffPath);
|
|
@@ -17639,13 +17945,13 @@ var handler11 = khReminderServer;
|
|
|
17639
17945
|
|
|
17640
17946
|
// lib/memories.ts
|
|
17641
17947
|
import { promises as fs15 } from "node:fs";
|
|
17642
|
-
import * as
|
|
17948
|
+
import * as path19 from "node:path";
|
|
17643
17949
|
import * as os5 from "node:os";
|
|
17644
17950
|
function resolveConfig(c) {
|
|
17645
17951
|
return {
|
|
17646
17952
|
projectRoot: c.projectRoot,
|
|
17647
17953
|
homeDir: c.homeDir ?? os5.homedir(),
|
|
17648
|
-
projectName: c.projectName ??
|
|
17954
|
+
projectName: c.projectName ?? path19.basename(c.projectRoot),
|
|
17649
17955
|
kh: c.kh,
|
|
17650
17956
|
now: c.now ?? Date.now,
|
|
17651
17957
|
log: c.log ?? (() => {}),
|
|
@@ -17654,9 +17960,9 @@ function resolveConfig(c) {
|
|
|
17654
17960
|
}
|
|
17655
17961
|
function fileFor(scope, cfg) {
|
|
17656
17962
|
if (scope === "project") {
|
|
17657
|
-
return
|
|
17963
|
+
return path19.join(cfg.projectRoot, ".codeforge", "memories.json");
|
|
17658
17964
|
}
|
|
17659
|
-
return
|
|
17965
|
+
return path19.join(cfg.homeDir, ".codeforge", "memories.json");
|
|
17660
17966
|
}
|
|
17661
17967
|
async function readBank(p) {
|
|
17662
17968
|
try {
|
|
@@ -17670,7 +17976,7 @@ async function readBank(p) {
|
|
|
17670
17976
|
}
|
|
17671
17977
|
}
|
|
17672
17978
|
async function writeBank(p, items) {
|
|
17673
|
-
await fs15.mkdir(
|
|
17979
|
+
await fs15.mkdir(path19.dirname(p), { recursive: true });
|
|
17674
17980
|
const tmp = `${p}.tmp`;
|
|
17675
17981
|
await fs15.writeFile(tmp, JSON.stringify(items, null, 2), "utf8");
|
|
17676
17982
|
await fs15.rename(tmp, p);
|
|
@@ -18217,7 +18523,7 @@ var handler13 = modelFallbackServer;
|
|
|
18217
18523
|
|
|
18218
18524
|
// plugins/subtask-heartbeat.ts
|
|
18219
18525
|
import { promises as fsPromises } from "node:fs";
|
|
18220
|
-
import * as
|
|
18526
|
+
import * as path20 from "node:path";
|
|
18221
18527
|
init_runtime_paths();
|
|
18222
18528
|
init_global_config();
|
|
18223
18529
|
var recordSessionParent2 = recordSessionParent;
|
|
@@ -18305,11 +18611,11 @@ function extractTaskArgs(args) {
|
|
|
18305
18611
|
const a = args;
|
|
18306
18612
|
const rawDesc = typeof a["description"] === "string" ? a["description"] : null;
|
|
18307
18613
|
const rawPrompt = typeof a["prompt"] === "string" ? a["prompt"] : null;
|
|
18308
|
-
const
|
|
18614
|
+
const description30 = rawDesc ?? (rawPrompt ? rawPrompt.slice(0, 60) : null);
|
|
18309
18615
|
const subagentType = typeof a["subagent_type"] === "string" && a["subagent_type"] || typeof a["agent"] === "string" && a["agent"] || typeof a["agentType"] === "string" && a["agentType"] || typeof a["agent_type"] === "string" && a["agent_type"] || null;
|
|
18310
|
-
if (!
|
|
18616
|
+
if (!description30 && !subagentType)
|
|
18311
18617
|
return null;
|
|
18312
|
-
return { description:
|
|
18618
|
+
return { description: description30, subagentType };
|
|
18313
18619
|
}
|
|
18314
18620
|
function enqueuePendingTask(parentID, entry, now = Date.now()) {
|
|
18315
18621
|
const ts = entry.ts ?? now;
|
|
@@ -18519,7 +18825,7 @@ function buildAfterLogLine(toolName, ok, durationMs, now = Date.now()) {
|
|
|
18519
18825
|
}
|
|
18520
18826
|
async function appendSubagentLog(filePath, line, log8) {
|
|
18521
18827
|
try {
|
|
18522
|
-
await fsPromises.mkdir(
|
|
18828
|
+
await fsPromises.mkdir(path20.dirname(filePath), { recursive: true });
|
|
18523
18829
|
await fsPromises.appendFile(filePath, line + `
|
|
18524
18830
|
`, "utf8");
|
|
18525
18831
|
} catch (err) {
|
|
@@ -18853,7 +19159,7 @@ var handler15 = parallelStatusServer;
|
|
|
18853
19159
|
|
|
18854
19160
|
// plugins/parallel-tool-nudge.ts
|
|
18855
19161
|
import { readFileSync as readFileSync4, readdirSync as readdirSync2, statSync as statSync4 } from "node:fs";
|
|
18856
|
-
import { join as
|
|
19162
|
+
import { join as join17 } from "node:path";
|
|
18857
19163
|
import { homedir as homedir6 } from "node:os";
|
|
18858
19164
|
var PLUGIN_NAME16 = "parallel-tool-nudge";
|
|
18859
19165
|
logLifecycle(PLUGIN_NAME16, "import", {});
|
|
@@ -18909,10 +19215,10 @@ function loadAgentToolsMap(rootDir, opts = {}) {
|
|
|
18909
19215
|
const reader = opts.reader ?? defaultReader2;
|
|
18910
19216
|
const dirReader = opts.dirReader ?? defaultDirReader2;
|
|
18911
19217
|
const dirExists = opts.dirExists ?? defaultDirExists2;
|
|
18912
|
-
const homeAgentsDir = opts.homeAgentsDir ??
|
|
19218
|
+
const homeAgentsDir = opts.homeAgentsDir ?? join17(homedir6(), ".config", "opencode", "agents");
|
|
18913
19219
|
const candidateDirs = [
|
|
18914
|
-
|
|
18915
|
-
|
|
19220
|
+
join17(rootDir, ".codeforge", "agents"),
|
|
19221
|
+
join17(rootDir, "agents"),
|
|
18916
19222
|
homeAgentsDir
|
|
18917
19223
|
];
|
|
18918
19224
|
const result = new Map;
|
|
@@ -18935,20 +19241,20 @@ function loadAgentToolsMap(rootDir, opts = {}) {
|
|
|
18935
19241
|
for (const entry of entries) {
|
|
18936
19242
|
if (!entry.endsWith(".md"))
|
|
18937
19243
|
continue;
|
|
18938
|
-
const
|
|
19244
|
+
const path21 = join17(dir, entry);
|
|
18939
19245
|
let content;
|
|
18940
19246
|
try {
|
|
18941
|
-
content = reader(
|
|
19247
|
+
content = reader(path21);
|
|
18942
19248
|
} catch (err) {
|
|
18943
19249
|
log9.warn(`agent.md 读取失败(已跳过)`, {
|
|
18944
|
-
path:
|
|
19250
|
+
path: path21,
|
|
18945
19251
|
error: err instanceof Error ? err.message : String(err)
|
|
18946
19252
|
});
|
|
18947
19253
|
continue;
|
|
18948
19254
|
}
|
|
18949
19255
|
const parsed = parseAgentFrontmatter(content);
|
|
18950
19256
|
if (!parsed) {
|
|
18951
|
-
log9.warn(`agent frontmatter 解析失败(已跳过)`, { path:
|
|
19257
|
+
log9.warn(`agent frontmatter 解析失败(已跳过)`, { path: path21 });
|
|
18952
19258
|
continue;
|
|
18953
19259
|
}
|
|
18954
19260
|
if (result.has(parsed.name))
|
|
@@ -19141,7 +19447,7 @@ var handler17 = async (_ctx3) => {
|
|
|
19141
19447
|
// lib/event-stream.ts
|
|
19142
19448
|
import { promises as fs16 } from "node:fs";
|
|
19143
19449
|
init_runtime_paths();
|
|
19144
|
-
import * as
|
|
19450
|
+
import * as path21 from "node:path";
|
|
19145
19451
|
async function loadSession(id, opts = {}) {
|
|
19146
19452
|
const file = resolveSessionFile(id, opts);
|
|
19147
19453
|
const raw = await fs16.readFile(file, "utf8");
|
|
@@ -19161,7 +19467,7 @@ async function listSessions(opts = {}) {
|
|
|
19161
19467
|
for (const e of entries) {
|
|
19162
19468
|
if (!e.isFile() || !e.name.endsWith(".jsonl"))
|
|
19163
19469
|
continue;
|
|
19164
|
-
const file =
|
|
19470
|
+
const file = path21.join(dir, e.name);
|
|
19165
19471
|
const id = e.name.replace(/\.jsonl$/, "");
|
|
19166
19472
|
try {
|
|
19167
19473
|
const stat = await fs16.stat(file);
|
|
@@ -19188,11 +19494,11 @@ async function listSessions(opts = {}) {
|
|
|
19188
19494
|
return out;
|
|
19189
19495
|
}
|
|
19190
19496
|
function resolveDir(opts = {}) {
|
|
19191
|
-
const root =
|
|
19192
|
-
return opts.sessions_dir ?
|
|
19497
|
+
const root = path21.resolve(opts.root ?? process.cwd());
|
|
19498
|
+
return opts.sessions_dir ? path21.resolve(root, opts.sessions_dir) : path21.join(runtimeDir(root), "sessions");
|
|
19193
19499
|
}
|
|
19194
19500
|
function resolveSessionFile(id, opts = {}) {
|
|
19195
|
-
return
|
|
19501
|
+
return path21.join(resolveDir(opts), `${id}.jsonl`);
|
|
19196
19502
|
}
|
|
19197
19503
|
function parseJsonl(id, raw) {
|
|
19198
19504
|
const events = [];
|
|
@@ -19457,10 +19763,10 @@ function isRecoveryWorthShowing(plan) {
|
|
|
19457
19763
|
// lib/block-pending.ts
|
|
19458
19764
|
init_runtime_paths();
|
|
19459
19765
|
import { promises as fs17 } from "node:fs";
|
|
19460
|
-
import * as
|
|
19766
|
+
import * as path22 from "node:path";
|
|
19461
19767
|
function blockPendingFilePath(absRoot) {
|
|
19462
19768
|
const rd = runtimeDir(absRoot, { ensure: false });
|
|
19463
|
-
return
|
|
19769
|
+
return path22.join(rd, "sessions", "autonomous-blocks.ndjson");
|
|
19464
19770
|
}
|
|
19465
19771
|
function consumeLockPath(absRoot) {
|
|
19466
19772
|
return blockPendingFilePath(absRoot) + ".consume.lock";
|
|
@@ -19525,7 +19831,7 @@ async function markBlocksConsumed(absRoot, entries) {
|
|
|
19525
19831
|
if (entries.length === 0)
|
|
19526
19832
|
return;
|
|
19527
19833
|
const file = blockPendingFilePath(absRoot);
|
|
19528
|
-
await fs17.mkdir(
|
|
19834
|
+
await fs17.mkdir(path22.dirname(file), { recursive: true });
|
|
19529
19835
|
const now = new Date().toISOString();
|
|
19530
19836
|
const lines = entries.map((e) => ({
|
|
19531
19837
|
type: "consume",
|
|
@@ -19675,7 +19981,7 @@ var handler18 = sessionRecoveryServer;
|
|
|
19675
19981
|
|
|
19676
19982
|
// plugins/subtasks.ts
|
|
19677
19983
|
import { promises as fs18 } from "node:fs";
|
|
19678
|
-
import * as
|
|
19984
|
+
import * as path23 from "node:path";
|
|
19679
19985
|
|
|
19680
19986
|
// lib/parallel-merge.ts
|
|
19681
19987
|
init_worktree_ops();
|
|
@@ -20290,7 +20596,7 @@ function buildSystemPrompt(maxSubtasks) {
|
|
|
20290
20596
|
].join(`
|
|
20291
20597
|
`);
|
|
20292
20598
|
}
|
|
20293
|
-
async function decomposeTask(
|
|
20599
|
+
async function decomposeTask(description30, opts) {
|
|
20294
20600
|
const log11 = opts.log ?? (() => {});
|
|
20295
20601
|
if (opts.mockResponse) {
|
|
20296
20602
|
return validateAndFinalize(opts.mockResponse, undefined, log11, opts.maxSubtasks ?? DEFAULT_MAX_SUBTASKS);
|
|
@@ -20300,7 +20606,7 @@ async function decomposeTask(description29, opts) {
|
|
|
20300
20606
|
let childSessionId;
|
|
20301
20607
|
try {
|
|
20302
20608
|
const created = await opts.client.session.create({
|
|
20303
|
-
body: { title: `decompose:${clip6(
|
|
20609
|
+
body: { title: `decompose:${clip6(description30, 60)}` },
|
|
20304
20610
|
query: opts.directory ? { directory: opts.directory } : undefined
|
|
20305
20611
|
});
|
|
20306
20612
|
if (created.error || !created.data?.id) {
|
|
@@ -20317,7 +20623,7 @@ async function decomposeTask(description29, opts) {
|
|
|
20317
20623
|
path: { id: childSessionId },
|
|
20318
20624
|
body: {
|
|
20319
20625
|
system: systemText,
|
|
20320
|
-
parts: [{ type: "text", text:
|
|
20626
|
+
parts: [{ type: "text", text: description30 }]
|
|
20321
20627
|
},
|
|
20322
20628
|
query: opts.directory ? { directory: opts.directory } : undefined
|
|
20323
20629
|
}));
|
|
@@ -20493,14 +20799,14 @@ function describe8(err) {
|
|
|
20493
20799
|
}
|
|
20494
20800
|
}
|
|
20495
20801
|
function sleep2(ms) {
|
|
20496
|
-
return new Promise((
|
|
20802
|
+
return new Promise((resolve17) => setTimeout(resolve17, ms));
|
|
20497
20803
|
}
|
|
20498
20804
|
|
|
20499
20805
|
// plugins/subtasks.ts
|
|
20500
20806
|
init_runtime_paths();
|
|
20501
20807
|
var PLUGIN_NAME19 = "subtasks";
|
|
20502
20808
|
function getLogFile(root = process.cwd()) {
|
|
20503
|
-
return
|
|
20809
|
+
return path23.join(runtimeDir(root), "logs", "subtasks.log");
|
|
20504
20810
|
}
|
|
20505
20811
|
var VERB_RE = /^([a-zA-Z]{3,12})/;
|
|
20506
20812
|
var CN_VERBS = [
|
|
@@ -20805,7 +21111,7 @@ async function writeLog(level, msg, data) {
|
|
|
20805
21111
|
`;
|
|
20806
21112
|
try {
|
|
20807
21113
|
const logFile = getLogFile();
|
|
20808
|
-
await fs18.mkdir(
|
|
21114
|
+
await fs18.mkdir(path23.dirname(logFile), { recursive: true });
|
|
20809
21115
|
await fs18.appendFile(logFile, line, "utf8");
|
|
20810
21116
|
} catch {}
|
|
20811
21117
|
}
|
|
@@ -20822,8 +21128,8 @@ var subtasksServer = async (ctx) => {
|
|
|
20822
21128
|
try {
|
|
20823
21129
|
if (input?.command !== "parallel")
|
|
20824
21130
|
return;
|
|
20825
|
-
const
|
|
20826
|
-
if (!
|
|
21131
|
+
const description30 = (input.arguments ?? "").trim();
|
|
21132
|
+
if (!description30) {
|
|
20827
21133
|
return;
|
|
20828
21134
|
}
|
|
20829
21135
|
let autoMerge = false;
|
|
@@ -20862,7 +21168,7 @@ var subtasksServer = async (ctx) => {
|
|
|
20862
21168
|
} : undefined;
|
|
20863
21169
|
const replyLines = [];
|
|
20864
21170
|
const messageCtx = {
|
|
20865
|
-
content: `/parallel ${
|
|
21171
|
+
content: `/parallel ${description30}`,
|
|
20866
21172
|
reply: (s) => {
|
|
20867
21173
|
replyLines.push(s);
|
|
20868
21174
|
return Promise.resolve();
|
|
@@ -21323,7 +21629,7 @@ var handler21 = tokenManagerServer;
|
|
|
21323
21629
|
|
|
21324
21630
|
// plugins/tool-policy.ts
|
|
21325
21631
|
import { promises as fs19 } from "node:fs";
|
|
21326
|
-
import * as
|
|
21632
|
+
import * as path25 from "node:path";
|
|
21327
21633
|
|
|
21328
21634
|
// lib/tool-risk.ts
|
|
21329
21635
|
var RISK_PATTERNS = [
|
|
@@ -21491,7 +21797,7 @@ function buildHaystackFor(args, matchOn) {
|
|
|
21491
21797
|
}
|
|
21492
21798
|
|
|
21493
21799
|
// lib/file-regex-acl.ts
|
|
21494
|
-
import * as
|
|
21800
|
+
import * as path24 from "node:path";
|
|
21495
21801
|
function compileRule(r) {
|
|
21496
21802
|
if (r instanceof RegExp)
|
|
21497
21803
|
return r;
|
|
@@ -21557,7 +21863,7 @@ function normalizePath2(p) {
|
|
|
21557
21863
|
let s = p.replace(/\\/g, "/");
|
|
21558
21864
|
if (s.startsWith("./"))
|
|
21559
21865
|
s = s.slice(2);
|
|
21560
|
-
s =
|
|
21866
|
+
s = path24.posix.normalize(s);
|
|
21561
21867
|
return s;
|
|
21562
21868
|
}
|
|
21563
21869
|
function checkFileAccess(acl, file, op) {
|
|
@@ -21660,9 +21966,9 @@ function decideToolCall(ctx, cfg = {}, currentAgent) {
|
|
|
21660
21966
|
const action = risks.length > 0 || worstAcl === "deny" ? "deny" : "allow";
|
|
21661
21967
|
return { action, reasons, risks, acl: aclResults };
|
|
21662
21968
|
}
|
|
21663
|
-
var POLICY_PATH =
|
|
21969
|
+
var POLICY_PATH = path25.join(".codeforge", "policy.json");
|
|
21664
21970
|
async function loadPolicy(root = process.cwd()) {
|
|
21665
|
-
const file =
|
|
21971
|
+
const file = path25.join(root, POLICY_PATH);
|
|
21666
21972
|
try {
|
|
21667
21973
|
const raw = await fs19.readFile(file, "utf8");
|
|
21668
21974
|
const data = JSON.parse(raw);
|
|
@@ -21760,15 +22066,15 @@ var toolPolicyServer = async (ctx) => {
|
|
|
21760
22066
|
var handler22 = toolPolicyServer;
|
|
21761
22067
|
|
|
21762
22068
|
// plugins/update-checker.ts
|
|
21763
|
-
import { existsSync as
|
|
22069
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
21764
22070
|
import { homedir as homedir8 } from "node:os";
|
|
21765
|
-
import { join as
|
|
22071
|
+
import { join as join23 } from "node:path";
|
|
21766
22072
|
|
|
21767
22073
|
// lib/update-checker-impl.ts
|
|
21768
22074
|
import { createHash as createHash5 } from "node:crypto";
|
|
21769
22075
|
import {
|
|
21770
22076
|
copyFileSync,
|
|
21771
|
-
existsSync as
|
|
22077
|
+
existsSync as existsSync5,
|
|
21772
22078
|
mkdirSync as mkdirSync3,
|
|
21773
22079
|
mkdtempSync,
|
|
21774
22080
|
readFileSync as readFileSync5,
|
|
@@ -21779,15 +22085,15 @@ import {
|
|
|
21779
22085
|
writeFileSync as writeFileSync2
|
|
21780
22086
|
} from "node:fs";
|
|
21781
22087
|
import { homedir as homedir7, tmpdir } from "node:os";
|
|
21782
|
-
import { dirname as
|
|
21783
|
-
import { fileURLToPath } from "node:url";
|
|
22088
|
+
import { dirname as dirname14, join as join22 } from "node:path";
|
|
22089
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
21784
22090
|
import * as https from "node:https";
|
|
21785
22091
|
import * as zlib from "node:zlib";
|
|
21786
22092
|
|
|
21787
22093
|
// lib/version-injected.ts
|
|
21788
22094
|
function getInjectedVersion() {
|
|
21789
22095
|
try {
|
|
21790
|
-
const v = "0.5.
|
|
22096
|
+
const v = "0.5.20";
|
|
21791
22097
|
if (typeof v === "string" && /^\d+\.\d+\.\d+/.test(v)) {
|
|
21792
22098
|
return v;
|
|
21793
22099
|
}
|
|
@@ -21875,23 +22181,23 @@ function readLocalVersion() {
|
|
|
21875
22181
|
if (injected)
|
|
21876
22182
|
return injected;
|
|
21877
22183
|
try {
|
|
21878
|
-
const here =
|
|
21879
|
-
const root =
|
|
21880
|
-
const pkg = JSON.parse(readFileSync5(
|
|
22184
|
+
const here = fileURLToPath2(import.meta.url);
|
|
22185
|
+
const root = dirname14(dirname14(here));
|
|
22186
|
+
const pkg = JSON.parse(readFileSync5(join22(root, "package.json"), "utf8"));
|
|
21881
22187
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
21882
22188
|
} catch {
|
|
21883
22189
|
return "0.0.0";
|
|
21884
22190
|
}
|
|
21885
22191
|
}
|
|
21886
22192
|
function defaultCacheDir() {
|
|
21887
|
-
return process.env["CODEFORGE_CACHE_DIR"] ??
|
|
22193
|
+
return process.env["CODEFORGE_CACHE_DIR"] ?? join22(homedir7(), ".cache", "codeforge");
|
|
21888
22194
|
}
|
|
21889
22195
|
function defaultCacheFile() {
|
|
21890
|
-
return
|
|
22196
|
+
return join22(defaultCacheDir(), "update-check.json");
|
|
21891
22197
|
}
|
|
21892
22198
|
function readCache(file) {
|
|
21893
22199
|
try {
|
|
21894
|
-
if (!
|
|
22200
|
+
if (!existsSync5(file))
|
|
21895
22201
|
return null;
|
|
21896
22202
|
const raw = readFileSync5(file, "utf8");
|
|
21897
22203
|
const obj = JSON.parse(raw);
|
|
@@ -21905,7 +22211,7 @@ function readCache(file) {
|
|
|
21905
22211
|
}
|
|
21906
22212
|
function writeCache(file, entry) {
|
|
21907
22213
|
try {
|
|
21908
|
-
mkdirSync3(
|
|
22214
|
+
mkdirSync3(dirname14(file), { recursive: true });
|
|
21909
22215
|
writeFileSync2(file, JSON.stringify(entry, null, 2), "utf8");
|
|
21910
22216
|
} catch {}
|
|
21911
22217
|
}
|
|
@@ -21923,9 +22229,9 @@ function fetchLatestTagFromGitHub(repo) {
|
|
|
21923
22229
|
}
|
|
21924
22230
|
});
|
|
21925
22231
|
}
|
|
21926
|
-
function getJsonWithRedirect(
|
|
21927
|
-
return new Promise((
|
|
21928
|
-
const u = new URL(
|
|
22232
|
+
function getJsonWithRedirect(url2, hopsLeft) {
|
|
22233
|
+
return new Promise((resolve17, reject) => {
|
|
22234
|
+
const u = new URL(url2);
|
|
21929
22235
|
const headers = {
|
|
21930
22236
|
"User-Agent": "codeforge-update-checker",
|
|
21931
22237
|
Accept: "application/vnd.github+json"
|
|
@@ -21947,13 +22253,13 @@ function getJsonWithRedirect(url, hopsLeft) {
|
|
|
21947
22253
|
reject(new Error("too_many_redirects"));
|
|
21948
22254
|
return;
|
|
21949
22255
|
}
|
|
21950
|
-
const next = new URL(res.headers.location,
|
|
21951
|
-
getJsonWithRedirect(next, hopsLeft - 1).then(
|
|
22256
|
+
const next = new URL(res.headers.location, url2).toString();
|
|
22257
|
+
getJsonWithRedirect(next, hopsLeft - 1).then(resolve17, reject);
|
|
21952
22258
|
return;
|
|
21953
22259
|
}
|
|
21954
22260
|
if (status === 404) {
|
|
21955
22261
|
res.resume();
|
|
21956
|
-
|
|
22262
|
+
resolve17(null);
|
|
21957
22263
|
return;
|
|
21958
22264
|
}
|
|
21959
22265
|
if (status >= 400) {
|
|
@@ -21964,7 +22270,7 @@ function getJsonWithRedirect(url, hopsLeft) {
|
|
|
21964
22270
|
let body = "";
|
|
21965
22271
|
res.setEncoding("utf8");
|
|
21966
22272
|
res.on("data", (chunk) => body += chunk);
|
|
21967
|
-
res.on("end", () =>
|
|
22273
|
+
res.on("end", () => resolve17(body));
|
|
21968
22274
|
});
|
|
21969
22275
|
req.on("timeout", () => {
|
|
21970
22276
|
req.destroy();
|
|
@@ -21979,9 +22285,9 @@ async function fetchLatestFromNpm(opts) {
|
|
|
21979
22285
|
const channel = opts.channel ?? "latest";
|
|
21980
22286
|
const timeoutMs = opts.timeoutMs ?? 5000;
|
|
21981
22287
|
const encodedPkg = opts.pkg.startsWith("@") ? opts.pkg.replace("/", "%2F") : opts.pkg;
|
|
21982
|
-
const
|
|
22288
|
+
const url2 = `${registry}/${encodedPkg}/${encodeURIComponent(channel)}`;
|
|
21983
22289
|
const fetcher = opts.httpFetcher ?? defaultHttpFetcher;
|
|
21984
|
-
const body = await fetcher(
|
|
22290
|
+
const body = await fetcher(url2, timeoutMs);
|
|
21985
22291
|
if (body === null)
|
|
21986
22292
|
return null;
|
|
21987
22293
|
let parsed;
|
|
@@ -22003,9 +22309,9 @@ async function fetchLatestFromNpm(opts) {
|
|
|
22003
22309
|
}
|
|
22004
22310
|
return { version, tarballUrl, integrity };
|
|
22005
22311
|
}
|
|
22006
|
-
function defaultHttpFetcher(
|
|
22007
|
-
return new Promise((
|
|
22008
|
-
const u = new URL(
|
|
22312
|
+
function defaultHttpFetcher(url2, timeoutMs) {
|
|
22313
|
+
return new Promise((resolve17, reject) => {
|
|
22314
|
+
const u = new URL(url2);
|
|
22009
22315
|
const headers = {
|
|
22010
22316
|
"User-Agent": "codeforge-update-checker",
|
|
22011
22317
|
Accept: "application/json"
|
|
@@ -22021,7 +22327,7 @@ function defaultHttpFetcher(url, timeoutMs) {
|
|
|
22021
22327
|
const status = res.statusCode ?? 0;
|
|
22022
22328
|
if (status === 404) {
|
|
22023
22329
|
res.resume();
|
|
22024
|
-
|
|
22330
|
+
resolve17(null);
|
|
22025
22331
|
return;
|
|
22026
22332
|
}
|
|
22027
22333
|
if (status >= 400) {
|
|
@@ -22032,7 +22338,7 @@ function defaultHttpFetcher(url, timeoutMs) {
|
|
|
22032
22338
|
let body = "";
|
|
22033
22339
|
res.setEncoding("utf8");
|
|
22034
22340
|
res.on("data", (chunk) => body += chunk);
|
|
22035
|
-
res.on("end", () =>
|
|
22341
|
+
res.on("end", () => resolve17(body));
|
|
22036
22342
|
});
|
|
22037
22343
|
req.on("timeout", () => {
|
|
22038
22344
|
req.destroy();
|
|
@@ -22043,15 +22349,15 @@ function defaultHttpFetcher(url, timeoutMs) {
|
|
|
22043
22349
|
});
|
|
22044
22350
|
}
|
|
22045
22351
|
async function downloadAndExtractBundle(opts) {
|
|
22046
|
-
const tmpRoot = opts.tmpDir ?? mkdtempSync(
|
|
22352
|
+
const tmpRoot = opts.tmpDir ?? mkdtempSync(join22(tmpdir(), "codeforge-update-"));
|
|
22047
22353
|
mkdirSync3(tmpRoot, { recursive: true });
|
|
22048
22354
|
const fetcher = opts.tarballFetcher ?? defaultBinaryFetcher;
|
|
22049
22355
|
const tarballBuf = await fetcher(opts.tarballUrl);
|
|
22050
22356
|
verifyIntegrity(tarballBuf, opts.expectedIntegrity);
|
|
22051
22357
|
const tarBuf = zlib.gunzipSync(tarballBuf);
|
|
22052
22358
|
extractTarToDir(tarBuf, tmpRoot);
|
|
22053
|
-
const bundlePath =
|
|
22054
|
-
if (!
|
|
22359
|
+
const bundlePath = join22(tmpRoot, "package", "dist", "index.js");
|
|
22360
|
+
if (!existsSync5(bundlePath)) {
|
|
22055
22361
|
throw new Error(`bundle_not_found: ${bundlePath}`);
|
|
22056
22362
|
}
|
|
22057
22363
|
return { bundlePath, extractDir: tmpRoot };
|
|
@@ -22090,21 +22396,21 @@ function extractTarToDir(tarBuf, destRoot) {
|
|
|
22090
22396
|
offset += 512;
|
|
22091
22397
|
if (typeFlag === "0" || typeFlag === "" || typeFlag === "\x00") {
|
|
22092
22398
|
const fileBuf = tarBuf.subarray(offset, offset + size);
|
|
22093
|
-
const dest =
|
|
22094
|
-
mkdirSync3(
|
|
22399
|
+
const dest = join22(destRoot, fullName);
|
|
22400
|
+
mkdirSync3(dirname14(dest), { recursive: true });
|
|
22095
22401
|
writeFileSync2(dest, fileBuf);
|
|
22096
22402
|
} else if (typeFlag === "5") {
|
|
22097
|
-
mkdirSync3(
|
|
22403
|
+
mkdirSync3(join22(destRoot, fullName), { recursive: true });
|
|
22098
22404
|
}
|
|
22099
22405
|
offset += Math.ceil(size / 512) * 512;
|
|
22100
22406
|
}
|
|
22101
22407
|
}
|
|
22102
|
-
function defaultBinaryFetcher(
|
|
22103
|
-
return downloadBinary(
|
|
22408
|
+
function defaultBinaryFetcher(url2) {
|
|
22409
|
+
return downloadBinary(url2, 3);
|
|
22104
22410
|
}
|
|
22105
|
-
function downloadBinary(
|
|
22106
|
-
return new Promise((
|
|
22107
|
-
const u = new URL(
|
|
22411
|
+
function downloadBinary(url2, hopsLeft) {
|
|
22412
|
+
return new Promise((resolve17, reject) => {
|
|
22413
|
+
const u = new URL(url2);
|
|
22108
22414
|
const req = https.request({
|
|
22109
22415
|
host: u.hostname,
|
|
22110
22416
|
port: u.port || undefined,
|
|
@@ -22120,8 +22426,8 @@ function downloadBinary(url, hopsLeft) {
|
|
|
22120
22426
|
reject(new Error("too_many_redirects"));
|
|
22121
22427
|
return;
|
|
22122
22428
|
}
|
|
22123
|
-
const next = new URL(res.headers.location,
|
|
22124
|
-
downloadBinary(next, hopsLeft - 1).then(
|
|
22429
|
+
const next = new URL(res.headers.location, url2).toString();
|
|
22430
|
+
downloadBinary(next, hopsLeft - 1).then(resolve17, reject);
|
|
22125
22431
|
return;
|
|
22126
22432
|
}
|
|
22127
22433
|
if (status >= 400) {
|
|
@@ -22131,7 +22437,7 @@ function downloadBinary(url, hopsLeft) {
|
|
|
22131
22437
|
}
|
|
22132
22438
|
const chunks = [];
|
|
22133
22439
|
res.on("data", (chunk) => chunks.push(chunk));
|
|
22134
|
-
res.on("end", () =>
|
|
22440
|
+
res.on("end", () => resolve17(Buffer.concat(chunks)));
|
|
22135
22441
|
});
|
|
22136
22442
|
req.on("timeout", () => {
|
|
22137
22443
|
req.destroy();
|
|
@@ -22144,16 +22450,16 @@ function downloadBinary(url, hopsLeft) {
|
|
|
22144
22450
|
function atomicReplaceBundle(opts) {
|
|
22145
22451
|
const { source, target, oldVersion } = opts;
|
|
22146
22452
|
const keep = opts.keepBackups ?? 3;
|
|
22147
|
-
if (!
|
|
22453
|
+
if (!existsSync5(source)) {
|
|
22148
22454
|
throw new Error(`atomic_source_missing: ${source}`);
|
|
22149
22455
|
}
|
|
22150
|
-
mkdirSync3(
|
|
22456
|
+
mkdirSync3(dirname14(target), { recursive: true });
|
|
22151
22457
|
const newPath = `${target}.new`;
|
|
22152
22458
|
const backupPath = `${target}.bak.${oldVersion}`;
|
|
22153
22459
|
let strategy = "rename";
|
|
22154
22460
|
try {
|
|
22155
22461
|
copyFileSync(source, newPath);
|
|
22156
|
-
if (
|
|
22462
|
+
if (existsSync5(target)) {
|
|
22157
22463
|
try {
|
|
22158
22464
|
renameSync(target, backupPath);
|
|
22159
22465
|
} catch (e) {
|
|
@@ -22189,7 +22495,7 @@ function atomicReplaceBundle(opts) {
|
|
|
22189
22495
|
return { backupPath, strategy };
|
|
22190
22496
|
} catch (e) {
|
|
22191
22497
|
try {
|
|
22192
|
-
if (
|
|
22498
|
+
if (existsSync5(newPath))
|
|
22193
22499
|
unlinkSync(newPath);
|
|
22194
22500
|
} catch {}
|
|
22195
22501
|
throw e;
|
|
@@ -22199,11 +22505,11 @@ function cleanupOldBackups(target, keep) {
|
|
|
22199
22505
|
if (keep <= 0)
|
|
22200
22506
|
return;
|
|
22201
22507
|
try {
|
|
22202
|
-
const dir =
|
|
22508
|
+
const dir = dirname14(target);
|
|
22203
22509
|
const base = target.substring(dir.length + 1);
|
|
22204
22510
|
const prefix = `${base}.bak.`;
|
|
22205
22511
|
const all = readdirSync3(dir).filter((f) => f.startsWith(prefix)).map((f) => {
|
|
22206
|
-
const full =
|
|
22512
|
+
const full = join22(dir, f);
|
|
22207
22513
|
let mtimeMs = 0;
|
|
22208
22514
|
try {
|
|
22209
22515
|
mtimeMs = statSync5(full).mtimeMs;
|
|
@@ -22225,9 +22531,9 @@ function loadCompatibility(opts) {
|
|
|
22225
22531
|
const root = opts?.cwd ?? inferPluginRoot();
|
|
22226
22532
|
if (!root)
|
|
22227
22533
|
return null;
|
|
22228
|
-
file =
|
|
22534
|
+
file = join22(root, "compatibility.json");
|
|
22229
22535
|
}
|
|
22230
|
-
if (!
|
|
22536
|
+
if (!existsSync5(file))
|
|
22231
22537
|
return null;
|
|
22232
22538
|
const raw = readFileSync5(file, "utf8");
|
|
22233
22539
|
const obj = JSON.parse(raw);
|
|
@@ -22249,8 +22555,8 @@ function loadCompatibility(opts) {
|
|
|
22249
22555
|
}
|
|
22250
22556
|
function inferPluginRoot() {
|
|
22251
22557
|
try {
|
|
22252
|
-
const here =
|
|
22253
|
-
return
|
|
22558
|
+
const here = fileURLToPath2(import.meta.url);
|
|
22559
|
+
return dirname14(dirname14(here));
|
|
22254
22560
|
} catch {
|
|
22255
22561
|
return null;
|
|
22256
22562
|
}
|
|
@@ -22445,17 +22751,17 @@ function detectOpencodeVersion() {
|
|
|
22445
22751
|
}
|
|
22446
22752
|
function getOpencodeBundlePath() {
|
|
22447
22753
|
const candidates = [];
|
|
22448
|
-
candidates.push(
|
|
22754
|
+
candidates.push(join23(homedir8(), ".config", "opencode", "codeforge", "index.js"));
|
|
22449
22755
|
if (process.platform === "win32") {
|
|
22450
22756
|
const appData = process.env["APPDATA"];
|
|
22451
22757
|
if (appData)
|
|
22452
|
-
candidates.push(
|
|
22758
|
+
candidates.push(join23(appData, "opencode", "codeforge", "index.js"));
|
|
22453
22759
|
const localAppData = process.env["LOCALAPPDATA"];
|
|
22454
22760
|
if (localAppData)
|
|
22455
|
-
candidates.push(
|
|
22761
|
+
candidates.push(join23(localAppData, "opencode", "codeforge", "index.js"));
|
|
22456
22762
|
}
|
|
22457
22763
|
for (const c of candidates) {
|
|
22458
|
-
if (
|
|
22764
|
+
if (existsSync6(c))
|
|
22459
22765
|
return c;
|
|
22460
22766
|
}
|
|
22461
22767
|
return candidates[0] ?? null;
|
|
@@ -22513,60 +22819,60 @@ async function postToast(ctx, message) {
|
|
|
22513
22819
|
var handler23 = updateCheckerServer;
|
|
22514
22820
|
|
|
22515
22821
|
// plugins/workflow-engine.ts
|
|
22516
|
-
import * as
|
|
22822
|
+
import * as path27 from "node:path";
|
|
22517
22823
|
|
|
22518
22824
|
// lib/workflow-loader.ts
|
|
22519
22825
|
import { promises as fs20 } from "node:fs";
|
|
22520
|
-
import * as
|
|
22521
|
-
import { z as
|
|
22522
|
-
var ActionSchema =
|
|
22523
|
-
tool:
|
|
22524
|
-
args:
|
|
22525
|
-
on_error:
|
|
22826
|
+
import * as path26 from "node:path";
|
|
22827
|
+
import { z as z33 } from "zod";
|
|
22828
|
+
var ActionSchema = z33.object({
|
|
22829
|
+
tool: z33.string().min(1, "action.tool 不能为空"),
|
|
22830
|
+
args: z33.record(z33.string(), z33.unknown()).optional().default({}),
|
|
22831
|
+
on_error: z33.enum(["retry", "skip", "abort"]).optional()
|
|
22526
22832
|
});
|
|
22527
|
-
var StepSchema =
|
|
22528
|
-
name:
|
|
22529
|
-
agent:
|
|
22530
|
-
description:
|
|
22531
|
-
inject_context:
|
|
22532
|
-
requires_human_approval:
|
|
22533
|
-
actions:
|
|
22534
|
-
on_error:
|
|
22535
|
-
max_retries:
|
|
22536
|
-
timeout:
|
|
22537
|
-
auto_feedback:
|
|
22538
|
-
test_cmd:
|
|
22539
|
-
lint_cmd:
|
|
22540
|
-
max_retries:
|
|
22541
|
-
error_excerpt_lines:
|
|
22542
|
-
escalate_to:
|
|
22833
|
+
var StepSchema = z33.object({
|
|
22834
|
+
name: z33.string().min(1, "step.name 不能为空"),
|
|
22835
|
+
agent: z33.string().min(1, "step.agent 不能为空").describe("agent 名(与 agents/<name>.md 对应)"),
|
|
22836
|
+
description: z33.string().optional(),
|
|
22837
|
+
inject_context: z33.record(z33.string(), z33.unknown()).optional(),
|
|
22838
|
+
requires_human_approval: z33.boolean().optional().default(false),
|
|
22839
|
+
actions: z33.array(ActionSchema).optional().default([]),
|
|
22840
|
+
on_error: z33.enum(["retry", "skip", "abort"]).optional().default("abort"),
|
|
22841
|
+
max_retries: z33.number().int().min(0).max(10).optional().default(2),
|
|
22842
|
+
timeout: z33.string().regex(/^\d+(?:ms|s|m|h)$/, "timeout 必须是 数字+单位(ms/s/m/h),如 5m").optional(),
|
|
22843
|
+
auto_feedback: z33.object({
|
|
22844
|
+
test_cmd: z33.string().optional().describe("测试命令,如 npm test"),
|
|
22845
|
+
lint_cmd: z33.string().optional().describe("lint 命令,如 npm run lint"),
|
|
22846
|
+
max_retries: z33.number().int().min(1).max(10).optional().default(3),
|
|
22847
|
+
error_excerpt_lines: z33.number().int().min(1).max(50).optional().default(5),
|
|
22848
|
+
escalate_to: z33.string().optional().default("reviewer").describe("超上限后兜底 agent,默认 reviewer")
|
|
22543
22849
|
}).refine((d) => Boolean(d.test_cmd || d.lint_cmd), { message: "auto_feedback 必须至少配置 test_cmd 或 lint_cmd 之一" }).optional(),
|
|
22544
|
-
on_decision:
|
|
22545
|
-
APPROVE:
|
|
22546
|
-
|
|
22547
|
-
|
|
22548
|
-
|
|
22850
|
+
on_decision: z33.object({
|
|
22851
|
+
APPROVE: z33.union([
|
|
22852
|
+
z33.literal("continue"),
|
|
22853
|
+
z33.literal("abort"),
|
|
22854
|
+
z33.object({ action: z33.literal("goto"), target: z33.string().min(1) })
|
|
22549
22855
|
]).optional(),
|
|
22550
|
-
REQUEST_CHANGES:
|
|
22551
|
-
|
|
22552
|
-
|
|
22553
|
-
|
|
22856
|
+
REQUEST_CHANGES: z33.union([
|
|
22857
|
+
z33.literal("continue"),
|
|
22858
|
+
z33.literal("abort"),
|
|
22859
|
+
z33.object({ action: z33.literal("goto"), target: z33.string().min(1) })
|
|
22554
22860
|
]).optional(),
|
|
22555
|
-
BLOCK:
|
|
22556
|
-
|
|
22557
|
-
|
|
22558
|
-
|
|
22861
|
+
BLOCK: z33.union([
|
|
22862
|
+
z33.literal("continue"),
|
|
22863
|
+
z33.literal("abort"),
|
|
22864
|
+
z33.object({ action: z33.literal("goto"), target: z33.string().min(1) })
|
|
22559
22865
|
]).optional()
|
|
22560
22866
|
}).refine((d) => Boolean(d.APPROVE || d.REQUEST_CHANGES || d.BLOCK), { message: "on_decision 必须至少配置 APPROVE / REQUEST_CHANGES / BLOCK 之一" }).optional()
|
|
22561
22867
|
}).strict();
|
|
22562
|
-
var WorkflowSchema =
|
|
22563
|
-
name:
|
|
22564
|
-
description:
|
|
22565
|
-
version:
|
|
22566
|
-
trigger:
|
|
22567
|
-
context_template:
|
|
22568
|
-
max_loops:
|
|
22569
|
-
steps:
|
|
22868
|
+
var WorkflowSchema = z33.object({
|
|
22869
|
+
name: z33.string().min(1, "workflow.name 不能为空"),
|
|
22870
|
+
description: z33.string().optional().default(""),
|
|
22871
|
+
version: z33.string().optional().default("1.0.0"),
|
|
22872
|
+
trigger: z33.string().min(1).refine((v) => /^\/[a-z][\w-]*$/.test(v) || /^event:[a-z][\w.-]+$/.test(v), "trigger 必须是 /command-name 或 event:xxx 形式"),
|
|
22873
|
+
context_template: z33.string().optional(),
|
|
22874
|
+
max_loops: z33.number().int().min(1).max(10).optional().default(3),
|
|
22875
|
+
steps: z33.array(StepSchema).min(1, "workflow.steps 不能为空")
|
|
22570
22876
|
}).strict();
|
|
22571
22877
|
function parseWorkflowYaml(yaml, sourcePath = "<inline>") {
|
|
22572
22878
|
let raw;
|
|
@@ -22630,7 +22936,7 @@ async function loadWorkflowsFromDir(dir) {
|
|
|
22630
22936
|
continue;
|
|
22631
22937
|
if (!/\.ya?ml$/i.test(name))
|
|
22632
22938
|
continue;
|
|
22633
|
-
const full =
|
|
22939
|
+
const full = path26.join(dir, name);
|
|
22634
22940
|
const r = await loadWorkflowFromFile(full);
|
|
22635
22941
|
if (r.ok)
|
|
22636
22942
|
loaded.push(r);
|
|
@@ -23020,7 +23326,7 @@ async function handleCommandInvoked(raw, workflowsDir = "workflows") {
|
|
|
23020
23326
|
}
|
|
23021
23327
|
var workflowEngineServer = async (ctx) => {
|
|
23022
23328
|
const directory = ctx.directory ?? process.cwd();
|
|
23023
|
-
const workflowsDir =
|
|
23329
|
+
const workflowsDir = path27.join(directory, "workflows");
|
|
23024
23330
|
ensureRegistry(workflowsDir).catch((err) => fallbackLog2.warn(`[${PLUGIN_NAME24}] preload workflows failed`, {
|
|
23025
23331
|
error: err instanceof Error ? err.message : String(err)
|
|
23026
23332
|
}));
|
|
@@ -23064,7 +23370,7 @@ var workflowEngineServer = async (ctx) => {
|
|
|
23064
23370
|
var handler24 = workflowEngineServer;
|
|
23065
23371
|
|
|
23066
23372
|
// plugins/session-worktree-guard.ts
|
|
23067
|
-
import
|
|
23373
|
+
import path28 from "node:path";
|
|
23068
23374
|
var PLUGIN_NAME25 = "session-worktree-guard";
|
|
23069
23375
|
logLifecycle(PLUGIN_NAME25, "import", {});
|
|
23070
23376
|
var WRITE_INTENT_RE = />(?![=&])(?!\s*\/dev\/(?:null|stdout|stderr|fd\/\d+)\b)|\btee\b|\brm\b|\bmv\b|\bcp\b|\bmkdir\b|\btouch\b|\bchmod\b|\bchown\b|\bln\b/;
|
|
@@ -23169,23 +23475,23 @@ var CLASS_B_CALLER_WHITELIST = new Set([
|
|
|
23169
23475
|
"reviewer-lite",
|
|
23170
23476
|
"general"
|
|
23171
23477
|
]);
|
|
23172
|
-
var CODEFORGE_WORKTREE_DIR_NAME =
|
|
23478
|
+
var CODEFORGE_WORKTREE_DIR_NAME = path28.join(".git", "codeforge-worktrees");
|
|
23173
23479
|
function worktreesRoot(mainRoot) {
|
|
23174
|
-
return
|
|
23480
|
+
return path28.join(mainRoot, CODEFORGE_WORKTREE_DIR_NAME);
|
|
23175
23481
|
}
|
|
23176
23482
|
function isInsideAnyWorktreeDir(absPath, mainRoot) {
|
|
23177
|
-
if (!
|
|
23483
|
+
if (!path28.isAbsolute(absPath))
|
|
23178
23484
|
return false;
|
|
23179
23485
|
const root = worktreesRoot(mainRoot);
|
|
23180
23486
|
if (absPath === root)
|
|
23181
23487
|
return false;
|
|
23182
|
-
const prefix = root.endsWith(
|
|
23488
|
+
const prefix = root.endsWith(path28.sep) ? root : root + path28.sep;
|
|
23183
23489
|
return absPath.startsWith(prefix);
|
|
23184
23490
|
}
|
|
23185
23491
|
function rewritePath(value, mainRoot, worktreeRoot) {
|
|
23186
23492
|
if (!value)
|
|
23187
23493
|
return null;
|
|
23188
|
-
const resolved =
|
|
23494
|
+
const resolved = path28.isAbsolute(value) ? value : path28.resolve(mainRoot, value);
|
|
23189
23495
|
const wtPrefix2 = worktreeRoot.endsWith("/") ? worktreeRoot : worktreeRoot + "/";
|
|
23190
23496
|
if (resolved === worktreeRoot || resolved.startsWith(wtPrefix2)) {
|
|
23191
23497
|
return null;
|
|
@@ -23223,7 +23529,7 @@ function commandContainsMainRootExcludingWorktree(command, mainRoot, worktreePat
|
|
|
23223
23529
|
}
|
|
23224
23530
|
}
|
|
23225
23531
|
const wtRoot = worktreesRoot(mainRoot);
|
|
23226
|
-
const wtRootPrefix = wtRoot +
|
|
23532
|
+
const wtRootPrefix = wtRoot + path28.sep;
|
|
23227
23533
|
const escapedWtRootPrefix = escapeRegex2(wtRootPrefix);
|
|
23228
23534
|
const wtPathPattern = escapedWtRootPrefix + `[^\\s'"\\x60)]*`;
|
|
23229
23535
|
const allWorktreePathsReForEscape = new RegExp(wtPathPattern, "g");
|
|
@@ -23278,8 +23584,8 @@ function collectWritePaths(toolName, argsObj, worktreeRoot) {
|
|
|
23278
23584
|
const candidate = toolName === "write" || toolName === "edit" ? argsObj["filePath"] : toolName === "ast_edit" ? argsObj["target"] : undefined;
|
|
23279
23585
|
if (typeof candidate !== "string" || candidate.length === 0)
|
|
23280
23586
|
return out;
|
|
23281
|
-
const abs =
|
|
23282
|
-
const rel =
|
|
23587
|
+
const abs = path28.isAbsolute(candidate) ? candidate : path28.resolve(worktreeRoot, candidate);
|
|
23588
|
+
const rel = path28.relative(worktreeRoot, abs).split(path28.sep).join("/");
|
|
23283
23589
|
out.push(rel);
|
|
23284
23590
|
return out;
|
|
23285
23591
|
}
|
|
@@ -23670,12 +23976,12 @@ var sessionWorktreeGuardPlugin = async (ctx) => {
|
|
|
23670
23976
|
var handler25 = sessionWorktreeGuardPlugin;
|
|
23671
23977
|
|
|
23672
23978
|
// lib/opencode-session-probe.ts
|
|
23673
|
-
import * as
|
|
23979
|
+
import * as path29 from "node:path";
|
|
23674
23980
|
import * as os6 from "node:os";
|
|
23675
23981
|
import { createRequire as createRequire2 } from "node:module";
|
|
23676
23982
|
var requireFromHere = createRequire2(import.meta.url);
|
|
23677
23983
|
var DEFAULT_LIVENESS_MS = 6 * 60 * 60000;
|
|
23678
|
-
var DEFAULT_DB_PATH =
|
|
23984
|
+
var DEFAULT_DB_PATH = path29.join(os6.homedir(), ".local/share/opencode/opencode.db");
|
|
23679
23985
|
function createSessionProbe(opts = {}) {
|
|
23680
23986
|
const dbPath = opts.dbPath ?? DEFAULT_DB_PATH;
|
|
23681
23987
|
const httpBaseUrl = opts.httpBaseUrl ?? process.env["OPENCODE_SERVER_URL"];
|