@mestreyoda/fabrica 0.2.22 → 0.2.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +137 -0
- package/README.md +1 -0
- package/defaults/fabrica/prompts/developer.md +22 -6
- package/defaults/fabrica/prompts/reviewer.md +15 -0
- package/defaults/fabrica/prompts/tester.md +9 -0
- package/dist/index.js +1256 -401
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -26948,14 +26948,14 @@ var require_tls_helpers = __commonJS({
|
|
|
26948
26948
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
26949
26949
|
exports2.CIPHER_SUITES = void 0;
|
|
26950
26950
|
exports2.getDefaultRootsData = getDefaultRootsData;
|
|
26951
|
-
var
|
|
26951
|
+
var fs46 = __require("fs");
|
|
26952
26952
|
exports2.CIPHER_SUITES = process.env.GRPC_SSL_CIPHER_SUITES;
|
|
26953
26953
|
var DEFAULT_ROOTS_FILE_PATH = process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH;
|
|
26954
26954
|
var defaultRootsData = null;
|
|
26955
26955
|
function getDefaultRootsData() {
|
|
26956
26956
|
if (DEFAULT_ROOTS_FILE_PATH) {
|
|
26957
26957
|
if (defaultRootsData === null) {
|
|
26958
|
-
defaultRootsData =
|
|
26958
|
+
defaultRootsData = fs46.readFileSync(DEFAULT_ROOTS_FILE_PATH);
|
|
26959
26959
|
}
|
|
26960
26960
|
return defaultRootsData;
|
|
26961
26961
|
}
|
|
@@ -31086,7 +31086,7 @@ var require_fetch = __commonJS({
|
|
|
31086
31086
|
module2.exports = fetch3;
|
|
31087
31087
|
var asPromise = require_aspromise();
|
|
31088
31088
|
var inquire2 = require_inquire();
|
|
31089
|
-
var
|
|
31089
|
+
var fs46 = inquire2("fs");
|
|
31090
31090
|
function fetch3(filename, options, callback) {
|
|
31091
31091
|
if (typeof options === "function") {
|
|
31092
31092
|
callback = options;
|
|
@@ -31095,8 +31095,8 @@ var require_fetch = __commonJS({
|
|
|
31095
31095
|
options = {};
|
|
31096
31096
|
if (!callback)
|
|
31097
31097
|
return asPromise(fetch3, this, filename, options);
|
|
31098
|
-
if (!options.xhr &&
|
|
31099
|
-
return
|
|
31098
|
+
if (!options.xhr && fs46 && fs46.readFile)
|
|
31099
|
+
return fs46.readFile(filename, function fetchReadFileCallback(err, contents) {
|
|
31100
31100
|
return err && typeof XMLHttpRequest !== "undefined" ? fetch3.xhr(filename, options, callback) : err ? callback(err) : callback(null, options.binary ? contents : contents.toString("utf8"));
|
|
31101
31101
|
});
|
|
31102
31102
|
return fetch3.xhr(filename, options, callback);
|
|
@@ -37370,7 +37370,7 @@ var require_util3 = __commonJS({
|
|
|
37370
37370
|
"use strict";
|
|
37371
37371
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
37372
37372
|
exports2.addCommonProtos = exports2.loadProtosWithOptionsSync = exports2.loadProtosWithOptions = void 0;
|
|
37373
|
-
var
|
|
37373
|
+
var fs46 = __require("fs");
|
|
37374
37374
|
var path47 = __require("path");
|
|
37375
37375
|
var Protobuf = require_protobufjs();
|
|
37376
37376
|
function addIncludePathResolver(root, includePaths) {
|
|
@@ -37382,7 +37382,7 @@ var require_util3 = __commonJS({
|
|
|
37382
37382
|
for (const directory of includePaths) {
|
|
37383
37383
|
const fullPath = path47.join(directory, target);
|
|
37384
37384
|
try {
|
|
37385
|
-
|
|
37385
|
+
fs46.accessSync(fullPath, fs46.constants.R_OK);
|
|
37386
37386
|
return fullPath;
|
|
37387
37387
|
} catch (err) {
|
|
37388
37388
|
continue;
|
|
@@ -47204,7 +47204,7 @@ var require_certificate_provider = __commonJS({
|
|
|
47204
47204
|
"use strict";
|
|
47205
47205
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
47206
47206
|
exports2.FileWatcherCertificateProvider = void 0;
|
|
47207
|
-
var
|
|
47207
|
+
var fs46 = __require("fs");
|
|
47208
47208
|
var logging = require_logging();
|
|
47209
47209
|
var constants_1 = require_constants2();
|
|
47210
47210
|
var util_1 = __require("util");
|
|
@@ -47212,7 +47212,7 @@ var require_certificate_provider = __commonJS({
|
|
|
47212
47212
|
function trace2(text) {
|
|
47213
47213
|
logging.trace(constants_1.LogVerbosity.DEBUG, TRACER_NAME2, text);
|
|
47214
47214
|
}
|
|
47215
|
-
var readFilePromise = (0, util_1.promisify)(
|
|
47215
|
+
var readFilePromise = (0, util_1.promisify)(fs46.readFile);
|
|
47216
47216
|
var FileWatcherCertificateProvider = class {
|
|
47217
47217
|
constructor(config2) {
|
|
47218
47218
|
this.config = config2;
|
|
@@ -49124,7 +49124,7 @@ var require_otlp_grpc_env_configuration = __commonJS({
|
|
|
49124
49124
|
var core_1 = require_src();
|
|
49125
49125
|
var grpc_exporter_transport_1 = require_grpc_exporter_transport();
|
|
49126
49126
|
var node_http_1 = (init_index_node_http(), __toCommonJS(index_node_http_exports));
|
|
49127
|
-
var
|
|
49127
|
+
var fs46 = __require("fs");
|
|
49128
49128
|
var path47 = __require("path");
|
|
49129
49129
|
var api_1 = (init_esm(), __toCommonJS(esm_exports));
|
|
49130
49130
|
function fallbackIfNullishOrBlank(signalSpecific, nonSignalSpecific) {
|
|
@@ -49174,7 +49174,7 @@ var require_otlp_grpc_env_configuration = __commonJS({
|
|
|
49174
49174
|
const filePath = fallbackIfNullishOrBlank(signalSpecificPath, nonSignalSpecificPath);
|
|
49175
49175
|
if (filePath != null) {
|
|
49176
49176
|
try {
|
|
49177
|
-
return
|
|
49177
|
+
return fs46.readFileSync(path47.resolve(process.cwd(), filePath));
|
|
49178
49178
|
} catch {
|
|
49179
49179
|
api_1.diag.warn(warningMessage);
|
|
49180
49180
|
return void 0;
|
|
@@ -59234,14 +59234,14 @@ var require_parser = __commonJS({
|
|
|
59234
59234
|
case "scalar":
|
|
59235
59235
|
case "single-quoted-scalar":
|
|
59236
59236
|
case "double-quoted-scalar": {
|
|
59237
|
-
const
|
|
59237
|
+
const fs46 = this.flowScalar(this.type);
|
|
59238
59238
|
if (atNextItem || it.value) {
|
|
59239
|
-
map2.items.push({ start, key:
|
|
59239
|
+
map2.items.push({ start, key: fs46, sep: [] });
|
|
59240
59240
|
this.onKeyLine = true;
|
|
59241
59241
|
} else if (it.sep) {
|
|
59242
|
-
this.stack.push(
|
|
59242
|
+
this.stack.push(fs46);
|
|
59243
59243
|
} else {
|
|
59244
|
-
Object.assign(it, { key:
|
|
59244
|
+
Object.assign(it, { key: fs46, sep: [] });
|
|
59245
59245
|
this.onKeyLine = true;
|
|
59246
59246
|
}
|
|
59247
59247
|
return;
|
|
@@ -59369,13 +59369,13 @@ var require_parser = __commonJS({
|
|
|
59369
59369
|
case "scalar":
|
|
59370
59370
|
case "single-quoted-scalar":
|
|
59371
59371
|
case "double-quoted-scalar": {
|
|
59372
|
-
const
|
|
59372
|
+
const fs46 = this.flowScalar(this.type);
|
|
59373
59373
|
if (!it || it.value)
|
|
59374
|
-
fc.items.push({ start: [], key:
|
|
59374
|
+
fc.items.push({ start: [], key: fs46, sep: [] });
|
|
59375
59375
|
else if (it.sep)
|
|
59376
|
-
this.stack.push(
|
|
59376
|
+
this.stack.push(fs46);
|
|
59377
59377
|
else
|
|
59378
|
-
Object.assign(it, { key:
|
|
59378
|
+
Object.assign(it, { key: fs46, sep: [] });
|
|
59379
59379
|
return;
|
|
59380
59380
|
}
|
|
59381
59381
|
case "flow-map-end":
|
|
@@ -59691,7 +59691,7 @@ var require_FileConfigFactory = __commonJS({
|
|
|
59691
59691
|
exports2.setLoggerProvider = exports2.getSeverity = exports2.setMeterProvider = exports2.getTemporalityPreference = exports2.setTracerProvider = exports2.setPropagator = exports2.setAttributeLimits = exports2.setResourceAttributes = exports2.parseConfigFile = exports2.hasValidConfigFile = exports2.FileConfigFactory = void 0;
|
|
59692
59692
|
var core_1 = require_src();
|
|
59693
59693
|
var configModel_1 = require_configModel();
|
|
59694
|
-
var
|
|
59694
|
+
var fs46 = __require("fs");
|
|
59695
59695
|
var yaml = require_dist();
|
|
59696
59696
|
var utils_1 = require_utils10();
|
|
59697
59697
|
var commonModel_1 = require_commonModel();
|
|
@@ -59713,7 +59713,7 @@ var require_FileConfigFactory = __commonJS({
|
|
|
59713
59713
|
function hasValidConfigFile() {
|
|
59714
59714
|
const configFile = (0, core_1.getStringFromEnv)("OTEL_EXPERIMENTAL_CONFIG_FILE");
|
|
59715
59715
|
if (configFile) {
|
|
59716
|
-
if (!(configFile.endsWith(".yaml") || configFile.endsWith(".yml")) || !
|
|
59716
|
+
if (!(configFile.endsWith(".yaml") || configFile.endsWith(".yml")) || !fs46.existsSync(configFile)) {
|
|
59717
59717
|
api_1.diag.warn(`Config file ${configFile} set on OTEL_EXPERIMENTAL_CONFIG_FILE is not valid`);
|
|
59718
59718
|
return false;
|
|
59719
59719
|
}
|
|
@@ -59725,7 +59725,7 @@ var require_FileConfigFactory = __commonJS({
|
|
|
59725
59725
|
function parseConfigFile(config2) {
|
|
59726
59726
|
const supportedFileVersions = ["1.0-rc.3"];
|
|
59727
59727
|
const configFile = (0, core_1.getStringFromEnv)("OTEL_EXPERIMENTAL_CONFIG_FILE") || "";
|
|
59728
|
-
const file2 =
|
|
59728
|
+
const file2 = fs46.readFileSync(configFile, "utf8");
|
|
59729
59729
|
const parsedContent = yaml.parse(file2);
|
|
59730
59730
|
if (parsedContent["file_format"] && supportedFileVersions.includes(parsedContent["file_format"])) {
|
|
59731
59731
|
const disabled = (0, utils_1.getBooleanFromConfigFile)(parsedContent["disabled"]);
|
|
@@ -61436,7 +61436,7 @@ var require_instrumentation3 = __commonJS({
|
|
|
61436
61436
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
61437
61437
|
exports2.AwsLambdaInstrumentation = exports2.AWS_HANDLER_STREAMING_RESPONSE = exports2.AWS_HANDLER_STREAMING_SYMBOL = exports2.lambdaMaxInitInMilliseconds = void 0;
|
|
61438
61438
|
var path47 = __require("path");
|
|
61439
|
-
var
|
|
61439
|
+
var fs46 = __require("fs");
|
|
61440
61440
|
var instrumentation_1 = require_src10();
|
|
61441
61441
|
var api_1 = (init_esm(), __toCommonJS(esm_exports));
|
|
61442
61442
|
var semantic_conventions_1 = (init_esm2(), __toCommonJS(esm_exports2));
|
|
@@ -61482,15 +61482,15 @@ var require_instrumentation3 = __commonJS({
|
|
|
61482
61482
|
let filename = path47.resolve(taskRoot, moduleRoot, module3);
|
|
61483
61483
|
if (!filename.endsWith(".js")) {
|
|
61484
61484
|
try {
|
|
61485
|
-
|
|
61485
|
+
fs46.statSync(`${filename}.js`);
|
|
61486
61486
|
filename += ".js";
|
|
61487
61487
|
} catch (e2) {
|
|
61488
61488
|
try {
|
|
61489
|
-
|
|
61489
|
+
fs46.statSync(`${filename}.mjs`);
|
|
61490
61490
|
filename += ".mjs";
|
|
61491
61491
|
} catch (e22) {
|
|
61492
61492
|
try {
|
|
61493
|
-
|
|
61493
|
+
fs46.statSync(`${filename}.cjs`);
|
|
61494
61494
|
filename += ".cjs";
|
|
61495
61495
|
} catch (e3) {
|
|
61496
61496
|
this._diag.warn("No handler file was able to resolved with one of the known extensions for the file", filename);
|
|
@@ -66162,19 +66162,19 @@ var require_utils17 = __commonJS({
|
|
|
66162
66162
|
}
|
|
66163
66163
|
}
|
|
66164
66164
|
exports2.splitTwoLevels = splitTwoLevels;
|
|
66165
|
-
function indexFs(
|
|
66165
|
+
function indexFs(fs46, member) {
|
|
66166
66166
|
if (!member)
|
|
66167
66167
|
throw new Error(JSON.stringify({ member }));
|
|
66168
66168
|
const splitResult = splitTwoLevels(member);
|
|
66169
66169
|
const [functionName1, functionName2] = splitResult;
|
|
66170
66170
|
if (functionName2) {
|
|
66171
66171
|
return {
|
|
66172
|
-
objectToPatch:
|
|
66172
|
+
objectToPatch: fs46[functionName1],
|
|
66173
66173
|
functionNameToPatch: functionName2
|
|
66174
66174
|
};
|
|
66175
66175
|
} else {
|
|
66176
66176
|
return {
|
|
66177
|
-
objectToPatch:
|
|
66177
|
+
objectToPatch: fs46,
|
|
66178
66178
|
functionNameToPatch: functionName1
|
|
66179
66179
|
};
|
|
66180
66180
|
}
|
|
@@ -66205,16 +66205,16 @@ var require_instrumentation12 = __commonJS({
|
|
|
66205
66205
|
}
|
|
66206
66206
|
init() {
|
|
66207
66207
|
return [
|
|
66208
|
-
new instrumentation_1.InstrumentationNodeModuleDefinition("fs", ["*"], (
|
|
66208
|
+
new instrumentation_1.InstrumentationNodeModuleDefinition("fs", ["*"], (fs46) => {
|
|
66209
66209
|
for (const fName of constants_1.SYNC_FUNCTIONS) {
|
|
66210
|
-
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(
|
|
66210
|
+
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(fs46, fName);
|
|
66211
66211
|
if ((0, instrumentation_1.isWrapped)(objectToPatch[functionNameToPatch])) {
|
|
66212
66212
|
this._unwrap(objectToPatch, functionNameToPatch);
|
|
66213
66213
|
}
|
|
66214
66214
|
this._wrap(objectToPatch, functionNameToPatch, this._patchSyncFunction.bind(this, fName));
|
|
66215
66215
|
}
|
|
66216
66216
|
for (const fName of constants_1.CALLBACK_FUNCTIONS) {
|
|
66217
|
-
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(
|
|
66217
|
+
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(fs46, fName);
|
|
66218
66218
|
if ((0, instrumentation_1.isWrapped)(objectToPatch[functionNameToPatch])) {
|
|
66219
66219
|
this._unwrap(objectToPatch, functionNameToPatch);
|
|
66220
66220
|
}
|
|
@@ -66225,30 +66225,30 @@ var require_instrumentation12 = __commonJS({
|
|
|
66225
66225
|
this._wrap(objectToPatch, functionNameToPatch, this._patchCallbackFunction.bind(this, fName));
|
|
66226
66226
|
}
|
|
66227
66227
|
for (const fName of constants_1.PROMISE_FUNCTIONS) {
|
|
66228
|
-
if ((0, instrumentation_1.isWrapped)(
|
|
66229
|
-
this._unwrap(
|
|
66228
|
+
if ((0, instrumentation_1.isWrapped)(fs46.promises[fName])) {
|
|
66229
|
+
this._unwrap(fs46.promises, fName);
|
|
66230
66230
|
}
|
|
66231
|
-
this._wrap(
|
|
66231
|
+
this._wrap(fs46.promises, fName, this._patchPromiseFunction.bind(this, fName));
|
|
66232
66232
|
}
|
|
66233
|
-
return
|
|
66234
|
-
}, (
|
|
66235
|
-
if (
|
|
66233
|
+
return fs46;
|
|
66234
|
+
}, (fs46) => {
|
|
66235
|
+
if (fs46 === void 0)
|
|
66236
66236
|
return;
|
|
66237
66237
|
for (const fName of constants_1.SYNC_FUNCTIONS) {
|
|
66238
|
-
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(
|
|
66238
|
+
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(fs46, fName);
|
|
66239
66239
|
if ((0, instrumentation_1.isWrapped)(objectToPatch[functionNameToPatch])) {
|
|
66240
66240
|
this._unwrap(objectToPatch, functionNameToPatch);
|
|
66241
66241
|
}
|
|
66242
66242
|
}
|
|
66243
66243
|
for (const fName of constants_1.CALLBACK_FUNCTIONS) {
|
|
66244
|
-
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(
|
|
66244
|
+
const { objectToPatch, functionNameToPatch } = (0, utils_1.indexFs)(fs46, fName);
|
|
66245
66245
|
if ((0, instrumentation_1.isWrapped)(objectToPatch[functionNameToPatch])) {
|
|
66246
66246
|
this._unwrap(objectToPatch, functionNameToPatch);
|
|
66247
66247
|
}
|
|
66248
66248
|
}
|
|
66249
66249
|
for (const fName of constants_1.PROMISE_FUNCTIONS) {
|
|
66250
|
-
if ((0, instrumentation_1.isWrapped)(
|
|
66251
|
-
this._unwrap(
|
|
66250
|
+
if ((0, instrumentation_1.isWrapped)(fs46.promises[fName])) {
|
|
66251
|
+
this._unwrap(fs46.promises, fName);
|
|
66252
66252
|
}
|
|
66253
66253
|
}
|
|
66254
66254
|
}),
|
|
@@ -79247,14 +79247,14 @@ var require_AwsBeanstalkDetector = __commonJS({
|
|
|
79247
79247
|
var core_1 = require_src();
|
|
79248
79248
|
var semantic_conventions_1 = (init_esm2(), __toCommonJS(esm_exports2));
|
|
79249
79249
|
var semconv_1 = require_semconv30();
|
|
79250
|
-
var
|
|
79250
|
+
var fs46 = __require("fs");
|
|
79251
79251
|
var util = __require("util");
|
|
79252
79252
|
var DEFAULT_BEANSTALK_CONF_PATH = "/var/elasticbeanstalk/xray/environment.conf";
|
|
79253
79253
|
var WIN_OS_BEANSTALK_CONF_PATH = "C:\\Program Files\\Amazon\\XRay\\environment.conf";
|
|
79254
79254
|
var AwsBeanstalkDetector = class _AwsBeanstalkDetector {
|
|
79255
79255
|
BEANSTALK_CONF_PATH;
|
|
79256
|
-
static readFileAsync = util.promisify(
|
|
79257
|
-
static fileAccessAsync = util.promisify(
|
|
79256
|
+
static readFileAsync = util.promisify(fs46.readFile);
|
|
79257
|
+
static fileAccessAsync = util.promisify(fs46.access);
|
|
79258
79258
|
constructor() {
|
|
79259
79259
|
if (process.platform === "win32") {
|
|
79260
79260
|
this.BEANSTALK_CONF_PATH = WIN_OS_BEANSTALK_CONF_PATH;
|
|
@@ -79283,7 +79283,7 @@ var require_AwsBeanstalkDetector = __commonJS({
|
|
|
79283
79283
|
*/
|
|
79284
79284
|
async _gatherData() {
|
|
79285
79285
|
try {
|
|
79286
|
-
await _AwsBeanstalkDetector.fileAccessAsync(this.BEANSTALK_CONF_PATH,
|
|
79286
|
+
await _AwsBeanstalkDetector.fileAccessAsync(this.BEANSTALK_CONF_PATH, fs46.constants.R_OK);
|
|
79287
79287
|
const rawData = await _AwsBeanstalkDetector.readFileAsync(this.BEANSTALK_CONF_PATH, "utf8");
|
|
79288
79288
|
const parsedData = JSON.parse(rawData);
|
|
79289
79289
|
return {
|
|
@@ -79458,14 +79458,14 @@ var require_AwsEcsDetector = __commonJS({
|
|
|
79458
79458
|
var semconv_1 = require_semconv30();
|
|
79459
79459
|
var http3 = __require("http");
|
|
79460
79460
|
var util = __require("util");
|
|
79461
|
-
var
|
|
79461
|
+
var fs46 = __require("fs");
|
|
79462
79462
|
var os5 = __require("os");
|
|
79463
79463
|
var HTTP_TIMEOUT_IN_MS = 1e3;
|
|
79464
79464
|
var AwsEcsDetector = class _AwsEcsDetector {
|
|
79465
79465
|
static CONTAINER_ID_LENGTH = 64;
|
|
79466
79466
|
static CONTAINER_ID_LENGTH_MIN = 32;
|
|
79467
79467
|
static DEFAULT_CGROUP_PATH = "/proc/self/cgroup";
|
|
79468
|
-
static readFileAsync = util.promisify(
|
|
79468
|
+
static readFileAsync = util.promisify(fs46.readFile);
|
|
79469
79469
|
detect() {
|
|
79470
79470
|
const attributes = api_1.context.with((0, core_1.suppressTracing)(api_1.context.active()), () => this._getAttributes());
|
|
79471
79471
|
return { attributes };
|
|
@@ -79669,7 +79669,7 @@ var require_AwsEksDetector = __commonJS({
|
|
|
79669
79669
|
var core_1 = require_src();
|
|
79670
79670
|
var semconv_1 = require_semconv30();
|
|
79671
79671
|
var https2 = __require("https");
|
|
79672
|
-
var
|
|
79672
|
+
var fs46 = __require("fs");
|
|
79673
79673
|
var util = __require("util");
|
|
79674
79674
|
var api_2 = (init_esm(), __toCommonJS(esm_exports));
|
|
79675
79675
|
var AwsEksDetector = class _AwsEksDetector {
|
|
@@ -79682,8 +79682,8 @@ var require_AwsEksDetector = __commonJS({
|
|
|
79682
79682
|
DEFAULT_CGROUP_PATH = "/proc/self/cgroup";
|
|
79683
79683
|
TIMEOUT_MS = 2e3;
|
|
79684
79684
|
UTF8_UNICODE = "utf8";
|
|
79685
|
-
static readFileAsync = util.promisify(
|
|
79686
|
-
static fileAccessAsync = util.promisify(
|
|
79685
|
+
static readFileAsync = util.promisify(fs46.readFile);
|
|
79686
|
+
static fileAccessAsync = util.promisify(fs46.access);
|
|
79687
79687
|
detect() {
|
|
79688
79688
|
const dataPromise = api_1.context.with((0, core_1.suppressTracing)(api_1.context.active()), () => this._gatherData());
|
|
79689
79689
|
const attrNames = [
|
|
@@ -80015,7 +80015,7 @@ var require_ContainerDetector = __commonJS({
|
|
|
80015
80015
|
"use strict";
|
|
80016
80016
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
80017
80017
|
exports2.containerDetector = exports2.ContainerDetector = void 0;
|
|
80018
|
-
var
|
|
80018
|
+
var fs46 = __require("fs");
|
|
80019
80019
|
var util = __require("util");
|
|
80020
80020
|
var api_1 = (init_esm(), __toCommonJS(esm_exports));
|
|
80021
80021
|
var core_1 = require_src();
|
|
@@ -80028,7 +80028,7 @@ var require_ContainerDetector = __commonJS({
|
|
|
80028
80028
|
UTF8_UNICODE = "utf8";
|
|
80029
80029
|
HOSTNAME = "hostname";
|
|
80030
80030
|
MARKING_PREFIX = ["containers", "overlay-containers"];
|
|
80031
|
-
static readFileAsync = util.promisify(
|
|
80031
|
+
static readFileAsync = util.promisify(fs46.readFile);
|
|
80032
80032
|
detect() {
|
|
80033
80033
|
const attributes = {
|
|
80034
80034
|
[semconv_1.ATTR_CONTAINER_ID]: this._getContainerIdWithSuppressedTracing()
|
|
@@ -91095,7 +91095,7 @@ var require_AzureAksDetector = __commonJS({
|
|
|
91095
91095
|
"use strict";
|
|
91096
91096
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
91097
91097
|
exports2.azureAksDetector = void 0;
|
|
91098
|
-
var
|
|
91098
|
+
var fs46 = __require("fs");
|
|
91099
91099
|
var api_1 = (init_esm(), __toCommonJS(esm_exports));
|
|
91100
91100
|
var semconv_1 = require_semconv33();
|
|
91101
91101
|
var types_1 = require_types13();
|
|
@@ -91136,10 +91136,10 @@ var require_AzureAksDetector = __commonJS({
|
|
|
91136
91136
|
}
|
|
91137
91137
|
getAksMetadataFromFile() {
|
|
91138
91138
|
try {
|
|
91139
|
-
if (!
|
|
91139
|
+
if (!fs46.existsSync(types_1.AKS_METADATA_FILE_PATH)) {
|
|
91140
91140
|
return void 0;
|
|
91141
91141
|
}
|
|
91142
|
-
const content =
|
|
91142
|
+
const content = fs46.readFileSync(types_1.AKS_METADATA_FILE_PATH, "utf8");
|
|
91143
91143
|
const metadata = {};
|
|
91144
91144
|
const lines = content.split("\n");
|
|
91145
91145
|
for (const line of lines) {
|
|
@@ -92919,7 +92919,7 @@ var require_atomic_sleep = __commonJS({
|
|
|
92919
92919
|
var require_sonic_boom = __commonJS({
|
|
92920
92920
|
"node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
92921
92921
|
"use strict";
|
|
92922
|
-
var
|
|
92922
|
+
var fs46 = __require("fs");
|
|
92923
92923
|
var EventEmitter = __require("events");
|
|
92924
92924
|
var inherits = __require("util").inherits;
|
|
92925
92925
|
var path47 = __require("path");
|
|
@@ -92976,20 +92976,20 @@ var require_sonic_boom = __commonJS({
|
|
|
92976
92976
|
const mode = sonic.mode;
|
|
92977
92977
|
if (sonic.sync) {
|
|
92978
92978
|
try {
|
|
92979
|
-
if (sonic.mkdir)
|
|
92980
|
-
const fd =
|
|
92979
|
+
if (sonic.mkdir) fs46.mkdirSync(path47.dirname(file2), { recursive: true });
|
|
92980
|
+
const fd = fs46.openSync(file2, flags, mode);
|
|
92981
92981
|
fileOpened(null, fd);
|
|
92982
92982
|
} catch (err) {
|
|
92983
92983
|
fileOpened(err);
|
|
92984
92984
|
throw err;
|
|
92985
92985
|
}
|
|
92986
92986
|
} else if (sonic.mkdir) {
|
|
92987
|
-
|
|
92987
|
+
fs46.mkdir(path47.dirname(file2), { recursive: true }, (err) => {
|
|
92988
92988
|
if (err) return fileOpened(err);
|
|
92989
|
-
|
|
92989
|
+
fs46.open(file2, flags, mode, fileOpened);
|
|
92990
92990
|
});
|
|
92991
92991
|
} else {
|
|
92992
|
-
|
|
92992
|
+
fs46.open(file2, flags, mode, fileOpened);
|
|
92993
92993
|
}
|
|
92994
92994
|
}
|
|
92995
92995
|
function SonicBoom(opts) {
|
|
@@ -93030,8 +93030,8 @@ var require_sonic_boom = __commonJS({
|
|
|
93030
93030
|
this.flush = flushBuffer;
|
|
93031
93031
|
this.flushSync = flushBufferSync;
|
|
93032
93032
|
this._actualWrite = actualWriteBuffer;
|
|
93033
|
-
fsWriteSync = () =>
|
|
93034
|
-
fsWrite = () =>
|
|
93033
|
+
fsWriteSync = () => fs46.writeSync(this.fd, this._writingBuf);
|
|
93034
|
+
fsWrite = () => fs46.write(this.fd, this._writingBuf, this.release);
|
|
93035
93035
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
93036
93036
|
this._writingBuf = "";
|
|
93037
93037
|
this.write = write2;
|
|
@@ -93040,15 +93040,15 @@ var require_sonic_boom = __commonJS({
|
|
|
93040
93040
|
this._actualWrite = actualWrite;
|
|
93041
93041
|
fsWriteSync = () => {
|
|
93042
93042
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
93043
|
-
return
|
|
93043
|
+
return fs46.writeSync(this.fd, this._writingBuf);
|
|
93044
93044
|
}
|
|
93045
|
-
return
|
|
93045
|
+
return fs46.writeSync(this.fd, this._writingBuf, "utf8");
|
|
93046
93046
|
};
|
|
93047
93047
|
fsWrite = () => {
|
|
93048
93048
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
93049
|
-
return
|
|
93049
|
+
return fs46.write(this.fd, this._writingBuf, this.release);
|
|
93050
93050
|
}
|
|
93051
|
-
return
|
|
93051
|
+
return fs46.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
93052
93052
|
};
|
|
93053
93053
|
} else {
|
|
93054
93054
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -93105,7 +93105,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93105
93105
|
}
|
|
93106
93106
|
}
|
|
93107
93107
|
if (this._fsync) {
|
|
93108
|
-
|
|
93108
|
+
fs46.fsyncSync(this.fd);
|
|
93109
93109
|
}
|
|
93110
93110
|
const len = this._len;
|
|
93111
93111
|
if (this._reopening) {
|
|
@@ -93219,7 +93219,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93219
93219
|
const onDrain = () => {
|
|
93220
93220
|
if (!this._fsync) {
|
|
93221
93221
|
try {
|
|
93222
|
-
|
|
93222
|
+
fs46.fsync(this.fd, (err) => {
|
|
93223
93223
|
this._flushPending = false;
|
|
93224
93224
|
cb(err);
|
|
93225
93225
|
});
|
|
@@ -93321,7 +93321,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93321
93321
|
const fd = this.fd;
|
|
93322
93322
|
this.once("ready", () => {
|
|
93323
93323
|
if (fd !== this.fd) {
|
|
93324
|
-
|
|
93324
|
+
fs46.close(fd, (err) => {
|
|
93325
93325
|
if (err) {
|
|
93326
93326
|
return this.emit("error", err);
|
|
93327
93327
|
}
|
|
@@ -93370,7 +93370,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93370
93370
|
buf = this._bufs[0];
|
|
93371
93371
|
}
|
|
93372
93372
|
try {
|
|
93373
|
-
const n = Buffer.isBuffer(buf) ?
|
|
93373
|
+
const n = Buffer.isBuffer(buf) ? fs46.writeSync(this.fd, buf) : fs46.writeSync(this.fd, buf, "utf8");
|
|
93374
93374
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
93375
93375
|
buf = releasedBufObj.writingBuf;
|
|
93376
93376
|
this._len = releasedBufObj.len;
|
|
@@ -93386,7 +93386,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93386
93386
|
}
|
|
93387
93387
|
}
|
|
93388
93388
|
try {
|
|
93389
|
-
|
|
93389
|
+
fs46.fsyncSync(this.fd);
|
|
93390
93390
|
} catch {
|
|
93391
93391
|
}
|
|
93392
93392
|
}
|
|
@@ -93407,7 +93407,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93407
93407
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
93408
93408
|
}
|
|
93409
93409
|
try {
|
|
93410
|
-
const n =
|
|
93410
|
+
const n = fs46.writeSync(this.fd, buf);
|
|
93411
93411
|
buf = buf.subarray(n);
|
|
93412
93412
|
this._len = Math.max(this._len - n, 0);
|
|
93413
93413
|
if (buf.length <= 0) {
|
|
@@ -93435,13 +93435,13 @@ var require_sonic_boom = __commonJS({
|
|
|
93435
93435
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
93436
93436
|
if (this.sync) {
|
|
93437
93437
|
try {
|
|
93438
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
93438
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs46.writeSync(this.fd, this._writingBuf) : fs46.writeSync(this.fd, this._writingBuf, "utf8");
|
|
93439
93439
|
release(null, written);
|
|
93440
93440
|
} catch (err) {
|
|
93441
93441
|
release(err);
|
|
93442
93442
|
}
|
|
93443
93443
|
} else {
|
|
93444
|
-
|
|
93444
|
+
fs46.write(this.fd, this._writingBuf, release);
|
|
93445
93445
|
}
|
|
93446
93446
|
}
|
|
93447
93447
|
function actualWriteBuffer() {
|
|
@@ -93450,7 +93450,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93450
93450
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
93451
93451
|
if (this.sync) {
|
|
93452
93452
|
try {
|
|
93453
|
-
const written =
|
|
93453
|
+
const written = fs46.writeSync(this.fd, this._writingBuf);
|
|
93454
93454
|
release(null, written);
|
|
93455
93455
|
} catch (err) {
|
|
93456
93456
|
release(err);
|
|
@@ -93459,7 +93459,7 @@ var require_sonic_boom = __commonJS({
|
|
|
93459
93459
|
if (kCopyBuffer) {
|
|
93460
93460
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
93461
93461
|
}
|
|
93462
|
-
|
|
93462
|
+
fs46.write(this.fd, this._writingBuf, release);
|
|
93463
93463
|
}
|
|
93464
93464
|
}
|
|
93465
93465
|
function actualClose(sonic) {
|
|
@@ -93475,12 +93475,12 @@ var require_sonic_boom = __commonJS({
|
|
|
93475
93475
|
sonic._lens = [];
|
|
93476
93476
|
assert2(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
93477
93477
|
try {
|
|
93478
|
-
|
|
93478
|
+
fs46.fsync(sonic.fd, closeWrapped);
|
|
93479
93479
|
} catch {
|
|
93480
93480
|
}
|
|
93481
93481
|
function closeWrapped() {
|
|
93482
93482
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
93483
|
-
|
|
93483
|
+
fs46.close(sonic.fd, done);
|
|
93484
93484
|
} else {
|
|
93485
93485
|
done();
|
|
93486
93486
|
}
|
|
@@ -96472,9 +96472,9 @@ var require_pump = __commonJS({
|
|
|
96472
96472
|
"node_modules/pump/index.js"(exports2, module2) {
|
|
96473
96473
|
var once = require_once();
|
|
96474
96474
|
var eos = require_end_of_stream();
|
|
96475
|
-
var
|
|
96475
|
+
var fs46;
|
|
96476
96476
|
try {
|
|
96477
|
-
|
|
96477
|
+
fs46 = __require("fs");
|
|
96478
96478
|
} catch (e2) {
|
|
96479
96479
|
}
|
|
96480
96480
|
var noop2 = function() {
|
|
@@ -96485,8 +96485,8 @@ var require_pump = __commonJS({
|
|
|
96485
96485
|
};
|
|
96486
96486
|
var isFS = function(stream) {
|
|
96487
96487
|
if (!ancient) return false;
|
|
96488
|
-
if (!
|
|
96489
|
-
return (stream instanceof (
|
|
96488
|
+
if (!fs46) return false;
|
|
96489
|
+
return (stream instanceof (fs46.ReadStream || noop2) || stream instanceof (fs46.WriteStream || noop2)) && isFn(stream.close);
|
|
96490
96490
|
};
|
|
96491
96491
|
var isRequest2 = function(stream) {
|
|
96492
96492
|
return stream.setHeader && isFn(stream.abort);
|
|
@@ -113905,8 +113905,8 @@ import fsSync from "node:fs";
|
|
|
113905
113905
|
import path5 from "node:path";
|
|
113906
113906
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
113907
113907
|
function getCurrentVersion() {
|
|
113908
|
-
if ("0.2.
|
|
113909
|
-
return "0.2.
|
|
113908
|
+
if ("0.2.23") {
|
|
113909
|
+
return "0.2.23";
|
|
113910
113910
|
}
|
|
113911
113911
|
try {
|
|
113912
113912
|
const pkgPath = path5.join(THIS_DIR, "..", "..", "package.json");
|
|
@@ -115213,7 +115213,9 @@ var init_labels = __esm({
|
|
|
115213
115213
|
{ name: "type:research", color: "0075CA" },
|
|
115214
115214
|
{ name: "type:infra", color: "5319E7" },
|
|
115215
115215
|
{ name: "needs-human", color: "d73a4a" },
|
|
115216
|
-
{ name: "approved", color: "0e8a16" }
|
|
115216
|
+
{ name: "approved", color: "0e8a16" },
|
|
115217
|
+
{ name: "decomposition:parent", color: "1d76db" },
|
|
115218
|
+
{ name: "decomposition:child", color: "5319e7" }
|
|
115217
115219
|
];
|
|
115218
115220
|
STEP_ROUTING_COLOR = "#d93f0b";
|
|
115219
115221
|
NOTIFY_LABEL_PREFIX = "notify:";
|
|
@@ -117293,21 +117295,21 @@ var init_types4 = __esm({
|
|
|
117293
117295
|
});
|
|
117294
117296
|
|
|
117295
117297
|
// lib/github/file-event-store.ts
|
|
117296
|
-
import
|
|
117298
|
+
import fs28 from "node:fs/promises";
|
|
117297
117299
|
import path27 from "node:path";
|
|
117298
117300
|
function encodeId(id) {
|
|
117299
117301
|
return Buffer.from(id, "utf-8").toString("base64url");
|
|
117300
117302
|
}
|
|
117301
117303
|
async function atomicWriteJson(filePath, value) {
|
|
117302
|
-
await
|
|
117304
|
+
await fs28.mkdir(path27.dirname(filePath), { recursive: true });
|
|
117303
117305
|
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
117304
|
-
await
|
|
117305
|
-
await
|
|
117306
|
+
await fs28.writeFile(tmpPath, JSON.stringify(value, null, 2) + "\n", "utf-8");
|
|
117307
|
+
await fs28.rename(tmpPath, filePath);
|
|
117306
117308
|
}
|
|
117307
117309
|
async function writeNewJsonExclusive(filePath, value) {
|
|
117308
|
-
await
|
|
117310
|
+
await fs28.mkdir(path27.dirname(filePath), { recursive: true });
|
|
117309
117311
|
try {
|
|
117310
|
-
await
|
|
117312
|
+
await fs28.writeFile(filePath, JSON.stringify(value, null, 2) + "\n", {
|
|
117311
117313
|
encoding: "utf-8",
|
|
117312
117314
|
flag: "wx"
|
|
117313
117315
|
});
|
|
@@ -117319,7 +117321,7 @@ async function writeNewJsonExclusive(filePath, value) {
|
|
|
117319
117321
|
}
|
|
117320
117322
|
async function readJsonFile(filePath) {
|
|
117321
117323
|
try {
|
|
117322
|
-
const raw = await
|
|
117324
|
+
const raw = await fs28.readFile(filePath, "utf-8");
|
|
117323
117325
|
return JSON.parse(raw);
|
|
117324
117326
|
} catch (error48) {
|
|
117325
117327
|
if (error48?.code === "ENOENT") return null;
|
|
@@ -117378,7 +117380,7 @@ var init_file_event_store = __esm({
|
|
|
117378
117380
|
const dir = this.storeDir;
|
|
117379
117381
|
let entries = [];
|
|
117380
117382
|
try {
|
|
117381
|
-
entries = await
|
|
117383
|
+
entries = await fs28.readdir(dir);
|
|
117382
117384
|
} catch (error48) {
|
|
117383
117385
|
if (error48?.code === "ENOENT") return [];
|
|
117384
117386
|
throw error48;
|
|
@@ -117396,7 +117398,7 @@ var init_file_event_store = __esm({
|
|
|
117396
117398
|
const dir = this.storeDir;
|
|
117397
117399
|
let entries = [];
|
|
117398
117400
|
try {
|
|
117399
|
-
entries = await
|
|
117401
|
+
entries = await fs28.readdir(dir);
|
|
117400
117402
|
} catch (error48) {
|
|
117401
117403
|
if (error48?.code === "ENOENT") return [];
|
|
117402
117404
|
throw error48;
|
|
@@ -117466,14 +117468,14 @@ var init_file_event_store = __esm({
|
|
|
117466
117468
|
async save(run) {
|
|
117467
117469
|
const validated = fabricaRunSchema.parse(run);
|
|
117468
117470
|
try {
|
|
117469
|
-
const entries = await
|
|
117471
|
+
const entries = await fs28.readdir(this.storeDir);
|
|
117470
117472
|
for (const entry of entries) {
|
|
117471
117473
|
const filePath = path27.join(this.storeDir, entry);
|
|
117472
117474
|
const existing = await readJsonFile(filePath);
|
|
117473
117475
|
if (!existing) continue;
|
|
117474
117476
|
const parsed = fabricaRunSchema.parse(existing);
|
|
117475
117477
|
if (parsed.runId !== validated.runId && parsed.installationId === validated.installationId && parsed.repositoryId === validated.repositoryId && parsed.prNumber === validated.prNumber) {
|
|
117476
|
-
await
|
|
117478
|
+
await fs28.rm(filePath, { force: true });
|
|
117477
117479
|
}
|
|
117478
117480
|
}
|
|
117479
117481
|
} catch (error48) {
|
|
@@ -117489,7 +117491,7 @@ var init_file_event_store = __esm({
|
|
|
117489
117491
|
const dir = this.storeDir;
|
|
117490
117492
|
let entries = [];
|
|
117491
117493
|
try {
|
|
117492
|
-
entries = await
|
|
117494
|
+
entries = await fs28.readdir(dir);
|
|
117493
117495
|
} catch (error48) {
|
|
117494
117496
|
if (error48?.code === "ENOENT") return [];
|
|
117495
117497
|
throw error48;
|
|
@@ -117510,7 +117512,7 @@ var init_file_event_store = __esm({
|
|
|
117510
117512
|
});
|
|
117511
117513
|
|
|
117512
117514
|
// lib/github/sqlite-event-store.ts
|
|
117513
|
-
import
|
|
117515
|
+
import fs29 from "node:fs/promises";
|
|
117514
117516
|
import path28 from "node:path";
|
|
117515
117517
|
function asNumber(value) {
|
|
117516
117518
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
@@ -117569,7 +117571,7 @@ async function loadSqliteModule() {
|
|
|
117569
117571
|
return loaded;
|
|
117570
117572
|
}
|
|
117571
117573
|
async function openDatabase(dbPath) {
|
|
117572
|
-
await
|
|
117574
|
+
await fs29.mkdir(path28.dirname(dbPath), { recursive: true });
|
|
117573
117575
|
const sqlite = await loadSqliteModule();
|
|
117574
117576
|
const db = new sqlite.DatabaseSync(dbPath);
|
|
117575
117577
|
db.exec(`
|
|
@@ -118183,7 +118185,7 @@ var init_extract_json = __esm({
|
|
|
118183
118185
|
});
|
|
118184
118186
|
|
|
118185
118187
|
// lib/intake/lib/runtime-paths.ts
|
|
118186
|
-
import
|
|
118188
|
+
import fs31 from "node:fs";
|
|
118187
118189
|
import fsp from "node:fs/promises";
|
|
118188
118190
|
import os4 from "node:os";
|
|
118189
118191
|
import path30 from "node:path";
|
|
@@ -118191,7 +118193,7 @@ import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
|
118191
118193
|
function isUsableFile(candidate) {
|
|
118192
118194
|
if (!candidate) return false;
|
|
118193
118195
|
try {
|
|
118194
|
-
return
|
|
118196
|
+
return fs31.existsSync(candidate) && fs31.statSync(candidate).isFile();
|
|
118195
118197
|
} catch {
|
|
118196
118198
|
return false;
|
|
118197
118199
|
}
|
|
@@ -118199,7 +118201,7 @@ function isUsableFile(candidate) {
|
|
|
118199
118201
|
function isUsableDir(candidate) {
|
|
118200
118202
|
if (!candidate) return false;
|
|
118201
118203
|
try {
|
|
118202
|
-
return
|
|
118204
|
+
return fs31.existsSync(candidate) && fs31.statSync(candidate).isDirectory();
|
|
118203
118205
|
} catch {
|
|
118204
118206
|
return false;
|
|
118205
118207
|
}
|
|
@@ -118207,7 +118209,7 @@ function isUsableDir(candidate) {
|
|
|
118207
118209
|
function findNewestNvmOpenClaw(homeDir, env) {
|
|
118208
118210
|
const versionsDir = path30.join(homeDir, ".nvm", "versions", "node");
|
|
118209
118211
|
try {
|
|
118210
|
-
const versions =
|
|
118212
|
+
const versions = fs31.readdirSync(versionsDir).sort().reverse();
|
|
118211
118213
|
for (const version2 of versions) {
|
|
118212
118214
|
const candidate = path30.join(versionsDir, version2, "bin", "openclaw");
|
|
118213
118215
|
if (isUsableFile(candidate)) return candidate;
|
|
@@ -122062,6 +122064,37 @@ function getRoleWorker(project, role) {
|
|
|
122062
122064
|
function getIssueRuntime(project, issueId) {
|
|
122063
122065
|
return project.issueRuntime?.[String(issueId)];
|
|
122064
122066
|
}
|
|
122067
|
+
function isParentIssue(project, issueId) {
|
|
122068
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
122069
|
+
return !!(runtime && ((runtime.childIssueIds?.length ?? 0) > 0 || runtime.decompositionMode === "parent_child"));
|
|
122070
|
+
}
|
|
122071
|
+
function isChildIssue(project, issueId) {
|
|
122072
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
122073
|
+
return runtime?.parentIssueId != null;
|
|
122074
|
+
}
|
|
122075
|
+
function getParentIssueRuntime(project, issueId) {
|
|
122076
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
122077
|
+
if (!runtime?.parentIssueId) return void 0;
|
|
122078
|
+
return getIssueRuntime(project, runtime.parentIssueId);
|
|
122079
|
+
}
|
|
122080
|
+
function getChildIssueRuntimes(project, issueId) {
|
|
122081
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
122082
|
+
return (runtime?.childIssueIds ?? []).map((childIssueId) => ({
|
|
122083
|
+
issueId: childIssueId,
|
|
122084
|
+
runtime: getIssueRuntime(project, childIssueId)
|
|
122085
|
+
}));
|
|
122086
|
+
}
|
|
122087
|
+
function getDependencyIssueRuntimes(project, issueId) {
|
|
122088
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
122089
|
+
return (runtime?.dependencyIssueIds ?? []).map((dependencyIssueId) => ({
|
|
122090
|
+
issueId: dependencyIssueId,
|
|
122091
|
+
runtime: getIssueRuntime(project, dependencyIssueId)
|
|
122092
|
+
}));
|
|
122093
|
+
}
|
|
122094
|
+
function isIssueExecutionComplete(project, issueId) {
|
|
122095
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
122096
|
+
return !!(runtime?.decompositionStatus === "completed" || runtime?.artifactOfRecord?.mergedAt || runtime?.sessionCompletedAt);
|
|
122097
|
+
}
|
|
122065
122098
|
async function updateSlot(workspaceDir, slugOrChannelId, role, level, slotIndex, updates) {
|
|
122066
122099
|
const { data } = await withProjectsMutation(workspaceDir, (data2) => {
|
|
122067
122100
|
const slug = resolveProjectSlug(data2, slugOrChannelId);
|
|
@@ -122226,7 +122259,22 @@ async function clearIssueRuntime(workspaceDir, slugOrChannelId, issueId) {
|
|
|
122226
122259
|
}
|
|
122227
122260
|
const project = data2.projects[slug];
|
|
122228
122261
|
if (project.issueRuntime) {
|
|
122229
|
-
|
|
122262
|
+
const key = String(issueId);
|
|
122263
|
+
const existing = project.issueRuntime[key];
|
|
122264
|
+
const preserved = existing ? {
|
|
122265
|
+
parentIssueId: existing.parentIssueId ?? null,
|
|
122266
|
+
childIssueIds: existing.childIssueIds,
|
|
122267
|
+
dependencyIssueIds: existing.dependencyIssueIds,
|
|
122268
|
+
decompositionMode: existing.decompositionMode ?? null,
|
|
122269
|
+
decompositionStatus: existing.parentIssueId ? "completed" : existing.decompositionStatus ?? null,
|
|
122270
|
+
sessionCompletedAt: existing.sessionCompletedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
122271
|
+
artifactOfRecord: existing.artifactOfRecord ?? null
|
|
122272
|
+
} : null;
|
|
122273
|
+
if (preserved && (preserved.parentIssueId != null || (preserved.childIssueIds?.length ?? 0) > 0 || (preserved.dependencyIssueIds?.length ?? 0) > 0 || preserved.decompositionMode != null)) {
|
|
122274
|
+
project.issueRuntime[key] = preserved;
|
|
122275
|
+
} else {
|
|
122276
|
+
delete project.issueRuntime[key];
|
|
122277
|
+
}
|
|
122230
122278
|
}
|
|
122231
122279
|
});
|
|
122232
122280
|
return data;
|
|
@@ -123104,11 +123152,11 @@ var GitLabProvider = class {
|
|
|
123104
123152
|
const token = tokenRaw.stdout.trim();
|
|
123105
123153
|
if (!token) return null;
|
|
123106
123154
|
const os5 = await import("node:os");
|
|
123107
|
-
const
|
|
123155
|
+
const fs46 = await import("node:fs/promises");
|
|
123108
123156
|
const path47 = await import("node:path");
|
|
123109
|
-
const tmpDir = await
|
|
123157
|
+
const tmpDir = await fs46.mkdtemp(path47.join(os5.tmpdir(), "fabrica-upload-"));
|
|
123110
123158
|
const tmpFile = path47.join(tmpDir, file2.filename);
|
|
123111
|
-
await
|
|
123159
|
+
await fs46.writeFile(tmpFile, file2.buffer);
|
|
123112
123160
|
try {
|
|
123113
123161
|
const apiBase = webUrl.replace(/\/[^/]+\/[^/]+\/?$/, "");
|
|
123114
123162
|
const result = await this.runCommand(
|
|
@@ -123130,9 +123178,9 @@ var GitLabProvider = class {
|
|
|
123130
123178
|
if (parsed.url) return `${webUrl}${parsed.url}`;
|
|
123131
123179
|
return null;
|
|
123132
123180
|
} finally {
|
|
123133
|
-
await
|
|
123181
|
+
await fs46.unlink(tmpFile).catch(() => {
|
|
123134
123182
|
});
|
|
123135
|
-
await
|
|
123183
|
+
await fs46.rmdir(tmpDir).catch(() => {
|
|
123136
123184
|
});
|
|
123137
123185
|
}
|
|
123138
123186
|
} catch {
|
|
@@ -125007,12 +125055,12 @@ function prLink(url2) {
|
|
|
125007
125055
|
function buildMessage(event) {
|
|
125008
125056
|
switch (event.type) {
|
|
125009
125057
|
case "workerStart": {
|
|
125010
|
-
const
|
|
125058
|
+
const semanticAction = event.dispatchSemantic === "feedback_redispatch" ? "\u{1F501} Re-dispatched after feedback" : event.dispatchSemantic === "recovery_redispatch" ? "\u267B\uFE0F Re-dispatched after recovery" : event.dispatchSemantic === "bootstrap_initial_dispatch" ? "\u{1F9F1} Started from bootstrap" : event.sessionAction === "spawn" ? "\u{1F680} Started" : "\u25B6\uFE0F Resumed";
|
|
125011
125059
|
const worker = formatWorkerString(event.role, {
|
|
125012
125060
|
name: event.name,
|
|
125013
125061
|
level: event.level
|
|
125014
125062
|
});
|
|
125015
|
-
let msg = `${
|
|
125063
|
+
let msg = `${semanticAction} ${worker} on #${event.issueId}: ${event.issueTitle}
|
|
125016
125064
|
\u{1F517} [Issue #${event.issueId}](${event.issueUrl})`;
|
|
125017
125065
|
if (event.modelDowngraded && event.originalModel && event.effectiveModel) {
|
|
125018
125066
|
msg += `
|
|
@@ -125457,6 +125505,45 @@ init_audit();
|
|
|
125457
125505
|
|
|
125458
125506
|
// lib/services/queue-scan.ts
|
|
125459
125507
|
init_roles();
|
|
125508
|
+
|
|
125509
|
+
// lib/services/family-scheduler.ts
|
|
125510
|
+
function countActiveSiblingChildren(project, parentIssueId, currentIssueId) {
|
|
125511
|
+
const activeIssueIds = /* @__PURE__ */ new Set();
|
|
125512
|
+
for (const roleWorker of Object.values(project.workers ?? {})) {
|
|
125513
|
+
for (const slots of Object.values(roleWorker.levels ?? {})) {
|
|
125514
|
+
for (const slot of slots) {
|
|
125515
|
+
if (!slot.active || !slot.issueId) continue;
|
|
125516
|
+
const activeIssueId = Number(slot.issueId);
|
|
125517
|
+
if (!Number.isFinite(activeIssueId) || activeIssueId === currentIssueId) continue;
|
|
125518
|
+
activeIssueIds.add(activeIssueId);
|
|
125519
|
+
}
|
|
125520
|
+
}
|
|
125521
|
+
}
|
|
125522
|
+
return [...activeIssueIds].filter((issueId) => getIssueRuntime(project, issueId)?.parentIssueId === parentIssueId).length;
|
|
125523
|
+
}
|
|
125524
|
+
function getFamilyDispatchBlockReason(project, issueId, role) {
|
|
125525
|
+
const runtime = getIssueRuntime(project, issueId);
|
|
125526
|
+
if (isParentIssue(project, issueId)) {
|
|
125527
|
+
return role === "developer" ? "family_parent_coordinator_only" : "family_parent_not_executable";
|
|
125528
|
+
}
|
|
125529
|
+
if (isChildIssue(project, issueId)) {
|
|
125530
|
+
const parentRuntime = getParentIssueRuntime(project, issueId);
|
|
125531
|
+
if (parentRuntime?.decompositionStatus === "draft") return "family_parent_decomposition_draft";
|
|
125532
|
+
if (parentRuntime?.decompositionStatus === "blocked") return "family_parent_blocked";
|
|
125533
|
+
if (parentRuntime?.decompositionStatus === "completed") return "family_parent_completed";
|
|
125534
|
+
if (!runtime?.parentIssueId) return "family_child_missing_parent_binding";
|
|
125535
|
+
const maxParallelChildren = parentRuntime?.maxParallelChildren ?? null;
|
|
125536
|
+
if (maxParallelChildren && maxParallelChildren > 0) {
|
|
125537
|
+
const activeSiblingChildren = countActiveSiblingChildren(project, runtime.parentIssueId, issueId);
|
|
125538
|
+
if (activeSiblingChildren >= maxParallelChildren) return `family_parallel_limit_reached:${maxParallelChildren}`;
|
|
125539
|
+
}
|
|
125540
|
+
const incompleteDependencies = getDependencyIssueRuntimes(project, issueId).filter((dependency) => !isIssueExecutionComplete(project, dependency.issueId)).map((dependency) => dependency.issueId);
|
|
125541
|
+
if (incompleteDependencies.length > 0) return `family_child_dependencies_pending:${incompleteDependencies.join(",")}`;
|
|
125542
|
+
}
|
|
125543
|
+
return null;
|
|
125544
|
+
}
|
|
125545
|
+
|
|
125546
|
+
// lib/services/queue-scan.ts
|
|
125460
125547
|
init_workflow();
|
|
125461
125548
|
function detectRoleLevelFromLabels(labels) {
|
|
125462
125549
|
for (const label of labels) {
|
|
@@ -125476,19 +125563,144 @@ function detectStepRouting(labels, step) {
|
|
|
125476
125563
|
const match = labels.find((l) => l.toLowerCase().startsWith(prefix));
|
|
125477
125564
|
return match ? match.slice(prefix.length).toLowerCase() : null;
|
|
125478
125565
|
}
|
|
125479
|
-
async function findNextIssueForRole(provider, role, workflow, instanceName) {
|
|
125566
|
+
async function findNextIssueForRole(provider, role, workflow, instanceName, project) {
|
|
125480
125567
|
const labels = getQueueLabels(workflow, role);
|
|
125481
125568
|
for (const label of labels) {
|
|
125482
125569
|
try {
|
|
125483
125570
|
const issues = await provider.listIssuesByLabel(label);
|
|
125484
125571
|
const eligible = instanceName ? issues.filter((i2) => isOwnedByOrUnclaimed(i2.labels, instanceName)) : issues;
|
|
125485
|
-
|
|
125572
|
+
for (let index = eligible.length - 1; index >= 0; index -= 1) {
|
|
125573
|
+
const issue2 = eligible[index];
|
|
125574
|
+
const blockReason = project ? getFamilyDispatchBlockReason(project, issue2.iid, role) : null;
|
|
125575
|
+
if (!blockReason) return { issue: issue2, label };
|
|
125576
|
+
}
|
|
125486
125577
|
} catch {
|
|
125487
125578
|
}
|
|
125488
125579
|
}
|
|
125489
125580
|
return null;
|
|
125490
125581
|
}
|
|
125491
125582
|
|
|
125583
|
+
// lib/services/parent-lifecycle.ts
|
|
125584
|
+
function getTerminalLabel(workflow) {
|
|
125585
|
+
return Object.values(workflow.states).find((state) => state.type === "terminal")?.label ?? null;
|
|
125586
|
+
}
|
|
125587
|
+
function getCurrentWorkflowLabel(issueLabels, workflow) {
|
|
125588
|
+
const labels = new Set(issueLabels);
|
|
125589
|
+
return Object.values(workflow.states).find((state) => labels.has(state.label))?.label ?? null;
|
|
125590
|
+
}
|
|
125591
|
+
function sameIds(a, b) {
|
|
125592
|
+
const left = [...a ?? []].sort((x2, y) => x2 - y);
|
|
125593
|
+
const right = [...b ?? []].sort((x2, y) => x2 - y);
|
|
125594
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
125595
|
+
}
|
|
125596
|
+
function resolveChildRollupState(runtime) {
|
|
125597
|
+
if (!runtime) return "pending_without_runtime";
|
|
125598
|
+
if (runtime.decompositionStatus === "blocked") return "blocked";
|
|
125599
|
+
if (runtime.artifactOfRecord?.mergedAt) return "completed_via_artifact";
|
|
125600
|
+
if (runtime.sessionCompletedAt) return "completed_via_session";
|
|
125601
|
+
if (runtime.currentPrUrl && runtime.currentPrState && runtime.currentPrState !== "merged" && runtime.currentPrState !== "closed") {
|
|
125602
|
+
return "pending_with_open_pr";
|
|
125603
|
+
}
|
|
125604
|
+
if (runtime.currentPrUrl) return "pending_with_pr";
|
|
125605
|
+
return "pending_without_pr";
|
|
125606
|
+
}
|
|
125607
|
+
function formatChildRollupLine(child) {
|
|
125608
|
+
const runtime = child.runtime;
|
|
125609
|
+
const state = resolveChildRollupState(runtime);
|
|
125610
|
+
const prUrl = runtime?.artifactOfRecord?.url ?? runtime?.currentPrUrl ?? null;
|
|
125611
|
+
const mergedAt = runtime?.artifactOfRecord?.mergedAt ?? null;
|
|
125612
|
+
const headSha = runtime?.artifactOfRecord?.headSha ?? runtime?.lastHeadSha ?? null;
|
|
125613
|
+
const extras = [
|
|
125614
|
+
prUrl ? `PR: ${prUrl}` : null,
|
|
125615
|
+
mergedAt ? `mergedAt: ${mergedAt}` : null,
|
|
125616
|
+
headSha ? `headSha: ${headSha}` : null
|
|
125617
|
+
].filter(Boolean);
|
|
125618
|
+
return `- #${child.issueId} \u2014 ${state}${extras.length > 0 ? ` \u2014 ${extras.join(" \u2014 ")}` : ""}`;
|
|
125619
|
+
}
|
|
125620
|
+
var PARENT_ROLLUP_START = "<!-- fabrica:parent-rollup:start -->";
|
|
125621
|
+
var PARENT_ROLLUP_END = "<!-- fabrica:parent-rollup:end -->";
|
|
125622
|
+
function buildParentRollupComment(status, completedChildIds, blockedChildIds, children) {
|
|
125623
|
+
const allChildIds = children.map((child) => child.issueId);
|
|
125624
|
+
const pendingChildIds = allChildIds.filter((id) => !completedChildIds.includes(id) && !blockedChildIds.includes(id));
|
|
125625
|
+
return [
|
|
125626
|
+
"## Parent Rollup",
|
|
125627
|
+
`- Status: ${status}`,
|
|
125628
|
+
`- Completed children (${completedChildIds.length}/${allChildIds.length}): ${completedChildIds.length > 0 ? completedChildIds.map((id) => `#${id}`).join(", ") : "none"}`,
|
|
125629
|
+
`- Pending children: ${pendingChildIds.length > 0 ? pendingChildIds.map((id) => `#${id}`).join(", ") : "none"}`,
|
|
125630
|
+
`- Blocked children: ${blockedChildIds.length > 0 ? blockedChildIds.map((id) => `#${id}`).join(", ") : "none"}`,
|
|
125631
|
+
"",
|
|
125632
|
+
"### Child Status",
|
|
125633
|
+
...children.map((child) => formatChildRollupLine(child))
|
|
125634
|
+
].join("\n");
|
|
125635
|
+
}
|
|
125636
|
+
function upsertParentRollupBlock(body, rollup) {
|
|
125637
|
+
const current = body ?? "";
|
|
125638
|
+
const block = `${PARENT_ROLLUP_START}
|
|
125639
|
+
${rollup}
|
|
125640
|
+
${PARENT_ROLLUP_END}`;
|
|
125641
|
+
const pattern = new RegExp(`${PARENT_ROLLUP_START}[\\s\\S]*?${PARENT_ROLLUP_END}`, "m");
|
|
125642
|
+
if (pattern.test(current)) {
|
|
125643
|
+
return current.replace(pattern, block);
|
|
125644
|
+
}
|
|
125645
|
+
return `${current.trimEnd()}${current.trim().length > 0 ? "\n\n" : ""}${block}`;
|
|
125646
|
+
}
|
|
125647
|
+
async function reconcileParentLifecycleForIssue(opts) {
|
|
125648
|
+
const project = await loadProjectBySlug(opts.workspaceDir, opts.projectSlug);
|
|
125649
|
+
if (!project || !isChildIssue(project, opts.issueId)) return;
|
|
125650
|
+
const childRuntime = getIssueRuntime(project, opts.issueId);
|
|
125651
|
+
const parentRuntime = getParentIssueRuntime(project, opts.issueId);
|
|
125652
|
+
const parentIssueId = childRuntime?.parentIssueId;
|
|
125653
|
+
if (!parentIssueId || !parentRuntime) return;
|
|
125654
|
+
const children = getChildIssueRuntimes(project, parentIssueId);
|
|
125655
|
+
if (children.length === 0) return;
|
|
125656
|
+
const completedChildIds = children.filter((child) => isIssueExecutionComplete(project, child.issueId)).map((child) => child.issueId);
|
|
125657
|
+
const blockedChildIds = children.filter((child) => child.runtime?.decompositionStatus === "blocked").map((child) => child.issueId);
|
|
125658
|
+
const hasBlockedChild = blockedChildIds.length > 0;
|
|
125659
|
+
const allChildrenComplete = completedChildIds.length === children.length;
|
|
125660
|
+
const targetStatus = allChildrenComplete ? "completed" : hasBlockedChild ? "blocked" : "active";
|
|
125661
|
+
const statusChanged = parentRuntime.decompositionStatus !== targetStatus;
|
|
125662
|
+
const completedChanged = !sameIds(parentRuntime.completedChildIssueIds, completedChildIds);
|
|
125663
|
+
const blockedChanged = !sameIds(parentRuntime.blockedChildIssueIds, blockedChildIds);
|
|
125664
|
+
const shouldUpdateRuntime = statusChanged || completedChanged || blockedChanged;
|
|
125665
|
+
const shouldCommentRollup = statusChanged || blockedChanged;
|
|
125666
|
+
if (shouldUpdateRuntime) {
|
|
125667
|
+
await updateIssueRuntime(opts.workspaceDir, opts.projectSlug, parentIssueId, {
|
|
125668
|
+
decompositionStatus: targetStatus,
|
|
125669
|
+
completedChildIssueIds: completedChildIds,
|
|
125670
|
+
blockedChildIssueIds: blockedChildIds,
|
|
125671
|
+
lastParentRollupAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
125672
|
+
}).catch(() => {
|
|
125673
|
+
});
|
|
125674
|
+
}
|
|
125675
|
+
const parentIssue = await opts.provider.getIssue(parentIssueId).catch(() => null);
|
|
125676
|
+
if (!parentIssue) return;
|
|
125677
|
+
const rollup = buildParentRollupComment(targetStatus, completedChildIds, blockedChildIds, children);
|
|
125678
|
+
if (shouldUpdateRuntime) {
|
|
125679
|
+
await opts.provider.editIssue(parentIssueId, {
|
|
125680
|
+
body: upsertParentRollupBlock(parentIssue.description, rollup)
|
|
125681
|
+
}).catch(() => {
|
|
125682
|
+
});
|
|
125683
|
+
if (shouldCommentRollup) {
|
|
125684
|
+
await opts.provider.addComment(parentIssueId, rollup).catch(() => {
|
|
125685
|
+
});
|
|
125686
|
+
}
|
|
125687
|
+
}
|
|
125688
|
+
if (!allChildrenComplete) return;
|
|
125689
|
+
const terminalLabel = getTerminalLabel(opts.workflow);
|
|
125690
|
+
const currentLabel = getCurrentWorkflowLabel(parentIssue.labels, opts.workflow);
|
|
125691
|
+
if (terminalLabel && currentLabel && currentLabel !== terminalLabel && !parentIssue.labels.includes(terminalLabel)) {
|
|
125692
|
+
await opts.provider.transitionLabel(parentIssueId, currentLabel, terminalLabel).catch(() => {
|
|
125693
|
+
});
|
|
125694
|
+
}
|
|
125695
|
+
await opts.provider.addComment(parentIssueId, [
|
|
125696
|
+
"\u2705 Parent coordination complete.",
|
|
125697
|
+
"",
|
|
125698
|
+
"All child issues in this decomposition family have completed execution.",
|
|
125699
|
+
...children.map((child) => formatChildRollupLine(child))
|
|
125700
|
+
].join("\n")).catch(() => {
|
|
125701
|
+
});
|
|
125702
|
+
}
|
|
125703
|
+
|
|
125492
125704
|
// lib/services/pipeline.ts
|
|
125493
125705
|
init_workflow();
|
|
125494
125706
|
init_context3();
|
|
@@ -125765,7 +125977,33 @@ async function executeCompletion(opts) {
|
|
|
125765
125977
|
break;
|
|
125766
125978
|
}
|
|
125767
125979
|
}
|
|
125980
|
+
if (issueRuntime?.parentIssueId) {
|
|
125981
|
+
const childDecompositionStatus = effectiveResult === "blocked" || effectiveResult === "refine" || effectiveResult === "fail_infra" ? "blocked" : effectiveResult === "fail" || effectiveResult === "reject" ? "active" : issueRuntime.decompositionStatus;
|
|
125982
|
+
if (childDecompositionStatus !== issueRuntime.decompositionStatus) {
|
|
125983
|
+
await updateIssueRuntime(workspaceDir, projectSlug, issueId, {
|
|
125984
|
+
decompositionStatus: childDecompositionStatus
|
|
125985
|
+
}).catch(() => {
|
|
125986
|
+
});
|
|
125987
|
+
}
|
|
125988
|
+
}
|
|
125989
|
+
if (issueRuntime?.parentIssueId) {
|
|
125990
|
+
const childDecompositionStatus = effectiveResult === "blocked" || effectiveResult === "refine" || effectiveResult === "fail_infra" ? "blocked" : effectiveResult === "fail" || effectiveResult === "reject" ? "active" : issueRuntime.decompositionStatus;
|
|
125991
|
+
if (childDecompositionStatus !== issueRuntime.decompositionStatus) {
|
|
125992
|
+
await updateIssueRuntime(workspaceDir, projectSlug, issueId, {
|
|
125993
|
+
decompositionStatus: childDecompositionStatus
|
|
125994
|
+
}).catch(() => {
|
|
125995
|
+
});
|
|
125996
|
+
}
|
|
125997
|
+
}
|
|
125768
125998
|
await deactivateWorker(workspaceDir, projectSlug, role, { level: opts.level, slotIndex: opts.slotIndex, issueId: String(issueId) });
|
|
125999
|
+
await reconcileParentLifecycleForIssue({
|
|
126000
|
+
workspaceDir,
|
|
126001
|
+
projectSlug,
|
|
126002
|
+
issueId,
|
|
126003
|
+
provider,
|
|
126004
|
+
workflow
|
|
126005
|
+
}).catch(() => {
|
|
126006
|
+
});
|
|
125769
126007
|
notify(
|
|
125770
126008
|
{
|
|
125771
126009
|
type: "workerComplete",
|
|
@@ -126138,7 +126376,7 @@ function validateCanonicalQaEvidence(body) {
|
|
|
126138
126376
|
}
|
|
126139
126377
|
function formatQaEvidenceValidationFailure(validation, actor) {
|
|
126140
126378
|
const intro = actor === "developer" ? "Cannot mark work_finish(done) with invalid QA Evidence in the PR body." : "Cannot approve review with invalid QA Evidence in the PR body.";
|
|
126141
|
-
const guidance = actor === "developer" ? 'Replace the existing "## QA Evidence" section with fresh sanitized output from scripts/qa.sh (exactly one section, Exit code: 0), then call work_finish again.' : 'Reject the PR and instruct the developer to replace the existing "## QA Evidence" section in the PR body with fresh sanitized output from scripts/qa.sh (exactly one section, Exit code: 0).';
|
|
126379
|
+
const guidance = actor === "developer" ? 'Replace the existing "## QA Evidence" section with fresh sanitized output from scripts/qa.sh (exactly one section, Exit code: 0), then call work_finish again. Do not rewrite or weaken scripts/qa.sh into ad-hoc scenario checks \u2014 preserve the canonical lint/types/security/tests/coverage gates and fix the underlying code or project setup instead.' : 'Reject the PR and instruct the developer to replace the existing "## QA Evidence" section in the PR body with fresh sanitized output from scripts/qa.sh (exactly one section, Exit code: 0). Do not accept ad-hoc scenario scripts or weakened QA gates in place of the canonical lint/types/security/tests/coverage contract.';
|
|
126142
126380
|
const allIssues = [...validation.problems, ...validation.errors];
|
|
126143
126381
|
return `${intro}
|
|
126144
126382
|
|
|
@@ -126826,13 +127064,17 @@ function createTaskCreateTool(ctx) {
|
|
|
126826
127064
|
});
|
|
126827
127065
|
if (parentIssueId) {
|
|
126828
127066
|
await updateIssueRuntime(workspaceDir, project.slug, issue2.iid, {
|
|
126829
|
-
parentIssueId
|
|
127067
|
+
parentIssueId,
|
|
127068
|
+
decompositionMode: "none",
|
|
127069
|
+
decompositionStatus: null
|
|
126830
127070
|
}).catch(() => {
|
|
126831
127071
|
});
|
|
126832
127072
|
const parentRuntime = project.issueRuntime?.[String(parentIssueId)] ?? {};
|
|
126833
127073
|
const previousChildren = Array.isArray(parentRuntime.childIssueIds) ? parentRuntime.childIssueIds : [];
|
|
126834
127074
|
await updateIssueRuntime(workspaceDir, project.slug, parentIssueId, {
|
|
126835
|
-
childIssueIds: [.../* @__PURE__ */ new Set([...previousChildren, issue2.iid])]
|
|
127075
|
+
childIssueIds: [.../* @__PURE__ */ new Set([...previousChildren, issue2.iid])],
|
|
127076
|
+
decompositionMode: "parent_child",
|
|
127077
|
+
decompositionStatus: "active"
|
|
126836
127078
|
}).catch(() => {
|
|
126837
127079
|
});
|
|
126838
127080
|
provider.addComment(
|
|
@@ -127716,6 +127958,7 @@ function createTaskOwnerTool(ctx) {
|
|
|
127716
127958
|
|
|
127717
127959
|
// lib/dispatch/index.ts
|
|
127718
127960
|
init_audit();
|
|
127961
|
+
import fs22 from "node:fs/promises";
|
|
127719
127962
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
127720
127963
|
init_roles();
|
|
127721
127964
|
init_workflow();
|
|
@@ -128136,6 +128379,13 @@ init_roles();
|
|
|
128136
128379
|
function toBranchSlug(value) {
|
|
128137
128380
|
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "task";
|
|
128138
128381
|
}
|
|
128382
|
+
function resolveExecutionSetup(opts) {
|
|
128383
|
+
const branchName = opts.prBranchName?.trim() ? opts.prBranchName.trim() : `feature/${opts.issueId}-${toBranchSlug(opts.projectName)}`;
|
|
128384
|
+
return {
|
|
128385
|
+
branchName,
|
|
128386
|
+
worktreePath: `${opts.repo}.worktrees/${branchName}`
|
|
128387
|
+
};
|
|
128388
|
+
}
|
|
128139
128389
|
function buildTaskMessage(opts) {
|
|
128140
128390
|
const {
|
|
128141
128391
|
projectName,
|
|
@@ -128150,8 +128400,12 @@ function buildTaskMessage(opts) {
|
|
|
128150
128400
|
} = opts;
|
|
128151
128401
|
const repoDisplay = repo;
|
|
128152
128402
|
const isFeedbackCycle = !!opts.prFeedback;
|
|
128153
|
-
const branchName
|
|
128154
|
-
|
|
128403
|
+
const { branchName, worktreePath } = resolveExecutionSetup({
|
|
128404
|
+
projectName,
|
|
128405
|
+
issueId,
|
|
128406
|
+
repo: repoDisplay,
|
|
128407
|
+
prBranchName: opts.prFeedback?.branchName
|
|
128408
|
+
});
|
|
128155
128409
|
const parts = [
|
|
128156
128410
|
`${role.toUpperCase()} task for project "${projectName}" \u2014 Issue #${issueId}`,
|
|
128157
128411
|
``,
|
|
@@ -128172,10 +128426,11 @@ ${issueDescription}` : ""
|
|
|
128172
128426
|
``,
|
|
128173
128427
|
`## Execution Setup (do this before editing files)`,
|
|
128174
128428
|
`Repo: ${repoDisplay} | Base branch: ${baseBranch} | ${issueUrl}`,
|
|
128175
|
-
`Execution path: ${
|
|
128429
|
+
`Execution path: ${worktreePath}`,
|
|
128430
|
+
`Main checkout: ${repoDisplay}`,
|
|
128176
128431
|
`Required branch: ${branchName}`,
|
|
128177
128432
|
`Required worktree: ${worktreePath}`,
|
|
128178
|
-
`Before editing any file,
|
|
128433
|
+
`Before editing any file, change into the execution path above and work only there.`,
|
|
128179
128434
|
`Do not re-initialize or replace the scaffold in the main checkout (for example: do not run npm init, cargo init, uv init, or create a second project skeleton) when the repo already contains scaffolded files. Modify the existing scaffold inside the worktree instead.`,
|
|
128180
128435
|
`If the repo path is missing or inaccessible, return the canonical blocked result instead of improvising in ~/.openclaw/workspace.`
|
|
128181
128436
|
);
|
|
@@ -128242,8 +128497,12 @@ function buildConflictFixMessage(opts) {
|
|
|
128242
128497
|
prFeedback
|
|
128243
128498
|
} = opts;
|
|
128244
128499
|
const repoDisplay = repo;
|
|
128245
|
-
const branchName
|
|
128246
|
-
|
|
128500
|
+
const { branchName, worktreePath } = resolveExecutionSetup({
|
|
128501
|
+
projectName,
|
|
128502
|
+
issueId,
|
|
128503
|
+
repo: repoDisplay,
|
|
128504
|
+
prBranchName: prFeedback.branchName
|
|
128505
|
+
});
|
|
128247
128506
|
const parts = [
|
|
128248
128507
|
`${role.toUpperCase()} task for project "${projectName}" \u2014 Issue #${issueId}`,
|
|
128249
128508
|
``,
|
|
@@ -128256,10 +128515,11 @@ function buildConflictFixMessage(opts) {
|
|
|
128256
128515
|
``,
|
|
128257
128516
|
`Repo: ${repoDisplay} | Base branch: ${baseBranch} | ${issueUrl}`,
|
|
128258
128517
|
`Project: ${projectName} | Channel: ${channelId}`,
|
|
128259
|
-
`Execution path: ${
|
|
128518
|
+
`Execution path: ${worktreePath}`,
|
|
128519
|
+
`Main checkout: ${repoDisplay}`,
|
|
128260
128520
|
`Required branch: ${branchName}`,
|
|
128261
128521
|
`Required worktree: ${worktreePath}`,
|
|
128262
|
-
`Start by changing into the
|
|
128522
|
+
`Start by changing into the execution path above before reusing the PR branch. Reuse the exact PR branch named above; do not switch to a new canonical issue branch during a feedback cycle. Do not resolve the issue inside ~/.openclaw/workspace unless the repo path itself points there.`
|
|
128263
128523
|
);
|
|
128264
128524
|
parts.push(...buildCompletionContract(role));
|
|
128265
128525
|
return parts.join("\n");
|
|
@@ -128592,23 +128852,24 @@ ${roleInstructions}`;
|
|
|
128592
128852
|
}
|
|
128593
128853
|
return effortPrefix ?? roleInstructions ?? "";
|
|
128594
128854
|
}
|
|
128595
|
-
function sendToAgent(sessionKey, taskMessage, opts) {
|
|
128855
|
+
async function sendToAgent(sessionKey, taskMessage, opts) {
|
|
128596
128856
|
const epoch = opts.dispatchEpoch ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
128597
128857
|
const idempotencyKey = `fabrica-${opts.projectName}-${opts.issueId}-${opts.role}-${opts.level ?? "unknown"}-${opts.slotIndex ?? 0}-${opts.fromLabel ?? "unknown"}-${sessionKey}-${epoch}`;
|
|
128598
128858
|
if (opts.runtime?.subagent?.run) {
|
|
128599
|
-
|
|
128600
|
-
|
|
128601
|
-
|
|
128602
|
-
|
|
128603
|
-
|
|
128604
|
-
|
|
128605
|
-
|
|
128606
|
-
|
|
128859
|
+
try {
|
|
128860
|
+
const result = await opts.runtime.subagent.run({
|
|
128861
|
+
sessionKey,
|
|
128862
|
+
message: taskMessage,
|
|
128863
|
+
idempotencyKey,
|
|
128864
|
+
lane: "subagent",
|
|
128865
|
+
deliver: false,
|
|
128866
|
+
...opts.extraSystemPrompt ? { extraSystemPrompt: opts.extraSystemPrompt } : {}
|
|
128867
|
+
});
|
|
128607
128868
|
if (result?.runId) {
|
|
128608
|
-
bindDispatchRunIdBySessionKey(opts.workspaceDir, sessionKey, result.runId).catch(() => {
|
|
128869
|
+
await bindDispatchRunIdBySessionKey(opts.workspaceDir, sessionKey, result.runId).catch(() => {
|
|
128609
128870
|
});
|
|
128610
128871
|
}
|
|
128611
|
-
log(opts.workspaceDir, "dispatch_agent_sent", {
|
|
128872
|
+
await log(opts.workspaceDir, "dispatch_agent_sent", {
|
|
128612
128873
|
step: "sendToAgent",
|
|
128613
128874
|
sessionKey,
|
|
128614
128875
|
issue: opts.issueId,
|
|
@@ -128617,7 +128878,7 @@ function sendToAgent(sessionKey, taskMessage, opts) {
|
|
|
128617
128878
|
runId: result?.runId ?? null
|
|
128618
128879
|
}).catch(() => {
|
|
128619
128880
|
});
|
|
128620
|
-
recordIssueLifecycle({
|
|
128881
|
+
await recordIssueLifecycle({
|
|
128621
128882
|
workspaceDir: opts.workspaceDir,
|
|
128622
128883
|
slug: opts.projectSlug ?? opts.projectName,
|
|
128623
128884
|
issueId: opts.issueId,
|
|
@@ -128626,18 +128887,23 @@ function sendToAgent(sessionKey, taskMessage, opts) {
|
|
|
128626
128887
|
details: { method: "runtime.subagent.run" }
|
|
128627
128888
|
}).catch(() => {
|
|
128628
128889
|
});
|
|
128629
|
-
|
|
128890
|
+
return { method: "runtime.subagent.run", runId: result?.runId ?? null };
|
|
128891
|
+
} catch (err) {
|
|
128892
|
+
const errorMessage = err.message ?? String(err);
|
|
128630
128893
|
log(opts.workspaceDir, "dispatch_warning", {
|
|
128631
128894
|
step: "sendToAgent",
|
|
128632
128895
|
sessionKey,
|
|
128633
128896
|
issue: opts.issueId,
|
|
128634
128897
|
role: opts.role,
|
|
128635
128898
|
method: "runtime.subagent.run",
|
|
128636
|
-
error:
|
|
128899
|
+
error: errorMessage
|
|
128637
128900
|
}).catch(() => {
|
|
128638
128901
|
});
|
|
128639
|
-
|
|
128640
|
-
|
|
128902
|
+
if (/only available during a gateway request/i.test(errorMessage)) {
|
|
128903
|
+
} else {
|
|
128904
|
+
throw err;
|
|
128905
|
+
}
|
|
128906
|
+
}
|
|
128641
128907
|
}
|
|
128642
128908
|
const rc = opts.runCommand;
|
|
128643
128909
|
const gatewayParams = JSON.stringify({
|
|
@@ -128650,11 +128916,45 @@ function sendToAgent(sessionKey, taskMessage, opts) {
|
|
|
128650
128916
|
...opts.orchestratorSessionKey ? { spawnedBy: opts.orchestratorSessionKey } : {},
|
|
128651
128917
|
...opts.extraSystemPrompt ? { extraSystemPrompt: opts.extraSystemPrompt } : {}
|
|
128652
128918
|
});
|
|
128653
|
-
|
|
128654
|
-
|
|
128655
|
-
|
|
128656
|
-
|
|
128657
|
-
|
|
128919
|
+
try {
|
|
128920
|
+
const response = await rc(
|
|
128921
|
+
["openclaw", "gateway", "call", "agent", "--params", gatewayParams, "--expect-final", "--json"],
|
|
128922
|
+
{ timeoutMs: opts.dispatchTimeoutMs ?? 6e4 }
|
|
128923
|
+
);
|
|
128924
|
+
const stdout = String(response.stdout ?? "").trim();
|
|
128925
|
+
let runId = null;
|
|
128926
|
+
if (stdout) {
|
|
128927
|
+
try {
|
|
128928
|
+
const parsed = JSON.parse(stdout);
|
|
128929
|
+
runId = parsed.runId ?? parsed.result?.runId ?? null;
|
|
128930
|
+
} catch {
|
|
128931
|
+
}
|
|
128932
|
+
}
|
|
128933
|
+
if (runId) {
|
|
128934
|
+
await bindDispatchRunIdBySessionKey(opts.workspaceDir, sessionKey, runId).catch(() => {
|
|
128935
|
+
});
|
|
128936
|
+
}
|
|
128937
|
+
await log(opts.workspaceDir, "dispatch_agent_sent", {
|
|
128938
|
+
step: "sendToAgent",
|
|
128939
|
+
sessionKey,
|
|
128940
|
+
issue: opts.issueId,
|
|
128941
|
+
role: opts.role,
|
|
128942
|
+
method: "subprocess_fallback",
|
|
128943
|
+
runId
|
|
128944
|
+
}).catch(() => {
|
|
128945
|
+
});
|
|
128946
|
+
await recordIssueLifecycle({
|
|
128947
|
+
workspaceDir: opts.workspaceDir,
|
|
128948
|
+
slug: opts.projectSlug ?? opts.projectName,
|
|
128949
|
+
issueId: opts.issueId,
|
|
128950
|
+
stage: "agent_accepted",
|
|
128951
|
+
sessionKey,
|
|
128952
|
+
details: { method: "subprocess_fallback", runId }
|
|
128953
|
+
}).catch(() => {
|
|
128954
|
+
});
|
|
128955
|
+
return { method: "subprocess_fallback", runId };
|
|
128956
|
+
} catch (err) {
|
|
128957
|
+
await log(opts.workspaceDir, "dispatch_warning", {
|
|
128658
128958
|
step: "sendToAgent",
|
|
128659
128959
|
sessionKey,
|
|
128660
128960
|
issue: opts.issueId,
|
|
@@ -128663,7 +128963,8 @@ function sendToAgent(sessionKey, taskMessage, opts) {
|
|
|
128663
128963
|
error: err.message ?? String(err)
|
|
128664
128964
|
}).catch(() => {
|
|
128665
128965
|
});
|
|
128666
|
-
|
|
128966
|
+
throw err;
|
|
128967
|
+
}
|
|
128667
128968
|
}
|
|
128668
128969
|
function normalizeGatewaySessionLabel(label, maxLength = GATEWAY_SESSION_LABEL_MAX) {
|
|
128669
128970
|
if (!label) return { truncated: false };
|
|
@@ -128784,7 +129085,8 @@ async function dispatchTask(opts) {
|
|
|
128784
129085
|
existingSessionKey = null;
|
|
128785
129086
|
}
|
|
128786
129087
|
}
|
|
128787
|
-
|
|
129088
|
+
const feedbackFreshSession = !!(existingSessionKey && role === "developer" && isFeedbackState(resolvedConfig.workflow, fromLabel));
|
|
129089
|
+
if (feedbackFreshSession) {
|
|
128788
129090
|
await rc(
|
|
128789
129091
|
["openclaw", "gateway", "call", "sessions.delete", "--params", JSON.stringify({ key: existingSessionKey })],
|
|
128790
129092
|
{ timeoutMs: 1e4 }
|
|
@@ -128818,8 +129120,10 @@ async function dispatchTask(opts) {
|
|
|
128818
129120
|
existingSessionKey = null;
|
|
128819
129121
|
}
|
|
128820
129122
|
}
|
|
129123
|
+
const dispatchCycleId = randomUUID2();
|
|
128821
129124
|
const botName = slotName(project.name, role, level, slotIndex);
|
|
128822
|
-
const
|
|
129125
|
+
const deterministicSessionKey = `agent:${agentId ?? "unknown"}:subagent:${project.name}-${role}-${level}-${botName.toLowerCase()}`;
|
|
129126
|
+
const sessionKey = feedbackFreshSession ? `${deterministicSessionKey}-retry-${dispatchCycleId.slice(0, 8)}` : deterministicSessionKey;
|
|
128823
129127
|
if (existingSessionKey && existingSessionKey !== sessionKey) {
|
|
128824
129128
|
const existingKeyIsForSameRole = existingSessionKey.includes(`:${project.name}-${role}-`);
|
|
128825
129129
|
if (existingKeyIsForSameRole) {
|
|
@@ -128830,8 +129134,27 @@ async function dispatchTask(opts) {
|
|
|
128830
129134
|
existingSessionKey = null;
|
|
128831
129135
|
}
|
|
128832
129136
|
}
|
|
129137
|
+
if (!existingSessionKey) {
|
|
129138
|
+
const gatewaySessions = await fetchGatewaySessions(void 0, rc).catch(() => null);
|
|
129139
|
+
if (gatewaySessions && isSessionAlive(sessionKey, gatewaySessions)) {
|
|
129140
|
+
await rc(
|
|
129141
|
+
["openclaw", "gateway", "call", "sessions.delete", "--params", JSON.stringify({ key: sessionKey })],
|
|
129142
|
+
{ timeoutMs: 1e4 }
|
|
129143
|
+
).catch((err) => console.error("[fabrica] silent-catch:", err.message));
|
|
129144
|
+
await log(workspaceDir, "session_orphan_reset", {
|
|
129145
|
+
project: project.name,
|
|
129146
|
+
projectSlug: project.slug,
|
|
129147
|
+
issue: issueId,
|
|
129148
|
+
role,
|
|
129149
|
+
level,
|
|
129150
|
+
sessionKey,
|
|
129151
|
+
reason: feedbackFreshSession ? "gateway_session_alive_without_local_slot_tracking_after_feedback_reset" : "gateway_session_alive_without_local_slot_tracking"
|
|
129152
|
+
}).catch(() => {
|
|
129153
|
+
});
|
|
129154
|
+
}
|
|
129155
|
+
}
|
|
128833
129156
|
const sessionAction = existingSessionKey ? "send" : "spawn";
|
|
128834
|
-
const
|
|
129157
|
+
const dispatchSemantic = feedbackFreshSession ? "feedback_redispatch" : sessionAction === "send" ? "session_resume" : "fresh_dispatch";
|
|
128835
129158
|
const allComments = await provider.listComments(issueId);
|
|
128836
129159
|
const { workflow } = resolvedConfig;
|
|
128837
129160
|
const prFeedback = isFeedbackState(workflow, fromLabel) ? await fetchPrFeedback(provider, issueId, prSelector) : void 0;
|
|
@@ -128850,6 +129173,60 @@ async function dispatchTask(opts) {
|
|
|
128850
129173
|
const primaryChannelId = project.slug;
|
|
128851
129174
|
const isConflictFix = prFeedback?.reason === "merge_conflict";
|
|
128852
129175
|
const repoContext = project.repo ? resolveRepoPath(project.repo) : project.repoRemote?.replace(/\.git$/, "") || project.slug;
|
|
129176
|
+
const executionSetup = resolveExecutionSetup({
|
|
129177
|
+
projectName: project.name,
|
|
129178
|
+
issueId,
|
|
129179
|
+
repo: repoContext,
|
|
129180
|
+
prBranchName: prFeedback?.branchName
|
|
129181
|
+
});
|
|
129182
|
+
const localRepoPath = project.repo ? resolveRepoPath(project.repo) : null;
|
|
129183
|
+
if (localRepoPath) {
|
|
129184
|
+
const remoteStartRef = prFeedback?.branchName?.trim() ? `origin/${executionSetup.branchName}` : `origin/${project.baseBranch}`;
|
|
129185
|
+
await fs22.mkdir(`${localRepoPath}.worktrees`, { recursive: true }).catch(() => {
|
|
129186
|
+
});
|
|
129187
|
+
const worktreeExists = await fs22.stat(executionSetup.worktreePath).then(() => true).catch(() => false);
|
|
129188
|
+
if (!worktreeExists) {
|
|
129189
|
+
await rc(["git", "fetch", "origin", project.baseBranch], { timeoutMs: 3e4, cwd: localRepoPath }).catch(() => {
|
|
129190
|
+
});
|
|
129191
|
+
if (prFeedback?.branchName?.trim()) {
|
|
129192
|
+
await rc(["git", "fetch", "origin", executionSetup.branchName], { timeoutMs: 3e4, cwd: localRepoPath }).catch(() => {
|
|
129193
|
+
});
|
|
129194
|
+
}
|
|
129195
|
+
await rc(
|
|
129196
|
+
["git", "worktree", "add", executionSetup.worktreePath, "-B", executionSetup.branchName, remoteStartRef],
|
|
129197
|
+
{ timeoutMs: 6e4, cwd: localRepoPath }
|
|
129198
|
+
);
|
|
129199
|
+
await log(workspaceDir, "dispatch_worktree_prepared", {
|
|
129200
|
+
project: project.name,
|
|
129201
|
+
projectSlug: project.slug,
|
|
129202
|
+
issue: issueId,
|
|
129203
|
+
role,
|
|
129204
|
+
level,
|
|
129205
|
+
branchName: executionSetup.branchName,
|
|
129206
|
+
worktreePath: executionSetup.worktreePath,
|
|
129207
|
+
mode: "create"
|
|
129208
|
+
}).catch(() => {
|
|
129209
|
+
});
|
|
129210
|
+
} else {
|
|
129211
|
+
await rc(["git", "checkout", executionSetup.branchName], { timeoutMs: 3e4, cwd: executionSetup.worktreePath }).catch(() => {
|
|
129212
|
+
});
|
|
129213
|
+
await rc(["git", "reset", "--hard", remoteStartRef], { timeoutMs: 3e4, cwd: executionSetup.worktreePath }).catch(() => {
|
|
129214
|
+
});
|
|
129215
|
+
await rc(["git", "clean", "-fd"], { timeoutMs: 3e4, cwd: executionSetup.worktreePath }).catch(() => {
|
|
129216
|
+
});
|
|
129217
|
+
await log(workspaceDir, "dispatch_worktree_prepared", {
|
|
129218
|
+
project: project.name,
|
|
129219
|
+
projectSlug: project.slug,
|
|
129220
|
+
issue: issueId,
|
|
129221
|
+
role,
|
|
129222
|
+
level,
|
|
129223
|
+
branchName: executionSetup.branchName,
|
|
129224
|
+
worktreePath: executionSetup.worktreePath,
|
|
129225
|
+
mode: "reuse"
|
|
129226
|
+
}).catch(() => {
|
|
129227
|
+
});
|
|
129228
|
+
}
|
|
129229
|
+
}
|
|
128853
129230
|
const taskMessage = isConflictFix && prFeedback ? buildConflictFixMessage({
|
|
128854
129231
|
projectName: project.name,
|
|
128855
129232
|
channelId: primaryChannelId,
|
|
@@ -128993,6 +129370,62 @@ async function dispatchTask(opts) {
|
|
|
128993
129370
|
}
|
|
128994
129371
|
} catch {
|
|
128995
129372
|
}
|
|
129373
|
+
const dispatchEpoch = (/* @__PURE__ */ new Date()).toISOString();
|
|
129374
|
+
let sendResult;
|
|
129375
|
+
try {
|
|
129376
|
+
sendResult = await sendToAgent(sessionKey, taskMessage, {
|
|
129377
|
+
agentId,
|
|
129378
|
+
projectName: project.name,
|
|
129379
|
+
projectSlug: project.slug,
|
|
129380
|
+
issueId,
|
|
129381
|
+
role,
|
|
129382
|
+
level,
|
|
129383
|
+
slotIndex,
|
|
129384
|
+
fromLabel,
|
|
129385
|
+
orchestratorSessionKey: opts.sessionKey,
|
|
129386
|
+
workspaceDir,
|
|
129387
|
+
dispatchTimeoutMs: timeouts.dispatchMs,
|
|
129388
|
+
extraSystemPrompt: buildEffortPrompt(
|
|
129389
|
+
resolvedRole?.effort?.[level],
|
|
129390
|
+
roleInstructions.trim() || void 0
|
|
129391
|
+
) || void 0,
|
|
129392
|
+
runCommand: rc,
|
|
129393
|
+
runtime,
|
|
129394
|
+
dispatchEpoch
|
|
129395
|
+
});
|
|
129396
|
+
} catch (err) {
|
|
129397
|
+
try {
|
|
129398
|
+
await resilientLabelTransition(
|
|
129399
|
+
provider,
|
|
129400
|
+
issueId,
|
|
129401
|
+
toLabel,
|
|
129402
|
+
fromLabel,
|
|
129403
|
+
(msg) => log(workspaceDir, "dispatch_warning", { step: "send_rollback_label", issue: issueId, msg }).catch(() => {
|
|
129404
|
+
})
|
|
129405
|
+
);
|
|
129406
|
+
await deactivateWorker(workspaceDir, project.slug, role, { level, slotIndex, issueId: String(issueId) });
|
|
129407
|
+
} catch {
|
|
129408
|
+
}
|
|
129409
|
+
throw new Error(`Dispatch send failed for issue #${issueId}: ${err.message ?? String(err)}`);
|
|
129410
|
+
}
|
|
129411
|
+
await recordIssueLifecycle({
|
|
129412
|
+
workspaceDir,
|
|
129413
|
+
slug: project.slug,
|
|
129414
|
+
issueId,
|
|
129415
|
+
stage: "dispatch_requested",
|
|
129416
|
+
sessionKey,
|
|
129417
|
+
details: { role, level, slotIndex, sessionAction }
|
|
129418
|
+
}).catch((err) => {
|
|
129419
|
+
log(workspaceDir, "dispatch_warning", {
|
|
129420
|
+
project: project.name,
|
|
129421
|
+
issue: issueId,
|
|
129422
|
+
role,
|
|
129423
|
+
warning: "Lifecycle event failed after successful dispatch",
|
|
129424
|
+
error: err.message,
|
|
129425
|
+
sessionKey
|
|
129426
|
+
}).catch(() => {
|
|
129427
|
+
});
|
|
129428
|
+
});
|
|
128996
129429
|
const notifyConfig = getNotificationConfig(pluginConfig);
|
|
128997
129430
|
const notifyTarget = resolveNotifyChannel(issue2?.labels ?? [], project.channels);
|
|
128998
129431
|
notify(
|
|
@@ -129006,11 +129439,12 @@ async function dispatchTask(opts) {
|
|
|
129006
129439
|
level,
|
|
129007
129440
|
name: botName,
|
|
129008
129441
|
sessionAction,
|
|
129442
|
+
dispatchSemantic,
|
|
129009
129443
|
modelDowngraded: effectiveModel.downgraded,
|
|
129010
129444
|
originalModel: effectiveModel.downgraded ? resolvedModel : void 0,
|
|
129011
129445
|
effectiveModel: effectiveModel.downgraded ? model : void 0,
|
|
129012
129446
|
dispatchCycleId,
|
|
129013
|
-
dispatchRunId:
|
|
129447
|
+
dispatchRunId: sendResult.runId
|
|
129014
129448
|
},
|
|
129015
129449
|
{
|
|
129016
129450
|
workspaceDir,
|
|
@@ -129030,45 +129464,6 @@ async function dispatchTask(opts) {
|
|
|
129030
129464
|
error: err.message ?? String(err)
|
|
129031
129465
|
}).catch((auditErr) => console.error("[fabrica] silent-catch:", auditErr.message));
|
|
129032
129466
|
});
|
|
129033
|
-
const dispatchEpoch = (/* @__PURE__ */ new Date()).toISOString();
|
|
129034
|
-
sendToAgent(sessionKey, taskMessage, {
|
|
129035
|
-
agentId,
|
|
129036
|
-
projectName: project.name,
|
|
129037
|
-
projectSlug: project.slug,
|
|
129038
|
-
issueId,
|
|
129039
|
-
role,
|
|
129040
|
-
level,
|
|
129041
|
-
slotIndex,
|
|
129042
|
-
fromLabel,
|
|
129043
|
-
orchestratorSessionKey: opts.sessionKey,
|
|
129044
|
-
workspaceDir,
|
|
129045
|
-
dispatchTimeoutMs: timeouts.dispatchMs,
|
|
129046
|
-
extraSystemPrompt: buildEffortPrompt(
|
|
129047
|
-
resolvedRole?.effort?.[level],
|
|
129048
|
-
roleInstructions.trim() || void 0
|
|
129049
|
-
) || void 0,
|
|
129050
|
-
runCommand: rc,
|
|
129051
|
-
runtime,
|
|
129052
|
-
dispatchEpoch
|
|
129053
|
-
});
|
|
129054
|
-
await recordIssueLifecycle({
|
|
129055
|
-
workspaceDir,
|
|
129056
|
-
slug: project.slug,
|
|
129057
|
-
issueId,
|
|
129058
|
-
stage: "dispatch_requested",
|
|
129059
|
-
sessionKey,
|
|
129060
|
-
details: { role, level, slotIndex, sessionAction }
|
|
129061
|
-
}).catch((err) => {
|
|
129062
|
-
log(workspaceDir, "dispatch_warning", {
|
|
129063
|
-
project: project.name,
|
|
129064
|
-
issue: issueId,
|
|
129065
|
-
role,
|
|
129066
|
-
warning: "Lifecycle event failed after successful dispatch",
|
|
129067
|
-
error: err.message,
|
|
129068
|
-
sessionKey
|
|
129069
|
-
}).catch(() => {
|
|
129070
|
-
});
|
|
129071
|
-
});
|
|
129072
129467
|
await auditDispatch(workspaceDir, {
|
|
129073
129468
|
project: project.name,
|
|
129074
129469
|
issueId,
|
|
@@ -129786,7 +130181,7 @@ function createProjectStatusTool(ctx) {
|
|
|
129786
130181
|
}
|
|
129787
130182
|
|
|
129788
130183
|
// lib/tools/admin/project-register.ts
|
|
129789
|
-
import
|
|
130184
|
+
import fs24 from "node:fs/promises";
|
|
129790
130185
|
import path24 from "node:path";
|
|
129791
130186
|
init_audit();
|
|
129792
130187
|
init_roles();
|
|
@@ -129794,7 +130189,7 @@ init_workflow();
|
|
|
129794
130189
|
init_constants();
|
|
129795
130190
|
|
|
129796
130191
|
// lib/telegram/topic-service.ts
|
|
129797
|
-
import
|
|
130192
|
+
import fs23 from "node:fs/promises";
|
|
129798
130193
|
async function sleep2(ms) {
|
|
129799
130194
|
await new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
129800
130195
|
}
|
|
@@ -129824,7 +130219,7 @@ async function tryReadTokenFile(filePath) {
|
|
|
129824
130219
|
const resolvedPath = readString(filePath);
|
|
129825
130220
|
if (!resolvedPath) return void 0;
|
|
129826
130221
|
try {
|
|
129827
|
-
const token = await
|
|
130222
|
+
const token = await fs23.readFile(resolvedPath, "utf-8");
|
|
129828
130223
|
const trimmed = token.trim();
|
|
129829
130224
|
return trimmed || void 0;
|
|
129830
130225
|
} catch {
|
|
@@ -129985,14 +130380,14 @@ function buildForumTopicArtifactId(channelId, messageThreadId) {
|
|
|
129985
130380
|
async function scaffoldPromptFiles(workspaceDir, projectName) {
|
|
129986
130381
|
const projectDir = path24.join(workspaceDir, DATA_DIR, "projects", projectName);
|
|
129987
130382
|
const promptsDir = path24.join(projectDir, "prompts");
|
|
129988
|
-
await
|
|
130383
|
+
await fs24.mkdir(promptsDir, { recursive: true });
|
|
129989
130384
|
const readmePath = path24.join(projectDir, "README.md");
|
|
129990
130385
|
try {
|
|
129991
|
-
await
|
|
130386
|
+
await fs24.access(readmePath);
|
|
129992
130387
|
return false;
|
|
129993
130388
|
} catch {
|
|
129994
130389
|
const roles = getAllRoleIds().join(", ");
|
|
129995
|
-
await
|
|
130390
|
+
await fs24.writeFile(readmePath, `# Project Overrides
|
|
129996
130391
|
|
|
129997
130392
|
This directory holds project-specific configuration that overrides the workspace defaults.
|
|
129998
130393
|
|
|
@@ -130048,12 +130443,12 @@ function getProjectReadmePath(workspaceDir, projectName) {
|
|
|
130048
130443
|
async function ensureAutonomousWorkflowOverride(workspaceDir, projectName, reviewPolicy = "agent") {
|
|
130049
130444
|
const projectDir = getProjectDir(workspaceDir, projectName);
|
|
130050
130445
|
const workflowPath = getProjectWorkflowPath(workspaceDir, projectName);
|
|
130051
|
-
await
|
|
130446
|
+
await fs24.mkdir(projectDir, { recursive: true });
|
|
130052
130447
|
try {
|
|
130053
|
-
await
|
|
130448
|
+
await fs24.access(workflowPath);
|
|
130054
130449
|
return false;
|
|
130055
130450
|
} catch {
|
|
130056
|
-
await
|
|
130451
|
+
await fs24.writeFile(workflowPath, `workflow:
|
|
130057
130452
|
reviewPolicy: ${reviewPolicy}
|
|
130058
130453
|
`, "utf-8");
|
|
130059
130454
|
return true;
|
|
@@ -130062,7 +130457,7 @@ async function ensureAutonomousWorkflowOverride(workspaceDir, projectName, revie
|
|
|
130062
130457
|
async function hasProjectWorkflowOverride(workspaceDir, projectName) {
|
|
130063
130458
|
const workflowPath = getProjectWorkflowPath(workspaceDir, projectName);
|
|
130064
130459
|
try {
|
|
130065
|
-
await
|
|
130460
|
+
await fs24.access(workflowPath);
|
|
130066
130461
|
return true;
|
|
130067
130462
|
} catch {
|
|
130068
130463
|
return false;
|
|
@@ -130077,7 +130472,7 @@ async function pruneEmptyProjectDirs(workspaceDir, projectName) {
|
|
|
130077
130472
|
for (const dir of candidateDirs2) {
|
|
130078
130473
|
if (!dir.startsWith(stopDir)) continue;
|
|
130079
130474
|
try {
|
|
130080
|
-
await
|
|
130475
|
+
await fs24.rmdir(dir);
|
|
130081
130476
|
} catch (error48) {
|
|
130082
130477
|
const code = error48.code;
|
|
130083
130478
|
if (code !== "ENOENT" && code !== "ENOTEMPTY") {
|
|
@@ -130088,10 +130483,10 @@ async function pruneEmptyProjectDirs(workspaceDir, projectName) {
|
|
|
130088
130483
|
}
|
|
130089
130484
|
async function cleanupLocalRegisterResidue(workspaceDir, projectName, opts) {
|
|
130090
130485
|
if (opts.removeWorkflowOverride) {
|
|
130091
|
-
await
|
|
130486
|
+
await fs24.rm(getProjectWorkflowPath(workspaceDir, projectName), { force: true });
|
|
130092
130487
|
}
|
|
130093
130488
|
if (opts.removePromptReadme) {
|
|
130094
|
-
await
|
|
130489
|
+
await fs24.rm(getProjectReadmePath(workspaceDir, projectName), { force: true });
|
|
130095
130490
|
}
|
|
130096
130491
|
await pruneEmptyProjectDirs(workspaceDir, projectName);
|
|
130097
130492
|
}
|
|
@@ -130124,7 +130519,7 @@ var NODE_STACKS = /* @__PURE__ */ new Set(["nextjs", "node-cli", "express"]);
|
|
|
130124
130519
|
var PYTHON_STACKS = /* @__PURE__ */ new Set(["fastapi", "flask", "django", "python-cli"]);
|
|
130125
130520
|
async function pathExists(candidate) {
|
|
130126
130521
|
try {
|
|
130127
|
-
await
|
|
130522
|
+
await fs24.access(candidate);
|
|
130128
130523
|
return true;
|
|
130129
130524
|
} catch {
|
|
130130
130525
|
return false;
|
|
@@ -130549,7 +130944,7 @@ init_labels();
|
|
|
130549
130944
|
|
|
130550
130945
|
// lib/services/worker-completion.ts
|
|
130551
130946
|
init_audit();
|
|
130552
|
-
import
|
|
130947
|
+
import fs25 from "node:fs/promises";
|
|
130553
130948
|
init_workflow();
|
|
130554
130949
|
|
|
130555
130950
|
// lib/services/worker-result.ts
|
|
@@ -130688,7 +131083,7 @@ function parseSessionTranscript(raw) {
|
|
|
130688
131083
|
async function readWorkerResultFromSessionFile(role, sessionFile) {
|
|
130689
131084
|
if (!sessionFile) return null;
|
|
130690
131085
|
try {
|
|
130691
|
-
const raw = await
|
|
131086
|
+
const raw = await fs25.readFile(sessionFile, "utf-8");
|
|
130692
131087
|
const messages = parseSessionTranscript(raw);
|
|
130693
131088
|
const result = extractWorkerResultFromMessages(role, messages);
|
|
130694
131089
|
return result ? {
|
|
@@ -132778,7 +133173,7 @@ ${channelList}`;
|
|
|
132778
133173
|
// lib/setup/index.ts
|
|
132779
133174
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
132780
133175
|
init_roles();
|
|
132781
|
-
import
|
|
133176
|
+
import fs39 from "node:fs/promises";
|
|
132782
133177
|
import path39 from "node:path";
|
|
132783
133178
|
|
|
132784
133179
|
// lib/setup/binding-manager.ts
|
|
@@ -132801,7 +133196,7 @@ async function migrateChannelBinding(api, channel, fromAgentId, toAgentId) {
|
|
|
132801
133196
|
|
|
132802
133197
|
// lib/setup/agent.ts
|
|
132803
133198
|
init_logger();
|
|
132804
|
-
import
|
|
133199
|
+
import fs26 from "node:fs/promises";
|
|
132805
133200
|
import path25 from "node:path";
|
|
132806
133201
|
async function createAgent(api, name, runCommand, channelBinding) {
|
|
132807
133202
|
const rc = runCommand;
|
|
@@ -132830,11 +133225,11 @@ function resolveWorkspacePath(api, agentId) {
|
|
|
132830
133225
|
}
|
|
132831
133226
|
async function cleanupWorkspace(workspacePath) {
|
|
132832
133227
|
try {
|
|
132833
|
-
await
|
|
133228
|
+
await fs26.rm(path25.join(workspacePath, ".git"), { recursive: true });
|
|
132834
133229
|
} catch {
|
|
132835
133230
|
}
|
|
132836
133231
|
try {
|
|
132837
|
-
await
|
|
133232
|
+
await fs26.unlink(path25.join(workspacePath, "BOOTSTRAP.md"));
|
|
132838
133233
|
} catch {
|
|
132839
133234
|
}
|
|
132840
133235
|
}
|
|
@@ -132897,7 +133292,7 @@ init_workspace();
|
|
|
132897
133292
|
|
|
132898
133293
|
// lib/services/heartbeat/agent-discovery.ts
|
|
132899
133294
|
init_constants();
|
|
132900
|
-
import
|
|
133295
|
+
import fs27 from "node:fs";
|
|
132901
133296
|
import path26 from "node:path";
|
|
132902
133297
|
function discoverAgents(config2) {
|
|
132903
133298
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -132924,7 +133319,7 @@ function discoverAgents(config2) {
|
|
|
132924
133319
|
return agents;
|
|
132925
133320
|
}
|
|
132926
133321
|
function hasProjects(workspace) {
|
|
132927
|
-
return
|
|
133322
|
+
return fs27.existsSync(path26.join(workspace, DATA_DIR, "projects.json")) || fs27.existsSync(path26.join(workspace, "projects.json")) || fs27.existsSync(path26.join(workspace, "projects", "projects.json"));
|
|
132928
133323
|
}
|
|
132929
133324
|
|
|
132930
133325
|
// lib/services/heartbeat/config.ts
|
|
@@ -137273,7 +137668,7 @@ async function processPendingGitHubEventsForWorkspace(params) {
|
|
|
137273
137668
|
}
|
|
137274
137669
|
|
|
137275
137670
|
// lib/machines/lifecycle-service.ts
|
|
137276
|
-
import
|
|
137671
|
+
import fs30 from "node:fs/promises";
|
|
137277
137672
|
import path29 from "node:path";
|
|
137278
137673
|
init_constants();
|
|
137279
137674
|
init_migrate_layout();
|
|
@@ -137366,9 +137761,9 @@ async function lifecycleSnapshotPath(workspaceDir) {
|
|
|
137366
137761
|
}
|
|
137367
137762
|
async function persistSnapshot(workspaceDir, actor) {
|
|
137368
137763
|
const filePath = await lifecycleSnapshotPath(workspaceDir);
|
|
137369
|
-
await
|
|
137764
|
+
await fs30.mkdir(path29.dirname(filePath), { recursive: true });
|
|
137370
137765
|
const snapshot = actor.getSnapshot();
|
|
137371
|
-
await
|
|
137766
|
+
await fs30.writeFile(filePath, JSON.stringify({
|
|
137372
137767
|
value: snapshot.value,
|
|
137373
137768
|
context: snapshot.context,
|
|
137374
137769
|
updatedAt: snapshot.context.updatedAt
|
|
@@ -137461,7 +137856,7 @@ async function raceWithTimeout(fn, timeoutMs, onTimeout) {
|
|
|
137461
137856
|
// lib/dispatch/telegram-bootstrap-hook.ts
|
|
137462
137857
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
137463
137858
|
import { homedir as homedir2 } from "node:os";
|
|
137464
|
-
import
|
|
137859
|
+
import fs37 from "node:fs/promises";
|
|
137465
137860
|
import path37 from "node:path";
|
|
137466
137861
|
|
|
137467
137862
|
// lib/dispatch/attachment-hook.ts
|
|
@@ -137908,7 +138303,7 @@ init_conduct_interview();
|
|
|
137908
138303
|
init_generate_spec();
|
|
137909
138304
|
|
|
137910
138305
|
// lib/intake/lib/project-map.ts
|
|
137911
|
-
import
|
|
138306
|
+
import fs32 from "node:fs/promises";
|
|
137912
138307
|
import path31 from "node:path";
|
|
137913
138308
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([
|
|
137914
138309
|
".git",
|
|
@@ -138008,7 +138403,7 @@ function matchProjectByRef(projects, ref) {
|
|
|
138008
138403
|
async function tryStatDir(candidate) {
|
|
138009
138404
|
if (!candidate) return false;
|
|
138010
138405
|
try {
|
|
138011
|
-
return (await
|
|
138406
|
+
return (await fs32.stat(candidate)).isDirectory();
|
|
138012
138407
|
} catch {
|
|
138013
138408
|
return false;
|
|
138014
138409
|
}
|
|
@@ -138109,7 +138504,7 @@ async function resolveProjectTarget(payload, workspaceDir, homeDir) {
|
|
|
138109
138504
|
async function collectFiles(root, relativeDir = "", files = [], limit = 800) {
|
|
138110
138505
|
if (files.length >= limit) return files;
|
|
138111
138506
|
const currentDir = path31.join(root, relativeDir);
|
|
138112
|
-
const entries = await
|
|
138507
|
+
const entries = await fs32.readdir(currentDir, { withFileTypes: true });
|
|
138113
138508
|
for (const entry of entries) {
|
|
138114
138509
|
if (files.length >= limit) break;
|
|
138115
138510
|
if (entry.name.startsWith(".") && entry.name !== ".env.example") {
|
|
@@ -138303,16 +138698,16 @@ var impactStep = {
|
|
|
138303
138698
|
const modules = map2?.modules ?? [];
|
|
138304
138699
|
const specText = `${spec.title} ${spec.objective} ${spec.scope_v1.join(" ")}`.toLowerCase();
|
|
138305
138700
|
const affected = symbols.filter((s2) => specText.includes(s2.name.toLowerCase())).map((s2) => s2.file);
|
|
138306
|
-
const
|
|
138701
|
+
const unique2 = [...new Set(affected)];
|
|
138307
138702
|
const affectedModules = modules.filter((moduleName2) => specText.includes(moduleName2.toLowerCase()));
|
|
138308
|
-
const confidence = map2?.confidence === "low" || !
|
|
138703
|
+
const confidence = map2?.confidence === "low" || !unique2.length && !affectedModules.length ? "low" : "high";
|
|
138309
138704
|
impact = {
|
|
138310
138705
|
is_greenfield: false,
|
|
138311
|
-
affected_files:
|
|
138706
|
+
affected_files: unique2,
|
|
138312
138707
|
affected_modules: [...new Set(affectedModules)],
|
|
138313
138708
|
new_files_needed: [],
|
|
138314
138709
|
risk_areas: spec.risks,
|
|
138315
|
-
estimated_files_changed: Math.max(1,
|
|
138710
|
+
estimated_files_changed: Math.max(1, unique2.length || affectedModules.length),
|
|
138316
138711
|
confidence
|
|
138317
138712
|
};
|
|
138318
138713
|
}
|
|
@@ -138334,7 +138729,7 @@ init_runtime_paths();
|
|
|
138334
138729
|
|
|
138335
138730
|
// lib/test-env/bootstrap.ts
|
|
138336
138731
|
import { createHash as createHash3 } from "node:crypto";
|
|
138337
|
-
import
|
|
138732
|
+
import fs33 from "node:fs/promises";
|
|
138338
138733
|
import path32 from "node:path";
|
|
138339
138734
|
var NODE_STACKS2 = /* @__PURE__ */ new Set(["nextjs", "node-cli", "express"]);
|
|
138340
138735
|
var PYTHON_STACKS2 = /* @__PURE__ */ new Set(["fastapi", "flask", "django", "python-cli"]);
|
|
@@ -138401,7 +138796,7 @@ var BOOTSTRAP_STATE_FILE = "test-env.sha256";
|
|
|
138401
138796
|
var DEFAULT_TIMEOUT = 18e4;
|
|
138402
138797
|
async function pathExists2(candidate) {
|
|
138403
138798
|
try {
|
|
138404
|
-
await
|
|
138799
|
+
await fs33.access(candidate);
|
|
138405
138800
|
return true;
|
|
138406
138801
|
} catch {
|
|
138407
138802
|
return false;
|
|
@@ -138409,7 +138804,7 @@ async function pathExists2(candidate) {
|
|
|
138409
138804
|
}
|
|
138410
138805
|
async function isValidBinary(filePath) {
|
|
138411
138806
|
try {
|
|
138412
|
-
const stat2 = await
|
|
138807
|
+
const stat2 = await fs33.stat(filePath);
|
|
138413
138808
|
return stat2.size > 0;
|
|
138414
138809
|
} catch {
|
|
138415
138810
|
return false;
|
|
@@ -138577,7 +138972,7 @@ async function computeFingerprint(repoPath, files) {
|
|
|
138577
138972
|
for (const file2 of existing.sort()) {
|
|
138578
138973
|
hash2.update(`${file2}
|
|
138579
138974
|
`);
|
|
138580
|
-
hash2.update(await
|
|
138975
|
+
hash2.update(await fs33.readFile(path32.join(repoPath, file2)));
|
|
138581
138976
|
hash2.update("\n");
|
|
138582
138977
|
}
|
|
138583
138978
|
return hash2.digest("hex");
|
|
@@ -138585,15 +138980,15 @@ async function computeFingerprint(repoPath, files) {
|
|
|
138585
138980
|
async function readBootstrapFingerprint(repoPath) {
|
|
138586
138981
|
const stateFile = path32.join(repoPath, BOOTSTRAP_STATE_DIR, BOOTSTRAP_STATE_FILE);
|
|
138587
138982
|
try {
|
|
138588
|
-
return (await
|
|
138983
|
+
return (await fs33.readFile(stateFile, "utf-8")).trim() || null;
|
|
138589
138984
|
} catch {
|
|
138590
138985
|
return null;
|
|
138591
138986
|
}
|
|
138592
138987
|
}
|
|
138593
138988
|
async function writeBootstrapFingerprint(repoPath, fingerprint) {
|
|
138594
138989
|
const stateDir = path32.join(repoPath, BOOTSTRAP_STATE_DIR);
|
|
138595
|
-
await
|
|
138596
|
-
await
|
|
138990
|
+
await fs33.mkdir(stateDir, { recursive: true });
|
|
138991
|
+
await fs33.writeFile(path32.join(stateDir, BOOTSTRAP_STATE_FILE), fingerprint, "utf-8");
|
|
138597
138992
|
}
|
|
138598
138993
|
async function toolExists(runCommand, cmd, args = ["--version"]) {
|
|
138599
138994
|
try {
|
|
@@ -138652,7 +139047,7 @@ Details: ${(install.stderr || install.stdout || "unknown error").trim()}`
|
|
|
138652
139047
|
const home = process.env.HOME ?? "";
|
|
138653
139048
|
const fallbackPath = path32.join(home, ".local", "bin", "uv");
|
|
138654
139049
|
try {
|
|
138655
|
-
await
|
|
139050
|
+
await fs33.access(fallbackPath);
|
|
138656
139051
|
emit2(`[test-env] uv installed at fallback path: ${fallbackPath}`);
|
|
138657
139052
|
return fallbackPath;
|
|
138658
139053
|
} catch {
|
|
@@ -138682,16 +139077,16 @@ async function ensurePythonToolchain(runCommand, homeDir) {
|
|
|
138682
139077
|
const expectedFp = await toolchainFingerprint(runCommand);
|
|
138683
139078
|
if (await isValidBinary(ruffPath)) {
|
|
138684
139079
|
try {
|
|
138685
|
-
const currentFp = (await
|
|
139080
|
+
const currentFp = (await fs33.readFile(fingerprintPath, "utf-8")).trim();
|
|
138686
139081
|
if (currentFp === expectedFp) {
|
|
138687
139082
|
return toolchainPath;
|
|
138688
139083
|
}
|
|
138689
139084
|
} catch {
|
|
138690
139085
|
}
|
|
138691
|
-
await
|
|
139086
|
+
await fs33.rm(toolchainPath, { recursive: true, force: true });
|
|
138692
139087
|
}
|
|
138693
139088
|
const uvCmd = await ensureUv(runCommand);
|
|
138694
|
-
await
|
|
139089
|
+
await fs33.mkdir(path32.dirname(toolchainPath), { recursive: true });
|
|
138695
139090
|
const venvResult = await runCommand(uvCmd, ["venv", toolchainPath], { timeout: 6e4 });
|
|
138696
139091
|
if (venvResult.exitCode !== 0) {
|
|
138697
139092
|
throw new Error(`Failed to create toolchain venv: ${venvResult.stderr}`);
|
|
@@ -138706,13 +139101,13 @@ async function ensurePythonToolchain(runCommand, homeDir) {
|
|
|
138706
139101
|
if (installResult.exitCode !== 0) {
|
|
138707
139102
|
throw new Error(`Failed to install toolchain packages: ${installResult.stderr}`);
|
|
138708
139103
|
}
|
|
138709
|
-
await
|
|
139104
|
+
await fs33.writeFile(fingerprintPath, expectedFp, "utf-8");
|
|
138710
139105
|
return toolchainPath;
|
|
138711
139106
|
}
|
|
138712
139107
|
async function hasPyprojectDevExtra(repoPath) {
|
|
138713
139108
|
const pyprojectPath = path32.join(repoPath, "pyproject.toml");
|
|
138714
139109
|
if (!await pathExists2(pyprojectPath)) return false;
|
|
138715
|
-
const content = await
|
|
139110
|
+
const content = await fs33.readFile(pyprojectPath, "utf-8");
|
|
138716
139111
|
const match = content.match(/\[project\.optional-dependencies\]([\s\S]*?)(?:\n\[|$)/);
|
|
138717
139112
|
if (!match) return false;
|
|
138718
139113
|
return /^\s*dev\s*=\s*\[/m.test(match[1] ?? "");
|
|
@@ -139352,7 +139747,7 @@ var scaffoldPassthroughStep = {
|
|
|
139352
139747
|
};
|
|
139353
139748
|
|
|
139354
139749
|
// lib/intake/lib/repository-provision-service.ts
|
|
139355
|
-
import
|
|
139750
|
+
import fs34 from "node:fs/promises";
|
|
139356
139751
|
import path34 from "node:path";
|
|
139357
139752
|
function normalizeText2(value) {
|
|
139358
139753
|
if (typeof value !== "string") return null;
|
|
@@ -139393,7 +139788,7 @@ function adaptRunCommand(ctx) {
|
|
|
139393
139788
|
async function pathExists3(candidate) {
|
|
139394
139789
|
if (!candidate) return false;
|
|
139395
139790
|
try {
|
|
139396
|
-
await
|
|
139791
|
+
await fs34.access(candidate);
|
|
139397
139792
|
return true;
|
|
139398
139793
|
} catch {
|
|
139399
139794
|
return false;
|
|
@@ -139768,7 +140163,7 @@ init_workflow();
|
|
|
139768
140163
|
// lib/dispatch/telegram-bootstrap-session.ts
|
|
139769
140164
|
init_constants();
|
|
139770
140165
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
139771
|
-
import
|
|
140166
|
+
import fs35 from "node:fs/promises";
|
|
139772
140167
|
import path35 from "node:path";
|
|
139773
140168
|
var SESSION_TTL_MS = 10 * 6e4;
|
|
139774
140169
|
var CLASSIFYING_TTL_MS = 15e3;
|
|
@@ -139878,7 +140273,7 @@ async function readTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
|
139878
140273
|
try {
|
|
139879
140274
|
for (const candidatePath of paths) {
|
|
139880
140275
|
try {
|
|
139881
|
-
const raw = await
|
|
140276
|
+
const raw = await fs35.readFile(candidatePath, "utf-8");
|
|
139882
140277
|
const session = normalizeStoredSession(JSON.parse(raw));
|
|
139883
140278
|
if (session.status === "failed" && isReleasedClassifyFailure(session.error)) {
|
|
139884
140279
|
await deleteTelegramBootstrapSession(workspaceDir, canonicalConversationId);
|
|
@@ -139897,25 +140292,25 @@ async function readTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
|
139897
140292
|
}
|
|
139898
140293
|
}
|
|
139899
140294
|
async function deleteTelegramBootstrapSession(workspaceDir, conversationId) {
|
|
139900
|
-
await
|
|
140295
|
+
await fs35.unlink(sessionPath(workspaceDir, conversationId)).catch(() => {
|
|
139901
140296
|
});
|
|
139902
140297
|
const legacyPath = alternateSessionPath(workspaceDir, conversationId);
|
|
139903
140298
|
if (legacyPath) {
|
|
139904
|
-
await
|
|
140299
|
+
await fs35.unlink(legacyPath).catch(() => {
|
|
139905
140300
|
});
|
|
139906
140301
|
}
|
|
139907
140302
|
}
|
|
139908
140303
|
async function writeTelegramBootstrapSession(workspaceDir, session) {
|
|
139909
140304
|
const canonicalSession = normalizeStoredSession(session);
|
|
139910
140305
|
const dir = sessionsDir(workspaceDir);
|
|
139911
|
-
await
|
|
140306
|
+
await fs35.mkdir(dir, { recursive: true });
|
|
139912
140307
|
const file2 = sessionPath(workspaceDir, canonicalSession.conversationId);
|
|
139913
140308
|
const tmp = `${file2}.${randomUUID4()}.tmp`;
|
|
139914
|
-
await
|
|
139915
|
-
await
|
|
140309
|
+
await fs35.writeFile(tmp, JSON.stringify(canonicalSession, null, 2) + "\n", "utf-8");
|
|
140310
|
+
await fs35.rename(tmp, file2);
|
|
139916
140311
|
const legacyPath = alternateSessionPath(workspaceDir, session.conversationId);
|
|
139917
140312
|
if (legacyPath) {
|
|
139918
|
-
await
|
|
140313
|
+
await fs35.unlink(legacyPath).catch(() => {
|
|
139919
140314
|
});
|
|
139920
140315
|
}
|
|
139921
140316
|
}
|
|
@@ -140303,9 +140698,66 @@ function determineLevel(effort, targetState) {
|
|
|
140303
140698
|
if (targetState === "To Research" && level === "medior") level = "junior";
|
|
140304
140699
|
return level;
|
|
140305
140700
|
}
|
|
140701
|
+
function assessComplexity(input) {
|
|
140702
|
+
const broadSignals = detectRawIdeaComplexity(input.rawIdea).signals.length;
|
|
140703
|
+
if (input.filesChanged >= 18 || input.acCount >= 8 || broadSignals >= 4 || input.totalRisks >= 4) return "high";
|
|
140704
|
+
if (input.filesChanged >= 8 || input.acCount >= 4 || broadSignals >= 2 || input.totalRisks >= 2) return "medium";
|
|
140705
|
+
return "low";
|
|
140706
|
+
}
|
|
140707
|
+
function assessCoupling(input) {
|
|
140708
|
+
const text = `${input.rawIdea} ${input.scopeText}`.toLowerCase();
|
|
140709
|
+
const crossCuttingSignals = [
|
|
140710
|
+
/\bauth\b|\bpermission\b|\brbac\b/,
|
|
140711
|
+
/\bmigration\b|\bschema\b|\bdatabase\b/,
|
|
140712
|
+
/\bbackground\b|\bworker\b|\bqueue\b|\bcron\b/,
|
|
140713
|
+
/\bfrontend\b|\bdashboard\b|\bui\b/,
|
|
140714
|
+
/\bintegration\b|\bwebhook\b|\bexternal\b/
|
|
140715
|
+
].filter((regex) => regex.test(text)).length;
|
|
140716
|
+
if (crossCuttingSignals >= 4) return "high";
|
|
140717
|
+
if (crossCuttingSignals >= 2) return "medium";
|
|
140718
|
+
return "low";
|
|
140719
|
+
}
|
|
140720
|
+
function assessParallelizability(input, coupling) {
|
|
140721
|
+
const text = `${input.rawIdea} ${input.scopeText}`.toLowerCase();
|
|
140722
|
+
const capabilitySignals = [
|
|
140723
|
+
/\bauth\b/,
|
|
140724
|
+
/\bapi\b|\bendpoint\b|\broute\b/,
|
|
140725
|
+
/\bfrontend\b|\bdashboard\b|\bui\b/,
|
|
140726
|
+
/\bworker\b|\bqueue\b|\bbackground\b/,
|
|
140727
|
+
/\bnotification\b|\bemail\b|\bsms\b|\balert\b/,
|
|
140728
|
+
/\bdatabase\b|\bmigration\b|\bschema\b/
|
|
140729
|
+
].filter((regex) => regex.test(text)).length;
|
|
140730
|
+
if (coupling === "high") return "low";
|
|
140731
|
+
if (capabilitySignals >= 4) return "high";
|
|
140732
|
+
if (capabilitySignals >= 2) return "medium";
|
|
140733
|
+
return "low";
|
|
140734
|
+
}
|
|
140735
|
+
function assessQualityCriticality(input) {
|
|
140736
|
+
const text = `${input.rawIdea} ${input.objective} ${input.scopeText}`.toLowerCase();
|
|
140737
|
+
if (/\bauth\b|\boauth\b|\bjwt\b|\brbac\b|\bpayment\b|\bbilling\b|\bpii\b|\bsecure\b|\bsecurity\b/.test(text)) return "high";
|
|
140738
|
+
if (/\bperformance\b|\bscalable\b|\bbackground\b|\bworker\b|\bintegration\b|\bwebhook\b/.test(text)) return "medium";
|
|
140739
|
+
return "low";
|
|
140740
|
+
}
|
|
140741
|
+
function buildRiskProfile(input) {
|
|
140742
|
+
const text = `${input.rawIdea} ${input.objective} ${input.scopeText}`.toLowerCase();
|
|
140743
|
+
const risks = [
|
|
140744
|
+
/\bauth\b|\boauth\b|\bjwt\b|\brbac\b/.test(text) ? "auth" : null,
|
|
140745
|
+
/\bpayment\b|\bbilling\b|\bsubscription\b/.test(text) ? "payments" : null,
|
|
140746
|
+
/\bdatabase\b|\bmigration\b|\bschema\b/.test(text) ? "data_model" : null,
|
|
140747
|
+
/\bworker\b|\bqueue\b|\bbackground\b|\bcron\b/.test(text) ? "async_processing" : null,
|
|
140748
|
+
/\bintegration\b|\bwebhook\b|\bexternal\b/.test(text) ? "external_integration" : null,
|
|
140749
|
+
/\bperformance\b|\blatency\b|\bthroughput\b/.test(text) ? "performance" : null
|
|
140750
|
+
];
|
|
140751
|
+
return Array.from(new Set(risks.filter((risk) => Boolean(risk))));
|
|
140752
|
+
}
|
|
140306
140753
|
function runTriageLogic(input, matrix) {
|
|
140307
140754
|
const effort = calculateEffort(input.filesChanged, input.acCount, input.rawIdea);
|
|
140308
140755
|
const { priority, label: priorityLabel } = calculatePriority(input.type, effort, input.totalRisks, matrix);
|
|
140756
|
+
const complexity = assessComplexity(input);
|
|
140757
|
+
const coupling = assessCoupling(input);
|
|
140758
|
+
const parallelizability = assessParallelizability(input, coupling);
|
|
140759
|
+
const qualityCriticality = assessQualityCriticality(input);
|
|
140760
|
+
const riskProfile = buildRiskProfile(input);
|
|
140309
140761
|
const effortLabel = matrix.effort_rules[effort]?.label ?? `effort:${effort}`;
|
|
140310
140762
|
const typeLabel = matrix.auto_labels[input.type] ?? "";
|
|
140311
140763
|
const targetState = matrix.target_state_by_type[input.type] ?? matrix.target_state_by_type.default ?? "To Do";
|
|
@@ -140325,6 +140777,11 @@ function runTriageLogic(input, matrix) {
|
|
|
140325
140777
|
priorityLabel,
|
|
140326
140778
|
effort,
|
|
140327
140779
|
effortLabel,
|
|
140780
|
+
complexity,
|
|
140781
|
+
coupling,
|
|
140782
|
+
parallelizability,
|
|
140783
|
+
qualityCriticality,
|
|
140784
|
+
riskProfile,
|
|
140328
140785
|
typeLabel,
|
|
140329
140786
|
targetState,
|
|
140330
140787
|
dispatchLabel,
|
|
@@ -140359,47 +140816,333 @@ function validateSpecQuality(input) {
|
|
|
140359
140816
|
return errors;
|
|
140360
140817
|
}
|
|
140361
140818
|
|
|
140819
|
+
// lib/intake/lib/decomposition-planner.ts
|
|
140820
|
+
var CAPABILITY_PATTERNS = [
|
|
140821
|
+
{ area: "auth", label: "Authentication & Access", regex: /\b(auth|oauth|jwt|login|register|session|permission|rbac|role)\b/i },
|
|
140822
|
+
{ area: "worker", label: "Background Jobs & Automation", regex: /\b(worker|background|queue|job|scheduler|reminder|async|cron)\b/i },
|
|
140823
|
+
{ area: "notifications", label: "Notifications & Delivery", regex: /\b(notification|notify|email|sms|webhook|alert|message)\b/i },
|
|
140824
|
+
{ area: "frontend", label: "Frontend & UX", regex: /\b(ui|frontend|page|screen|dashboard|view|form)\b/i },
|
|
140825
|
+
{ area: "data", label: "Data Model & Persistence", regex: /\b(database|schema|model|migration|persist|storage|repository|crud)\b/i },
|
|
140826
|
+
{ area: "api", label: "API & Application Flow", regex: /\b(api|endpoint|route|http|rest|graphql|handler)\b/i },
|
|
140827
|
+
{ area: "integration", label: "Integrations & External Services", regex: /\b(integration|provider|third-party|external|sync|import|export)\b/i },
|
|
140828
|
+
{ area: "qa", label: "QA, Docs & Release Readiness", regex: /\b(test|qa|coverage|document|docs|guide|readme|validation)\b/i },
|
|
140829
|
+
{ area: "core", label: "Core Workflow", regex: /./i }
|
|
140830
|
+
];
|
|
140831
|
+
var AREA_LABEL = Object.fromEntries(
|
|
140832
|
+
CAPABILITY_PATTERNS.map((entry) => [entry.area, entry.label])
|
|
140833
|
+
);
|
|
140834
|
+
function normalizeLines(items) {
|
|
140835
|
+
return items.map((item) => item.trim()).filter(Boolean);
|
|
140836
|
+
}
|
|
140837
|
+
function detectCapabilityArea(text, deliveryTarget) {
|
|
140838
|
+
const normalized = text.trim();
|
|
140839
|
+
for (const entry of CAPABILITY_PATTERNS) {
|
|
140840
|
+
if (entry.regex.test(normalized)) return entry.area;
|
|
140841
|
+
}
|
|
140842
|
+
if (deliveryTarget === "api") return "api";
|
|
140843
|
+
if (deliveryTarget === "web-ui") return "frontend";
|
|
140844
|
+
return "core";
|
|
140845
|
+
}
|
|
140846
|
+
function matchesArea(text, area) {
|
|
140847
|
+
const entry = CAPABILITY_PATTERNS.find((candidate) => candidate.area === area);
|
|
140848
|
+
return entry ? entry.regex.test(text) : false;
|
|
140849
|
+
}
|
|
140850
|
+
function estimateEffort(scopeItems, area) {
|
|
140851
|
+
if (scopeItems.length >= 3 || ["auth", "worker", "integration"].includes(area)) return "large";
|
|
140852
|
+
if (scopeItems.length === 2 || ["api", "data", "frontend", "notifications"].includes(area)) return "medium";
|
|
140853
|
+
return "small";
|
|
140854
|
+
}
|
|
140855
|
+
function recommendedLevelFor(area, estimatedEffort) {
|
|
140856
|
+
if (estimatedEffort === "large") return "senior";
|
|
140857
|
+
if (["auth", "worker", "integration"].includes(area)) return "senior";
|
|
140858
|
+
if (estimatedEffort === "medium") return "medior";
|
|
140859
|
+
if (area === "qa") return "junior";
|
|
140860
|
+
return "medior";
|
|
140861
|
+
}
|
|
140862
|
+
function isFoundationArea(area) {
|
|
140863
|
+
return area === "auth" || area === "data" || area === "core";
|
|
140864
|
+
}
|
|
140865
|
+
function filterRelevantItems(items, scopeItems, area) {
|
|
140866
|
+
const normalized = normalizeLines(items);
|
|
140867
|
+
if (normalized.length === 0) return [];
|
|
140868
|
+
const scopeText = scopeItems.join(" ");
|
|
140869
|
+
const matches2 = normalized.filter((item) => matchesArea(item, area) || scopeItems.some((scopeItem) => item.includes(scopeItem)) || item.includes(scopeText));
|
|
140870
|
+
if (matches2.length > 0) return matches2;
|
|
140871
|
+
return normalized.slice(0, Math.min(normalized.length, Math.max(2, scopeItems.length)));
|
|
140872
|
+
}
|
|
140873
|
+
function buildObjective(parentObjective, area, scopeItems) {
|
|
140874
|
+
const label = AREA_LABEL[area];
|
|
140875
|
+
const primaryScope = scopeItems[0] ?? parentObjective;
|
|
140876
|
+
return `Deliver the ${label.toLowerCase()} slice of the parent initiative by completing ${primaryScope.toLowerCase()}.`;
|
|
140877
|
+
}
|
|
140878
|
+
function buildDependencyIndexes(area, priorAreas) {
|
|
140879
|
+
const indexes = [];
|
|
140880
|
+
priorAreas.forEach((priorArea, index) => {
|
|
140881
|
+
if (isFoundationArea(priorArea) && !isFoundationArea(area)) indexes.push(index);
|
|
140882
|
+
if (area !== "auth" && priorArea === "auth") indexes.push(index);
|
|
140883
|
+
if (["api", "frontend", "worker", "notifications"].includes(area) && priorArea === "data") indexes.push(index);
|
|
140884
|
+
if (["worker", "notifications", "integration"].includes(area) && priorArea === "api") indexes.push(index);
|
|
140885
|
+
});
|
|
140886
|
+
return Array.from(new Set(indexes));
|
|
140887
|
+
}
|
|
140888
|
+
function buildDependencyHints(area, priorAreas, allAreas) {
|
|
140889
|
+
const hints = [];
|
|
140890
|
+
if (area !== "auth" && allAreas.includes("auth")) hints.push("Coordinate with the authentication/access child before changing protected flows.");
|
|
140891
|
+
if (["worker", "notifications", "integration"].includes(area) && allAreas.includes("api")) {
|
|
140892
|
+
hints.push("Align payload contracts and triggering conditions with the API/application-flow child.");
|
|
140893
|
+
}
|
|
140894
|
+
if (["api", "frontend", "worker", "notifications"].includes(area) && allAreas.includes("data")) {
|
|
140895
|
+
hints.push("Reuse the canonical data model/migration decisions from the persistence child.");
|
|
140896
|
+
}
|
|
140897
|
+
if (priorAreas.some(isFoundationArea) && !isFoundationArea(area)) {
|
|
140898
|
+
hints.push("Start after foundational contracts are stable, but keep implementation isolated enough for a separate PR.");
|
|
140899
|
+
}
|
|
140900
|
+
return Array.from(new Set(hints));
|
|
140901
|
+
}
|
|
140902
|
+
function buildPlannedChildren(spec, effort) {
|
|
140903
|
+
const scopeItems = normalizeLines(spec.scope_v1);
|
|
140904
|
+
const maxChildren = effort === "xlarge" ? 4 : 3;
|
|
140905
|
+
const orderedAreas = [];
|
|
140906
|
+
const areaToItems = /* @__PURE__ */ new Map();
|
|
140907
|
+
for (const item of scopeItems) {
|
|
140908
|
+
const area = detectCapabilityArea(item, spec.delivery_target);
|
|
140909
|
+
if (!areaToItems.has(area)) {
|
|
140910
|
+
areaToItems.set(area, []);
|
|
140911
|
+
orderedAreas.push(area);
|
|
140912
|
+
}
|
|
140913
|
+
areaToItems.get(area).push(item);
|
|
140914
|
+
}
|
|
140915
|
+
let planned = orderedAreas.map((area) => ({ capabilityArea: area, scopeItems: areaToItems.get(area) ?? [] }));
|
|
140916
|
+
if (planned.length > maxChildren) {
|
|
140917
|
+
const kept = planned.slice(0, maxChildren - 1);
|
|
140918
|
+
const merged = planned.slice(maxChildren - 1).flatMap((entry) => entry.scopeItems);
|
|
140919
|
+
kept.push({ capabilityArea: planned[maxChildren - 1]?.capabilityArea ?? "core", scopeItems: merged });
|
|
140920
|
+
planned = kept;
|
|
140921
|
+
}
|
|
140922
|
+
if (planned.length === 1 && scopeItems.length >= 4) {
|
|
140923
|
+
const midpoint = Math.ceil(scopeItems.length / 2);
|
|
140924
|
+
planned = [
|
|
140925
|
+
{ capabilityArea: planned[0]?.capabilityArea ?? "core", scopeItems: scopeItems.slice(0, midpoint) },
|
|
140926
|
+
{ capabilityArea: planned[0]?.capabilityArea ?? "core", scopeItems: scopeItems.slice(midpoint) }
|
|
140927
|
+
];
|
|
140928
|
+
}
|
|
140929
|
+
return planned.filter((entry) => entry.scopeItems.length > 0);
|
|
140930
|
+
}
|
|
140931
|
+
function buildDescription(opts) {
|
|
140932
|
+
const { issueNumber, child, outOfScope, constraints, risks } = opts;
|
|
140933
|
+
return [
|
|
140934
|
+
"## Objective",
|
|
140935
|
+
child.objective,
|
|
140936
|
+
"",
|
|
140937
|
+
"## Parent Issue",
|
|
140938
|
+
`Parent issue: #${issueNumber}`,
|
|
140939
|
+
"",
|
|
140940
|
+
"## Capability Area",
|
|
140941
|
+
`- ${AREA_LABEL[child.capabilityArea]}`,
|
|
140942
|
+
"",
|
|
140943
|
+
"## Execution Profile",
|
|
140944
|
+
`- Recommended level: ${child.recommendedLevel}`,
|
|
140945
|
+
`- Estimated effort: ${child.estimatedEffort}`,
|
|
140946
|
+
`- Parallelizable: ${child.parallelizable ? "yes" : "no"}`,
|
|
140947
|
+
...child.dependencyHints.map((hint) => `- Dependency hint: ${hint}`),
|
|
140948
|
+
"",
|
|
140949
|
+
"## Scope",
|
|
140950
|
+
...child.scopeItems.map((item) => `- ${item}`),
|
|
140951
|
+
"",
|
|
140952
|
+
"## Acceptance Criteria",
|
|
140953
|
+
...child.acceptanceCriteria.map((item) => `- ${item}`),
|
|
140954
|
+
"",
|
|
140955
|
+
"## Definition of Done",
|
|
140956
|
+
...child.definitionOfDone.map((item) => `- ${item}`),
|
|
140957
|
+
...outOfScope.length > 0 ? ["", "## Out of Scope", ...outOfScope.map((item) => `- ${item}`)] : [],
|
|
140958
|
+
...constraints?.trim() ? ["", "## Constraints", constraints.trim()] : [],
|
|
140959
|
+
...risks.length > 0 ? ["", "## Risks / Coordination Notes", ...risks.map((item) => `- ${item}`)] : []
|
|
140960
|
+
].join("\n");
|
|
140961
|
+
}
|
|
140962
|
+
function buildDecompositionChildDrafts(spec, issueNumber, effort) {
|
|
140963
|
+
const plannedChildren = buildPlannedChildren(spec, effort);
|
|
140964
|
+
const allAreas = plannedChildren.map((entry) => entry.capabilityArea);
|
|
140965
|
+
const areaCounts = /* @__PURE__ */ new Map();
|
|
140966
|
+
return plannedChildren.map((plannedChild, index) => {
|
|
140967
|
+
const estimatedEffort = estimateEffort(plannedChild.scopeItems, plannedChild.capabilityArea);
|
|
140968
|
+
const recommendedLevel = recommendedLevelFor(plannedChild.capabilityArea, estimatedEffort);
|
|
140969
|
+
const priorAreas = plannedChildren.slice(0, index).map((entry) => entry.capabilityArea);
|
|
140970
|
+
const dependencyIndexes = buildDependencyIndexes(plannedChild.capabilityArea, priorAreas);
|
|
140971
|
+
const dependencyHints = buildDependencyHints(plannedChild.capabilityArea, priorAreas, allAreas);
|
|
140972
|
+
const parallelizable = dependencyIndexes.length === 0 && !isFoundationArea(plannedChild.capabilityArea);
|
|
140973
|
+
const acceptanceCriteria = filterRelevantItems(spec.acceptance_criteria, plannedChild.scopeItems, plannedChild.capabilityArea);
|
|
140974
|
+
const definitionOfDone = filterRelevantItems(spec.definition_of_done, plannedChild.scopeItems, plannedChild.capabilityArea);
|
|
140975
|
+
const occurrence = (areaCounts.get(plannedChild.capabilityArea) ?? 0) + 1;
|
|
140976
|
+
areaCounts.set(plannedChild.capabilityArea, occurrence);
|
|
140977
|
+
const titleSuffix = occurrence > 1 ? ` ${occurrence}` : "";
|
|
140978
|
+
const title = `${spec.title} \u2014 ${AREA_LABEL[plannedChild.capabilityArea]}${titleSuffix}`;
|
|
140979
|
+
const child = {
|
|
140980
|
+
title,
|
|
140981
|
+
objective: buildObjective(spec.objective, plannedChild.capabilityArea, plannedChild.scopeItems),
|
|
140982
|
+
scopeItems: plannedChild.scopeItems,
|
|
140983
|
+
acceptanceCriteria,
|
|
140984
|
+
definitionOfDone,
|
|
140985
|
+
recommendedLevel,
|
|
140986
|
+
estimatedEffort,
|
|
140987
|
+
dependencyHints,
|
|
140988
|
+
dependencyIndexes,
|
|
140989
|
+
capabilityArea: plannedChild.capabilityArea,
|
|
140990
|
+
parallelizable,
|
|
140991
|
+
description: ""
|
|
140992
|
+
};
|
|
140993
|
+
child.description = buildDescription({
|
|
140994
|
+
issueNumber,
|
|
140995
|
+
parentObjective: spec.objective,
|
|
140996
|
+
child,
|
|
140997
|
+
outOfScope: normalizeLines(spec.out_of_scope),
|
|
140998
|
+
constraints: spec.constraints,
|
|
140999
|
+
risks: normalizeLines(spec.risks)
|
|
141000
|
+
});
|
|
141001
|
+
return child;
|
|
141002
|
+
});
|
|
141003
|
+
}
|
|
141004
|
+
|
|
141005
|
+
// lib/intake/lib/fidelity-brief.ts
|
|
141006
|
+
var HARD_CONSTRAINT_PATTERNS = [
|
|
141007
|
+
{ regex: /\bmust use ([a-z0-9.+#_-]+)/i, value: "explicit_stack_requirement" },
|
|
141008
|
+
{ regex: /\buse ([a-z0-9.+#_-]+)\b/i, value: "explicit_technology_requirement" },
|
|
141009
|
+
{ regex: /\bwithout ([a-z0-9.+#_-]+)/i, value: "explicit_technology_exclusion" },
|
|
141010
|
+
{ regex: /\bself-host(?:ed)?\b/i, value: "self_hosted" },
|
|
141011
|
+
{ regex: /\boffline\b/i, value: "offline_capable" },
|
|
141012
|
+
{ regex: /\bopen source\b/i, value: "open_source_only" }
|
|
141013
|
+
];
|
|
141014
|
+
var SOFT_PREFERENCE_PATTERNS = [
|
|
141015
|
+
{ regex: /\bprefer\b/i, value: "explicit_preference" },
|
|
141016
|
+
{ regex: /\bclean (?:architecture|code)\b/i, value: "clean_code_preference" },
|
|
141017
|
+
{ regex: /\bmodern\b/i, value: "modern_stack_preference" },
|
|
141018
|
+
{ regex: /\bsimple\b/i, value: "simplicity_preference" }
|
|
141019
|
+
];
|
|
141020
|
+
var QUALITY_EXPECTATION_PATTERNS = [
|
|
141021
|
+
{ regex: /\bproduction[- ]ready\b/i, value: "production_ready" },
|
|
141022
|
+
{ regex: /\bhigh[- ]performance\b|\bperformant\b/i, value: "performance" },
|
|
141023
|
+
{ regex: /\bsecure\b|\bsecurity\b/i, value: "security" },
|
|
141024
|
+
{ regex: /\bscalable\b|\bscale\b/i, value: "scalability" },
|
|
141025
|
+
{ regex: /\bmaintainable\b|\bclean code\b/i, value: "maintainability" },
|
|
141026
|
+
{ regex: /\bwell[- ]tested\b|\bhigh[- ]quality\b/i, value: "high_quality" }
|
|
141027
|
+
];
|
|
141028
|
+
var RISK_SIGNAL_PATTERNS = [
|
|
141029
|
+
{ regex: /\bauth\b|\blogin\b|\boauth\b|\bjwt\b|\brbac\b|\bpermission/i, value: "auth_security_sensitive" },
|
|
141030
|
+
{ regex: /\bpayment\b|\bbilling\b|\bsubscription/i, value: "payment_sensitive" },
|
|
141031
|
+
{ regex: /\bmigration\b|\bschema\b|\bdatabase\b/i, value: "data_model_change" },
|
|
141032
|
+
{ regex: /\bworker\b|\bqueue\b|\bcron\b|\bbackground job\b/i, value: "async_orchestration" },
|
|
141033
|
+
{ regex: /\bintegration\b|\bwebhook\b|\bthird-party\b|\bexternal service\b/i, value: "external_integration" },
|
|
141034
|
+
{ regex: /\bperformance\b|\bhigh traffic\b|\blow latency\b/i, value: "performance_sensitive" }
|
|
141035
|
+
];
|
|
141036
|
+
var EXPLICIT_NON_GOAL_PATTERNS = [
|
|
141037
|
+
{ regex: /\bdo not add ([^.\n]+)/i, value: "no_extra_features" },
|
|
141038
|
+
{ regex: /\bout of scope\b/i, value: "explicit_out_of_scope" },
|
|
141039
|
+
{ regex: /\bnot required\b/i, value: "explicit_not_required" }
|
|
141040
|
+
];
|
|
141041
|
+
function unique(values) {
|
|
141042
|
+
return Array.from(new Set(values.filter((value) => Boolean(value && value.trim()))));
|
|
141043
|
+
}
|
|
141044
|
+
function normalizeText3(text) {
|
|
141045
|
+
return text.replace(/\s+/g, " ").trim();
|
|
141046
|
+
}
|
|
141047
|
+
function inferDeliverable(rawIdea, spec, metadata) {
|
|
141048
|
+
const target = spec?.delivery_target ?? metadata?.delivery_target;
|
|
141049
|
+
if (target && target !== "unknown") return target;
|
|
141050
|
+
const text = rawIdea.toLowerCase();
|
|
141051
|
+
if (/\bcli\b|\bcommand line\b/.test(text)) return "cli";
|
|
141052
|
+
if (/\bapi\b|\bendpoint\b|\brest\b|\bgraphql\b/.test(text)) return "api";
|
|
141053
|
+
if (/\bweb app\b|\bfrontend\b|\bui\b|\bdashboard\b|\bpage\b/.test(text)) return "web-ui";
|
|
141054
|
+
if (/\blibrary\b|\bsdk\b|\bpackage\b/.test(text)) return "library";
|
|
141055
|
+
if (/\bautomation\b|\bworker\b|\bjob\b|\bbot\b/.test(text)) return "automation";
|
|
141056
|
+
return "unknown";
|
|
141057
|
+
}
|
|
141058
|
+
function inferPrimaryObjective(rawIdea, spec) {
|
|
141059
|
+
if (spec?.objective?.trim()) return normalizeText3(spec.objective);
|
|
141060
|
+
const sentence = rawIdea.split(/(?<=[.!?])\s+/)[0] ?? rawIdea;
|
|
141061
|
+
return normalizeText3(sentence);
|
|
141062
|
+
}
|
|
141063
|
+
function collectMatches(text, patterns) {
|
|
141064
|
+
return unique(patterns.map((pattern) => pattern.regex.test(text) ? pattern.value : null));
|
|
141065
|
+
}
|
|
141066
|
+
function deriveAmbiguityFlags(rawIdea, deliverable, requestedStack, inferredStack, spec) {
|
|
141067
|
+
const flags = [];
|
|
141068
|
+
if (deliverable === "unknown") flags.push("ambiguous_deliverable");
|
|
141069
|
+
if (!requestedStack && !inferredStack && /\bbuild|create|make\b/i.test(rawIdea) && deliverable !== "unknown") {
|
|
141070
|
+
flags.push("missing_stack_preference");
|
|
141071
|
+
}
|
|
141072
|
+
if (!spec?.scope_v1?.length) flags.push("missing_structured_scope");
|
|
141073
|
+
if (spec && spec.acceptance_criteria.length === 0) flags.push("missing_acceptance_criteria");
|
|
141074
|
+
return unique(flags);
|
|
141075
|
+
}
|
|
141076
|
+
function deriveConfidence(ambiguityFlags, spec, metadata) {
|
|
141077
|
+
if (metadata?.stack_confidence === "high" && ambiguityFlags.length === 0 && (spec?.acceptance_criteria.length ?? 0) >= 2) {
|
|
141078
|
+
return "high";
|
|
141079
|
+
}
|
|
141080
|
+
if (ambiguityFlags.some((flag) => flag === "ambiguous_deliverable" || flag === "missing_structured_scope")) {
|
|
141081
|
+
return "low";
|
|
141082
|
+
}
|
|
141083
|
+
return "medium";
|
|
141084
|
+
}
|
|
141085
|
+
function buildFidelityBrief(opts) {
|
|
141086
|
+
const rawIdea = normalizeText3(opts.rawIdea);
|
|
141087
|
+
const spec = opts.spec;
|
|
141088
|
+
const metadata = opts.metadata;
|
|
141089
|
+
const combinedText = [
|
|
141090
|
+
rawIdea,
|
|
141091
|
+
spec?.objective,
|
|
141092
|
+
spec?.constraints,
|
|
141093
|
+
...spec?.scope_v1 ?? [],
|
|
141094
|
+
...spec?.out_of_scope ?? [],
|
|
141095
|
+
...spec?.acceptance_criteria ?? [],
|
|
141096
|
+
...spec?.definition_of_done ?? [],
|
|
141097
|
+
...spec?.risks ?? []
|
|
141098
|
+
].filter(Boolean).join("\n");
|
|
141099
|
+
const requestedDeliverable = inferDeliverable(rawIdea, spec, metadata);
|
|
141100
|
+
const requestedStack = metadata?.stack_hint ?? null;
|
|
141101
|
+
const inferredStack = requestedStack ?? null;
|
|
141102
|
+
const hardConstraints = collectMatches(combinedText, HARD_CONSTRAINT_PATTERNS);
|
|
141103
|
+
const softPreferences = collectMatches(combinedText, SOFT_PREFERENCE_PATTERNS);
|
|
141104
|
+
const explicitNonGoals = unique([
|
|
141105
|
+
...collectMatches(combinedText, EXPLICIT_NON_GOAL_PATTERNS),
|
|
141106
|
+
...(spec?.out_of_scope ?? []).map((item) => normalizeText3(item))
|
|
141107
|
+
]);
|
|
141108
|
+
const qualityExpectations = collectMatches(combinedText, QUALITY_EXPECTATION_PATTERNS);
|
|
141109
|
+
const riskSignals = collectMatches(combinedText, RISK_SIGNAL_PATTERNS);
|
|
141110
|
+
const ambiguityFlags = deriveAmbiguityFlags(rawIdea, requestedDeliverable, requestedStack, inferredStack, spec);
|
|
141111
|
+
const confidence = deriveConfidence(ambiguityFlags, spec, metadata);
|
|
141112
|
+
return {
|
|
141113
|
+
primary_objective: inferPrimaryObjective(rawIdea, spec),
|
|
141114
|
+
requested_deliverable: requestedDeliverable,
|
|
141115
|
+
requested_stack: requestedStack,
|
|
141116
|
+
inferred_stack: inferredStack,
|
|
141117
|
+
hard_constraints: hardConstraints,
|
|
141118
|
+
soft_preferences: softPreferences,
|
|
141119
|
+
explicit_non_goals: explicitNonGoals,
|
|
141120
|
+
quality_expectations: qualityExpectations,
|
|
141121
|
+
ambiguity_flags: ambiguityFlags,
|
|
141122
|
+
risk_signals: riskSignals,
|
|
141123
|
+
confidence
|
|
141124
|
+
};
|
|
141125
|
+
}
|
|
141126
|
+
|
|
140362
141127
|
// lib/intake/steps/triage.ts
|
|
140363
141128
|
import { createRequire as createRequire3 } from "node:module";
|
|
140364
141129
|
var _require3 = createRequire3(import.meta.url);
|
|
140365
141130
|
var cachedMatrix = null;
|
|
141131
|
+
function shouldAutoDecompose(decision) {
|
|
141132
|
+
if (!decision.readyForDispatch || decision.specQualityBlock) return false;
|
|
141133
|
+
if (decision.effort === "xlarge") return true;
|
|
141134
|
+
if (decision.effort !== "large") return false;
|
|
141135
|
+
return decision.parallelizability !== "low" && decision.coupling !== "high";
|
|
141136
|
+
}
|
|
141137
|
+
function computeMaxParallelChildren(drafts) {
|
|
141138
|
+
const parallelizableCount = drafts.filter((draft) => draft.parallelizable).length;
|
|
141139
|
+
return Math.min(4, Math.max(1, parallelizableCount || 1));
|
|
141140
|
+
}
|
|
140366
141141
|
function loadMatrix() {
|
|
140367
141142
|
if (cachedMatrix) return cachedMatrix;
|
|
140368
141143
|
cachedMatrix = _require3("../configs/triage-matrix.json");
|
|
140369
141144
|
return cachedMatrix;
|
|
140370
141145
|
}
|
|
140371
|
-
function buildChildDrafts(payload, issueNumber, effort) {
|
|
140372
|
-
const spec = payload.spec;
|
|
140373
|
-
const scopeItems = spec.scope_v1.filter((item) => item.trim().length > 0);
|
|
140374
|
-
const maxChildren = effort === "xlarge" ? 4 : 3;
|
|
140375
|
-
const chunkSize = 2;
|
|
140376
|
-
const drafts = [];
|
|
140377
|
-
for (let i2 = 0; i2 < scopeItems.length && drafts.length < maxChildren; i2 += chunkSize) {
|
|
140378
|
-
const slice = scopeItems.slice(i2, i2 + chunkSize);
|
|
140379
|
-
if (slice.length === 0) continue;
|
|
140380
|
-
const childIndex = drafts.length + 1;
|
|
140381
|
-
drafts.push({
|
|
140382
|
-
title: `${spec.title} \u2014 Part ${childIndex}`,
|
|
140383
|
-
description: [
|
|
140384
|
-
`## Objective`,
|
|
140385
|
-
spec.objective,
|
|
140386
|
-
"",
|
|
140387
|
-
`## Parent Issue`,
|
|
140388
|
-
`Parent issue: #${issueNumber}`,
|
|
140389
|
-
"",
|
|
140390
|
-
`## This Part`,
|
|
140391
|
-
...slice.map((item) => `- ${item}`),
|
|
140392
|
-
"",
|
|
140393
|
-
`## Acceptance Criteria`,
|
|
140394
|
-
...spec.acceptance_criteria.map((item) => `- ${item}`),
|
|
140395
|
-
"",
|
|
140396
|
-
`## Definition of Done`,
|
|
140397
|
-
...spec.definition_of_done.map((item) => `- ${item}`)
|
|
140398
|
-
].join("\n")
|
|
140399
|
-
});
|
|
140400
|
-
}
|
|
140401
|
-
return drafts;
|
|
140402
|
-
}
|
|
140403
141146
|
var triageStep = {
|
|
140404
141147
|
name: "triage",
|
|
140405
141148
|
shouldRun: (payload) => !!payload.issues?.length && !payload.dry_run,
|
|
@@ -140409,6 +141152,11 @@ var triageStep = {
|
|
|
140409
141152
|
const impact = payload.impact;
|
|
140410
141153
|
const issue2 = payload.issues[0];
|
|
140411
141154
|
ctx.log(`Running triage for issue #${issue2.number}`);
|
|
141155
|
+
const fidelityBrief = buildFidelityBrief({
|
|
141156
|
+
rawIdea: payload.raw_idea,
|
|
141157
|
+
spec,
|
|
141158
|
+
metadata: payload.metadata
|
|
141159
|
+
});
|
|
140412
141160
|
const decision = runTriageLogic({
|
|
140413
141161
|
type: spec.type,
|
|
140414
141162
|
deliveryTarget: spec.delivery_target,
|
|
@@ -140434,8 +141182,9 @@ var triageStep = {
|
|
|
140434
141182
|
if (decision.typeLabel) allLabels.push(decision.typeLabel);
|
|
140435
141183
|
if (!decision.readyForDispatch || decision.specQualityBlock) allLabels.push("needs-human");
|
|
140436
141184
|
const uniqueLabels = Array.from(new Set(allLabels.filter(Boolean)));
|
|
140437
|
-
const
|
|
140438
|
-
const
|
|
141185
|
+
const decompositionRequested = decision.readyForDispatch && !decision.specQualityBlock && ["large", "xlarge"].includes(decision.effort);
|
|
141186
|
+
const shouldDecompose = shouldAutoDecompose(decision);
|
|
141187
|
+
const decompositionDrafts = shouldDecompose ? buildDecompositionChildDrafts(spec, issue2.number, decision.effort) : [];
|
|
140439
141188
|
const canDecompose = decompositionDrafts.length >= 2;
|
|
140440
141189
|
let createdChildIssueNumbers = [];
|
|
140441
141190
|
if (ctx.createIssueProvider && repoPath) {
|
|
@@ -140456,25 +141205,55 @@ var triageStep = {
|
|
|
140456
141205
|
} else if (canDecompose) {
|
|
140457
141206
|
await provider.addLabel(issue2.number, "decomposition:parent");
|
|
140458
141207
|
const childIssues = [];
|
|
141208
|
+
const createdChildren = [];
|
|
140459
141209
|
for (const draft of decompositionDrafts) {
|
|
140460
141210
|
const child = await provider.createIssue(draft.title, draft.description, initialLabel);
|
|
140461
141211
|
childIssues.push({ iid: child.iid, title: child.title, web_url: child.web_url });
|
|
141212
|
+
createdChildren.push({ iid: child.iid, title: child.title, web_url: child.web_url, draft });
|
|
140462
141213
|
createdChildIssueNumbers.push(child.iid);
|
|
140463
141214
|
for (const label of uniqueLabels) {
|
|
140464
141215
|
await provider.addLabel(child.iid, label);
|
|
140465
141216
|
}
|
|
140466
141217
|
await provider.addLabel(child.iid, "decomposition:child");
|
|
141218
|
+
await provider.transitionLabel(child.iid, initialLabel, decision.targetState);
|
|
141219
|
+
if (decision.targetState === "To Do" && decision.dispatchLabel) {
|
|
141220
|
+
await provider.addLabel(child.iid, decision.dispatchLabel);
|
|
141221
|
+
}
|
|
141222
|
+
if (decision.targetState === "To Do") {
|
|
141223
|
+
await provider.addLabel(child.iid, `developer:${draft.recommendedLevel}`);
|
|
141224
|
+
}
|
|
141225
|
+
}
|
|
141226
|
+
if (projectSlug) {
|
|
141227
|
+
for (const child of createdChildren) {
|
|
141228
|
+
await updateIssueRuntime(ctx.workspaceDir, projectSlug, child.iid, {
|
|
141229
|
+
parentIssueId: issue2.number,
|
|
141230
|
+
dependencyIssueIds: child.draft.dependencyIndexes.map((index) => createdChildren[index]?.iid).filter((value) => Number.isFinite(value)),
|
|
141231
|
+
childReadyForDispatch: decision.targetState === "To Do",
|
|
141232
|
+
parallelizable: child.draft.parallelizable,
|
|
141233
|
+
recommendedLevel: child.draft.recommendedLevel,
|
|
141234
|
+
decompositionMode: "none",
|
|
141235
|
+
decompositionStatus: null
|
|
141236
|
+
}).catch(() => {
|
|
141237
|
+
});
|
|
141238
|
+
}
|
|
141239
|
+
await updateIssueRuntime(ctx.workspaceDir, projectSlug, issue2.number, {
|
|
141240
|
+
childIssueIds: createdChildIssueNumbers,
|
|
141241
|
+
maxParallelChildren: computeMaxParallelChildren(decompositionDrafts),
|
|
141242
|
+
decompositionMode: "parent_child",
|
|
141243
|
+
decompositionStatus: "active"
|
|
141244
|
+
}).catch(() => {
|
|
141245
|
+
});
|
|
140467
141246
|
}
|
|
140468
141247
|
await provider.addComment(issue2.number, [
|
|
140469
141248
|
"## Decomposition Plan",
|
|
140470
141249
|
...childIssues.map((child) => `- [ ] #${child.iid} ${child.title}`)
|
|
140471
141250
|
].join("\n"));
|
|
140472
|
-
} else if (shouldDecompose) {
|
|
141251
|
+
} else if (decompositionRequested && shouldDecompose) {
|
|
140473
141252
|
await provider.addLabel(issue2.number, "needs-human");
|
|
140474
141253
|
await provider.addComment(issue2.number, [
|
|
140475
|
-
"\u26A0\uFE0F Automatic decomposition was requested, but the generated spec did not yield at least two independently scoped child tasks.",
|
|
141254
|
+
shouldDecompose ? "\u26A0\uFE0F Automatic decomposition was requested, but the generated spec did not yield at least two independently scoped child tasks." : "\u26A0\uFE0F This request is large, but triage detected high coupling / low parallelizability. Fabrica will keep it as one executable issue unless a human explicitly splits it.",
|
|
140476
141255
|
"",
|
|
140477
|
-
"Refine the scope/acceptance criteria or split the plan manually before dispatch."
|
|
141256
|
+
shouldDecompose ? "Refine the scope/acceptance criteria or split the plan manually before dispatch." : "If you still want multiple child issues, split the plan manually along stable boundaries before dispatch."
|
|
140478
141257
|
].join("\n"));
|
|
140479
141258
|
} else if (decision.readyForDispatch) {
|
|
140480
141259
|
await provider.transitionLabel(issue2.number, initialLabel, decision.targetState);
|
|
@@ -140536,6 +141315,11 @@ var triageStep = {
|
|
|
140536
141315
|
const triage = {
|
|
140537
141316
|
priority: decision.priority,
|
|
140538
141317
|
effort: decision.effort,
|
|
141318
|
+
complexity: decision.complexity,
|
|
141319
|
+
coupling: decision.coupling,
|
|
141320
|
+
parallelizability: decision.parallelizability,
|
|
141321
|
+
quality_criticality: decision.qualityCriticality,
|
|
141322
|
+
risk_profile: decision.riskProfile,
|
|
140539
141323
|
target_state: decision.targetState,
|
|
140540
141324
|
project_slug: payload.scaffold?.project_slug ?? null,
|
|
140541
141325
|
project_channel_id: null,
|
|
@@ -140545,7 +141329,7 @@ var triageStep = {
|
|
|
140545
141329
|
errors: [
|
|
140546
141330
|
...decision.errors,
|
|
140547
141331
|
...decision.specQualityBlock ? ["spec_quality_block"] : [],
|
|
140548
|
-
...shouldDecompose && !canDecompose ? ["decomposition_needs_human"] : []
|
|
141332
|
+
...decompositionRequested && shouldDecompose && !canDecompose ? ["decomposition_needs_human"] : []
|
|
140549
141333
|
],
|
|
140550
141334
|
decomposition_mode: canDecompose ? "parent_child" : "none",
|
|
140551
141335
|
child_issue_numbers: createdChildIssueNumbers
|
|
@@ -140575,6 +141359,11 @@ var triageStep = {
|
|
|
140575
141359
|
return {
|
|
140576
141360
|
...payload,
|
|
140577
141361
|
step: "triage",
|
|
141362
|
+
fidelity_brief: fidelityBrief,
|
|
141363
|
+
metadata: {
|
|
141364
|
+
...payload.metadata,
|
|
141365
|
+
fidelity_brief: fidelityBrief
|
|
141366
|
+
},
|
|
140578
141367
|
triage
|
|
140579
141368
|
};
|
|
140580
141369
|
}
|
|
@@ -140702,6 +141491,43 @@ function mergeArtifacts(primary, secondary) {
|
|
|
140702
141491
|
return merged;
|
|
140703
141492
|
}
|
|
140704
141493
|
|
|
141494
|
+
// lib/intake/lib/clarification-policy.ts
|
|
141495
|
+
function detectScopeClarificationNeed(rawIdea, stackHint) {
|
|
141496
|
+
const text = rawIdea.toLowerCase();
|
|
141497
|
+
if (/\b(livre|free.?choice|your.?call|pode.?escolher|voc[eê].?decide|qualquer)\b/i.test(text)) {
|
|
141498
|
+
return { ask: false };
|
|
141499
|
+
}
|
|
141500
|
+
const subsystems = [
|
|
141501
|
+
/\bauth\b|\blogin\b|\bregister\b|\bjwt\b|\boauth\b/,
|
|
141502
|
+
/\bpayment\b|\bbilling\b|\bsubscription\b/,
|
|
141503
|
+
/\bemail\b|\bnotification\b|\balert\b|\bsms\b/,
|
|
141504
|
+
/\badmin\b|\bdashboard\b|\breport\b/,
|
|
141505
|
+
/\bqueue\b|\bworker\b|\bcron\b|\bjob\b/,
|
|
141506
|
+
/\bdatabase\b|\bmigration\b|\bschema\b/,
|
|
141507
|
+
/\bapi\b|\bwebhook\b|\bintegration\b|\bexternal service\b/
|
|
141508
|
+
].filter((regex) => regex.test(text)).length;
|
|
141509
|
+
const missingKeyTechChoice = !stackHint || (!/postgres|mysql|sqlite|mongodb/i.test(text) || !/jwt|oauth|session|rbac/i.test(text));
|
|
141510
|
+
if (subsystems >= 3 && missingKeyTechChoice) {
|
|
141511
|
+
return { ask: true, kind: "scope", reason: "scope_ambiguity_across_multiple_subsystems" };
|
|
141512
|
+
}
|
|
141513
|
+
return { ask: false };
|
|
141514
|
+
}
|
|
141515
|
+
function decideBootstrapClarification(opts) {
|
|
141516
|
+
if (opts.scopeAmbiguous) {
|
|
141517
|
+
return { ask: true, kind: "scope", reason: "scope_ambiguity_requires_structuring" };
|
|
141518
|
+
}
|
|
141519
|
+
if (!opts.stackHint && !opts.projectName) {
|
|
141520
|
+
return { ask: true, kind: "stack_and_name", reason: "missing_stack_and_name" };
|
|
141521
|
+
}
|
|
141522
|
+
if (!opts.stackHint) {
|
|
141523
|
+
return { ask: true, kind: "stack", reason: "missing_stack" };
|
|
141524
|
+
}
|
|
141525
|
+
if (!opts.projectName) {
|
|
141526
|
+
return { ask: true, kind: "name", reason: "missing_project_name" };
|
|
141527
|
+
}
|
|
141528
|
+
return { ask: false };
|
|
141529
|
+
}
|
|
141530
|
+
|
|
140705
141531
|
// lib/services/tick.ts
|
|
140706
141532
|
init_audit();
|
|
140707
141533
|
|
|
@@ -140919,12 +141745,14 @@ init_workflow();
|
|
|
140919
141745
|
|
|
140920
141746
|
// lib/dispatch/dispatch-dedup.ts
|
|
140921
141747
|
init_constants();
|
|
140922
|
-
import
|
|
141748
|
+
import fs36 from "node:fs/promises";
|
|
140923
141749
|
import path36 from "node:path";
|
|
140924
141750
|
import { createHash as createHash5 } from "node:crypto";
|
|
140925
141751
|
var DEDUP_FILE = "dispatch-dedup.ndjson";
|
|
140926
141752
|
var BUCKET_MS = 5 * 6e4;
|
|
140927
141753
|
var DEFAULT_TTL_MS2 = 30 * 6e4;
|
|
141754
|
+
var ACTIVE_CLAIM_TTL_MS = 10 * 6e4;
|
|
141755
|
+
var activeClaims = /* @__PURE__ */ new Map();
|
|
140928
141756
|
function dedupPath(workspaceDir) {
|
|
140929
141757
|
return path36.join(workspaceDir, DATA_DIR, DEDUP_FILE);
|
|
140930
141758
|
}
|
|
@@ -140935,7 +141763,7 @@ function computeDispatchId(projectSlug, issueId, role, level, now2 = Date.now())
|
|
|
140935
141763
|
}
|
|
140936
141764
|
async function readEntries2(filePath) {
|
|
140937
141765
|
try {
|
|
140938
|
-
const content = await
|
|
141766
|
+
const content = await fs36.readFile(filePath, "utf-8");
|
|
140939
141767
|
return content.split("\n").filter(Boolean).map((line) => {
|
|
140940
141768
|
try {
|
|
140941
141769
|
return JSON.parse(line);
|
|
@@ -140948,15 +141776,34 @@ async function readEntries2(filePath) {
|
|
|
140948
141776
|
throw err;
|
|
140949
141777
|
}
|
|
140950
141778
|
}
|
|
141779
|
+
function sweepExpiredClaims(now2 = Date.now()) {
|
|
141780
|
+
for (const [dispatchId, expiresAt] of activeClaims.entries()) {
|
|
141781
|
+
if (expiresAt <= now2) activeClaims.delete(dispatchId);
|
|
141782
|
+
}
|
|
141783
|
+
}
|
|
140951
141784
|
async function isDuplicate(workspaceDir, dispatchId) {
|
|
141785
|
+
sweepExpiredClaims();
|
|
141786
|
+
if (activeClaims.has(dispatchId)) return true;
|
|
140952
141787
|
const entries = await readEntries2(dedupPath(workspaceDir));
|
|
140953
141788
|
return entries.some((e2) => e2.id === dispatchId);
|
|
140954
141789
|
}
|
|
141790
|
+
async function claimDispatch(workspaceDir, dispatchId) {
|
|
141791
|
+
sweepExpiredClaims();
|
|
141792
|
+
if (activeClaims.has(dispatchId)) return false;
|
|
141793
|
+
const entries = await readEntries2(dedupPath(workspaceDir));
|
|
141794
|
+
if (entries.some((e2) => e2.id === dispatchId)) return false;
|
|
141795
|
+
activeClaims.set(dispatchId, Date.now() + ACTIVE_CLAIM_TTL_MS);
|
|
141796
|
+
return true;
|
|
141797
|
+
}
|
|
141798
|
+
function releaseDispatchClaim(dispatchId) {
|
|
141799
|
+
activeClaims.delete(dispatchId);
|
|
141800
|
+
}
|
|
140955
141801
|
async function recordDispatch(workspaceDir, dispatchId) {
|
|
140956
141802
|
const filePath = dedupPath(workspaceDir);
|
|
140957
|
-
await
|
|
141803
|
+
await fs36.mkdir(path36.dirname(filePath), { recursive: true });
|
|
140958
141804
|
const entry = { id: dispatchId, ts: Date.now() };
|
|
140959
|
-
await
|
|
141805
|
+
await fs36.appendFile(filePath, JSON.stringify(entry) + "\n", "utf-8");
|
|
141806
|
+
activeClaims.delete(dispatchId);
|
|
140960
141807
|
}
|
|
140961
141808
|
async function cleanupExpired(workspaceDir, ttlMs = DEFAULT_TTL_MS2) {
|
|
140962
141809
|
const filePath = dedupPath(workspaceDir);
|
|
@@ -140966,8 +141813,8 @@ async function cleanupExpired(workspaceDir, ttlMs = DEFAULT_TTL_MS2) {
|
|
|
140966
141813
|
if (kept.length < entries.length) {
|
|
140967
141814
|
const content = kept.map((e2) => JSON.stringify(e2)).join("\n") + (kept.length > 0 ? "\n" : "");
|
|
140968
141815
|
const tmpPath = filePath + ".tmp";
|
|
140969
|
-
await
|
|
140970
|
-
await
|
|
141816
|
+
await fs36.writeFile(tmpPath, content, "utf-8");
|
|
141817
|
+
await fs36.rename(tmpPath, filePath);
|
|
140971
141818
|
}
|
|
140972
141819
|
}
|
|
140973
141820
|
|
|
@@ -141044,7 +141891,7 @@ async function projectTick(opts) {
|
|
|
141044
141891
|
continue;
|
|
141045
141892
|
}
|
|
141046
141893
|
}
|
|
141047
|
-
const next = await findNextIssueForRole(provider, role, workflow, instanceName);
|
|
141894
|
+
const next = await findNextIssueForRole(provider, role, workflow, instanceName, fresh);
|
|
141048
141895
|
if (!next) continue;
|
|
141049
141896
|
const { issue: issue2, label: currentLabel } = next;
|
|
141050
141897
|
const targetLabel = getActiveLabel(workflow, role);
|
|
@@ -141185,11 +142032,6 @@ async function projectTick(opts) {
|
|
|
141185
142032
|
skipped.push({ role, reason: `${effectiveLevel} slots full` });
|
|
141186
142033
|
continue;
|
|
141187
142034
|
}
|
|
141188
|
-
const dispatchId = computeDispatchId(projectSlug, issue2.iid, role, effectiveLevel);
|
|
141189
|
-
if (await isDuplicate(workspaceDir, dispatchId)) {
|
|
141190
|
-
skipped.push({ role, reason: `dispatch_dedup: ${dispatchId}` });
|
|
141191
|
-
continue;
|
|
141192
|
-
}
|
|
141193
142035
|
if (role === "developer" || role === "tester") {
|
|
141194
142036
|
const stack = fresh.stack;
|
|
141195
142037
|
if (!stack) {
|
|
@@ -141236,6 +142078,17 @@ async function projectTick(opts) {
|
|
|
141236
142078
|
continue;
|
|
141237
142079
|
}
|
|
141238
142080
|
}
|
|
142081
|
+
const dispatchId = computeDispatchId(projectSlug, issue2.iid, role, effectiveLevel);
|
|
142082
|
+
if (!dryRun) {
|
|
142083
|
+
if (await isDuplicate(workspaceDir, dispatchId)) {
|
|
142084
|
+
skipped.push({ role, reason: `dispatch_dedup: ${dispatchId}` });
|
|
142085
|
+
continue;
|
|
142086
|
+
}
|
|
142087
|
+
if (!await claimDispatch(workspaceDir, dispatchId)) {
|
|
142088
|
+
skipped.push({ role, reason: `dispatch_claimed: ${dispatchId}` });
|
|
142089
|
+
continue;
|
|
142090
|
+
}
|
|
142091
|
+
}
|
|
141239
142092
|
if (dryRun) {
|
|
141240
142093
|
const existingSession = roleWorker.levels[effectiveLevel]?.[freeSlot]?.sessionKey;
|
|
141241
142094
|
pickups.push({
|
|
@@ -141285,6 +142138,7 @@ async function projectTick(opts) {
|
|
|
141285
142138
|
await recordDispatch(workspaceDir, dispatchId).catch(() => {
|
|
141286
142139
|
});
|
|
141287
142140
|
} catch (err) {
|
|
142141
|
+
releaseDispatchClaim(dispatchId);
|
|
141288
142142
|
skipped.push({ role, reason: `Dispatch failed: ${err.message}` });
|
|
141289
142143
|
continue;
|
|
141290
142144
|
}
|
|
@@ -141400,26 +142254,7 @@ I'll continue the flow at ${link}`
|
|
|
141400
142254
|
}
|
|
141401
142255
|
};
|
|
141402
142256
|
function detectScopeAmbiguity(rawIdea, stackHint) {
|
|
141403
|
-
|
|
141404
|
-
if (/\b(livre|free.?choice|your.?call|pode.?escolher|voc[eê].?decide|qualquer)\b/i.test(text)) {
|
|
141405
|
-
return false;
|
|
141406
|
-
}
|
|
141407
|
-
const subsystems = [
|
|
141408
|
-
/\b(worker|background.?job|queue|task.?runner|celery|bull)\b/i,
|
|
141409
|
-
/\b(websocket|sse|real.?time|realtime|push.?notif)\b/i,
|
|
141410
|
-
/\b(auth|oauth|jwt|login|register|signup|autenticac)\b/i,
|
|
141411
|
-
/\b(notif|alert|assinatura|subscription|subscribe|email|sms)\b/i,
|
|
141412
|
-
/\b(banco|database|db|postgres|mysql|mongodb|redis|sqlite)\b/i,
|
|
141413
|
-
/\b(api\s+rest|rest\s+api|endpoint|graphql|grpc)\b/i,
|
|
141414
|
-
/\b(dashboard|frontend|interface|ui|tela)\b/i
|
|
141415
|
-
];
|
|
141416
|
-
const matchedSubsystems = subsystems.filter((r2) => r2.test(text)).length;
|
|
141417
|
-
if (matchedSubsystems < 3) return false;
|
|
141418
|
-
const hasExplicitDB = /\b(postgres(ql)?|mysql|mongodb|mongo|redis|sqlite|supabase|dynamodb|cockroach)\b/i.test(text);
|
|
141419
|
-
const hasExplicitAuth = /\b(jwt|oauth2?|basic.?auth|api.?key|session.?based|cookie.?auth)\b/i.test(text);
|
|
141420
|
-
const hasExplicitStack = !!stackHint && !["api", "rest-api", "backend"].includes(stackHint);
|
|
141421
|
-
const unspecifiedDimensions = [!hasExplicitDB, !hasExplicitAuth, !hasExplicitStack].filter(Boolean).length;
|
|
141422
|
-
return unspecifiedDimensions >= 2;
|
|
142257
|
+
return detectScopeClarificationNeed(rawIdea, stackHint).ask;
|
|
141423
142258
|
}
|
|
141424
142259
|
function inferProjectSlug(text) {
|
|
141425
142260
|
let cleaned = text.replace(/^(create|build|crie|cria|criar|fazer?|quero|i need|i want)\s+(uma|um|me\s+a?|an|a)?\s*/i, "").replace(/\s+(that|which|que|para|for|pra)\s+.*/i, "").trim();
|
|
@@ -141428,11 +142263,11 @@ function inferProjectSlug(text) {
|
|
|
141428
142263
|
return slug || void 0;
|
|
141429
142264
|
}
|
|
141430
142265
|
function normalizeProjectNameCandidate(value) {
|
|
141431
|
-
const normalized =
|
|
142266
|
+
const normalized = normalizeText4(value);
|
|
141432
142267
|
if (!normalized) return void 0;
|
|
141433
142268
|
return inferProjectSlug(normalized) ?? void 0;
|
|
141434
142269
|
}
|
|
141435
|
-
function
|
|
142270
|
+
function normalizeText4(value) {
|
|
141436
142271
|
const trimmed = value?.trim();
|
|
141437
142272
|
return trimmed ? trimmed : void 0;
|
|
141438
142273
|
}
|
|
@@ -141457,15 +142292,19 @@ function parseField(text, labels) {
|
|
|
141457
142292
|
for (const label of labels) {
|
|
141458
142293
|
const regex = new RegExp(`(?:^|[\\n.,;!?]\\s*)${label}\\s*:\\s*(.+)$`, "im");
|
|
141459
142294
|
const match = text.match(regex);
|
|
141460
|
-
if (match?.[1]) return
|
|
142295
|
+
if (match?.[1]) return normalizeText4(match[1]);
|
|
141461
142296
|
}
|
|
141462
142297
|
return void 0;
|
|
141463
142298
|
}
|
|
141464
142299
|
function parseIdeaBlock(text) {
|
|
141465
142300
|
const match = text.match(/^\s*(idea|ideia|objetivo)\s*:\s*([\s\S]+)$/im);
|
|
141466
|
-
return
|
|
142301
|
+
return normalizeText4(match?.[2]);
|
|
141467
142302
|
}
|
|
141468
142303
|
function parseExplicitProjectName(text) {
|
|
142304
|
+
const naturalLanguageMatch = text.match(/\b(?:please\s+)?(?:use|set|keep)\s+(?:the\s+)?(?:project name|repo name|repository name|nome do projeto)\s+(?:as\s+)?[`"'“”‘’]?([a-z0-9][a-z0-9-]{1,63})[`"'“”‘’]?(?=$|[\s.,!?;:])/i);
|
|
142305
|
+
if (naturalLanguageMatch?.[1]) {
|
|
142306
|
+
return normalizeProjectNameCandidate(naturalLanguageMatch[1].toLowerCase());
|
|
142307
|
+
}
|
|
141469
142308
|
const match = text.match(/\b(?:called|named|chamado)\s+[`"'“”‘’]?([a-z0-9][a-z0-9-]{1,63})[`"'“”‘’]?(?=$|[\s.,!?;:])/i);
|
|
141470
142309
|
return normalizeProjectNameCandidate(match?.[1]?.toLowerCase());
|
|
141471
142310
|
}
|
|
@@ -141703,6 +142542,9 @@ function buildClarificationMessage(parsed, pendingClarification, language = "pt"
|
|
|
141703
142542
|
if (pendingClarification === "name") {
|
|
141704
142543
|
return BOOTSTRAP_MESSAGES.clarifyName[language];
|
|
141705
142544
|
}
|
|
142545
|
+
if (pendingClarification === "scope") {
|
|
142546
|
+
return BOOTSTRAP_MESSAGES.clarifyScope[language](parsed.rawIdea);
|
|
142547
|
+
}
|
|
141706
142548
|
if (pendingClarification === "stack_and_name" || !parsed.stackHint && !parsed.projectName) {
|
|
141707
142549
|
return BOOTSTRAP_MESSAGES.clarifyBoth[language];
|
|
141708
142550
|
}
|
|
@@ -141903,12 +142745,12 @@ async function handleTelegramBootstrapDmMessage(ctx, rawConversationId, content)
|
|
|
141903
142745
|
conversationId,
|
|
141904
142746
|
rawIdea: content,
|
|
141905
142747
|
stackHint: parsed.stackHint ?? void 0,
|
|
141906
|
-
projectName: parsed.projectName ?? parsed.
|
|
142748
|
+
projectName: parsed.projectName ?? inferProjectSlug(parsed.rawIdea) ?? void 0,
|
|
141907
142749
|
status: "clarifying",
|
|
141908
142750
|
pendingClarification: "scope",
|
|
141909
142751
|
language
|
|
141910
142752
|
});
|
|
141911
|
-
const clarifyMsg =
|
|
142753
|
+
const clarifyMsg = buildClarificationMessage(parsed, "scope", language);
|
|
141912
142754
|
await sendTelegramText(ctx, rawConversationId, clarifyMsg);
|
|
141913
142755
|
return;
|
|
141914
142756
|
}
|
|
@@ -142094,6 +142936,9 @@ async function persistOwnedBootstrapCheckpoint(workspaceDir, owner, input) {
|
|
|
142094
142936
|
bootstrapStep: input.bootstrapStep,
|
|
142095
142937
|
projectSlug: input.projectSlug ?? void 0,
|
|
142096
142938
|
issueId: input.issueId,
|
|
142939
|
+
issueUrl: input.issueUrl,
|
|
142940
|
+
triageReadyForDispatch: input.triageReadyForDispatch,
|
|
142941
|
+
triageErrors: input.triageErrors,
|
|
142097
142942
|
messageThreadId: input.messageThreadId,
|
|
142098
142943
|
projectChannelId: input.projectChannelId,
|
|
142099
142944
|
language: input.language,
|
|
@@ -142559,7 +143404,7 @@ async function recoverDueTelegramBootstrapSessions(ctx, workspaceDir) {
|
|
|
142559
143404
|
const sessionsDir2 = path37.join(workspaceDir, DATA_DIR, "bootstrap-sessions");
|
|
142560
143405
|
let files;
|
|
142561
143406
|
try {
|
|
142562
|
-
files = await
|
|
143407
|
+
files = await fs37.readdir(sessionsDir2);
|
|
142563
143408
|
} catch {
|
|
142564
143409
|
return 0;
|
|
142565
143410
|
}
|
|
@@ -142945,20 +143790,25 @@ async function continueBootstrap(ctx, conversationId, workspaceDir, request, sou
|
|
|
142945
143790
|
return;
|
|
142946
143791
|
}
|
|
142947
143792
|
const telegramConfig = readFabricaTelegramConfig(ctx.pluginConfig);
|
|
142948
|
-
const
|
|
142949
|
-
|
|
142950
|
-
|
|
142951
|
-
|
|
143793
|
+
const existingSession = await readTelegramBootstrapSession(workspaceDir, conversationId);
|
|
143794
|
+
const lang = existingSession?.language ?? "pt";
|
|
143795
|
+
const inferredProjectName = request.projectName ?? inferProjectSlug(request.rawIdea) ?? null;
|
|
143796
|
+
const clarificationDecision = decideBootstrapClarification({
|
|
143797
|
+
projectName: inferredProjectName,
|
|
143798
|
+
stackHint: request.stackHint
|
|
143799
|
+
});
|
|
143800
|
+
if (clarificationDecision.ask && (clarificationDecision.kind === "stack" || clarificationDecision.kind === "stack_and_name")) {
|
|
143801
|
+
const clarificationKind = clarificationDecision.kind;
|
|
142952
143802
|
const owner = buildBootstrapAttemptOwner(existingSession);
|
|
142953
143803
|
if (owner) {
|
|
142954
143804
|
await persistOwnedBootstrapCheckpoint(workspaceDir, owner, {
|
|
142955
143805
|
rawIdea: request.rawIdea,
|
|
142956
|
-
projectName:
|
|
143806
|
+
projectName: inferredProjectName ?? void 0,
|
|
142957
143807
|
stackHint: request.stackHint ?? void 0,
|
|
142958
143808
|
sourceRoute,
|
|
142959
143809
|
status: "clarifying",
|
|
142960
143810
|
bootstrapStep: existingSession?.bootstrapStep ?? "awaiting_pipeline",
|
|
142961
|
-
pendingClarification:
|
|
143811
|
+
pendingClarification: clarificationKind,
|
|
142962
143812
|
language: lang,
|
|
142963
143813
|
ackSentAt: existingSession?.ackSentAt ?? null,
|
|
142964
143814
|
lastError: null,
|
|
@@ -142968,64 +143818,63 @@ async function continueBootstrap(ctx, conversationId, workspaceDir, request, sou
|
|
|
142968
143818
|
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
142969
143819
|
conversationId,
|
|
142970
143820
|
rawIdea: request.rawIdea,
|
|
142971
|
-
projectName:
|
|
143821
|
+
projectName: inferredProjectName ?? void 0,
|
|
142972
143822
|
status: "clarifying",
|
|
142973
|
-
pendingClarification:
|
|
143823
|
+
pendingClarification: clarificationKind,
|
|
142974
143824
|
language: lang
|
|
142975
143825
|
});
|
|
142976
143826
|
}
|
|
142977
143827
|
await sendTelegramText(ctx, conversationId, buildClarificationMessage(
|
|
142978
|
-
{ rawIdea: request.rawIdea, projectName:
|
|
142979
|
-
|
|
143828
|
+
{ rawIdea: request.rawIdea, projectName: inferredProjectName ?? void 0, stackHint: request.stackHint ?? void 0 },
|
|
143829
|
+
clarificationKind,
|
|
142980
143830
|
lang
|
|
142981
143831
|
));
|
|
142982
143832
|
return;
|
|
142983
143833
|
}
|
|
142984
|
-
if (!request.projectName) {
|
|
143834
|
+
if (inferredProjectName && !request.projectName) {
|
|
143835
|
+
request.projectName = inferredProjectName;
|
|
143836
|
+
}
|
|
143837
|
+
if (clarificationDecision.ask && clarificationDecision.kind === "name") {
|
|
142985
143838
|
const inferredSlug = inferProjectSlug(request.rawIdea);
|
|
142986
143839
|
if (inferredSlug) {
|
|
142987
143840
|
request.projectName = inferredSlug;
|
|
143841
|
+
} else if (existingSession?.pendingClarification === "name") {
|
|
143842
|
+
request.projectName = `project-${Date.now()}`;
|
|
142988
143843
|
} else {
|
|
142989
|
-
const
|
|
142990
|
-
if (existingSession
|
|
142991
|
-
|
|
143844
|
+
const owner = existingSession ? buildBootstrapAttemptOwner(existingSession) : null;
|
|
143845
|
+
if (existingSession && owner) {
|
|
143846
|
+
await persistOwnedBootstrapCheckpoint(workspaceDir, owner, {
|
|
143847
|
+
rawIdea: request.rawIdea,
|
|
143848
|
+
stackHint: request.stackHint ?? void 0,
|
|
143849
|
+
sourceRoute,
|
|
143850
|
+
status: "clarifying",
|
|
143851
|
+
bootstrapStep: existingSession.bootstrapStep ?? "awaiting_pipeline",
|
|
143852
|
+
pendingClarification: "name",
|
|
143853
|
+
language: lang,
|
|
143854
|
+
ackSentAt: existingSession.ackSentAt ?? null,
|
|
143855
|
+
lastError: null,
|
|
143856
|
+
nextRetryAt: null
|
|
143857
|
+
});
|
|
142992
143858
|
} else {
|
|
142993
|
-
|
|
142994
|
-
const owner = existingSession ? buildBootstrapAttemptOwner(existingSession) : null;
|
|
142995
|
-
if (existingSession && owner) {
|
|
142996
|
-
await persistOwnedBootstrapCheckpoint(workspaceDir, owner, {
|
|
142997
|
-
rawIdea: request.rawIdea,
|
|
142998
|
-
stackHint: request.stackHint ?? void 0,
|
|
142999
|
-
sourceRoute,
|
|
143000
|
-
status: "clarifying",
|
|
143001
|
-
bootstrapStep: existingSession.bootstrapStep ?? "awaiting_pipeline",
|
|
143002
|
-
pendingClarification: "name",
|
|
143003
|
-
language: lang,
|
|
143004
|
-
ackSentAt: existingSession.ackSentAt ?? null,
|
|
143005
|
-
lastError: null,
|
|
143006
|
-
nextRetryAt: null
|
|
143007
|
-
});
|
|
143008
|
-
} else {
|
|
143009
|
-
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
143010
|
-
conversationId,
|
|
143011
|
-
rawIdea: request.rawIdea,
|
|
143012
|
-
stackHint: request.stackHint ?? void 0,
|
|
143013
|
-
status: "clarifying",
|
|
143014
|
-
pendingClarification: "name",
|
|
143015
|
-
language: lang
|
|
143016
|
-
});
|
|
143017
|
-
}
|
|
143018
|
-
await sendTelegramText(
|
|
143019
|
-
ctx,
|
|
143859
|
+
await upsertTelegramBootstrapSession(workspaceDir, {
|
|
143020
143860
|
conversationId,
|
|
143021
|
-
|
|
143022
|
-
|
|
143023
|
-
|
|
143024
|
-
|
|
143025
|
-
|
|
143026
|
-
);
|
|
143027
|
-
return;
|
|
143861
|
+
rawIdea: request.rawIdea,
|
|
143862
|
+
stackHint: request.stackHint ?? void 0,
|
|
143863
|
+
status: "clarifying",
|
|
143864
|
+
pendingClarification: "name",
|
|
143865
|
+
language: lang
|
|
143866
|
+
});
|
|
143028
143867
|
}
|
|
143868
|
+
await sendTelegramText(
|
|
143869
|
+
ctx,
|
|
143870
|
+
conversationId,
|
|
143871
|
+
buildClarificationMessage(
|
|
143872
|
+
{ rawIdea: request.rawIdea, projectName: void 0, stackHint: request.stackHint ?? void 0 },
|
|
143873
|
+
"name",
|
|
143874
|
+
lang
|
|
143875
|
+
)
|
|
143876
|
+
);
|
|
143877
|
+
return;
|
|
143029
143878
|
}
|
|
143030
143879
|
}
|
|
143031
143880
|
const stepCtx = {
|
|
@@ -143056,10 +143905,11 @@ async function continueBootstrap(ctx, conversationId, workspaceDir, request, sou
|
|
|
143056
143905
|
config: ctx.config,
|
|
143057
143906
|
pluginConfig: ctx.pluginConfig
|
|
143058
143907
|
};
|
|
143908
|
+
const stackHint = request.stackHint ?? null;
|
|
143059
143909
|
const payload = {
|
|
143060
|
-
session_id:
|
|
143910
|
+
session_id: randomUUID5(),
|
|
143061
143911
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
143062
|
-
step: "
|
|
143912
|
+
step: "telegram-bootstrap",
|
|
143063
143913
|
raw_idea: request.rawIdea,
|
|
143064
143914
|
answers: {},
|
|
143065
143915
|
metadata: {
|
|
@@ -144809,7 +145659,7 @@ async function runPrDiscoveryPass(params) {
|
|
|
144809
145659
|
// lib/services/heartbeat/genesis-health.ts
|
|
144810
145660
|
init_logger();
|
|
144811
145661
|
init_constants();
|
|
144812
|
-
import
|
|
145662
|
+
import fs38 from "node:fs/promises";
|
|
144813
145663
|
import path38 from "node:path";
|
|
144814
145664
|
var STALE_THRESHOLD_MS = 5 * 6e4;
|
|
144815
145665
|
var STALE_STATUSES = /* @__PURE__ */ new Set(["pending_classify", "classifying"]);
|
|
@@ -144824,7 +145674,7 @@ async function checkGenesisHealth(workspaceDir) {
|
|
|
144824
145674
|
const sessionsDir2 = path38.join(workspaceDir, DATA_DIR, "bootstrap-sessions");
|
|
144825
145675
|
let files;
|
|
144826
145676
|
try {
|
|
144827
|
-
files = await
|
|
145677
|
+
files = await fs38.readdir(sessionsDir2);
|
|
144828
145678
|
} catch {
|
|
144829
145679
|
return;
|
|
144830
145680
|
}
|
|
@@ -144832,7 +145682,7 @@ async function checkGenesisHealth(workspaceDir) {
|
|
|
144832
145682
|
for (const file2 of files) {
|
|
144833
145683
|
if (!file2.endsWith(".json")) continue;
|
|
144834
145684
|
try {
|
|
144835
|
-
const raw = await
|
|
145685
|
+
const raw = await fs38.readFile(path38.join(sessionsDir2, file2), "utf-8");
|
|
144836
145686
|
const data = JSON.parse(raw);
|
|
144837
145687
|
const id = data.conversationId ?? file2.replace(/\.json$/, "");
|
|
144838
145688
|
const updatedAt = typeof data.updatedAt === "string" ? new Date(data.updatedAt).getTime() : Number(data.updatedAt ?? 0);
|
|
@@ -145456,7 +146306,7 @@ async function writeModelsToWorkflow(workspacePath, models) {
|
|
|
145456
146306
|
const workflowPath = path39.join(workspacePath, DATA_DIR, "workflow.yaml");
|
|
145457
146307
|
let content = "";
|
|
145458
146308
|
try {
|
|
145459
|
-
content = await
|
|
146309
|
+
content = await fs39.readFile(workflowPath, "utf-8");
|
|
145460
146310
|
} catch {
|
|
145461
146311
|
}
|
|
145462
146312
|
const doc = content ? import_yaml3.default.parseDocument(content) : new import_yaml3.default.Document({});
|
|
@@ -145472,7 +146322,7 @@ async function writeModelsToWorkflow(workspacePath, models) {
|
|
|
145472
146322
|
roleNode.set("models", doc.createNode(levels));
|
|
145473
146323
|
}
|
|
145474
146324
|
}
|
|
145475
|
-
await
|
|
146325
|
+
await fs39.writeFile(workflowPath, doc.toString({ lineWidth: 120 }), "utf-8");
|
|
145476
146326
|
}
|
|
145477
146327
|
|
|
145478
146328
|
// lib/tools/admin/setup.ts
|
|
@@ -145596,7 +146446,7 @@ ${written.map((f3) => ` ${f3}`).join("\n")}` : "All files already exist \u2014
|
|
|
145596
146446
|
|
|
145597
146447
|
// lib/setup/onboarding.ts
|
|
145598
146448
|
init_roles();
|
|
145599
|
-
import
|
|
146449
|
+
import fs40 from "node:fs/promises";
|
|
145600
146450
|
import path40 from "node:path";
|
|
145601
146451
|
function isPluginConfigured(pluginConfig) {
|
|
145602
146452
|
return !!pluginConfig && Object.keys(pluginConfig).length > 0;
|
|
@@ -145604,7 +146454,7 @@ function isPluginConfigured(pluginConfig) {
|
|
|
145604
146454
|
async function hasWorkspaceFiles(workspaceDir) {
|
|
145605
146455
|
if (!workspaceDir) return false;
|
|
145606
146456
|
try {
|
|
145607
|
-
const content = await
|
|
146457
|
+
const content = await fs40.readFile(
|
|
145608
146458
|
path40.join(workspaceDir, "AGENTS.md"),
|
|
145609
146459
|
"utf-8"
|
|
145610
146460
|
);
|
|
@@ -146420,7 +147270,7 @@ These completely replace (not merge with) the workspace-level prompts for that r
|
|
|
146420
147270
|
}
|
|
146421
147271
|
|
|
146422
147272
|
// lib/tools/admin/config.ts
|
|
146423
|
-
import
|
|
147273
|
+
import fs41 from "node:fs/promises";
|
|
146424
147274
|
import path41 from "node:path";
|
|
146425
147275
|
init_workspace();
|
|
146426
147276
|
init_templates();
|
|
@@ -146525,7 +147375,7 @@ async function handleDiff(workspacePath) {
|
|
|
146525
147375
|
summary: "No workflow.yaml found in workspace \u2014 using package defaults."
|
|
146526
147376
|
});
|
|
146527
147377
|
}
|
|
146528
|
-
const current = await
|
|
147378
|
+
const current = await fs41.readFile(workflowPath, "utf-8");
|
|
146529
147379
|
const template = WORKFLOW_YAML_TEMPLATE;
|
|
146530
147380
|
if (current.trim() === template.trim()) {
|
|
146531
147381
|
return jsonResult({
|
|
@@ -146685,6 +147535,8 @@ function extractExplicitProjectName(text) {
|
|
|
146685
147535
|
if (!text) return null;
|
|
146686
147536
|
const fieldMatch = text.match(/(?:^|[\n.,;!?]\s*)(?:project name|repo name|repository name|nome do projeto)\s*:\s*([a-z0-9][a-z0-9-]{1,63})\b/i);
|
|
146687
147537
|
if (fieldMatch?.[1]) return fieldMatch[1].trim().toLowerCase();
|
|
147538
|
+
const naturalLanguageMatch = text.match(/\b(?:please\s+)?(?:use|set|keep)\s+(?:the\s+)?(?:project name|repo name|repository name|nome do projeto)\s+(?:as\s+)?[`"'“”‘’]?([a-z0-9][a-z0-9-]{1,63})[`"'“”‘’]?(?=$|[\s.,!?;:])/i);
|
|
147539
|
+
if (naturalLanguageMatch?.[1]) return naturalLanguageMatch[1].trim().toLowerCase();
|
|
146688
147540
|
const inlineMatch = text.match(/\b(?:called|named|chamado)\s+[`"'“”‘’]?([a-z0-9][a-z0-9-]{1,63})[`"'“”‘’]?(?=$|[\s.,!?;:])/i);
|
|
146689
147541
|
if (inlineMatch?.[1]) return inlineMatch[1].trim().toLowerCase();
|
|
146690
147542
|
return null;
|
|
@@ -147199,7 +148051,7 @@ function getPendingQuestions(payload, answers = payload.answers ?? {}) {
|
|
|
147199
148051
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
147200
148052
|
init_constants();
|
|
147201
148053
|
init_migrate_layout();
|
|
147202
|
-
import
|
|
148054
|
+
import fs42 from "node:fs/promises";
|
|
147203
148055
|
import path42 from "node:path";
|
|
147204
148056
|
init_roles();
|
|
147205
148057
|
async function runDoctor(opts) {
|
|
@@ -147244,14 +148096,14 @@ async function runDoctor(opts) {
|
|
|
147244
148096
|
if (check2.name.startsWith("file:")) {
|
|
147245
148097
|
const recheckPath = check2.name.replace("file:", "");
|
|
147246
148098
|
try {
|
|
147247
|
-
await
|
|
148099
|
+
await fs42.access(recheckPath);
|
|
147248
148100
|
recheckOk = true;
|
|
147249
148101
|
} catch {
|
|
147250
148102
|
}
|
|
147251
148103
|
} else if (check2.name.startsWith("dir:")) {
|
|
147252
148104
|
const recheckPath = check2.name.replace("dir:", "");
|
|
147253
148105
|
try {
|
|
147254
|
-
const stat2 = await
|
|
148106
|
+
const stat2 = await fs42.stat(recheckPath);
|
|
147255
148107
|
recheckOk = stat2.isDirectory();
|
|
147256
148108
|
} catch {
|
|
147257
148109
|
}
|
|
@@ -147280,7 +148132,7 @@ async function runDoctor(opts) {
|
|
|
147280
148132
|
}
|
|
147281
148133
|
async function checkDirExists(dirPath, label) {
|
|
147282
148134
|
try {
|
|
147283
|
-
const stat2 = await
|
|
148135
|
+
const stat2 = await fs42.stat(dirPath);
|
|
147284
148136
|
if (stat2.isDirectory()) {
|
|
147285
148137
|
return { name: `dir:${dirPath}`, severity: "ok", message: `${label} exists` };
|
|
147286
148138
|
}
|
|
@@ -147291,7 +148143,7 @@ async function checkDirExists(dirPath, label) {
|
|
|
147291
148143
|
}
|
|
147292
148144
|
async function checkFileExists(filePath, label) {
|
|
147293
148145
|
try {
|
|
147294
|
-
await
|
|
148146
|
+
await fs42.access(filePath);
|
|
147295
148147
|
return { name: `file:${filePath}`, severity: "ok", message: `${label} exists` };
|
|
147296
148148
|
} catch {
|
|
147297
148149
|
return { name: `file:${filePath}`, severity: "error", message: `${label} missing` };
|
|
@@ -147300,7 +148152,7 @@ async function checkFileExists(filePath, label) {
|
|
|
147300
148152
|
async function checkWorkflowYaml(dataDir) {
|
|
147301
148153
|
const filePath = path42.join(dataDir, "workflow.yaml");
|
|
147302
148154
|
try {
|
|
147303
|
-
const content = await
|
|
148155
|
+
const content = await fs42.readFile(filePath, "utf-8");
|
|
147304
148156
|
const parsed = import_yaml4.default.parse(content);
|
|
147305
148157
|
if (!parsed || typeof parsed !== "object") {
|
|
147306
148158
|
return { name: "yaml:workflow", severity: "error", message: "workflow.yaml is empty or not an object" };
|
|
@@ -147319,7 +148171,7 @@ async function checkWorkflowYaml(dataDir) {
|
|
|
147319
148171
|
async function checkProjectsJson(dataDir) {
|
|
147320
148172
|
const filePath = path42.join(dataDir, "projects.json");
|
|
147321
148173
|
try {
|
|
147322
|
-
const content = await
|
|
148174
|
+
const content = await fs42.readFile(filePath, "utf-8");
|
|
147323
148175
|
const parsed = JSON.parse(content);
|
|
147324
148176
|
if (!parsed || typeof parsed !== "object") {
|
|
147325
148177
|
return { name: "json:projects", severity: "error", message: "projects.json is not an object" };
|
|
@@ -147396,7 +148248,7 @@ async function checkProjects(dataDir) {
|
|
|
147396
148248
|
const filePath = path42.join(dataDir, "projects.json");
|
|
147397
148249
|
let data;
|
|
147398
148250
|
try {
|
|
147399
|
-
const content = await
|
|
148251
|
+
const content = await fs42.readFile(filePath, "utf-8");
|
|
147400
148252
|
data = JSON.parse(content);
|
|
147401
148253
|
} catch {
|
|
147402
148254
|
return results;
|
|
@@ -147436,7 +148288,7 @@ async function checkProjects(dataDir) {
|
|
|
147436
148288
|
if (project.repo && path42.isAbsolute(project.repo)) {
|
|
147437
148289
|
const qaPath = path42.join(project.repo, "scripts", "qa.sh");
|
|
147438
148290
|
try {
|
|
147439
|
-
await
|
|
148291
|
+
await fs42.access(qaPath);
|
|
147440
148292
|
} catch {
|
|
147441
148293
|
results.push({
|
|
147442
148294
|
name: `project:${slug}:qa`,
|
|
@@ -147560,7 +148412,7 @@ function formatMetrics(metrics2) {
|
|
|
147560
148412
|
|
|
147561
148413
|
// lib/setup/security-doctor.ts
|
|
147562
148414
|
init_constants();
|
|
147563
|
-
import
|
|
148415
|
+
import fs43 from "node:fs/promises";
|
|
147564
148416
|
import path43 from "node:path";
|
|
147565
148417
|
var LEGACY_EXTENSION_PATH_PATTERNS = [
|
|
147566
148418
|
"/extensions/secureclaw/",
|
|
@@ -147585,7 +148437,7 @@ async function runSecurityDoctor(openclawHome) {
|
|
|
147585
148437
|
const checklistPath = path43.join(workspacePath, DATA_DIR, "prompts", "security-checklist.md");
|
|
147586
148438
|
let config2 = null;
|
|
147587
148439
|
try {
|
|
147588
|
-
config2 = JSON.parse(await
|
|
148440
|
+
config2 = JSON.parse(await fs43.readFile(configPath, "utf-8"));
|
|
147589
148441
|
checks.push({
|
|
147590
148442
|
name: "config:openclaw-json",
|
|
147591
148443
|
severity: "ok",
|
|
@@ -147652,7 +148504,7 @@ async function runSecurityDoctor(openclawHome) {
|
|
|
147652
148504
|
message: genesisBinding ? "Genesis agent owns the channel-wide Telegram DM binding" : "Genesis agent does not own a channel-wide Telegram binding"
|
|
147653
148505
|
});
|
|
147654
148506
|
try {
|
|
147655
|
-
await
|
|
148507
|
+
await fs43.access(checklistPath);
|
|
147656
148508
|
checks.push({
|
|
147657
148509
|
name: "workspace:security-checklist",
|
|
147658
148510
|
severity: "ok",
|
|
@@ -147666,7 +148518,7 @@ async function runSecurityDoctor(openclawHome) {
|
|
|
147666
148518
|
});
|
|
147667
148519
|
}
|
|
147668
148520
|
try {
|
|
147669
|
-
const jobsJson = JSON.parse(await
|
|
148521
|
+
const jobsJson = JSON.parse(await fs43.readFile(jobsPath, "utf-8"));
|
|
147670
148522
|
const jobs = jobsJson.jobs ?? [];
|
|
147671
148523
|
const legacyJobFindings = jobs.filter((job) => job.enabled !== false).flatMap((job) => {
|
|
147672
148524
|
const text = `${job.payload?.text ?? ""} ${job.payload?.message ?? ""}`;
|
|
@@ -148806,7 +149658,7 @@ function registerGitHubWebhookRoute(api, ctx) {
|
|
|
148806
149658
|
// lib/setup/gateway-lifecycle-hook.ts
|
|
148807
149659
|
init_constants();
|
|
148808
149660
|
init_audit();
|
|
148809
|
-
import * as
|
|
149661
|
+
import * as fs44 from "node:fs/promises";
|
|
148810
149662
|
import * as path45 from "node:path";
|
|
148811
149663
|
function registerGatewayLifecycleHook(api, ctx) {
|
|
148812
149664
|
const workspaceDir = resolveWorkspaceDir(ctx.config);
|
|
@@ -148815,7 +149667,7 @@ function registerGatewayLifecycleHook(api, ctx) {
|
|
|
148815
149667
|
const bootTime = Date.now();
|
|
148816
149668
|
const dataPath = path45.join(workspaceDir, DATA_DIR);
|
|
148817
149669
|
try {
|
|
148818
|
-
await
|
|
149670
|
+
await fs44.access(dataPath);
|
|
148819
149671
|
} catch {
|
|
148820
149672
|
await log(workspaceDir, "gateway_start_warning", {
|
|
148821
149673
|
message: `Workspace data directory missing: ${dataPath}`
|
|
@@ -148825,7 +149677,7 @@ function registerGatewayLifecycleHook(api, ctx) {
|
|
|
148825
149677
|
}
|
|
148826
149678
|
const projectsPath2 = path45.join(dataPath, "projects.json");
|
|
148827
149679
|
try {
|
|
148828
|
-
const raw = await
|
|
149680
|
+
const raw = await fs44.readFile(projectsPath2, "utf-8");
|
|
148829
149681
|
JSON.parse(raw);
|
|
148830
149682
|
} catch (err) {
|
|
148831
149683
|
await log(workspaceDir, "gateway_start_warning", {
|
|
@@ -149107,7 +149959,7 @@ function registerSubagentLifecycleHook(api, ctx) {
|
|
|
149107
149959
|
init_constants();
|
|
149108
149960
|
init_registry();
|
|
149109
149961
|
init_roles();
|
|
149110
|
-
import * as
|
|
149962
|
+
import * as fs45 from "node:fs";
|
|
149111
149963
|
import * as path46 from "node:path";
|
|
149112
149964
|
var ESCALATION_MAP = {
|
|
149113
149965
|
junior: "medior",
|
|
@@ -149134,7 +149986,7 @@ function registerModelResolveHook(api, ctx) {
|
|
|
149134
149986
|
if (!level) return;
|
|
149135
149987
|
try {
|
|
149136
149988
|
const projectsPath2 = path46.join(workspaceDir, DATA_DIR, "projects.json");
|
|
149137
|
-
const raw = await
|
|
149989
|
+
const raw = await fs45.promises.readFile(projectsPath2, "utf-8");
|
|
149138
149990
|
const projects = JSON.parse(raw);
|
|
149139
149991
|
const project = Object.values(projects).find((p) => p.slug === projectName);
|
|
149140
149992
|
if (!project?.workers?.[role]?.levels?.[level]) return;
|
|
@@ -149203,6 +150055,9 @@ Do not delegate implementation, testing, review, or planning to another coding a
|
|
|
149203
150055
|
Do not use nested coding agents.
|
|
149204
150056
|
Do not use planning or meta-skills such as brainstorming, writing-plans, or coding-agent.
|
|
149205
150057
|
Do not spawn, supervise, or instruct another agent to do the work for you.
|
|
150058
|
+
Do not weaken, replace, or bypass the canonical scripts/qa.sh contract just to make the task pass.
|
|
150059
|
+
Preserve the canonical QA gates: lint, types, security, tests, and coverage.
|
|
150060
|
+
If QA fails, fix the product code or project setup instead of rewriting the QA contract into ad-hoc scenario checks.
|
|
149206
150061
|
If you cannot proceed directly in the assigned worktree, end with your role's canonical blocked result line.
|
|
149207
150062
|
`;
|
|
149208
150063
|
var REVIEWER_EXECUTION_CONTRACT_CONTEXT = `## Execution Contract
|