@clawos-dev/clawd 0.2.452 → 0.2.454
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/dist/app-builder-plugin/mcp-server.cjs +25338 -0
- package/dist/cli.cjs +981 -810
- package/dist/dispatch/mcp-server.cjs +1 -1
- package/dist/persona-defaults/persona-app-builder/CLAUDE.md +41 -42
- package/dist/persona-defaults/persona-dataclaw-builder/CLAUDE.md +10 -10
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/guest-D_OYvJIg.css +32 -0
- package/dist/share-ui/assets/{guest-CilettnR.js → guest-Dh-ssMM-.js} +124 -124
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-7QsWRy9Q.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -450,8 +450,8 @@ var init_parseUtil = __esm({
|
|
|
450
450
|
init_errors();
|
|
451
451
|
init_en();
|
|
452
452
|
makeIssue = (params) => {
|
|
453
|
-
const { data, path:
|
|
454
|
-
const fullPath = [...
|
|
453
|
+
const { data, path: path94, errorMaps, issueData } = params;
|
|
454
|
+
const fullPath = [...path94, ...issueData.path || []];
|
|
455
455
|
const fullIssue = {
|
|
456
456
|
...issueData,
|
|
457
457
|
path: fullPath
|
|
@@ -762,11 +762,11 @@ var init_types = __esm({
|
|
|
762
762
|
init_parseUtil();
|
|
763
763
|
init_util();
|
|
764
764
|
ParseInputLazyPath = class {
|
|
765
|
-
constructor(parent, value,
|
|
765
|
+
constructor(parent, value, path94, key) {
|
|
766
766
|
this._cachedPath = [];
|
|
767
767
|
this.parent = parent;
|
|
768
768
|
this.data = value;
|
|
769
|
-
this._path =
|
|
769
|
+
this._path = path94;
|
|
770
770
|
this._key = key;
|
|
771
771
|
}
|
|
772
772
|
get path() {
|
|
@@ -8804,7 +8804,7 @@ var init_methods = __esm({
|
|
|
8804
8804
|
args: WorkspaceReadArgs
|
|
8805
8805
|
},
|
|
8806
8806
|
"deploy:start": {
|
|
8807
|
-
summary: "\
|
|
8807
|
+
summary: "\u5BF9\u67D0\u4E2A persona \u8D77\u4E00\u6B21**\u65B0\u7684**\u4E0A\u4E91\u626B\u63CF\uFF1A\u5EFA\u4E00\u5F20\u65B0\u5355\u636E\u5E76\u5F02\u6B65\u626B\uFF08\u4EBA\u4F1A\u70B9\u8FD9\u4E2A\u53EA\u53EF\u80FD\u662F\u56E0\u4E3A persona \u8FED\u4EE3\u4E86\uFF0C\u62FF\u65E7\u6E05\u5355\u53BB\u90E8\u7F72\u662F\u9519\u7684\uFF09\u3002**\u5DF2\u586B\u7684\u51ED\u636E\u503C\u548C\u5C65\u7EA6\u9009\u62E9\u4ECE\u4E0A\u4E00\u5F20\u5355\u7EE7\u627F\u8FC7\u6765**\uFF0C\u4E0D\u7528\u6BCF\u8FED\u4EE3\u4E00\u6B21\u91CD\u8D34\u4E00\u904D key\u3002\u5DF2\u7ECF\u5728\u626B\u7684\u8BDD\u8FD4\u56DE\u90A3\u5F20\u3001\u4E0D\u5E76\u53D1\u8D77\u7B2C\u4E8C\u4E2A\u626B\u63CF\u4F1A\u8BDD\u3002\u56DE\u770B\u65E7\u7684\u90A3\u6B21\u8D70 deploy:list + deploy:get\uFF1Bowner-only",
|
|
8808
8808
|
args: DeployStartArgsSchema
|
|
8809
8809
|
},
|
|
8810
8810
|
"deploy:rescan": {
|
|
@@ -9823,8 +9823,8 @@ var require_req = __commonJS({
|
|
|
9823
9823
|
if (req.originalUrl) {
|
|
9824
9824
|
_req.url = req.originalUrl;
|
|
9825
9825
|
} else {
|
|
9826
|
-
const
|
|
9827
|
-
_req.url = typeof
|
|
9826
|
+
const path94 = req.path;
|
|
9827
|
+
_req.url = typeof path94 === "string" ? path94 : req.url ? req.url.path || req.url : void 0;
|
|
9828
9828
|
}
|
|
9829
9829
|
if (req.query) {
|
|
9830
9830
|
_req.query = req.query;
|
|
@@ -9989,14 +9989,14 @@ var require_redact = __commonJS({
|
|
|
9989
9989
|
}
|
|
9990
9990
|
return obj;
|
|
9991
9991
|
}
|
|
9992
|
-
function parsePath(
|
|
9992
|
+
function parsePath(path94) {
|
|
9993
9993
|
const parts = [];
|
|
9994
9994
|
let current = "";
|
|
9995
9995
|
let inBrackets = false;
|
|
9996
9996
|
let inQuotes = false;
|
|
9997
9997
|
let quoteChar = "";
|
|
9998
|
-
for (let i = 0; i <
|
|
9999
|
-
const char =
|
|
9998
|
+
for (let i = 0; i < path94.length; i++) {
|
|
9999
|
+
const char = path94[i];
|
|
10000
10000
|
if (!inBrackets && char === ".") {
|
|
10001
10001
|
if (current) {
|
|
10002
10002
|
parts.push(current);
|
|
@@ -10127,10 +10127,10 @@ var require_redact = __commonJS({
|
|
|
10127
10127
|
return current;
|
|
10128
10128
|
}
|
|
10129
10129
|
function redactPaths(obj, paths, censor, remove = false) {
|
|
10130
|
-
for (const
|
|
10131
|
-
const parts = parsePath(
|
|
10130
|
+
for (const path94 of paths) {
|
|
10131
|
+
const parts = parsePath(path94);
|
|
10132
10132
|
if (parts.includes("*")) {
|
|
10133
|
-
redactWildcardPath(obj, parts, censor,
|
|
10133
|
+
redactWildcardPath(obj, parts, censor, path94, remove);
|
|
10134
10134
|
} else {
|
|
10135
10135
|
if (remove) {
|
|
10136
10136
|
removeKey(obj, parts);
|
|
@@ -10215,8 +10215,8 @@ var require_redact = __commonJS({
|
|
|
10215
10215
|
}
|
|
10216
10216
|
} else {
|
|
10217
10217
|
if (afterWildcard.includes("*")) {
|
|
10218
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
10219
|
-
const fullPath = [...pathArray.slice(0, pathLength), ...
|
|
10218
|
+
const wrappedCensor = typeof censor === "function" ? (value, path94) => {
|
|
10219
|
+
const fullPath = [...pathArray.slice(0, pathLength), ...path94];
|
|
10220
10220
|
return censor(value, fullPath);
|
|
10221
10221
|
} : censor;
|
|
10222
10222
|
redactWildcardPath(current, afterWildcard, wrappedCensor, originalPath, remove);
|
|
@@ -10251,8 +10251,8 @@ var require_redact = __commonJS({
|
|
|
10251
10251
|
return null;
|
|
10252
10252
|
}
|
|
10253
10253
|
const pathStructure = /* @__PURE__ */ new Map();
|
|
10254
|
-
for (const
|
|
10255
|
-
const parts = parsePath(
|
|
10254
|
+
for (const path94 of pathsToClone) {
|
|
10255
|
+
const parts = parsePath(path94);
|
|
10256
10256
|
let current = pathStructure;
|
|
10257
10257
|
for (let i = 0; i < parts.length; i++) {
|
|
10258
10258
|
const part = parts[i];
|
|
@@ -10304,24 +10304,24 @@ var require_redact = __commonJS({
|
|
|
10304
10304
|
}
|
|
10305
10305
|
return cloneSelectively(obj, pathStructure);
|
|
10306
10306
|
}
|
|
10307
|
-
function validatePath(
|
|
10308
|
-
if (typeof
|
|
10307
|
+
function validatePath(path94) {
|
|
10308
|
+
if (typeof path94 !== "string") {
|
|
10309
10309
|
throw new Error("Paths must be (non-empty) strings");
|
|
10310
10310
|
}
|
|
10311
|
-
if (
|
|
10311
|
+
if (path94 === "") {
|
|
10312
10312
|
throw new Error("Invalid redaction path ()");
|
|
10313
10313
|
}
|
|
10314
|
-
if (
|
|
10315
|
-
throw new Error(`Invalid redaction path (${
|
|
10314
|
+
if (path94.includes("..")) {
|
|
10315
|
+
throw new Error(`Invalid redaction path (${path94})`);
|
|
10316
10316
|
}
|
|
10317
|
-
if (
|
|
10318
|
-
throw new Error(`Invalid redaction path (${
|
|
10317
|
+
if (path94.includes(",")) {
|
|
10318
|
+
throw new Error(`Invalid redaction path (${path94})`);
|
|
10319
10319
|
}
|
|
10320
10320
|
let bracketCount = 0;
|
|
10321
10321
|
let inQuotes = false;
|
|
10322
10322
|
let quoteChar = "";
|
|
10323
|
-
for (let i = 0; i <
|
|
10324
|
-
const char =
|
|
10323
|
+
for (let i = 0; i < path94.length; i++) {
|
|
10324
|
+
const char = path94[i];
|
|
10325
10325
|
if ((char === '"' || char === "'") && bracketCount > 0) {
|
|
10326
10326
|
if (!inQuotes) {
|
|
10327
10327
|
inQuotes = true;
|
|
@@ -10335,20 +10335,20 @@ var require_redact = __commonJS({
|
|
|
10335
10335
|
} else if (char === "]" && !inQuotes) {
|
|
10336
10336
|
bracketCount--;
|
|
10337
10337
|
if (bracketCount < 0) {
|
|
10338
|
-
throw new Error(`Invalid redaction path (${
|
|
10338
|
+
throw new Error(`Invalid redaction path (${path94})`);
|
|
10339
10339
|
}
|
|
10340
10340
|
}
|
|
10341
10341
|
}
|
|
10342
10342
|
if (bracketCount !== 0) {
|
|
10343
|
-
throw new Error(`Invalid redaction path (${
|
|
10343
|
+
throw new Error(`Invalid redaction path (${path94})`);
|
|
10344
10344
|
}
|
|
10345
10345
|
}
|
|
10346
10346
|
function validatePaths(paths) {
|
|
10347
10347
|
if (!Array.isArray(paths)) {
|
|
10348
10348
|
throw new TypeError("paths must be an array");
|
|
10349
10349
|
}
|
|
10350
|
-
for (const
|
|
10351
|
-
validatePath(
|
|
10350
|
+
for (const path94 of paths) {
|
|
10351
|
+
validatePath(path94);
|
|
10352
10352
|
}
|
|
10353
10353
|
}
|
|
10354
10354
|
function slowRedact(options = {}) {
|
|
@@ -10516,8 +10516,8 @@ var require_redaction = __commonJS({
|
|
|
10516
10516
|
if (shape[k2] === null) {
|
|
10517
10517
|
o[k2] = (value) => topCensor(value, [k2]);
|
|
10518
10518
|
} else {
|
|
10519
|
-
const wrappedCensor = typeof censor === "function" ? (value,
|
|
10520
|
-
return censor(value, [k2, ...
|
|
10519
|
+
const wrappedCensor = typeof censor === "function" ? (value, path94) => {
|
|
10520
|
+
return censor(value, [k2, ...path94]);
|
|
10521
10521
|
} : censor;
|
|
10522
10522
|
o[k2] = Redact({
|
|
10523
10523
|
paths: shape[k2],
|
|
@@ -10735,10 +10735,10 @@ var require_atomic_sleep = __commonJS({
|
|
|
10735
10735
|
var require_sonic_boom = __commonJS({
|
|
10736
10736
|
"../node_modules/.pnpm/sonic-boom@4.2.1/node_modules/sonic-boom/index.js"(exports2, module2) {
|
|
10737
10737
|
"use strict";
|
|
10738
|
-
var
|
|
10738
|
+
var fs83 = require("fs");
|
|
10739
10739
|
var EventEmitter3 = require("events");
|
|
10740
10740
|
var inherits = require("util").inherits;
|
|
10741
|
-
var
|
|
10741
|
+
var path94 = require("path");
|
|
10742
10742
|
var sleep2 = require_atomic_sleep();
|
|
10743
10743
|
var assert = require("assert");
|
|
10744
10744
|
var BUSY_WRITE_TIMEOUT = 100;
|
|
@@ -10792,20 +10792,20 @@ var require_sonic_boom = __commonJS({
|
|
|
10792
10792
|
const mode = sonic.mode;
|
|
10793
10793
|
if (sonic.sync) {
|
|
10794
10794
|
try {
|
|
10795
|
-
if (sonic.mkdir)
|
|
10796
|
-
const fd =
|
|
10795
|
+
if (sonic.mkdir) fs83.mkdirSync(path94.dirname(file), { recursive: true });
|
|
10796
|
+
const fd = fs83.openSync(file, flags, mode);
|
|
10797
10797
|
fileOpened(null, fd);
|
|
10798
10798
|
} catch (err) {
|
|
10799
10799
|
fileOpened(err);
|
|
10800
10800
|
throw err;
|
|
10801
10801
|
}
|
|
10802
10802
|
} else if (sonic.mkdir) {
|
|
10803
|
-
|
|
10803
|
+
fs83.mkdir(path94.dirname(file), { recursive: true }, (err) => {
|
|
10804
10804
|
if (err) return fileOpened(err);
|
|
10805
|
-
|
|
10805
|
+
fs83.open(file, flags, mode, fileOpened);
|
|
10806
10806
|
});
|
|
10807
10807
|
} else {
|
|
10808
|
-
|
|
10808
|
+
fs83.open(file, flags, mode, fileOpened);
|
|
10809
10809
|
}
|
|
10810
10810
|
}
|
|
10811
10811
|
function SonicBoom(opts) {
|
|
@@ -10846,8 +10846,8 @@ var require_sonic_boom = __commonJS({
|
|
|
10846
10846
|
this.flush = flushBuffer;
|
|
10847
10847
|
this.flushSync = flushBufferSync;
|
|
10848
10848
|
this._actualWrite = actualWriteBuffer;
|
|
10849
|
-
fsWriteSync = () =>
|
|
10850
|
-
fsWrite = () =>
|
|
10849
|
+
fsWriteSync = () => fs83.writeSync(this.fd, this._writingBuf);
|
|
10850
|
+
fsWrite = () => fs83.write(this.fd, this._writingBuf, this.release);
|
|
10851
10851
|
} else if (contentMode === void 0 || contentMode === kContentModeUtf8) {
|
|
10852
10852
|
this._writingBuf = "";
|
|
10853
10853
|
this.write = write;
|
|
@@ -10856,15 +10856,15 @@ var require_sonic_boom = __commonJS({
|
|
|
10856
10856
|
this._actualWrite = actualWrite;
|
|
10857
10857
|
fsWriteSync = () => {
|
|
10858
10858
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
10859
|
-
return
|
|
10859
|
+
return fs83.writeSync(this.fd, this._writingBuf);
|
|
10860
10860
|
}
|
|
10861
|
-
return
|
|
10861
|
+
return fs83.writeSync(this.fd, this._writingBuf, "utf8");
|
|
10862
10862
|
};
|
|
10863
10863
|
fsWrite = () => {
|
|
10864
10864
|
if (Buffer.isBuffer(this._writingBuf)) {
|
|
10865
|
-
return
|
|
10865
|
+
return fs83.write(this.fd, this._writingBuf, this.release);
|
|
10866
10866
|
}
|
|
10867
|
-
return
|
|
10867
|
+
return fs83.write(this.fd, this._writingBuf, "utf8", this.release);
|
|
10868
10868
|
};
|
|
10869
10869
|
} else {
|
|
10870
10870
|
throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`);
|
|
@@ -10921,7 +10921,7 @@ var require_sonic_boom = __commonJS({
|
|
|
10921
10921
|
}
|
|
10922
10922
|
}
|
|
10923
10923
|
if (this._fsync) {
|
|
10924
|
-
|
|
10924
|
+
fs83.fsyncSync(this.fd);
|
|
10925
10925
|
}
|
|
10926
10926
|
const len = this._len;
|
|
10927
10927
|
if (this._reopening) {
|
|
@@ -11035,7 +11035,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11035
11035
|
const onDrain = () => {
|
|
11036
11036
|
if (!this._fsync) {
|
|
11037
11037
|
try {
|
|
11038
|
-
|
|
11038
|
+
fs83.fsync(this.fd, (err) => {
|
|
11039
11039
|
this._flushPending = false;
|
|
11040
11040
|
cb(err);
|
|
11041
11041
|
});
|
|
@@ -11137,7 +11137,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11137
11137
|
const fd = this.fd;
|
|
11138
11138
|
this.once("ready", () => {
|
|
11139
11139
|
if (fd !== this.fd) {
|
|
11140
|
-
|
|
11140
|
+
fs83.close(fd, (err) => {
|
|
11141
11141
|
if (err) {
|
|
11142
11142
|
return this.emit("error", err);
|
|
11143
11143
|
}
|
|
@@ -11186,7 +11186,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11186
11186
|
buf = this._bufs[0];
|
|
11187
11187
|
}
|
|
11188
11188
|
try {
|
|
11189
|
-
const n = Buffer.isBuffer(buf) ?
|
|
11189
|
+
const n = Buffer.isBuffer(buf) ? fs83.writeSync(this.fd, buf) : fs83.writeSync(this.fd, buf, "utf8");
|
|
11190
11190
|
const releasedBufObj = releaseWritingBuf(buf, this._len, n);
|
|
11191
11191
|
buf = releasedBufObj.writingBuf;
|
|
11192
11192
|
this._len = releasedBufObj.len;
|
|
@@ -11202,7 +11202,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11202
11202
|
}
|
|
11203
11203
|
}
|
|
11204
11204
|
try {
|
|
11205
|
-
|
|
11205
|
+
fs83.fsyncSync(this.fd);
|
|
11206
11206
|
} catch {
|
|
11207
11207
|
}
|
|
11208
11208
|
}
|
|
@@ -11223,7 +11223,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11223
11223
|
buf = mergeBuf(this._bufs[0], this._lens[0]);
|
|
11224
11224
|
}
|
|
11225
11225
|
try {
|
|
11226
|
-
const n =
|
|
11226
|
+
const n = fs83.writeSync(this.fd, buf);
|
|
11227
11227
|
buf = buf.subarray(n);
|
|
11228
11228
|
this._len = Math.max(this._len - n, 0);
|
|
11229
11229
|
if (buf.length <= 0) {
|
|
@@ -11251,13 +11251,13 @@ var require_sonic_boom = __commonJS({
|
|
|
11251
11251
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : this._bufs.shift() || "";
|
|
11252
11252
|
if (this.sync) {
|
|
11253
11253
|
try {
|
|
11254
|
-
const written = Buffer.isBuffer(this._writingBuf) ?
|
|
11254
|
+
const written = Buffer.isBuffer(this._writingBuf) ? fs83.writeSync(this.fd, this._writingBuf) : fs83.writeSync(this.fd, this._writingBuf, "utf8");
|
|
11255
11255
|
release(null, written);
|
|
11256
11256
|
} catch (err) {
|
|
11257
11257
|
release(err);
|
|
11258
11258
|
}
|
|
11259
11259
|
} else {
|
|
11260
|
-
|
|
11260
|
+
fs83.write(this.fd, this._writingBuf, release);
|
|
11261
11261
|
}
|
|
11262
11262
|
}
|
|
11263
11263
|
function actualWriteBuffer() {
|
|
@@ -11266,7 +11266,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11266
11266
|
this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift());
|
|
11267
11267
|
if (this.sync) {
|
|
11268
11268
|
try {
|
|
11269
|
-
const written =
|
|
11269
|
+
const written = fs83.writeSync(this.fd, this._writingBuf);
|
|
11270
11270
|
release(null, written);
|
|
11271
11271
|
} catch (err) {
|
|
11272
11272
|
release(err);
|
|
@@ -11275,7 +11275,7 @@ var require_sonic_boom = __commonJS({
|
|
|
11275
11275
|
if (kCopyBuffer) {
|
|
11276
11276
|
this._writingBuf = Buffer.from(this._writingBuf);
|
|
11277
11277
|
}
|
|
11278
|
-
|
|
11278
|
+
fs83.write(this.fd, this._writingBuf, release);
|
|
11279
11279
|
}
|
|
11280
11280
|
}
|
|
11281
11281
|
function actualClose(sonic) {
|
|
@@ -11291,12 +11291,12 @@ var require_sonic_boom = __commonJS({
|
|
|
11291
11291
|
sonic._lens = [];
|
|
11292
11292
|
assert(typeof sonic.fd === "number", `sonic.fd must be a number, got ${typeof sonic.fd}`);
|
|
11293
11293
|
try {
|
|
11294
|
-
|
|
11294
|
+
fs83.fsync(sonic.fd, closeWrapped);
|
|
11295
11295
|
} catch {
|
|
11296
11296
|
}
|
|
11297
11297
|
function closeWrapped() {
|
|
11298
11298
|
if (sonic.fd !== 1 && sonic.fd !== 2) {
|
|
11299
|
-
|
|
11299
|
+
fs83.close(sonic.fd, done);
|
|
11300
11300
|
} else {
|
|
11301
11301
|
done();
|
|
11302
11302
|
}
|
|
@@ -14431,11 +14431,11 @@ var init_lib = __esm({
|
|
|
14431
14431
|
}
|
|
14432
14432
|
}
|
|
14433
14433
|
},
|
|
14434
|
-
addToPath: function addToPath(
|
|
14435
|
-
var last =
|
|
14434
|
+
addToPath: function addToPath(path94, added, removed, oldPosInc, options) {
|
|
14435
|
+
var last = path94.lastComponent;
|
|
14436
14436
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
14437
14437
|
return {
|
|
14438
|
-
oldPos:
|
|
14438
|
+
oldPos: path94.oldPos + oldPosInc,
|
|
14439
14439
|
lastComponent: {
|
|
14440
14440
|
count: last.count + 1,
|
|
14441
14441
|
added,
|
|
@@ -14445,7 +14445,7 @@ var init_lib = __esm({
|
|
|
14445
14445
|
};
|
|
14446
14446
|
} else {
|
|
14447
14447
|
return {
|
|
14448
|
-
oldPos:
|
|
14448
|
+
oldPos: path94.oldPos + oldPosInc,
|
|
14449
14449
|
lastComponent: {
|
|
14450
14450
|
count: 1,
|
|
14451
14451
|
added,
|
|
@@ -15027,10 +15027,10 @@ function attachmentToHistoryMessage(o, ts) {
|
|
|
15027
15027
|
const memories = raw.map((m2) => {
|
|
15028
15028
|
if (!m2 || typeof m2 !== "object") return null;
|
|
15029
15029
|
const rec4 = m2;
|
|
15030
|
-
const
|
|
15030
|
+
const path94 = typeof rec4.path === "string" ? rec4.path : null;
|
|
15031
15031
|
const content = typeof rec4.content === "string" ? rec4.content : null;
|
|
15032
|
-
if (!
|
|
15033
|
-
const entry = { path:
|
|
15032
|
+
if (!path94 || content == null) return null;
|
|
15033
|
+
const entry = { path: path94, content };
|
|
15034
15034
|
if (typeof rec4.mtimeMs === "number") entry.mtimeMs = rec4.mtimeMs;
|
|
15035
15035
|
return entry;
|
|
15036
15036
|
}).filter((m2) => m2 !== null);
|
|
@@ -15896,10 +15896,10 @@ function parseAttachment(obj) {
|
|
|
15896
15896
|
const memories = raw.map((m2) => {
|
|
15897
15897
|
if (!m2 || typeof m2 !== "object") return null;
|
|
15898
15898
|
const rec4 = m2;
|
|
15899
|
-
const
|
|
15899
|
+
const path94 = typeof rec4.path === "string" ? rec4.path : null;
|
|
15900
15900
|
const content = typeof rec4.content === "string" ? rec4.content : null;
|
|
15901
|
-
if (!
|
|
15902
|
-
const out = { path:
|
|
15901
|
+
if (!path94 || content == null) return null;
|
|
15902
|
+
const out = { path: path94, content };
|
|
15903
15903
|
if (typeof rec4.mtimeMs === "number") out.mtimeMs = rec4.mtimeMs;
|
|
15904
15904
|
return out;
|
|
15905
15905
|
}).filter((m2) => m2 !== null);
|
|
@@ -36873,8 +36873,8 @@ var require_utils = __commonJS({
|
|
|
36873
36873
|
var result = transform[inputType][outputType](input);
|
|
36874
36874
|
return result;
|
|
36875
36875
|
};
|
|
36876
|
-
exports2.resolve = function(
|
|
36877
|
-
var parts =
|
|
36876
|
+
exports2.resolve = function(path94) {
|
|
36877
|
+
var parts = path94.split("/");
|
|
36878
36878
|
var result = [];
|
|
36879
36879
|
for (var index = 0; index < parts.length; index++) {
|
|
36880
36880
|
var part = parts[index];
|
|
@@ -42727,18 +42727,18 @@ var require_object = __commonJS({
|
|
|
42727
42727
|
var object = new ZipObject(name, zipObjectContent, o);
|
|
42728
42728
|
this.files[name] = object;
|
|
42729
42729
|
};
|
|
42730
|
-
var parentFolder = function(
|
|
42731
|
-
if (
|
|
42732
|
-
|
|
42730
|
+
var parentFolder = function(path94) {
|
|
42731
|
+
if (path94.slice(-1) === "/") {
|
|
42732
|
+
path94 = path94.substring(0, path94.length - 1);
|
|
42733
42733
|
}
|
|
42734
|
-
var lastSlash =
|
|
42735
|
-
return lastSlash > 0 ?
|
|
42734
|
+
var lastSlash = path94.lastIndexOf("/");
|
|
42735
|
+
return lastSlash > 0 ? path94.substring(0, lastSlash) : "";
|
|
42736
42736
|
};
|
|
42737
|
-
var forceTrailingSlash = function(
|
|
42738
|
-
if (
|
|
42739
|
-
|
|
42737
|
+
var forceTrailingSlash = function(path94) {
|
|
42738
|
+
if (path94.slice(-1) !== "/") {
|
|
42739
|
+
path94 += "/";
|
|
42740
42740
|
}
|
|
42741
|
-
return
|
|
42741
|
+
return path94;
|
|
42742
42742
|
};
|
|
42743
42743
|
var folderAdd = function(name, createFolders) {
|
|
42744
42744
|
createFolders = typeof createFolders !== "undefined" ? createFolders : defaults.createFolders;
|
|
@@ -43740,7 +43740,7 @@ var require_lib3 = __commonJS({
|
|
|
43740
43740
|
// src/run-case/recorder.ts
|
|
43741
43741
|
function startRunCaseRecorder(opts) {
|
|
43742
43742
|
const now = opts.now ?? Date.now;
|
|
43743
|
-
const dir =
|
|
43743
|
+
const dir = import_node_path76.default.dirname(opts.recordPath);
|
|
43744
43744
|
let stream = null;
|
|
43745
43745
|
let closing = false;
|
|
43746
43746
|
let closedSettled = false;
|
|
@@ -43754,8 +43754,8 @@ function startRunCaseRecorder(opts) {
|
|
|
43754
43754
|
});
|
|
43755
43755
|
const ensureStream = () => {
|
|
43756
43756
|
if (stream) return stream;
|
|
43757
|
-
|
|
43758
|
-
stream =
|
|
43757
|
+
import_node_fs55.default.mkdirSync(dir, { recursive: true });
|
|
43758
|
+
stream = import_node_fs55.default.createWriteStream(opts.recordPath, { flags: "a" });
|
|
43759
43759
|
stream.on("close", () => closedResolve());
|
|
43760
43760
|
return stream;
|
|
43761
43761
|
};
|
|
@@ -43780,12 +43780,12 @@ function startRunCaseRecorder(opts) {
|
|
|
43780
43780
|
};
|
|
43781
43781
|
return { tap, close, closed };
|
|
43782
43782
|
}
|
|
43783
|
-
var
|
|
43783
|
+
var import_node_fs55, import_node_path76;
|
|
43784
43784
|
var init_recorder = __esm({
|
|
43785
43785
|
"src/run-case/recorder.ts"() {
|
|
43786
43786
|
"use strict";
|
|
43787
|
-
|
|
43788
|
-
|
|
43787
|
+
import_node_fs55 = __toESM(require("fs"), 1);
|
|
43788
|
+
import_node_path76 = __toESM(require("path"), 1);
|
|
43789
43789
|
}
|
|
43790
43790
|
});
|
|
43791
43791
|
|
|
@@ -43828,7 +43828,7 @@ var init_wire = __esm({
|
|
|
43828
43828
|
// src/run-case/controller.ts
|
|
43829
43829
|
async function runController(opts) {
|
|
43830
43830
|
const now = opts.now ?? Date.now;
|
|
43831
|
-
const cwd = opts.cwd ?? (0,
|
|
43831
|
+
const cwd = opts.cwd ?? (0, import_node_fs56.mkdtempSync)(import_node_path77.default.join(import_node_os27.default.tmpdir(), "clawd-runcase-"));
|
|
43832
43832
|
const ownsCwd = opts.cwd === void 0;
|
|
43833
43833
|
const recorder = startRunCaseRecorder({ recordPath: opts.record, now });
|
|
43834
43834
|
const spawnCtx = { cwd };
|
|
@@ -43989,19 +43989,19 @@ async function runController(opts) {
|
|
|
43989
43989
|
if (sigintHandler) process.off("SIGINT", sigintHandler);
|
|
43990
43990
|
if (ownsCwd) {
|
|
43991
43991
|
try {
|
|
43992
|
-
(0,
|
|
43992
|
+
(0, import_node_fs56.rmSync)(cwd, { recursive: true, force: true });
|
|
43993
43993
|
} catch {
|
|
43994
43994
|
}
|
|
43995
43995
|
}
|
|
43996
43996
|
return exitCode ?? 0;
|
|
43997
43997
|
}
|
|
43998
|
-
var
|
|
43998
|
+
var import_node_fs56, import_node_os27, import_node_path77;
|
|
43999
43999
|
var init_controller = __esm({
|
|
44000
44000
|
"src/run-case/controller.ts"() {
|
|
44001
44001
|
"use strict";
|
|
44002
|
-
|
|
44002
|
+
import_node_fs56 = require("fs");
|
|
44003
44003
|
import_node_os27 = __toESM(require("os"), 1);
|
|
44004
|
-
|
|
44004
|
+
import_node_path77 = __toESM(require("path"), 1);
|
|
44005
44005
|
init_claude();
|
|
44006
44006
|
init_stdout_splitter();
|
|
44007
44007
|
init_permission_stdio();
|
|
@@ -44276,8 +44276,8 @@ Env (advanced):
|
|
|
44276
44276
|
`;
|
|
44277
44277
|
|
|
44278
44278
|
// src/index.ts
|
|
44279
|
-
var
|
|
44280
|
-
var
|
|
44279
|
+
var import_node_path75 = __toESM(require("path"), 1);
|
|
44280
|
+
var import_node_fs54 = __toESM(require("fs"), 1);
|
|
44281
44281
|
var import_node_os26 = __toESM(require("os"), 1);
|
|
44282
44282
|
var import_node_crypto22 = require("crypto");
|
|
44283
44283
|
var import_node_url4 = require("url");
|
|
@@ -45582,7 +45582,9 @@ function buildSpawnContext(state, deps) {
|
|
|
45582
45582
|
if (dispatchId) env.CLAWD_DISPATCH_ID = dispatchId;
|
|
45583
45583
|
const personaId2 = file.ownerPersonaId;
|
|
45584
45584
|
if (personaId2) env.CLAWD_PERSONA_ID = personaId2;
|
|
45585
|
-
const mcpConfigs = deps.getMcpConfigs?.() ?? []
|
|
45585
|
+
const mcpConfigs = (deps.getMcpConfigs?.() ?? []).filter(
|
|
45586
|
+
(c) => !c.personas || personaId2 != null && c.personas.includes(personaId2)
|
|
45587
|
+
);
|
|
45586
45588
|
const ctx = {
|
|
45587
45589
|
cwd: file.cwd,
|
|
45588
45590
|
toolSessionId: file.toolSessionId,
|
|
@@ -51424,8 +51426,8 @@ function turnStartInput(text) {
|
|
|
51424
51426
|
const items = [];
|
|
51425
51427
|
let leftover = text;
|
|
51426
51428
|
for (const m2 of text.matchAll(SKILL_RE)) {
|
|
51427
|
-
const [marker, name,
|
|
51428
|
-
items.push({ type: "skill", name, path:
|
|
51429
|
+
const [marker, name, path94] = m2;
|
|
51430
|
+
items.push({ type: "skill", name, path: path94 });
|
|
51429
51431
|
leftover = leftover.replace(marker, "");
|
|
51430
51432
|
}
|
|
51431
51433
|
for (const m2 of text.matchAll(ATTACHMENT_RE2)) {
|
|
@@ -54423,13 +54425,20 @@ function buildDeployHandlers(deps) {
|
|
|
54423
54425
|
if (!deps.hasPersona(args.personaId)) {
|
|
54424
54426
|
throw new ClawdError(ERROR_CODES.PERSONA_NOT_FOUND, `PERSONA_NOT_FOUND: \u6CA1\u6709\u8FD9\u4E2A persona\uFF08${args.personaId}\uFF09`);
|
|
54425
54427
|
}
|
|
54426
|
-
const
|
|
54427
|
-
if (
|
|
54428
|
+
const inFlight = deps.receipts.list().find((r) => r.personaId === args.personaId && r.status === "scanning");
|
|
54429
|
+
if (inFlight) return view(inFlight);
|
|
54430
|
+
const prev = deps.receipts.list().find((r) => r.personaId === args.personaId);
|
|
54428
54431
|
const receipt = deps.receipts.create({
|
|
54429
54432
|
deployId: deps.genId(),
|
|
54430
54433
|
personaId: args.personaId,
|
|
54431
54434
|
status: "scanning"
|
|
54432
54435
|
});
|
|
54436
|
+
if (prev) {
|
|
54437
|
+
deps.secrets.copyDeployment(prev.deployId, receipt.deployId);
|
|
54438
|
+
if (Object.keys(prev.fulfillment).length > 0) {
|
|
54439
|
+
deps.receipts.update(receipt.deployId, { fulfillment: prev.fulfillment });
|
|
54440
|
+
}
|
|
54441
|
+
}
|
|
54433
54442
|
const scanSessionId = deps.startScan(receipt.deployId, args.personaId);
|
|
54434
54443
|
if (scanSessionId) deps.receipts.update(receipt.deployId, { scanSessionId });
|
|
54435
54444
|
return view(deps.receipts.get(receipt.deployId) ?? receipt);
|
|
@@ -54704,6 +54713,18 @@ function createSecretStore(deps) {
|
|
|
54704
54713
|
}
|
|
54705
54714
|
scheduleFlush();
|
|
54706
54715
|
},
|
|
54716
|
+
copyDeployment(fromDeployId, toDeployId) {
|
|
54717
|
+
const src = entries.filter((e) => e.deployId === fromDeployId);
|
|
54718
|
+
let copied = 0;
|
|
54719
|
+
for (const e of src) {
|
|
54720
|
+
const exists = entries.some((x) => sameScope(x, toDeployId, e.name, e.userId));
|
|
54721
|
+
if (exists) continue;
|
|
54722
|
+
entries.push({ ...e, deployId: toDeployId, updatedAt: deps.now() });
|
|
54723
|
+
copied++;
|
|
54724
|
+
}
|
|
54725
|
+
if (copied > 0) scheduleFlush();
|
|
54726
|
+
return copied;
|
|
54727
|
+
},
|
|
54707
54728
|
resolve(deployId, userId) {
|
|
54708
54729
|
const out = {};
|
|
54709
54730
|
for (const e of entries) {
|
|
@@ -56518,13 +56539,13 @@ function mapSkillsListResponse(res) {
|
|
|
56518
56539
|
const r = s ?? {};
|
|
56519
56540
|
const name = str3(r.name);
|
|
56520
56541
|
if (!name) continue;
|
|
56521
|
-
const
|
|
56542
|
+
const path94 = str3(r.path);
|
|
56522
56543
|
const description = str3(r.description);
|
|
56523
56544
|
const isPlugin = name.includes(":");
|
|
56524
56545
|
out.push({
|
|
56525
56546
|
name,
|
|
56526
56547
|
source: isPlugin ? "plugin" : "project",
|
|
56527
|
-
...
|
|
56548
|
+
...path94 ? { path: path94 } : {},
|
|
56528
56549
|
...description ? { description } : {},
|
|
56529
56550
|
...isPlugin ? { plugin: name.split(":")[0] } : {}
|
|
56530
56551
|
});
|
|
@@ -60846,9 +60867,9 @@ var CentralClientError = class extends Error {
|
|
|
60846
60867
|
code;
|
|
60847
60868
|
cause;
|
|
60848
60869
|
};
|
|
60849
|
-
async function centralRequest(opts,
|
|
60870
|
+
async function centralRequest(opts, path94, init) {
|
|
60850
60871
|
const f = opts.fetchImpl ?? globalThis.fetch;
|
|
60851
|
-
const url = `${opts.api.replace(/\/+$/, "")}${
|
|
60872
|
+
const url = `${opts.api.replace(/\/+$/, "")}${path94}`;
|
|
60852
60873
|
const ctrl = new AbortController();
|
|
60853
60874
|
const timer = setTimeout(() => ctrl.abort(), opts.timeoutMs ?? 15e3);
|
|
60854
60875
|
let res;
|
|
@@ -61329,7 +61350,7 @@ var ServerKeyStore = class {
|
|
|
61329
61350
|
init_protocol();
|
|
61330
61351
|
|
|
61331
61352
|
// src/handlers/index.ts
|
|
61332
|
-
var
|
|
61353
|
+
var import_node_path68 = __toESM(require("path"), 1);
|
|
61333
61354
|
|
|
61334
61355
|
// src/handlers/session.ts
|
|
61335
61356
|
init_protocol();
|
|
@@ -63670,7 +63691,7 @@ function computeMethodAccess(args) {
|
|
|
63670
63691
|
}
|
|
63671
63692
|
|
|
63672
63693
|
// src/version.ts
|
|
63673
|
-
var version = "0.2.
|
|
63694
|
+
var version = "0.2.454".length > 0 ? "0.2.454" : "dev";
|
|
63674
63695
|
|
|
63675
63696
|
// src/cli-probe/probe.ts
|
|
63676
63697
|
var fs68 = __toESM(require("fs"), 1);
|
|
@@ -64698,218 +64719,8 @@ function buildExtensionHandlers(deps) {
|
|
|
64698
64719
|
};
|
|
64699
64720
|
}
|
|
64700
64721
|
|
|
64701
|
-
// src/app-builder/project-store.ts
|
|
64702
|
-
var import_node_fs50 = require("fs");
|
|
64703
|
-
var import_node_child_process15 = require("child_process");
|
|
64704
|
-
var import_node_path65 = require("path");
|
|
64705
|
-
init_protocol();
|
|
64706
|
-
var PROJECTS_DIR = "projects";
|
|
64707
|
-
var META_FILE = ".clawd-project.json";
|
|
64708
|
-
var DEFAULT_TEMPLATE = "nestjs-react";
|
|
64709
|
-
var SCAFFOLD_TIMEOUT_MS = 3e4;
|
|
64710
|
-
var ProjectStore = class {
|
|
64711
|
-
/** @param root projects 父目录,例如 `~/.clawd/users/<userId>/`(v2 per-user) */
|
|
64712
|
-
constructor(root) {
|
|
64713
|
-
this.root = root;
|
|
64714
|
-
}
|
|
64715
|
-
root;
|
|
64716
|
-
/** projects/<name>/.clawd-project.json 路径 */
|
|
64717
|
-
metaPath(name) {
|
|
64718
|
-
return (0, import_node_path65.join)(this.projectsRoot(), name, META_FILE);
|
|
64719
|
-
}
|
|
64720
|
-
/** projects/<name>/ 目录路径(cwd 用) */
|
|
64721
|
-
projectDir(name) {
|
|
64722
|
-
return (0, import_node_path65.join)(this.projectsRoot(), name);
|
|
64723
|
-
}
|
|
64724
|
-
projectsRoot() {
|
|
64725
|
-
return (0, import_node_path65.join)(this.root, PROJECTS_DIR);
|
|
64726
|
-
}
|
|
64727
|
-
async list() {
|
|
64728
|
-
let entries;
|
|
64729
|
-
try {
|
|
64730
|
-
entries = await import_node_fs50.promises.readdir(this.projectsRoot());
|
|
64731
|
-
} catch (err) {
|
|
64732
|
-
if (err.code === "ENOENT") return [];
|
|
64733
|
-
throw err;
|
|
64734
|
-
}
|
|
64735
|
-
const out = [];
|
|
64736
|
-
for (const name of entries) {
|
|
64737
|
-
try {
|
|
64738
|
-
const raw = await import_node_fs50.promises.readFile(this.metaPath(name), "utf8");
|
|
64739
|
-
const json = JSON.parse(raw);
|
|
64740
|
-
let migrated = false;
|
|
64741
|
-
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
64742
|
-
json.devCommand = DEFAULT_DEV_COMMAND;
|
|
64743
|
-
migrated = true;
|
|
64744
|
-
}
|
|
64745
|
-
const parsed = ProjectMetadataSchema.safeParse(json);
|
|
64746
|
-
if (parsed.success) {
|
|
64747
|
-
out.push(parsed.data);
|
|
64748
|
-
if (migrated) {
|
|
64749
|
-
void import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
64750
|
-
});
|
|
64751
|
-
}
|
|
64752
|
-
}
|
|
64753
|
-
} catch {
|
|
64754
|
-
}
|
|
64755
|
-
}
|
|
64756
|
-
return out.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
64757
|
-
}
|
|
64758
|
-
/**
|
|
64759
|
-
* @param reservedPorts 其它 user 已占端口(v2 per-user:端口必须全局唯一,所有 user 的
|
|
64760
|
-
* dev server 同机跑;per-user store 各自只 list 自己,靠 handler 收集全局端口传进来,
|
|
64761
|
-
* 否则不同 user 的首个项目都从 PROJECT_PORT_MIN 起 → 全撞 6173)。
|
|
64762
|
-
*/
|
|
64763
|
-
async create(name, reservedPorts) {
|
|
64764
|
-
const existing = await this.list();
|
|
64765
|
-
if (existing.some((p2) => p2.name === name)) {
|
|
64766
|
-
throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
|
|
64767
|
-
}
|
|
64768
|
-
const usedPorts = new Set(existing.map((p2) => p2.port));
|
|
64769
|
-
if (reservedPorts) for (const p2 of reservedPorts) usedPorts.add(p2);
|
|
64770
|
-
let port = -1;
|
|
64771
|
-
for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
|
|
64772
|
-
if (!usedPorts.has(p2)) {
|
|
64773
|
-
port = p2;
|
|
64774
|
-
break;
|
|
64775
|
-
}
|
|
64776
|
-
}
|
|
64777
|
-
if (port < 0) {
|
|
64778
|
-
throw new Error(
|
|
64779
|
-
`port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
|
|
64780
|
-
);
|
|
64781
|
-
}
|
|
64782
|
-
const meta = {
|
|
64783
|
-
name,
|
|
64784
|
-
port,
|
|
64785
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
64786
|
-
devCommand: DEFAULT_DEV_COMMAND
|
|
64787
|
-
};
|
|
64788
|
-
const validated = ProjectMetadataSchema.safeParse(meta);
|
|
64789
|
-
if (!validated.success) {
|
|
64790
|
-
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
64791
|
-
}
|
|
64792
|
-
const dir = this.projectDir(name);
|
|
64793
|
-
await import_node_fs50.promises.mkdir(dir, { recursive: true });
|
|
64794
|
-
await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
64795
|
-
return meta;
|
|
64796
|
-
}
|
|
64797
|
-
/**
|
|
64798
|
-
* 同步内联 scaffold:spawn `extension-kit/scripts/new-extension.sh <name>` 等 exit。
|
|
64799
|
-
* 必须在 `create()` 之后调(脚本期望 projects/<name>/.clawd-project.json 已就位 = picker 模式)。
|
|
64800
|
-
* 失败抛错;上层(handler)应当 catch 后回滚(删 dir + 不 mutate session)。
|
|
64801
|
-
*
|
|
64802
|
-
* spec 2026-06-02 §5.6.3:scaffold 对 assistant 不可见,避免 assistant 被诱导去"读 example
|
|
64803
|
-
* 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
|
|
64804
|
-
*/
|
|
64805
|
-
async scaffold(name, templateSrcDir, scaffoldScriptPath) {
|
|
64806
|
-
const destDir = this.projectDir(name);
|
|
64807
|
-
return await new Promise((resolve9, reject) => {
|
|
64808
|
-
const child = (0, import_node_child_process15.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
|
|
64809
|
-
env: { ...process.env, PATH: process.env.PATH ?? "" },
|
|
64810
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
64811
|
-
});
|
|
64812
|
-
let stdout = "";
|
|
64813
|
-
let stderr = "";
|
|
64814
|
-
child.stdout.on("data", (d) => {
|
|
64815
|
-
stdout += d.toString("utf8");
|
|
64816
|
-
});
|
|
64817
|
-
child.stderr.on("data", (d) => {
|
|
64818
|
-
stderr += d.toString("utf8");
|
|
64819
|
-
});
|
|
64820
|
-
const timer = setTimeout(() => {
|
|
64821
|
-
child.kill("SIGKILL");
|
|
64822
|
-
reject(new Error(`scaffold timeout (>${SCAFFOLD_TIMEOUT_MS}ms): ${scaffoldScriptPath} ${name}`));
|
|
64823
|
-
}, SCAFFOLD_TIMEOUT_MS);
|
|
64824
|
-
child.on("error", (err) => {
|
|
64825
|
-
clearTimeout(timer);
|
|
64826
|
-
reject(new Error(`scaffold spawn failed: ${err.message}`));
|
|
64827
|
-
});
|
|
64828
|
-
child.on("exit", (code, signal) => {
|
|
64829
|
-
clearTimeout(timer);
|
|
64830
|
-
if (code === 0) resolve9({ stdout, stderr });
|
|
64831
|
-
else reject(new Error(`scaffold exit ${code ?? signal}: ${stderr.slice(0, 500)}`));
|
|
64832
|
-
});
|
|
64833
|
-
});
|
|
64834
|
-
}
|
|
64835
|
-
async delete(name) {
|
|
64836
|
-
const dir = this.projectDir(name);
|
|
64837
|
-
await import_node_fs50.promises.rm(dir, { recursive: true, force: true });
|
|
64838
|
-
}
|
|
64839
|
-
async updatePort(name, newPort) {
|
|
64840
|
-
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
64841
|
-
throw new Error(
|
|
64842
|
-
`port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
|
|
64843
|
-
);
|
|
64844
|
-
}
|
|
64845
|
-
const list = await this.list();
|
|
64846
|
-
const target = list.find((p2) => p2.name === name);
|
|
64847
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
64848
|
-
const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
|
|
64849
|
-
if (conflict) {
|
|
64850
|
-
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
64851
|
-
}
|
|
64852
|
-
const updated = { ...target, port: newPort };
|
|
64853
|
-
await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
64854
|
-
return updated;
|
|
64855
|
-
}
|
|
64856
|
-
/**
|
|
64857
|
-
* 单栏 refactor (spec 2026-06-02 §5.6.1):发布上线后写公网 URL 到 .clawd-project.json.prodUrl。
|
|
64858
|
-
* UI 通过 listProjects 读到 prodUrl 后切预览栏到线上 URL,取代旧 prod marker 机制。
|
|
64859
|
-
* 重复调用幂等(覆盖旧 URL)。url 由 ProjectMetadataSchema 校验 url() 格式。
|
|
64860
|
-
*/
|
|
64861
|
-
async setProdUrl(name, url) {
|
|
64862
|
-
const list = await this.list();
|
|
64863
|
-
const target = list.find((p2) => p2.name === name);
|
|
64864
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
64865
|
-
const updated = { ...target, prodUrl: url };
|
|
64866
|
-
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
64867
|
-
if (!validated.success) {
|
|
64868
|
-
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
64869
|
-
}
|
|
64870
|
-
await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
64871
|
-
return validated.data;
|
|
64872
|
-
}
|
|
64873
|
-
/**
|
|
64874
|
-
* 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
|
|
64875
|
-
* 写 publishJob 字段到 .clawd-project.json。仅承载 in-flight 状态 ——
|
|
64876
|
-
* - daemon 收到第一个 ::stage::build marker 时写入
|
|
64877
|
-
* - 每次 stage 切换更新 stage 字段(jobId / startedAt 不变)
|
|
64878
|
-
* - 成功 / 失败 / dismiss 时调 clearPublishJob 清掉
|
|
64879
|
-
* - 只有 daemon 崩才会留残骸
|
|
64880
|
-
* 写入时保留所有其他字段(prodUrl 等不受影响)。
|
|
64881
|
-
*/
|
|
64882
|
-
async setPublishJob(name, job) {
|
|
64883
|
-
const list = await this.list();
|
|
64884
|
-
const target = list.find((p2) => p2.name === name);
|
|
64885
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
64886
|
-
const updated = { ...target, publishJob: job };
|
|
64887
|
-
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
64888
|
-
if (!validated.success) {
|
|
64889
|
-
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
64890
|
-
}
|
|
64891
|
-
await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
64892
|
-
return validated.data;
|
|
64893
|
-
}
|
|
64894
|
-
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
64895
|
-
async clearPublishJob(name) {
|
|
64896
|
-
const list = await this.list();
|
|
64897
|
-
const target = list.find((p2) => p2.name === name);
|
|
64898
|
-
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
64899
|
-
if (!target.publishJob) return target;
|
|
64900
|
-
const { publishJob: _drop, ...rest } = target;
|
|
64901
|
-
void _drop;
|
|
64902
|
-
const validated = ProjectMetadataSchema.safeParse(rest);
|
|
64903
|
-
if (!validated.success) {
|
|
64904
|
-
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
64905
|
-
}
|
|
64906
|
-
await import_node_fs50.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
64907
|
-
return validated.data;
|
|
64908
|
-
}
|
|
64909
|
-
};
|
|
64910
|
-
|
|
64911
64722
|
// src/app-builder/kill-port.ts
|
|
64912
|
-
var
|
|
64723
|
+
var import_node_child_process15 = require("child_process");
|
|
64913
64724
|
async function killPortOccupants(port, ownedPids, logger) {
|
|
64914
64725
|
let pids;
|
|
64915
64726
|
try {
|
|
@@ -64951,7 +64762,7 @@ async function killPortOccupants(port, ownedPids, logger) {
|
|
|
64951
64762
|
}
|
|
64952
64763
|
function listPidsOnPort(port) {
|
|
64953
64764
|
return new Promise((resolve9, reject) => {
|
|
64954
|
-
(0,
|
|
64765
|
+
(0, import_node_child_process15.execFile)(
|
|
64955
64766
|
"lsof",
|
|
64956
64767
|
["-ti", `:${port}`],
|
|
64957
64768
|
{ timeout: 3e3 },
|
|
@@ -64972,361 +64783,15 @@ function listPidsOnPort(port) {
|
|
|
64972
64783
|
});
|
|
64973
64784
|
}
|
|
64974
64785
|
|
|
64975
|
-
// src/app-builder/
|
|
64976
|
-
var
|
|
64977
|
-
var PublishJobRegistry = class {
|
|
64978
|
-
jobs = /* @__PURE__ */ new Map();
|
|
64979
|
-
has(name) {
|
|
64980
|
-
return this.jobs.has(name);
|
|
64981
|
-
}
|
|
64982
|
-
get(name) {
|
|
64983
|
-
return this.jobs.get(name);
|
|
64984
|
-
}
|
|
64985
|
-
/**
|
|
64986
|
-
* args.jobId 仅用于测试注入;生产代码不传,registry 自己生成。
|
|
64987
|
-
* args.now 仅用于测试注入;生产代码不传,用 Date.now()。
|
|
64988
|
-
*/
|
|
64989
|
-
create(args) {
|
|
64990
|
-
if (this.jobs.has(args.name)) {
|
|
64991
|
-
throw new Error(`already publishing: ${args.name}`);
|
|
64992
|
-
}
|
|
64993
|
-
const jobId = args.jobId ?? `job-${(0, import_node_crypto20.randomUUID)()}`;
|
|
64994
|
-
this.jobs.set(args.name, {
|
|
64995
|
-
jobId,
|
|
64996
|
-
name: args.name,
|
|
64997
|
-
stage: "build",
|
|
64998
|
-
sessionId: args.sessionId,
|
|
64999
|
-
childProc: args.childProc,
|
|
65000
|
-
dismissed: false,
|
|
65001
|
-
sawAnyStage: false,
|
|
65002
|
-
startedAt: args.now ?? Date.now()
|
|
65003
|
-
});
|
|
65004
|
-
return jobId;
|
|
65005
|
-
}
|
|
65006
|
-
updateStage(name, stage) {
|
|
65007
|
-
const job = this.jobs.get(name);
|
|
65008
|
-
if (!job) return;
|
|
65009
|
-
job.stage = stage;
|
|
65010
|
-
job.sawAnyStage = true;
|
|
65011
|
-
}
|
|
65012
|
-
markDismissed(name) {
|
|
65013
|
-
const job = this.jobs.get(name);
|
|
65014
|
-
if (!job) return;
|
|
65015
|
-
job.dismissed = true;
|
|
65016
|
-
}
|
|
65017
|
-
remove(name) {
|
|
65018
|
-
const job = this.jobs.get(name);
|
|
65019
|
-
if (!job) return void 0;
|
|
65020
|
-
this.jobs.delete(name);
|
|
65021
|
-
return { sessionId: job.sessionId };
|
|
65022
|
-
}
|
|
65023
|
-
};
|
|
65024
|
-
|
|
65025
|
-
// src/app-builder/publish-job-runner.ts
|
|
65026
|
-
var import_node_child_process17 = require("child_process");
|
|
65027
|
-
var import_node_fs51 = require("fs");
|
|
65028
|
-
var import_node_path66 = require("path");
|
|
65029
|
-
|
|
65030
|
-
// src/app-builder/publish-stage-parser.ts
|
|
65031
|
-
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
65032
|
-
var PROD_URL_RE = /^\s*::prod-url::(\S+)\s*$/;
|
|
65033
|
-
var URL_RE = /\bhttps?:\/\/[^\s]+/;
|
|
65034
|
-
function parsePublishLine(line) {
|
|
65035
|
-
const stageMatch = STAGE_RE.exec(line);
|
|
65036
|
-
if (stageMatch) return { kind: "stage", stage: stageMatch[1] };
|
|
65037
|
-
const urlMatch = PROD_URL_RE.exec(line);
|
|
65038
|
-
if (urlMatch) return { kind: "prod-url", url: urlMatch[1] };
|
|
65039
|
-
return null;
|
|
65040
|
-
}
|
|
65041
|
-
function extractProdUrl(text) {
|
|
65042
|
-
const m2 = URL_RE.exec(text);
|
|
65043
|
-
return m2 ? m2[0] : null;
|
|
65044
|
-
}
|
|
65045
|
-
function tailStderrLines(buf, n) {
|
|
65046
|
-
if (!buf) return "";
|
|
65047
|
-
const lines = buf.split("\n");
|
|
65048
|
-
if (lines.length <= n) return buf;
|
|
65049
|
-
return lines.slice(lines.length - n).join("\n");
|
|
65050
|
-
}
|
|
65051
|
-
|
|
65052
|
-
// src/app-builder/publish-job-runner.ts
|
|
65053
|
-
async function startPublishJob(deps, args) {
|
|
65054
|
-
const { registry: registry2, projectDir } = deps;
|
|
65055
|
-
const spawn13 = deps.spawnImpl ?? import_node_child_process17.spawn;
|
|
65056
|
-
if (registry2.has(args.name)) {
|
|
65057
|
-
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
65058
|
-
}
|
|
65059
|
-
const projDir = projectDir(args.name);
|
|
65060
|
-
const logPath = (0, import_node_path66.join)(projDir, ".publish.log");
|
|
65061
|
-
let logStream = null;
|
|
65062
|
-
try {
|
|
65063
|
-
logStream = (0, import_node_fs51.createWriteStream)(logPath, { flags: "w" });
|
|
65064
|
-
} catch {
|
|
65065
|
-
logStream = null;
|
|
65066
|
-
}
|
|
65067
|
-
const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
|
|
65068
|
-
cwd: projDir,
|
|
65069
|
-
env: process.env,
|
|
65070
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
65071
|
-
});
|
|
65072
|
-
const jobId = registry2.create({
|
|
65073
|
-
name: args.name,
|
|
65074
|
-
sessionId: args.sessionId,
|
|
65075
|
-
childProc: child
|
|
65076
|
-
});
|
|
65077
|
-
deps.logger?.info("app-builder.publish.spawned", {
|
|
65078
|
-
name: args.name,
|
|
65079
|
-
jobId,
|
|
65080
|
-
pid: child.pid ?? null,
|
|
65081
|
-
scriptPath: args.scriptPath,
|
|
65082
|
-
logPath
|
|
65083
|
-
});
|
|
65084
|
-
child.on("error", (err) => {
|
|
65085
|
-
deps.logger?.warn("app-builder.publish.spawn-error", {
|
|
65086
|
-
name: args.name,
|
|
65087
|
-
jobId,
|
|
65088
|
-
error: err instanceof Error ? err.message : String(err)
|
|
65089
|
-
});
|
|
65090
|
-
void handleExit(deps, {
|
|
65091
|
-
name: args.name,
|
|
65092
|
-
jobId,
|
|
65093
|
-
code: null,
|
|
65094
|
-
signal: null,
|
|
65095
|
-
urlCandidate: null,
|
|
65096
|
-
stderrTail: err instanceof Error ? err.message : String(err),
|
|
65097
|
-
logPath
|
|
65098
|
-
});
|
|
65099
|
-
});
|
|
65100
|
-
let urlFromMarker = null;
|
|
65101
|
-
let urlFallback = null;
|
|
65102
|
-
let stdoutBuf = "";
|
|
65103
|
-
child.stdout?.on("data", (chunk) => {
|
|
65104
|
-
if (logStream) logStream.write(chunk);
|
|
65105
|
-
stdoutBuf += chunk.toString();
|
|
65106
|
-
let nlIdx;
|
|
65107
|
-
while ((nlIdx = stdoutBuf.indexOf("\n")) >= 0) {
|
|
65108
|
-
const line = stdoutBuf.slice(0, nlIdx);
|
|
65109
|
-
stdoutBuf = stdoutBuf.slice(nlIdx + 1);
|
|
65110
|
-
handleStdoutLine(deps, args.name, jobId, line);
|
|
65111
|
-
const parsedForUrl = parsePublishLine(line);
|
|
65112
|
-
if (parsedForUrl?.kind === "prod-url") urlFromMarker = parsedForUrl.url;
|
|
65113
|
-
const url = extractProdUrl(line);
|
|
65114
|
-
if (url && !urlFallback) urlFallback = url;
|
|
65115
|
-
}
|
|
65116
|
-
});
|
|
65117
|
-
let stderrBuf = "";
|
|
65118
|
-
child.stderr?.on("data", (chunk) => {
|
|
65119
|
-
if (logStream) logStream.write(chunk);
|
|
65120
|
-
stderrBuf += chunk.toString();
|
|
65121
|
-
});
|
|
65122
|
-
child.on("exit", (code, signal) => {
|
|
65123
|
-
if (logStream) logStream.end();
|
|
65124
|
-
const urlCandidate = urlFromMarker ?? urlFallback;
|
|
65125
|
-
deps.logger?.info("app-builder.publish.child-exit", {
|
|
65126
|
-
name: args.name,
|
|
65127
|
-
jobId,
|
|
65128
|
-
code,
|
|
65129
|
-
signal,
|
|
65130
|
-
hadUrl: !!urlCandidate,
|
|
65131
|
-
urlSource: urlFromMarker ? "marker" : urlFallback ? "fallback" : "none",
|
|
65132
|
-
stderrBytes: stderrBuf.length
|
|
65133
|
-
});
|
|
65134
|
-
void handleExit(deps, {
|
|
65135
|
-
name: args.name,
|
|
65136
|
-
jobId,
|
|
65137
|
-
code,
|
|
65138
|
-
signal,
|
|
65139
|
-
urlCandidate,
|
|
65140
|
-
stderrTail: tailStderrLines(stderrBuf, 20),
|
|
65141
|
-
logPath
|
|
65142
|
-
});
|
|
65143
|
-
});
|
|
65144
|
-
return { jobId, status: "started" };
|
|
65145
|
-
}
|
|
65146
|
-
function handleStdoutLine(deps, name, jobId, line) {
|
|
65147
|
-
const parsed = parsePublishLine(line);
|
|
65148
|
-
if (parsed?.kind !== "stage") return;
|
|
65149
|
-
advanceStage(deps, name, jobId, parsed.stage);
|
|
65150
|
-
}
|
|
65151
|
-
function advanceStage(deps, name, jobId, next) {
|
|
65152
|
-
const job = deps.registry.get(name);
|
|
65153
|
-
if (!job) return;
|
|
65154
|
-
const prev = job.stage;
|
|
65155
|
-
const wasFirstStage = !job.sawAnyStage;
|
|
65156
|
-
deps.logger?.info("app-builder.publish.stage-advance", {
|
|
65157
|
-
name,
|
|
65158
|
-
jobId,
|
|
65159
|
-
prev: wasFirstStage ? null : prev,
|
|
65160
|
-
next,
|
|
65161
|
-
firstStage: wasFirstStage
|
|
65162
|
-
});
|
|
65163
|
-
if (wasFirstStage) {
|
|
65164
|
-
deps.registry.updateStage(name, next);
|
|
65165
|
-
void deps.setPublishJob(name, {
|
|
65166
|
-
jobId,
|
|
65167
|
-
stage: next,
|
|
65168
|
-
startedAt: job.startedAt
|
|
65169
|
-
});
|
|
65170
|
-
deps.broadcast({
|
|
65171
|
-
type: "appBuilder:publish-progress",
|
|
65172
|
-
name,
|
|
65173
|
-
jobId,
|
|
65174
|
-
stage: next,
|
|
65175
|
-
status: "started"
|
|
65176
|
-
});
|
|
65177
|
-
return;
|
|
65178
|
-
}
|
|
65179
|
-
if (prev === next) {
|
|
65180
|
-
return;
|
|
65181
|
-
}
|
|
65182
|
-
deps.broadcast({
|
|
65183
|
-
type: "appBuilder:publish-progress",
|
|
65184
|
-
name,
|
|
65185
|
-
jobId,
|
|
65186
|
-
stage: prev,
|
|
65187
|
-
status: "completed"
|
|
65188
|
-
});
|
|
65189
|
-
deps.registry.updateStage(name, next);
|
|
65190
|
-
void deps.setPublishJob(name, {
|
|
65191
|
-
jobId,
|
|
65192
|
-
stage: next,
|
|
65193
|
-
startedAt: job.startedAt
|
|
65194
|
-
});
|
|
65195
|
-
deps.broadcast({
|
|
65196
|
-
type: "appBuilder:publish-progress",
|
|
65197
|
-
name,
|
|
65198
|
-
jobId,
|
|
65199
|
-
stage: next,
|
|
65200
|
-
status: "started"
|
|
65201
|
-
});
|
|
65202
|
-
}
|
|
65203
|
-
async function handleExit(deps, args) {
|
|
65204
|
-
const job = deps.registry.get(args.name);
|
|
65205
|
-
if (args.signal === "SIGTERM" && job?.dismissed) {
|
|
65206
|
-
try {
|
|
65207
|
-
await deps.clearPublishJob(args.name);
|
|
65208
|
-
} catch (err) {
|
|
65209
|
-
console.error("[publish] clearPublishJob failed (dismissed branch)", err);
|
|
65210
|
-
}
|
|
65211
|
-
deps.registry.remove(args.name);
|
|
65212
|
-
return;
|
|
65213
|
-
}
|
|
65214
|
-
if (args.code === 0 && args.urlCandidate) {
|
|
65215
|
-
if (job?.sawAnyStage) {
|
|
65216
|
-
deps.broadcast({
|
|
65217
|
-
type: "appBuilder:publish-progress",
|
|
65218
|
-
name: args.name,
|
|
65219
|
-
jobId: args.jobId,
|
|
65220
|
-
stage: job.stage,
|
|
65221
|
-
status: "completed"
|
|
65222
|
-
});
|
|
65223
|
-
}
|
|
65224
|
-
try {
|
|
65225
|
-
await deps.setProdUrl(args.name, args.urlCandidate);
|
|
65226
|
-
} catch (err) {
|
|
65227
|
-
console.error("[publish] setProdUrl failed; falling through to failure branch", err);
|
|
65228
|
-
await emitFailure(deps, args, "\u8C03 setProdUrl \u5931\u8D25\uFF1A" + (err instanceof Error ? err.message : String(err)));
|
|
65229
|
-
return;
|
|
65230
|
-
}
|
|
65231
|
-
try {
|
|
65232
|
-
await deps.clearPublishJob(args.name);
|
|
65233
|
-
} catch (err) {
|
|
65234
|
-
console.error("[publish] clearPublishJob failed (success branch)", err);
|
|
65235
|
-
}
|
|
65236
|
-
deps.registry.remove(args.name);
|
|
65237
|
-
return;
|
|
65238
|
-
}
|
|
65239
|
-
await emitFailure(deps, args, buildErrorSummary(args));
|
|
65240
|
-
}
|
|
65241
|
-
async function emitFailure(deps, args, errorSummary) {
|
|
65242
|
-
const job = deps.registry.get(args.name);
|
|
65243
|
-
const failStage = job?.sawAnyStage ? job.stage : "unknown";
|
|
65244
|
-
deps.logger?.warn("app-builder.publish.failed", {
|
|
65245
|
-
name: args.name,
|
|
65246
|
-
jobId: args.jobId,
|
|
65247
|
-
stage: failStage,
|
|
65248
|
-
errorSummary: errorSummary.slice(0, 500)
|
|
65249
|
-
});
|
|
65250
|
-
try {
|
|
65251
|
-
await deps.clearPublishJob(args.name);
|
|
65252
|
-
} catch (err) {
|
|
65253
|
-
deps.logger?.warn("app-builder.publish.clear-field-failed", {
|
|
65254
|
-
name: args.name,
|
|
65255
|
-
jobId: args.jobId,
|
|
65256
|
-
error: err instanceof Error ? err.message : String(err)
|
|
65257
|
-
});
|
|
65258
|
-
}
|
|
65259
|
-
const removed = deps.registry.remove(args.name);
|
|
65260
|
-
deps.broadcast({
|
|
65261
|
-
type: "appBuilder:publish-failed",
|
|
65262
|
-
name: args.name,
|
|
65263
|
-
jobId: args.jobId,
|
|
65264
|
-
stage: failStage,
|
|
65265
|
-
errorSummary
|
|
65266
|
-
});
|
|
65267
|
-
if (removed) {
|
|
65268
|
-
const msg = formatFailureMessage(failStage, errorSummary, args.logPath);
|
|
65269
|
-
try {
|
|
65270
|
-
await deps.injectUserText(removed.sessionId, msg);
|
|
65271
|
-
deps.logger?.info("app-builder.publish.failure-injected-to-chat", {
|
|
65272
|
-
name: args.name,
|
|
65273
|
-
jobId: args.jobId,
|
|
65274
|
-
sessionId: removed.sessionId
|
|
65275
|
-
});
|
|
65276
|
-
} catch (err) {
|
|
65277
|
-
deps.logger?.warn("app-builder.publish.inject-user-text-failed", {
|
|
65278
|
-
name: args.name,
|
|
65279
|
-
jobId: args.jobId,
|
|
65280
|
-
sessionId: removed.sessionId,
|
|
65281
|
-
error: err instanceof Error ? err.message : String(err)
|
|
65282
|
-
});
|
|
65283
|
-
}
|
|
65284
|
-
} else {
|
|
65285
|
-
deps.logger?.warn("app-builder.publish.no-registry-entry-on-failure", {
|
|
65286
|
-
name: args.name,
|
|
65287
|
-
jobId: args.jobId
|
|
65288
|
-
});
|
|
65289
|
-
}
|
|
65290
|
-
}
|
|
65291
|
-
function buildErrorSummary(args) {
|
|
65292
|
-
if (args.signal) {
|
|
65293
|
-
return `publish.sh \u88AB\u4E2D\u65AD\uFF08signal: ${args.signal}\uFF09`;
|
|
65294
|
-
}
|
|
65295
|
-
if (args.code === 0 && !args.urlCandidate) {
|
|
65296
|
-
return "publish.sh \u6210\u529F\u9000\u51FA\u4F46\u672A\u8F93\u51FA\u516C\u7F51 URL";
|
|
65297
|
-
}
|
|
65298
|
-
return args.stderrTail || `publish.sh \u5F02\u5E38\u9000\u51FA\uFF08exit code: ${args.code}\uFF09`;
|
|
65299
|
-
}
|
|
65300
|
-
function formatFailureMessage(stage, errorSummary, logPath) {
|
|
65301
|
-
return `\u53D1\u5E03\u5931\u8D25\uFF1A[${stage}] \u9636\u6BB5
|
|
65302
|
-
${errorSummary}
|
|
65303
|
-
|
|
65304
|
-
\u5B8C\u6574\u65E5\u5FD7\uFF1A${logPath}
|
|
65305
|
-
\u8BF7\u4F60\u63A5\u7BA1\u5B8C\u6210\u672C\u6B21\u53D1\u5E03\uFF1A\u5148\u6839\u636E\u65E5\u5FD7\u4FEE\u590D\u95EE\u9898\uFF0C\u7136\u540E\u91CD\u8DD1 publish.sh \u76F4\u5230\u4E0A\u7EBF\u6210\u529F\uFF0C\u6700\u540E\u7528 appBuilder.setProdUrl \u5199\u5165\u516C\u7F51 URL\u3002`;
|
|
65306
|
-
}
|
|
65307
|
-
async function recoverInterruptedJobs(deps) {
|
|
65308
|
-
const projects = await deps.listAllProjects();
|
|
65309
|
-
for (const p2 of projects) {
|
|
65310
|
-
if (p2.publishJob) {
|
|
65311
|
-
deps.log(
|
|
65312
|
-
`[publish] found interrupted job ${p2.publishJob.jobId} for ${p2.name}, stage=${p2.publishJob.stage}`
|
|
65313
|
-
);
|
|
65314
|
-
}
|
|
65315
|
-
}
|
|
65316
|
-
}
|
|
64786
|
+
// src/app-builder/ports.ts
|
|
64787
|
+
var APP_BUILDER_PERSONAS = ["persona-app-builder", "persona-dataclaw-builder"];
|
|
65317
64788
|
|
|
65318
64789
|
// src/handlers/app-builder.ts
|
|
65319
64790
|
init_protocol();
|
|
65320
|
-
var
|
|
65321
|
-
var
|
|
65322
|
-
var
|
|
64791
|
+
var import_node_path65 = require("path");
|
|
64792
|
+
var import_node_fs50 = require("fs");
|
|
64793
|
+
var DEFAULT_TEMPLATE = "nestjs-react";
|
|
65323
64794
|
var DEV_SERVER_READY_TIMEOUT_MS = 3e4;
|
|
65324
|
-
async function recoverInterruptedPublishJobs(store, logger) {
|
|
65325
|
-
await recoverInterruptedJobs({
|
|
65326
|
-
listAllProjects: async () => store.list(),
|
|
65327
|
-
log: (msg) => logger?.info(msg)
|
|
65328
|
-
});
|
|
65329
|
-
}
|
|
65330
64795
|
function buildAppBuilderHandlers(deps) {
|
|
65331
64796
|
const { store, devServerLifecycle, sessionManager, getTunnelUrl, broadcastProjectUpdated } = deps;
|
|
65332
64797
|
function resolveStore(opts) {
|
|
@@ -65353,11 +64818,9 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65353
64818
|
}
|
|
65354
64819
|
}
|
|
65355
64820
|
const stages = /* @__PURE__ */ new Map();
|
|
65356
|
-
const publishRegistry = new PublishJobRegistry();
|
|
65357
64821
|
function withPublishJobStatus(meta) {
|
|
65358
64822
|
if (!meta.publishJob) return void 0;
|
|
65359
|
-
const
|
|
65360
|
-
const inFlight = !!job && job.jobId === meta.publishJob.jobId;
|
|
64823
|
+
const inFlight = deps.publishService.inFlightJobId(meta.name) === meta.publishJob.jobId;
|
|
65361
64824
|
return {
|
|
65362
64825
|
...meta.publishJob,
|
|
65363
64826
|
status: inFlight ? "in-flight" : "interrupted"
|
|
@@ -65399,7 +64862,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65399
64862
|
async function listAllUsersProjects() {
|
|
65400
64863
|
if (!deps.usersRoot || !deps.getStore) return [];
|
|
65401
64864
|
const getStore = deps.getStore;
|
|
65402
|
-
const userIds = await
|
|
64865
|
+
const userIds = await import_node_fs50.promises.readdir(deps.usersRoot).catch(() => []);
|
|
65403
64866
|
const perUser = await Promise.all(
|
|
65404
64867
|
userIds.map((uid) => getStore(uid).list().catch(() => []))
|
|
65405
64868
|
);
|
|
@@ -65465,26 +64928,26 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65465
64928
|
const userStore = resolveStore({ ctx, sessionId: f.sessionId });
|
|
65466
64929
|
deps.logger?.info("app-builder.create-project.start", { name: f.name, sessionId: f.sessionId });
|
|
65467
64930
|
const reservedPorts = new Set((await listAllUsersProjects()).map((p2) => p2.port));
|
|
65468
|
-
const
|
|
64931
|
+
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(session.ownerPersonaId ?? "") : deps.personaRoot;
|
|
64932
|
+
let project;
|
|
64933
|
+
let projectDir;
|
|
65469
64934
|
try {
|
|
65470
|
-
const
|
|
65471
|
-
|
|
65472
|
-
|
|
65473
|
-
|
|
65474
|
-
|
|
65475
|
-
|
|
65476
|
-
|
|
64935
|
+
const created = await deps.createProjectOnDisk({
|
|
64936
|
+
store: userStore,
|
|
64937
|
+
name: f.name,
|
|
64938
|
+
templateSrcDir: (0, import_node_path65.join)(personaRoot, "extension-kit", "examples", DEFAULT_TEMPLATE),
|
|
64939
|
+
scaffoldScript: (0, import_node_path65.join)(deps.deployKitRoot, "scripts", "new-extension.sh"),
|
|
64940
|
+
reservedPorts,
|
|
64941
|
+
...deps.logger ? { logger: deps.logger } : {}
|
|
65477
64942
|
});
|
|
64943
|
+
project = created.project;
|
|
64944
|
+
projectDir = created.projectDir;
|
|
65478
64945
|
} catch (err) {
|
|
65479
64946
|
const message = err instanceof Error ? err.message : String(err);
|
|
65480
|
-
|
|
65481
|
-
|
|
65482
|
-
|
|
65483
|
-
|
|
65484
|
-
error: delErr instanceof Error ? delErr.message : String(delErr)
|
|
65485
|
-
});
|
|
65486
|
-
});
|
|
65487
|
-
throw new ClawdError(ERROR_CODES.INTERNAL, `scaffold failed: ${message}`);
|
|
64947
|
+
if (message.startsWith("scaffold failed")) {
|
|
64948
|
+
throw new ClawdError(ERROR_CODES.INTERNAL, message);
|
|
64949
|
+
}
|
|
64950
|
+
throw err;
|
|
65488
64951
|
}
|
|
65489
64952
|
const { broadcast } = sessionManager.update({
|
|
65490
64953
|
sessionId: f.sessionId,
|
|
@@ -65496,7 +64959,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65496
64959
|
port: project.port,
|
|
65497
64960
|
sessionId: f.sessionId
|
|
65498
64961
|
});
|
|
65499
|
-
return { response: { project, projectDir
|
|
64962
|
+
return { response: { project, projectDir }, broadcast };
|
|
65500
64963
|
};
|
|
65501
64964
|
const deleteProject = async (frame, _client, ctx) => {
|
|
65502
64965
|
const { name } = parseArgs2(DeleteProjectArgsSchema, frame, "deleteProject");
|
|
@@ -65664,7 +65127,7 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65664
65127
|
`publish: project "${args.name}" has no bound session (orphan); cannot inject failure to chat`
|
|
65665
65128
|
);
|
|
65666
65129
|
}
|
|
65667
|
-
if (project.publishJob &&
|
|
65130
|
+
if (project.publishJob && deps.publishService.inFlightJobId(args.name) === null) {
|
|
65668
65131
|
deps.logger?.info("app-builder.publish.clear-interrupted", {
|
|
65669
65132
|
name: args.name,
|
|
65670
65133
|
previousJobId: project.publishJob.jobId,
|
|
@@ -65673,28 +65136,25 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65673
65136
|
await userStore.clearPublishJob(args.name);
|
|
65674
65137
|
}
|
|
65675
65138
|
const personaRoot = deps.resolvePersonaRoot ? deps.resolvePersonaRoot(boundSession.ownerPersonaId ?? "") : deps.personaRoot;
|
|
65676
|
-
const scriptPath = (0,
|
|
65139
|
+
const scriptPath = (0, import_node_path65.join)(deps.deployKitRoot, "scripts", "publish.sh");
|
|
65677
65140
|
deps.logger?.info("app-builder.publish.start", {
|
|
65678
65141
|
name: args.name,
|
|
65679
65142
|
sessionId: boundSession.sessionId,
|
|
65680
65143
|
scriptPath,
|
|
65681
65144
|
personaRoot
|
|
65682
65145
|
});
|
|
65683
|
-
const result = await
|
|
65684
|
-
|
|
65685
|
-
|
|
65686
|
-
|
|
65687
|
-
|
|
65688
|
-
|
|
65689
|
-
|
|
65690
|
-
|
|
65691
|
-
|
|
65692
|
-
|
|
65693
|
-
|
|
65694
|
-
|
|
65695
|
-
},
|
|
65696
|
-
setProdUrl: async (name, url) => {
|
|
65697
|
-
await userStore.setProdUrl(name, url);
|
|
65146
|
+
const result = await deps.publishService.start({
|
|
65147
|
+
name: args.name,
|
|
65148
|
+
sessionId: boundSession.sessionId,
|
|
65149
|
+
scriptPath,
|
|
65150
|
+
personaRoot,
|
|
65151
|
+
store: userStore,
|
|
65152
|
+
hooks: {
|
|
65153
|
+
// 元数据每次写盘(publishJob 起落 / prodUrl 回填)后重推一帧:UI 渲染 PublishProgress
|
|
65154
|
+
// 三段 checklist 依赖 project.publishJob.status==='in-flight',而 publishJob 字段只有
|
|
65155
|
+
// 通过 project-updated 帧才能到达 UI(publish-progress 帧 UI 端只用来设 currentStage,
|
|
65156
|
+
// 不更新 currentProject)。prodUrl 同理,靠这条链路让 PreviewPane 切线上预览。
|
|
65157
|
+
onProjectChanged: async (name) => {
|
|
65698
65158
|
const current = getStageOf(name);
|
|
65699
65159
|
await setStageAndBroadcast(name, current.stage, current.reason, userStore);
|
|
65700
65160
|
},
|
|
@@ -65713,17 +65173,10 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65713
65173
|
for (const entry of broadcast) {
|
|
65714
65174
|
deps.broadcastSessionFrame(entry.frame, entry.target);
|
|
65715
65175
|
}
|
|
65716
|
-
}
|
|
65717
|
-
projectDir: (name) => userStore.projectDir(name),
|
|
65718
|
-
logger: deps.logger
|
|
65176
|
+
}
|
|
65719
65177
|
},
|
|
65720
|
-
{
|
|
65721
|
-
|
|
65722
|
-
sessionId: boundSession.sessionId,
|
|
65723
|
-
scriptPath,
|
|
65724
|
-
personaRoot
|
|
65725
|
-
}
|
|
65726
|
-
);
|
|
65178
|
+
...deps.logger ? { logger: deps.logger } : {}
|
|
65179
|
+
});
|
|
65727
65180
|
return { response: { ...result } };
|
|
65728
65181
|
};
|
|
65729
65182
|
const dismissPublishJob = async (frame, _client, ctx) => {
|
|
@@ -65738,15 +65191,13 @@ function buildAppBuilderHandlers(deps) {
|
|
|
65738
65191
|
`dismissPublishJob: project "${args.name}" not found`
|
|
65739
65192
|
);
|
|
65740
65193
|
}
|
|
65741
|
-
const
|
|
65742
|
-
if (
|
|
65194
|
+
const inFlightJobId = deps.publishService.inFlightJobId(args.name);
|
|
65195
|
+
if (inFlightJobId) {
|
|
65743
65196
|
deps.logger?.info("app-builder.publish.dismiss.in-flight", {
|
|
65744
65197
|
name: args.name,
|
|
65745
|
-
jobId:
|
|
65746
|
-
stage: job.stage
|
|
65198
|
+
jobId: inFlightJobId
|
|
65747
65199
|
});
|
|
65748
|
-
|
|
65749
|
-
job.childProc.kill("SIGTERM");
|
|
65200
|
+
deps.publishService.dismiss(args.name);
|
|
65750
65201
|
} else if (project.publishJob) {
|
|
65751
65202
|
deps.logger?.info("app-builder.publish.dismiss.interrupted", {
|
|
65752
65203
|
name: args.name,
|
|
@@ -66432,7 +65883,7 @@ function buildVisitorHandlers(deps) {
|
|
|
66432
65883
|
|
|
66433
65884
|
// src/extension/registry.ts
|
|
66434
65885
|
var import_promises16 = __toESM(require("fs/promises"), 1);
|
|
66435
|
-
var
|
|
65886
|
+
var import_node_path66 = __toESM(require("path"), 1);
|
|
66436
65887
|
async function loadAll(root) {
|
|
66437
65888
|
let entries;
|
|
66438
65889
|
try {
|
|
@@ -66445,13 +65896,13 @@ async function loadAll(root) {
|
|
|
66445
65896
|
for (const ent of entries) {
|
|
66446
65897
|
if (!ent.isDirectory()) continue;
|
|
66447
65898
|
if (ent.name.startsWith(".")) continue;
|
|
66448
|
-
records.push(await loadOne(
|
|
65899
|
+
records.push(await loadOne(import_node_path66.default.join(root, ent.name), ent.name));
|
|
66449
65900
|
}
|
|
66450
65901
|
records.sort((a, b2) => a.extId < b2.extId ? -1 : a.extId > b2.extId ? 1 : 0);
|
|
66451
65902
|
return records;
|
|
66452
65903
|
}
|
|
66453
65904
|
async function loadOne(dir, dirName) {
|
|
66454
|
-
const manifestPath =
|
|
65905
|
+
const manifestPath = import_node_path66.default.join(dir, "manifest.json");
|
|
66455
65906
|
let raw;
|
|
66456
65907
|
try {
|
|
66457
65908
|
raw = await import_promises16.default.readFile(manifestPath, "utf8");
|
|
@@ -66496,7 +65947,7 @@ async function loadOne(dir, dirName) {
|
|
|
66496
65947
|
|
|
66497
65948
|
// src/extension/uninstall.ts
|
|
66498
65949
|
var import_promises17 = __toESM(require("fs/promises"), 1);
|
|
66499
|
-
var
|
|
65950
|
+
var import_node_path67 = __toESM(require("path"), 1);
|
|
66500
65951
|
var UninstallError = class extends Error {
|
|
66501
65952
|
constructor(code, message) {
|
|
66502
65953
|
super(message);
|
|
@@ -66505,7 +65956,7 @@ var UninstallError = class extends Error {
|
|
|
66505
65956
|
code;
|
|
66506
65957
|
};
|
|
66507
65958
|
async function uninstall(deps) {
|
|
66508
|
-
const dir =
|
|
65959
|
+
const dir = import_node_path67.default.join(deps.root, deps.extId);
|
|
66509
65960
|
try {
|
|
66510
65961
|
await import_promises17.default.access(dir);
|
|
66511
65962
|
} catch {
|
|
@@ -66516,13 +65967,13 @@ async function uninstall(deps) {
|
|
|
66516
65967
|
}
|
|
66517
65968
|
|
|
66518
65969
|
// src/handlers/index.ts
|
|
66519
|
-
var
|
|
65970
|
+
var import_node_crypto20 = require("crypto");
|
|
66520
65971
|
|
|
66521
65972
|
// src/handlers/peer-exec.ts
|
|
66522
65973
|
init_protocol();
|
|
66523
65974
|
|
|
66524
65975
|
// src/peer-ops/run-command.ts
|
|
66525
|
-
var
|
|
65976
|
+
var import_node_child_process16 = require("child_process");
|
|
66526
65977
|
var import_node_os24 = __toESM(require("os"), 1);
|
|
66527
65978
|
var DEFAULT_TIMEOUT_MS5 = 3e4;
|
|
66528
65979
|
var MAX_TIMEOUT_MS = 3e5;
|
|
@@ -66530,7 +65981,7 @@ var MAX_OUTPUT_BYTES = 1048576;
|
|
|
66530
65981
|
function runCommand(command, opts = {}) {
|
|
66531
65982
|
const timeoutMs = Math.min(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS5, MAX_TIMEOUT_MS);
|
|
66532
65983
|
return new Promise((resolve9) => {
|
|
66533
|
-
const child = (0,
|
|
65984
|
+
const child = (0, import_node_child_process16.spawn)("bash", ["-c", command], { cwd: import_node_os24.default.homedir() });
|
|
66534
65985
|
const out = [];
|
|
66535
65986
|
const err = [];
|
|
66536
65987
|
let outBytes = 0;
|
|
@@ -66672,7 +66123,7 @@ function buildMethodHandlers(deps) {
|
|
|
66672
66123
|
const c = deps.contactStore.get(deviceId);
|
|
66673
66124
|
return c ? { deviceId: c.deviceId, remoteUrl: c.remoteUrl, connectToken: c.connectToken } : null;
|
|
66674
66125
|
},
|
|
66675
|
-
genId: () => (0,
|
|
66126
|
+
genId: () => (0, import_node_crypto20.randomUUID)(),
|
|
66676
66127
|
now: () => Date.now(),
|
|
66677
66128
|
forwardInboxPostToPeer,
|
|
66678
66129
|
logger: deps.logger
|
|
@@ -66715,6 +66166,8 @@ function buildMethodHandlers(deps) {
|
|
|
66715
66166
|
...buildAppBuilderHandlers({
|
|
66716
66167
|
store: deps.appBuilderStore,
|
|
66717
66168
|
getStore: deps.getProjectStore,
|
|
66169
|
+
publishService: deps.publishService,
|
|
66170
|
+
createProjectOnDisk: deps.createProjectOnDisk,
|
|
66718
66171
|
usersRoot: deps.usersRoot,
|
|
66719
66172
|
devServerLifecycle: deps.devServerLifecycle,
|
|
66720
66173
|
sessionManager: deps.manager,
|
|
@@ -66738,7 +66191,7 @@ function buildMethodHandlers(deps) {
|
|
|
66738
66191
|
broadcast: deps.broadcastToOwners
|
|
66739
66192
|
}),
|
|
66740
66193
|
...buildMasterHandlers({
|
|
66741
|
-
authorityTablePath:
|
|
66194
|
+
authorityTablePath: import_node_path68.default.join(deps.masterDataDir, "master-authority.json")
|
|
66742
66195
|
}),
|
|
66743
66196
|
...buildTopicHandlers({
|
|
66744
66197
|
topicStore: deps.topicStore,
|
|
@@ -66769,23 +66222,23 @@ function buildMethodHandlers(deps) {
|
|
|
66769
66222
|
init_protocol();
|
|
66770
66223
|
|
|
66771
66224
|
// src/tools/version-probe.ts
|
|
66772
|
-
var
|
|
66225
|
+
var import_node_child_process18 = require("child_process");
|
|
66773
66226
|
init_claude();
|
|
66774
66227
|
|
|
66775
66228
|
// src/tools/shell-path.ts
|
|
66776
|
-
var
|
|
66229
|
+
var import_node_child_process17 = require("child_process");
|
|
66777
66230
|
var import_node_os25 = __toESM(require("os"), 1);
|
|
66778
66231
|
function refreshPathFromLoginShell() {
|
|
66779
66232
|
if (process.platform === "win32") return;
|
|
66780
66233
|
const shell = process.env.SHELL ?? import_node_os25.default.userInfo().shell ?? "/bin/zsh";
|
|
66781
66234
|
try {
|
|
66782
|
-
const out = (0,
|
|
66235
|
+
const out = (0, import_node_child_process17.execFileSync)(shell, ["-ilc", 'command echo -n "$PATH"'], {
|
|
66783
66236
|
encoding: "utf8",
|
|
66784
66237
|
timeout: 3e3,
|
|
66785
66238
|
stdio: ["ignore", "pipe", "ignore"]
|
|
66786
66239
|
});
|
|
66787
|
-
const
|
|
66788
|
-
if (
|
|
66240
|
+
const path94 = out.trim();
|
|
66241
|
+
if (path94) process.env.PATH = path94;
|
|
66789
66242
|
} catch {
|
|
66790
66243
|
}
|
|
66791
66244
|
}
|
|
@@ -66796,7 +66249,7 @@ function parseVersionOutput(out) {
|
|
|
66796
66249
|
}
|
|
66797
66250
|
function execVersion(bin) {
|
|
66798
66251
|
return new Promise((resolve9, reject) => {
|
|
66799
|
-
(0,
|
|
66252
|
+
(0, import_node_child_process18.execFile)(bin, ["--version"], { timeout: 5e3 }, (err, stdout) => {
|
|
66800
66253
|
if (err) reject(err);
|
|
66801
66254
|
else resolve9(String(stdout));
|
|
66802
66255
|
});
|
|
@@ -66908,8 +66361,242 @@ function buildOnboardingHandlers(deps) {
|
|
|
66908
66361
|
return { "onboarding:complete": complete, "tools:probe": toolsProbe, "onboarding:iosInterest": iosInterest };
|
|
66909
66362
|
}
|
|
66910
66363
|
|
|
66364
|
+
// src/app-builder-plugin/project-store.ts
|
|
66365
|
+
var import_node_fs51 = require("fs");
|
|
66366
|
+
var import_node_child_process19 = require("child_process");
|
|
66367
|
+
var import_node_path69 = require("path");
|
|
66368
|
+
init_protocol();
|
|
66369
|
+
var PROJECTS_DIR = "projects";
|
|
66370
|
+
var META_FILE = ".clawd-project.json";
|
|
66371
|
+
var SCAFFOLD_TIMEOUT_MS = 3e4;
|
|
66372
|
+
var metaWriteQueues = /* @__PURE__ */ new Map();
|
|
66373
|
+
function serializeMetaWrite(metaPath, op) {
|
|
66374
|
+
const prev = metaWriteQueues.get(metaPath) ?? Promise.resolve();
|
|
66375
|
+
const next = prev.then(op, op);
|
|
66376
|
+
const settled = next.then(
|
|
66377
|
+
() => void 0,
|
|
66378
|
+
() => void 0
|
|
66379
|
+
);
|
|
66380
|
+
metaWriteQueues.set(metaPath, settled);
|
|
66381
|
+
void settled.then(() => {
|
|
66382
|
+
if (metaWriteQueues.get(metaPath) === settled) metaWriteQueues.delete(metaPath);
|
|
66383
|
+
});
|
|
66384
|
+
return next;
|
|
66385
|
+
}
|
|
66386
|
+
var ProjectStore = class {
|
|
66387
|
+
/** @param root projects 父目录,例如 `~/.clawd/users/<userId>/`(v2 per-user) */
|
|
66388
|
+
constructor(root) {
|
|
66389
|
+
this.root = root;
|
|
66390
|
+
}
|
|
66391
|
+
root;
|
|
66392
|
+
serializeWrite(name, op) {
|
|
66393
|
+
return serializeMetaWrite(this.metaPath(name), op);
|
|
66394
|
+
}
|
|
66395
|
+
/** projects/<name>/.clawd-project.json 路径 */
|
|
66396
|
+
metaPath(name) {
|
|
66397
|
+
return (0, import_node_path69.join)(this.projectsRoot(), name, META_FILE);
|
|
66398
|
+
}
|
|
66399
|
+
/** projects/<name>/ 目录路径(cwd 用) */
|
|
66400
|
+
projectDir(name) {
|
|
66401
|
+
return (0, import_node_path69.join)(this.projectsRoot(), name);
|
|
66402
|
+
}
|
|
66403
|
+
projectsRoot() {
|
|
66404
|
+
return (0, import_node_path69.join)(this.root, PROJECTS_DIR);
|
|
66405
|
+
}
|
|
66406
|
+
async list() {
|
|
66407
|
+
let entries;
|
|
66408
|
+
try {
|
|
66409
|
+
entries = await import_node_fs51.promises.readdir(this.projectsRoot());
|
|
66410
|
+
} catch (err) {
|
|
66411
|
+
if (err.code === "ENOENT") return [];
|
|
66412
|
+
throw err;
|
|
66413
|
+
}
|
|
66414
|
+
const out = [];
|
|
66415
|
+
for (const name of entries) {
|
|
66416
|
+
try {
|
|
66417
|
+
const raw = await import_node_fs51.promises.readFile(this.metaPath(name), "utf8");
|
|
66418
|
+
const json = JSON.parse(raw);
|
|
66419
|
+
let migrated = false;
|
|
66420
|
+
if (typeof json.devCommand !== "string" || json.devCommand.length === 0) {
|
|
66421
|
+
json.devCommand = DEFAULT_DEV_COMMAND;
|
|
66422
|
+
migrated = true;
|
|
66423
|
+
}
|
|
66424
|
+
const parsed = ProjectMetadataSchema.safeParse(json);
|
|
66425
|
+
if (parsed.success) {
|
|
66426
|
+
out.push(parsed.data);
|
|
66427
|
+
if (migrated) {
|
|
66428
|
+
void import_node_fs51.promises.writeFile(this.metaPath(name), JSON.stringify(parsed.data, null, 2) + "\n", "utf8").catch(() => {
|
|
66429
|
+
});
|
|
66430
|
+
}
|
|
66431
|
+
}
|
|
66432
|
+
} catch {
|
|
66433
|
+
}
|
|
66434
|
+
}
|
|
66435
|
+
return out.sort((a, b2) => a.name.localeCompare(b2.name));
|
|
66436
|
+
}
|
|
66437
|
+
/**
|
|
66438
|
+
* @param reservedPorts 其它 user 已占端口(v2 per-user:端口必须全局唯一,所有 user 的
|
|
66439
|
+
* dev server 同机跑;per-user store 各自只 list 自己,靠 handler 收集全局端口传进来,
|
|
66440
|
+
* 否则不同 user 的首个项目都从 PROJECT_PORT_MIN 起 → 全撞 6173)。
|
|
66441
|
+
*/
|
|
66442
|
+
async create(name, reservedPorts) {
|
|
66443
|
+
const existing = await this.list();
|
|
66444
|
+
if (existing.some((p2) => p2.name === name)) {
|
|
66445
|
+
throw new Error(`project "${name}" already exists / \u5DF2\u5B58\u5728`);
|
|
66446
|
+
}
|
|
66447
|
+
const usedPorts = new Set(existing.map((p2) => p2.port));
|
|
66448
|
+
if (reservedPorts) for (const p2 of reservedPorts) usedPorts.add(p2);
|
|
66449
|
+
let port = -1;
|
|
66450
|
+
for (let p2 = PROJECT_PORT_MIN; p2 <= PROJECT_PORT_MAX; p2++) {
|
|
66451
|
+
if (!usedPorts.has(p2)) {
|
|
66452
|
+
port = p2;
|
|
66453
|
+
break;
|
|
66454
|
+
}
|
|
66455
|
+
}
|
|
66456
|
+
if (port < 0) {
|
|
66457
|
+
throw new Error(
|
|
66458
|
+
`port pool exhausted / \u7AEF\u53E3\u6C60\u5DF2\u6EE1\uFF08${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}\uFF09\uFF0C\u5148\u5220\u4E00\u4E2A project \u91CA\u653E\u7AEF\u53E3`
|
|
66459
|
+
);
|
|
66460
|
+
}
|
|
66461
|
+
const meta = {
|
|
66462
|
+
name,
|
|
66463
|
+
port,
|
|
66464
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
66465
|
+
devCommand: DEFAULT_DEV_COMMAND
|
|
66466
|
+
};
|
|
66467
|
+
const validated = ProjectMetadataSchema.safeParse(meta);
|
|
66468
|
+
if (!validated.success) {
|
|
66469
|
+
throw new Error(`invalid name "${name}": ${validated.error.message}`);
|
|
66470
|
+
}
|
|
66471
|
+
const dir = this.projectDir(name);
|
|
66472
|
+
await import_node_fs51.promises.mkdir(dir, { recursive: true });
|
|
66473
|
+
await import_node_fs51.promises.writeFile(this.metaPath(name), JSON.stringify(meta, null, 2) + "\n", "utf8");
|
|
66474
|
+
return meta;
|
|
66475
|
+
}
|
|
66476
|
+
/**
|
|
66477
|
+
* 同步内联 scaffold:spawn `extension-kit/scripts/new-extension.sh <name>` 等 exit。
|
|
66478
|
+
* 必须在 `create()` 之后调(脚本期望 projects/<name>/.clawd-project.json 已就位 = picker 模式)。
|
|
66479
|
+
* 失败抛错;上层(handler)应当 catch 后回滚(删 dir + 不 mutate session)。
|
|
66480
|
+
*
|
|
66481
|
+
* spec 2026-06-02 §5.6.3:scaffold 对 assistant 不可见,避免 assistant 被诱导去"读 example
|
|
66482
|
+
* 代码再参考"。assistant 进 project 时目录已是完整模板,直接 pnpm install 即可。
|
|
66483
|
+
*/
|
|
66484
|
+
async scaffold(name, templateSrcDir, scaffoldScriptPath) {
|
|
66485
|
+
const destDir = this.projectDir(name);
|
|
66486
|
+
return await new Promise((resolve9, reject) => {
|
|
66487
|
+
const child = (0, import_node_child_process19.spawn)("bash", [scaffoldScriptPath, name, templateSrcDir, destDir], {
|
|
66488
|
+
env: { ...process.env, PATH: process.env.PATH ?? "" },
|
|
66489
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
66490
|
+
});
|
|
66491
|
+
let stdout = "";
|
|
66492
|
+
let stderr = "";
|
|
66493
|
+
child.stdout.on("data", (d) => {
|
|
66494
|
+
stdout += d.toString("utf8");
|
|
66495
|
+
});
|
|
66496
|
+
child.stderr.on("data", (d) => {
|
|
66497
|
+
stderr += d.toString("utf8");
|
|
66498
|
+
});
|
|
66499
|
+
const timer = setTimeout(() => {
|
|
66500
|
+
child.kill("SIGKILL");
|
|
66501
|
+
reject(new Error(`scaffold timeout (>${SCAFFOLD_TIMEOUT_MS}ms): ${scaffoldScriptPath} ${name}`));
|
|
66502
|
+
}, SCAFFOLD_TIMEOUT_MS);
|
|
66503
|
+
child.on("error", (err) => {
|
|
66504
|
+
clearTimeout(timer);
|
|
66505
|
+
reject(new Error(`scaffold spawn failed: ${err.message}`));
|
|
66506
|
+
});
|
|
66507
|
+
child.on("exit", (code, signal) => {
|
|
66508
|
+
clearTimeout(timer);
|
|
66509
|
+
if (code === 0) resolve9({ stdout, stderr });
|
|
66510
|
+
else reject(new Error(`scaffold exit ${code ?? signal}: ${stderr.slice(0, 500)}`));
|
|
66511
|
+
});
|
|
66512
|
+
});
|
|
66513
|
+
}
|
|
66514
|
+
async delete(name) {
|
|
66515
|
+
const dir = this.projectDir(name);
|
|
66516
|
+
await import_node_fs51.promises.rm(dir, { recursive: true, force: true });
|
|
66517
|
+
}
|
|
66518
|
+
async updatePort(name, newPort) {
|
|
66519
|
+
if (newPort < PROJECT_PORT_MIN || newPort > PROJECT_PORT_MAX) {
|
|
66520
|
+
throw new Error(
|
|
66521
|
+
`port range invalid: must be ${PROJECT_PORT_MIN}-${PROJECT_PORT_MAX}, got ${newPort}`
|
|
66522
|
+
);
|
|
66523
|
+
}
|
|
66524
|
+
return await this.serializeWrite(name, async () => {
|
|
66525
|
+
const list = await this.list();
|
|
66526
|
+
const target = list.find((p2) => p2.name === name);
|
|
66527
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
66528
|
+
const conflict = list.find((p2) => p2.name !== name && p2.port === newPort);
|
|
66529
|
+
if (conflict) {
|
|
66530
|
+
throw new Error(`port ${newPort} already used / \u5DF2\u88AB project "${conflict.name}" \u5360\u7528`);
|
|
66531
|
+
}
|
|
66532
|
+
const updated = { ...target, port: newPort };
|
|
66533
|
+
await import_node_fs51.promises.writeFile(this.metaPath(name), JSON.stringify(updated, null, 2) + "\n", "utf8");
|
|
66534
|
+
return updated;
|
|
66535
|
+
});
|
|
66536
|
+
}
|
|
66537
|
+
/**
|
|
66538
|
+
* 单栏 refactor (spec 2026-06-02 §5.6.1):发布上线后写公网 URL 到 .clawd-project.json.prodUrl。
|
|
66539
|
+
* UI 通过 listProjects 读到 prodUrl 后切预览栏到线上 URL,取代旧 prod marker 机制。
|
|
66540
|
+
* 重复调用幂等(覆盖旧 URL)。url 由 ProjectMetadataSchema 校验 url() 格式。
|
|
66541
|
+
*/
|
|
66542
|
+
async setProdUrl(name, url) {
|
|
66543
|
+
return await this.serializeWrite(name, async () => {
|
|
66544
|
+
const list = await this.list();
|
|
66545
|
+
const target = list.find((p2) => p2.name === name);
|
|
66546
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
66547
|
+
const updated = { ...target, prodUrl: url };
|
|
66548
|
+
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
66549
|
+
if (!validated.success) {
|
|
66550
|
+
throw new Error(`invalid prodUrl "${url}": ${validated.error.message}`);
|
|
66551
|
+
}
|
|
66552
|
+
await import_node_fs51.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
66553
|
+
return validated.data;
|
|
66554
|
+
});
|
|
66555
|
+
}
|
|
66556
|
+
/**
|
|
66557
|
+
* 发布上线脚手架化 (spec 2026-06-03-app-builder-publish-scaffold-design §5.1.4):
|
|
66558
|
+
* 写 publishJob 字段到 .clawd-project.json。仅承载 in-flight 状态 ——
|
|
66559
|
+
* - daemon 收到第一个 ::stage::build marker 时写入
|
|
66560
|
+
* - 每次 stage 切换更新 stage 字段(jobId / startedAt 不变)
|
|
66561
|
+
* - 成功 / 失败 / dismiss 时调 clearPublishJob 清掉
|
|
66562
|
+
* - 只有 daemon 崩才会留残骸
|
|
66563
|
+
* 写入时保留所有其他字段(prodUrl 等不受影响)。
|
|
66564
|
+
*/
|
|
66565
|
+
async setPublishJob(name, job) {
|
|
66566
|
+
return await this.serializeWrite(name, async () => {
|
|
66567
|
+
const list = await this.list();
|
|
66568
|
+
const target = list.find((p2) => p2.name === name);
|
|
66569
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
66570
|
+
const updated = { ...target, publishJob: job };
|
|
66571
|
+
const validated = ProjectMetadataSchema.safeParse(updated);
|
|
66572
|
+
if (!validated.success) {
|
|
66573
|
+
throw new Error(`invalid publishJob: ${validated.error.message}`);
|
|
66574
|
+
}
|
|
66575
|
+
await import_node_fs51.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
66576
|
+
return validated.data;
|
|
66577
|
+
});
|
|
66578
|
+
}
|
|
66579
|
+
/** 清掉 .clawd-project.json.publishJob 字段。其他字段保持原样。 */
|
|
66580
|
+
async clearPublishJob(name) {
|
|
66581
|
+
return await this.serializeWrite(name, async () => {
|
|
66582
|
+
const list = await this.list();
|
|
66583
|
+
const target = list.find((p2) => p2.name === name);
|
|
66584
|
+
if (!target) throw new Error(`project "${name}" not found / \u4E0D\u5B58\u5728`);
|
|
66585
|
+
if (!target.publishJob) return target;
|
|
66586
|
+
const { publishJob: _drop, ...rest } = target;
|
|
66587
|
+
void _drop;
|
|
66588
|
+
const validated = ProjectMetadataSchema.safeParse(rest);
|
|
66589
|
+
if (!validated.success) {
|
|
66590
|
+
throw new Error(`failed to clear publishJob: ${validated.error.message}`);
|
|
66591
|
+
}
|
|
66592
|
+
await import_node_fs51.promises.writeFile(this.metaPath(name), JSON.stringify(validated.data, null, 2) + "\n", "utf8");
|
|
66593
|
+
return validated.data;
|
|
66594
|
+
});
|
|
66595
|
+
}
|
|
66596
|
+
};
|
|
66597
|
+
|
|
66911
66598
|
// src/app-builder/dev-server-supervisor.ts
|
|
66912
|
-
var
|
|
66599
|
+
var import_node_child_process20 = require("child_process");
|
|
66913
66600
|
var import_node_events2 = require("events");
|
|
66914
66601
|
var DEFAULT_READY_PATTERN = /Local:\s+https?:\/\/|Nest application successfully started|server listening on/i;
|
|
66915
66602
|
var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
@@ -66946,7 +66633,7 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
|
66946
66633
|
tunnelHost: args.tunnelHost,
|
|
66947
66634
|
devCommand: cmd
|
|
66948
66635
|
});
|
|
66949
|
-
const child = (0,
|
|
66636
|
+
const child = (0, import_node_child_process20.spawn)("sh", ["-c", cmd], {
|
|
66950
66637
|
cwd: args.cwd,
|
|
66951
66638
|
env,
|
|
66952
66639
|
stdio: "pipe",
|
|
@@ -67162,6 +66849,460 @@ var DevServerSupervisor = class extends import_node_events2.EventEmitter {
|
|
|
67162
66849
|
}
|
|
67163
66850
|
};
|
|
67164
66851
|
|
|
66852
|
+
// src/app-builder-plugin/publish-registry.ts
|
|
66853
|
+
var import_node_crypto21 = require("crypto");
|
|
66854
|
+
var PublishJobRegistry = class {
|
|
66855
|
+
jobs = /* @__PURE__ */ new Map();
|
|
66856
|
+
has(name) {
|
|
66857
|
+
return this.jobs.has(name);
|
|
66858
|
+
}
|
|
66859
|
+
get(name) {
|
|
66860
|
+
return this.jobs.get(name);
|
|
66861
|
+
}
|
|
66862
|
+
/**
|
|
66863
|
+
* args.jobId 仅用于测试注入;生产代码不传,registry 自己生成。
|
|
66864
|
+
* args.now 仅用于测试注入;生产代码不传,用 Date.now()。
|
|
66865
|
+
*/
|
|
66866
|
+
create(args) {
|
|
66867
|
+
if (this.jobs.has(args.name)) {
|
|
66868
|
+
throw new Error(`already publishing: ${args.name}`);
|
|
66869
|
+
}
|
|
66870
|
+
const jobId = args.jobId ?? `job-${(0, import_node_crypto21.randomUUID)()}`;
|
|
66871
|
+
this.jobs.set(args.name, {
|
|
66872
|
+
jobId,
|
|
66873
|
+
name: args.name,
|
|
66874
|
+
stage: "build",
|
|
66875
|
+
sessionId: args.sessionId,
|
|
66876
|
+
childProc: args.childProc,
|
|
66877
|
+
dismissed: false,
|
|
66878
|
+
sawAnyStage: false,
|
|
66879
|
+
startedAt: args.now ?? Date.now()
|
|
66880
|
+
});
|
|
66881
|
+
return jobId;
|
|
66882
|
+
}
|
|
66883
|
+
updateStage(name, stage) {
|
|
66884
|
+
const job = this.jobs.get(name);
|
|
66885
|
+
if (!job) return;
|
|
66886
|
+
job.stage = stage;
|
|
66887
|
+
job.sawAnyStage = true;
|
|
66888
|
+
}
|
|
66889
|
+
markDismissed(name) {
|
|
66890
|
+
const job = this.jobs.get(name);
|
|
66891
|
+
if (!job) return;
|
|
66892
|
+
job.dismissed = true;
|
|
66893
|
+
}
|
|
66894
|
+
remove(name) {
|
|
66895
|
+
const job = this.jobs.get(name);
|
|
66896
|
+
if (!job) return void 0;
|
|
66897
|
+
this.jobs.delete(name);
|
|
66898
|
+
return { sessionId: job.sessionId };
|
|
66899
|
+
}
|
|
66900
|
+
};
|
|
66901
|
+
|
|
66902
|
+
// src/app-builder-plugin/publish-job-runner.ts
|
|
66903
|
+
var import_node_child_process21 = require("child_process");
|
|
66904
|
+
var import_node_fs52 = require("fs");
|
|
66905
|
+
var import_node_path70 = require("path");
|
|
66906
|
+
|
|
66907
|
+
// src/app-builder-plugin/publish-stage-parser.ts
|
|
66908
|
+
var STAGE_RE = /^\s*::stage::(build|deploy|verify)\s*$/;
|
|
66909
|
+
var PROD_URL_RE = /^\s*::prod-url::(\S+)\s*$/;
|
|
66910
|
+
var URL_RE = /\bhttps?:\/\/[^\s]+/;
|
|
66911
|
+
function parsePublishLine(line) {
|
|
66912
|
+
const stageMatch = STAGE_RE.exec(line);
|
|
66913
|
+
if (stageMatch) return { kind: "stage", stage: stageMatch[1] };
|
|
66914
|
+
const urlMatch = PROD_URL_RE.exec(line);
|
|
66915
|
+
if (urlMatch) return { kind: "prod-url", url: urlMatch[1] };
|
|
66916
|
+
return null;
|
|
66917
|
+
}
|
|
66918
|
+
function extractProdUrl(text) {
|
|
66919
|
+
const m2 = URL_RE.exec(text);
|
|
66920
|
+
return m2 ? m2[0] : null;
|
|
66921
|
+
}
|
|
66922
|
+
function tailStderrLines(buf, n) {
|
|
66923
|
+
if (!buf) return "";
|
|
66924
|
+
const lines = buf.split("\n");
|
|
66925
|
+
if (lines.length <= n) return buf;
|
|
66926
|
+
return lines.slice(lines.length - n).join("\n");
|
|
66927
|
+
}
|
|
66928
|
+
|
|
66929
|
+
// src/app-builder-plugin/publish-job-runner.ts
|
|
66930
|
+
async function startPublishJob(deps, args) {
|
|
66931
|
+
const { registry: registry2, projectDir } = deps;
|
|
66932
|
+
const spawn13 = deps.spawnImpl ?? import_node_child_process21.spawn;
|
|
66933
|
+
if (registry2.has(args.name)) {
|
|
66934
|
+
return { jobId: registry2.get(args.name).jobId, status: "already-publishing" };
|
|
66935
|
+
}
|
|
66936
|
+
const projDir = projectDir(args.name);
|
|
66937
|
+
const logPath = (0, import_node_path70.join)(projDir, ".publish.log");
|
|
66938
|
+
let logStream = null;
|
|
66939
|
+
try {
|
|
66940
|
+
logStream = (0, import_node_fs52.createWriteStream)(logPath, { flags: "w" });
|
|
66941
|
+
} catch {
|
|
66942
|
+
logStream = null;
|
|
66943
|
+
}
|
|
66944
|
+
const child = spawn13("bash", [args.scriptPath, projDir, args.personaRoot ?? ""], {
|
|
66945
|
+
cwd: projDir,
|
|
66946
|
+
env: process.env,
|
|
66947
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
66948
|
+
});
|
|
66949
|
+
const jobId = registry2.create({
|
|
66950
|
+
name: args.name,
|
|
66951
|
+
sessionId: args.sessionId,
|
|
66952
|
+
childProc: child
|
|
66953
|
+
});
|
|
66954
|
+
deps.logger?.info("app-builder.publish.spawned", {
|
|
66955
|
+
name: args.name,
|
|
66956
|
+
jobId,
|
|
66957
|
+
pid: child.pid ?? null,
|
|
66958
|
+
scriptPath: args.scriptPath,
|
|
66959
|
+
logPath
|
|
66960
|
+
});
|
|
66961
|
+
child.on("error", (err) => {
|
|
66962
|
+
deps.logger?.warn("app-builder.publish.spawn-error", {
|
|
66963
|
+
name: args.name,
|
|
66964
|
+
jobId,
|
|
66965
|
+
error: err instanceof Error ? err.message : String(err)
|
|
66966
|
+
});
|
|
66967
|
+
void handleExit(deps, {
|
|
66968
|
+
name: args.name,
|
|
66969
|
+
jobId,
|
|
66970
|
+
code: null,
|
|
66971
|
+
signal: null,
|
|
66972
|
+
urlCandidate: null,
|
|
66973
|
+
stderrTail: err instanceof Error ? err.message : String(err),
|
|
66974
|
+
logPath
|
|
66975
|
+
});
|
|
66976
|
+
});
|
|
66977
|
+
let urlFromMarker = null;
|
|
66978
|
+
let urlFallback = null;
|
|
66979
|
+
let stdoutBuf = "";
|
|
66980
|
+
child.stdout?.on("data", (chunk) => {
|
|
66981
|
+
if (logStream) logStream.write(chunk);
|
|
66982
|
+
stdoutBuf += chunk.toString();
|
|
66983
|
+
let nlIdx;
|
|
66984
|
+
while ((nlIdx = stdoutBuf.indexOf("\n")) >= 0) {
|
|
66985
|
+
const line = stdoutBuf.slice(0, nlIdx);
|
|
66986
|
+
stdoutBuf = stdoutBuf.slice(nlIdx + 1);
|
|
66987
|
+
handleStdoutLine(deps, args.name, jobId, line);
|
|
66988
|
+
const parsedForUrl = parsePublishLine(line);
|
|
66989
|
+
if (parsedForUrl?.kind === "prod-url") urlFromMarker = parsedForUrl.url;
|
|
66990
|
+
const url = extractProdUrl(line);
|
|
66991
|
+
if (url && !urlFallback) urlFallback = url;
|
|
66992
|
+
}
|
|
66993
|
+
});
|
|
66994
|
+
let stderrBuf = "";
|
|
66995
|
+
child.stderr?.on("data", (chunk) => {
|
|
66996
|
+
if (logStream) logStream.write(chunk);
|
|
66997
|
+
stderrBuf += chunk.toString();
|
|
66998
|
+
});
|
|
66999
|
+
child.on("exit", (code, signal) => {
|
|
67000
|
+
if (logStream) logStream.end();
|
|
67001
|
+
const urlCandidate = urlFromMarker ?? urlFallback;
|
|
67002
|
+
deps.logger?.info("app-builder.publish.child-exit", {
|
|
67003
|
+
name: args.name,
|
|
67004
|
+
jobId,
|
|
67005
|
+
code,
|
|
67006
|
+
signal,
|
|
67007
|
+
hadUrl: !!urlCandidate,
|
|
67008
|
+
urlSource: urlFromMarker ? "marker" : urlFallback ? "fallback" : "none",
|
|
67009
|
+
stderrBytes: stderrBuf.length
|
|
67010
|
+
});
|
|
67011
|
+
void handleExit(deps, {
|
|
67012
|
+
name: args.name,
|
|
67013
|
+
jobId,
|
|
67014
|
+
code,
|
|
67015
|
+
signal,
|
|
67016
|
+
urlCandidate,
|
|
67017
|
+
stderrTail: tailStderrLines(stderrBuf, 20),
|
|
67018
|
+
logPath
|
|
67019
|
+
});
|
|
67020
|
+
});
|
|
67021
|
+
return { jobId, status: "started" };
|
|
67022
|
+
}
|
|
67023
|
+
function handleStdoutLine(deps, name, jobId, line) {
|
|
67024
|
+
const parsed = parsePublishLine(line);
|
|
67025
|
+
if (parsed?.kind !== "stage") return;
|
|
67026
|
+
advanceStage(deps, name, jobId, parsed.stage);
|
|
67027
|
+
}
|
|
67028
|
+
function advanceStage(deps, name, jobId, next) {
|
|
67029
|
+
const job = deps.registry.get(name);
|
|
67030
|
+
if (!job) return;
|
|
67031
|
+
const prev = job.stage;
|
|
67032
|
+
const wasFirstStage = !job.sawAnyStage;
|
|
67033
|
+
deps.logger?.info("app-builder.publish.stage-advance", {
|
|
67034
|
+
name,
|
|
67035
|
+
jobId,
|
|
67036
|
+
prev: wasFirstStage ? null : prev,
|
|
67037
|
+
next,
|
|
67038
|
+
firstStage: wasFirstStage
|
|
67039
|
+
});
|
|
67040
|
+
if (wasFirstStage) {
|
|
67041
|
+
deps.registry.updateStage(name, next);
|
|
67042
|
+
void deps.setPublishJob(name, {
|
|
67043
|
+
jobId,
|
|
67044
|
+
stage: next,
|
|
67045
|
+
startedAt: job.startedAt
|
|
67046
|
+
});
|
|
67047
|
+
deps.broadcast({
|
|
67048
|
+
type: "appBuilder:publish-progress",
|
|
67049
|
+
name,
|
|
67050
|
+
jobId,
|
|
67051
|
+
stage: next,
|
|
67052
|
+
status: "started"
|
|
67053
|
+
});
|
|
67054
|
+
return;
|
|
67055
|
+
}
|
|
67056
|
+
if (prev === next) {
|
|
67057
|
+
return;
|
|
67058
|
+
}
|
|
67059
|
+
deps.broadcast({
|
|
67060
|
+
type: "appBuilder:publish-progress",
|
|
67061
|
+
name,
|
|
67062
|
+
jobId,
|
|
67063
|
+
stage: prev,
|
|
67064
|
+
status: "completed"
|
|
67065
|
+
});
|
|
67066
|
+
deps.registry.updateStage(name, next);
|
|
67067
|
+
void deps.setPublishJob(name, {
|
|
67068
|
+
jobId,
|
|
67069
|
+
stage: next,
|
|
67070
|
+
startedAt: job.startedAt
|
|
67071
|
+
});
|
|
67072
|
+
deps.broadcast({
|
|
67073
|
+
type: "appBuilder:publish-progress",
|
|
67074
|
+
name,
|
|
67075
|
+
jobId,
|
|
67076
|
+
stage: next,
|
|
67077
|
+
status: "started"
|
|
67078
|
+
});
|
|
67079
|
+
}
|
|
67080
|
+
async function handleExit(deps, args) {
|
|
67081
|
+
const job = deps.registry.get(args.name);
|
|
67082
|
+
if (args.signal === "SIGTERM" && job?.dismissed) {
|
|
67083
|
+
try {
|
|
67084
|
+
await deps.clearPublishJob(args.name);
|
|
67085
|
+
} catch (err) {
|
|
67086
|
+
console.error("[publish] clearPublishJob failed (dismissed branch)", err);
|
|
67087
|
+
}
|
|
67088
|
+
deps.registry.remove(args.name);
|
|
67089
|
+
deps.onSettled?.({ kind: "dismissed" });
|
|
67090
|
+
return;
|
|
67091
|
+
}
|
|
67092
|
+
if (args.code === 0 && args.urlCandidate) {
|
|
67093
|
+
if (job?.sawAnyStage) {
|
|
67094
|
+
deps.broadcast({
|
|
67095
|
+
type: "appBuilder:publish-progress",
|
|
67096
|
+
name: args.name,
|
|
67097
|
+
jobId: args.jobId,
|
|
67098
|
+
stage: job.stage,
|
|
67099
|
+
status: "completed"
|
|
67100
|
+
});
|
|
67101
|
+
}
|
|
67102
|
+
try {
|
|
67103
|
+
await deps.setProdUrl(args.name, args.urlCandidate);
|
|
67104
|
+
} catch (err) {
|
|
67105
|
+
console.error("[publish] setProdUrl failed; falling through to failure branch", err);
|
|
67106
|
+
await emitFailure(deps, args, "\u8C03 setProdUrl \u5931\u8D25\uFF1A" + (err instanceof Error ? err.message : String(err)));
|
|
67107
|
+
return;
|
|
67108
|
+
}
|
|
67109
|
+
try {
|
|
67110
|
+
await deps.clearPublishJob(args.name);
|
|
67111
|
+
} catch (err) {
|
|
67112
|
+
console.error("[publish] clearPublishJob failed (success branch)", err);
|
|
67113
|
+
}
|
|
67114
|
+
deps.registry.remove(args.name);
|
|
67115
|
+
deps.onSettled?.({ kind: "published", url: args.urlCandidate });
|
|
67116
|
+
return;
|
|
67117
|
+
}
|
|
67118
|
+
await emitFailure(deps, args, buildErrorSummary(args));
|
|
67119
|
+
}
|
|
67120
|
+
async function emitFailure(deps, args, errorSummary) {
|
|
67121
|
+
const job = deps.registry.get(args.name);
|
|
67122
|
+
const failStage = job?.sawAnyStage ? job.stage : "unknown";
|
|
67123
|
+
deps.logger?.warn("app-builder.publish.failed", {
|
|
67124
|
+
name: args.name,
|
|
67125
|
+
jobId: args.jobId,
|
|
67126
|
+
stage: failStage,
|
|
67127
|
+
errorSummary: errorSummary.slice(0, 500)
|
|
67128
|
+
});
|
|
67129
|
+
try {
|
|
67130
|
+
await deps.clearPublishJob(args.name);
|
|
67131
|
+
} catch (err) {
|
|
67132
|
+
deps.logger?.warn("app-builder.publish.clear-field-failed", {
|
|
67133
|
+
name: args.name,
|
|
67134
|
+
jobId: args.jobId,
|
|
67135
|
+
error: err instanceof Error ? err.message : String(err)
|
|
67136
|
+
});
|
|
67137
|
+
}
|
|
67138
|
+
const removed = deps.registry.remove(args.name);
|
|
67139
|
+
deps.broadcast({
|
|
67140
|
+
type: "appBuilder:publish-failed",
|
|
67141
|
+
name: args.name,
|
|
67142
|
+
jobId: args.jobId,
|
|
67143
|
+
stage: failStage,
|
|
67144
|
+
errorSummary
|
|
67145
|
+
});
|
|
67146
|
+
if (removed) {
|
|
67147
|
+
const msg = formatFailureMessage(failStage, errorSummary, args.logPath);
|
|
67148
|
+
try {
|
|
67149
|
+
await deps.injectUserText(removed.sessionId, msg);
|
|
67150
|
+
deps.logger?.info("app-builder.publish.failure-injected-to-chat", {
|
|
67151
|
+
name: args.name,
|
|
67152
|
+
jobId: args.jobId,
|
|
67153
|
+
sessionId: removed.sessionId
|
|
67154
|
+
});
|
|
67155
|
+
} catch (err) {
|
|
67156
|
+
deps.logger?.warn("app-builder.publish.inject-user-text-failed", {
|
|
67157
|
+
name: args.name,
|
|
67158
|
+
jobId: args.jobId,
|
|
67159
|
+
sessionId: removed.sessionId,
|
|
67160
|
+
error: err instanceof Error ? err.message : String(err)
|
|
67161
|
+
});
|
|
67162
|
+
}
|
|
67163
|
+
} else {
|
|
67164
|
+
deps.logger?.warn("app-builder.publish.no-registry-entry-on-failure", {
|
|
67165
|
+
name: args.name,
|
|
67166
|
+
jobId: args.jobId
|
|
67167
|
+
});
|
|
67168
|
+
}
|
|
67169
|
+
deps.onSettled?.({ kind: "failed", stage: failStage, errorSummary });
|
|
67170
|
+
}
|
|
67171
|
+
function buildErrorSummary(args) {
|
|
67172
|
+
if (args.signal) {
|
|
67173
|
+
return `publish.sh \u88AB\u4E2D\u65AD\uFF08signal: ${args.signal}\uFF09`;
|
|
67174
|
+
}
|
|
67175
|
+
if (args.code === 0 && !args.urlCandidate) {
|
|
67176
|
+
return "publish.sh \u6210\u529F\u9000\u51FA\u4F46\u672A\u8F93\u51FA\u516C\u7F51 URL";
|
|
67177
|
+
}
|
|
67178
|
+
return args.stderrTail || `publish.sh \u5F02\u5E38\u9000\u51FA\uFF08exit code: ${args.code}\uFF09`;
|
|
67179
|
+
}
|
|
67180
|
+
function formatFailureMessage(stage, errorSummary, logPath) {
|
|
67181
|
+
return `\u53D1\u5E03\u5931\u8D25\uFF1A[${stage}] \u9636\u6BB5
|
|
67182
|
+
${errorSummary}
|
|
67183
|
+
|
|
67184
|
+
\u5B8C\u6574\u65E5\u5FD7\uFF1A${logPath}
|
|
67185
|
+
\u8BF7\u4F60\u63A5\u7BA1\u5B8C\u6210\u672C\u6B21\u53D1\u5E03\uFF1A\u5148\u6839\u636E\u65E5\u5FD7\u4FEE\u590D\u95EE\u9898\uFF0C\u7136\u540E\u91CD\u8DD1 publish.sh \u76F4\u5230\u4E0A\u7EBF\u6210\u529F\uFF0C\u6700\u540E\u7528 appBuilder.setProdUrl \u5199\u5165\u516C\u7F51 URL\u3002`;
|
|
67186
|
+
}
|
|
67187
|
+
async function recoverInterruptedJobs(deps) {
|
|
67188
|
+
const projects = await deps.listAllProjects();
|
|
67189
|
+
for (const p2 of projects) {
|
|
67190
|
+
if (p2.publishJob) {
|
|
67191
|
+
deps.log(
|
|
67192
|
+
`[publish] found interrupted job ${p2.publishJob.jobId} for ${p2.name}, stage=${p2.publishJob.stage}`
|
|
67193
|
+
);
|
|
67194
|
+
}
|
|
67195
|
+
}
|
|
67196
|
+
}
|
|
67197
|
+
|
|
67198
|
+
// src/app-builder-plugin/core.ts
|
|
67199
|
+
function createPublishService() {
|
|
67200
|
+
const registry2 = new PublishJobRegistry();
|
|
67201
|
+
return {
|
|
67202
|
+
inFlightJobId(name) {
|
|
67203
|
+
return registry2.get(name)?.jobId ?? null;
|
|
67204
|
+
},
|
|
67205
|
+
async start(args) {
|
|
67206
|
+
const { store, hooks, logger } = args;
|
|
67207
|
+
const changed = async (name) => {
|
|
67208
|
+
await hooks?.onProjectChanged?.(name);
|
|
67209
|
+
};
|
|
67210
|
+
return await startPublishJob(
|
|
67211
|
+
{
|
|
67212
|
+
registry: registry2,
|
|
67213
|
+
setPublishJob: async (name, job) => {
|
|
67214
|
+
await store.setPublishJob(name, job);
|
|
67215
|
+
await changed(name);
|
|
67216
|
+
},
|
|
67217
|
+
clearPublishJob: async (name) => {
|
|
67218
|
+
await store.clearPublishJob(name);
|
|
67219
|
+
await changed(name);
|
|
67220
|
+
},
|
|
67221
|
+
setProdUrl: async (name, url) => {
|
|
67222
|
+
await store.setProdUrl(name, url);
|
|
67223
|
+
await changed(name);
|
|
67224
|
+
},
|
|
67225
|
+
broadcast: (frame) => hooks?.broadcast?.(frame),
|
|
67226
|
+
injectUserText: async (sessionId, text) => {
|
|
67227
|
+
await hooks?.injectUserText?.(sessionId, text);
|
|
67228
|
+
},
|
|
67229
|
+
projectDir: (name) => store.projectDir(name),
|
|
67230
|
+
...hooks?.onSettled ? { onSettled: hooks.onSettled } : {},
|
|
67231
|
+
...logger ? { logger } : {}
|
|
67232
|
+
},
|
|
67233
|
+
{
|
|
67234
|
+
name: args.name,
|
|
67235
|
+
sessionId: args.sessionId,
|
|
67236
|
+
scriptPath: args.scriptPath,
|
|
67237
|
+
personaRoot: args.personaRoot
|
|
67238
|
+
}
|
|
67239
|
+
);
|
|
67240
|
+
},
|
|
67241
|
+
dismiss(name) {
|
|
67242
|
+
const job = registry2.get(name);
|
|
67243
|
+
if (!job) return false;
|
|
67244
|
+
registry2.markDismissed(name);
|
|
67245
|
+
job.childProc.kill("SIGTERM");
|
|
67246
|
+
return true;
|
|
67247
|
+
}
|
|
67248
|
+
};
|
|
67249
|
+
}
|
|
67250
|
+
async function createProjectOnDisk(args) {
|
|
67251
|
+
const { store, name, templateSrcDir, scaffoldScript, logger } = args;
|
|
67252
|
+
const project = await store.create(name, args.reservedPorts);
|
|
67253
|
+
try {
|
|
67254
|
+
const result = await store.scaffold(name, templateSrcDir, scaffoldScript);
|
|
67255
|
+
logger?.info("app-builder.scaffold.done", { name, stdout: result.stdout.slice(0, 200) });
|
|
67256
|
+
} catch (err) {
|
|
67257
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
67258
|
+
logger?.warn("app-builder.scaffold.failed", { name, error: message });
|
|
67259
|
+
await store.delete(name).catch((delErr) => {
|
|
67260
|
+
logger?.warn("app-builder.scaffold.rollback-failed", {
|
|
67261
|
+
name,
|
|
67262
|
+
error: delErr instanceof Error ? delErr.message : String(delErr)
|
|
67263
|
+
});
|
|
67264
|
+
});
|
|
67265
|
+
throw new Error(`scaffold failed: ${message}`);
|
|
67266
|
+
}
|
|
67267
|
+
return { project, projectDir: store.projectDir(name) };
|
|
67268
|
+
}
|
|
67269
|
+
async function recoverInterruptedPublishJobs(store, logger) {
|
|
67270
|
+
await recoverInterruptedJobs({
|
|
67271
|
+
listAllProjects: async () => store.list(),
|
|
67272
|
+
log: (msg) => logger?.info(msg)
|
|
67273
|
+
});
|
|
67274
|
+
}
|
|
67275
|
+
|
|
67276
|
+
// src/app-builder-plugin/mcp-config.ts
|
|
67277
|
+
var import_node_fs53 = __toESM(require("fs"), 1);
|
|
67278
|
+
var import_node_path71 = __toESM(require("path"), 1);
|
|
67279
|
+
function appBuilderMcpConfigPath(dataDir) {
|
|
67280
|
+
return import_node_path71.default.join(dataDir, "app-builder.mcp.json");
|
|
67281
|
+
}
|
|
67282
|
+
function writeAppBuilderMcpConfig(args) {
|
|
67283
|
+
const cfgPath = appBuilderMcpConfigPath(args.dataDir);
|
|
67284
|
+
const cfg = {
|
|
67285
|
+
_comment: "daemon \u542F\u52A8\u81EA\u52A8\u751F\u6210\uFF1Bagent spawn \u901A\u8FC7 --mcp-config \u6CE8\u5165\u3002app-builder-plugin/mcp-server.cjs \u662F clawd-app-builder \u63D2\u4EF6\uFF08app-builder persona \u79C1\u6709\u7684\u540E\u7AEF\uFF1Aproject \u76EE\u5F55/\u5143\u6570\u636E + \u53D1\u5E03\u6D41\u6C34\u7EBF\uFF09\u3002\u6709 CLAWD_DAEMON_URL \u65F6\u8F6C\u8C03 appBuilder:* RPC\uFF08\u7AEF\u53E3\u6C60 / \u4F1A\u8BDD\u7ED1\u5B9A / UI \u5E7F\u64AD\u5F52 daemon\uFF09\uFF0C\u6CA1\u6709\u65F6\u7528\u540C\u4E00\u4EFD\u5185\u6838\u81EA\u5DF1\u5E72\uFF08\u4E91\u4E0A\u5BB9\u5668\uFF09\u3002\u975E app-builder \u7CFB persona \u7684\u4F1A\u8BDD\u91CC\u672C server \u4E0D\u6CE8\u518C\u4EFB\u4F55 tool\u3002",
|
|
67286
|
+
mcpServers: {
|
|
67287
|
+
"clawd-app-builder": {
|
|
67288
|
+
type: "stdio",
|
|
67289
|
+
command: "node",
|
|
67290
|
+
args: [args.serverScriptPath],
|
|
67291
|
+
env: {
|
|
67292
|
+
CLAWD_DAEMON_TOKEN: args.daemonToken,
|
|
67293
|
+
CLAWD_DAEMON_URL: args.daemonUrl,
|
|
67294
|
+
CLAWD_APP_BUILDER_SCAFFOLD_SCRIPT: import_node_path71.default.join(args.deployKitScriptsDir, "new-extension.sh"),
|
|
67295
|
+
CLAWD_APP_BUILDER_PUBLISH_SCRIPT: import_node_path71.default.join(args.deployKitScriptsDir, "publish.sh"),
|
|
67296
|
+
...args.logPath ? { CLAWD_APP_BUILDER_LOG: args.logPath } : {}
|
|
67297
|
+
}
|
|
67298
|
+
}
|
|
67299
|
+
}
|
|
67300
|
+
};
|
|
67301
|
+
import_node_fs53.default.mkdirSync(args.dataDir, { recursive: true });
|
|
67302
|
+
import_node_fs53.default.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), "utf8");
|
|
67303
|
+
return cfgPath;
|
|
67304
|
+
}
|
|
67305
|
+
|
|
67165
67306
|
// src/handlers/dispatch-rpc.ts
|
|
67166
67307
|
init_zod();
|
|
67167
67308
|
init_protocol();
|
|
@@ -67199,7 +67340,7 @@ async function dispatchRpc(method, frame, client, ctx, deps) {
|
|
|
67199
67340
|
|
|
67200
67341
|
// src/extension/runtime.ts
|
|
67201
67342
|
var import_node_child_process22 = require("child_process");
|
|
67202
|
-
var
|
|
67343
|
+
var import_node_path72 = __toESM(require("path"), 1);
|
|
67203
67344
|
var import_promises18 = require("timers/promises");
|
|
67204
67345
|
|
|
67205
67346
|
// src/extension/port-allocator.ts
|
|
@@ -67300,7 +67441,7 @@ var Runtime = class {
|
|
|
67300
67441
|
/\$CLAWOS_EXT_PORT/g,
|
|
67301
67442
|
String(port)
|
|
67302
67443
|
);
|
|
67303
|
-
const dir =
|
|
67444
|
+
const dir = import_node_path72.default.join(this.root, extId);
|
|
67304
67445
|
const env = {
|
|
67305
67446
|
...process.env,
|
|
67306
67447
|
CLAWOS_EXT_PORT: String(port),
|
|
@@ -67412,7 +67553,7 @@ ${handle.stderrTail}`
|
|
|
67412
67553
|
|
|
67413
67554
|
// src/extension/published-channels.ts
|
|
67414
67555
|
var import_promises19 = __toESM(require("fs/promises"), 1);
|
|
67415
|
-
var
|
|
67556
|
+
var import_node_path73 = __toESM(require("path"), 1);
|
|
67416
67557
|
init_zod();
|
|
67417
67558
|
var PublishedChannelsError = class extends Error {
|
|
67418
67559
|
constructor(code, message) {
|
|
@@ -67511,7 +67652,7 @@ var PublishedChannelStore = class {
|
|
|
67511
67652
|
)
|
|
67512
67653
|
};
|
|
67513
67654
|
const tmp = `${this.filePath}.tmp`;
|
|
67514
|
-
await import_promises19.default.mkdir(
|
|
67655
|
+
await import_promises19.default.mkdir(import_node_path73.default.dirname(this.filePath), { recursive: true });
|
|
67515
67656
|
await import_promises19.default.writeFile(tmp, JSON.stringify(data, null, 2), { mode: 384 });
|
|
67516
67657
|
await import_promises19.default.rename(tmp, this.filePath);
|
|
67517
67658
|
}
|
|
@@ -67519,7 +67660,7 @@ var PublishedChannelStore = class {
|
|
|
67519
67660
|
|
|
67520
67661
|
// src/extension/bundle-cache.ts
|
|
67521
67662
|
var import_promises20 = __toESM(require("fs/promises"), 1);
|
|
67522
|
-
var
|
|
67663
|
+
var import_node_path74 = __toESM(require("path"), 1);
|
|
67523
67664
|
var BundleCache = class {
|
|
67524
67665
|
constructor(rootDir) {
|
|
67525
67666
|
this.rootDir = rootDir;
|
|
@@ -67528,14 +67669,14 @@ var BundleCache = class {
|
|
|
67528
67669
|
/** Atomic write: stage tmp → rename. Caller passes the hex sha256. */
|
|
67529
67670
|
async write(snapshotHash, buffer) {
|
|
67530
67671
|
await import_promises20.default.mkdir(this.rootDir, { recursive: true });
|
|
67531
|
-
const file =
|
|
67672
|
+
const file = import_node_path74.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
67532
67673
|
const tmp = `${file}.tmp`;
|
|
67533
67674
|
await import_promises20.default.writeFile(tmp, buffer, { mode: 384 });
|
|
67534
67675
|
await import_promises20.default.rename(tmp, file);
|
|
67535
67676
|
}
|
|
67536
67677
|
/** Returns the bundle bytes, or null when the file doesn't exist. */
|
|
67537
67678
|
async read(snapshotHash) {
|
|
67538
|
-
const file =
|
|
67679
|
+
const file = import_node_path74.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
67539
67680
|
try {
|
|
67540
67681
|
return await import_promises20.default.readFile(file);
|
|
67541
67682
|
} catch (e) {
|
|
@@ -67545,7 +67686,7 @@ var BundleCache = class {
|
|
|
67545
67686
|
}
|
|
67546
67687
|
/** Idempotent — missing file is not an error. */
|
|
67547
67688
|
async delete(snapshotHash) {
|
|
67548
|
-
const file =
|
|
67689
|
+
const file = import_node_path74.default.join(this.rootDir, `${snapshotHash}.zip`);
|
|
67549
67690
|
await import_promises20.default.rm(file, { force: true });
|
|
67550
67691
|
}
|
|
67551
67692
|
};
|
|
@@ -67568,24 +67709,24 @@ async function startDaemon(config) {
|
|
|
67568
67709
|
sampling: logShippingCfg.sampling,
|
|
67569
67710
|
homeDir: import_node_os26.default.homedir()
|
|
67570
67711
|
});
|
|
67571
|
-
const logDir =
|
|
67572
|
-
|
|
67712
|
+
const logDir = import_node_path75.default.join(config.dataDir, "log");
|
|
67713
|
+
import_node_fs54.default.mkdirSync(logDir, { recursive: true });
|
|
67573
67714
|
const logger = createLogger({
|
|
67574
67715
|
level: config.logLevel,
|
|
67575
|
-
file:
|
|
67716
|
+
file: import_node_path75.default.join(logDir, "clawd.log"),
|
|
67576
67717
|
logClient
|
|
67577
67718
|
});
|
|
67578
67719
|
logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
|
|
67579
67720
|
const screenIdleProbeLogger = createFileOnlyLogger({
|
|
67580
|
-
file:
|
|
67721
|
+
file: import_node_path75.default.join(logDir, "screen-idle-probe.log"),
|
|
67581
67722
|
level: "debug"
|
|
67582
67723
|
});
|
|
67583
67724
|
logger.info("screen-idle probe logger enabled", {
|
|
67584
|
-
file:
|
|
67725
|
+
file: import_node_path75.default.join(logDir, "screen-idle-probe.log")
|
|
67585
67726
|
});
|
|
67586
67727
|
const CAP_TARGETS = [
|
|
67587
|
-
|
|
67588
|
-
|
|
67728
|
+
import_node_path75.default.join(logDir, "clawd.log"),
|
|
67729
|
+
import_node_path75.default.join(logDir, "screen-idle-probe.log")
|
|
67589
67730
|
];
|
|
67590
67731
|
const LOG_CAP_MAX_BYTES = 10 * 1024 * 1024;
|
|
67591
67732
|
const LOG_CAP_KEEP_BYTES = 5 * 1024 * 1024;
|
|
@@ -67707,8 +67848,8 @@ async function startDaemon(config) {
|
|
|
67707
67848
|
const agents = new AgentsScanner();
|
|
67708
67849
|
const history = new ClaudeHistoryReader();
|
|
67709
67850
|
let transport = null;
|
|
67710
|
-
const personaStore = new PersonaStore(
|
|
67711
|
-
const usersRoot =
|
|
67851
|
+
const personaStore = new PersonaStore(import_node_path75.default.join(config.dataDir, "personas"));
|
|
67852
|
+
const usersRoot = import_node_path75.default.join(config.dataDir, "users");
|
|
67712
67853
|
const defaultsRoot = findDefaultsRoot(logger);
|
|
67713
67854
|
if (defaultsRoot) {
|
|
67714
67855
|
seedDefaultPersonas({ store: personaStore, defaultsRoot, logger });
|
|
@@ -67732,7 +67873,7 @@ async function startDaemon(config) {
|
|
|
67732
67873
|
retirePersonaBuilder({ store: personaStore, logger });
|
|
67733
67874
|
const groupFileStore = new GroupFileStore({ dataDir: config.dataDir, logger });
|
|
67734
67875
|
const dispatchStore = createDispatchStore({
|
|
67735
|
-
filePath:
|
|
67876
|
+
filePath: import_node_path75.default.join(config.dataDir, "dispatch.json"),
|
|
67736
67877
|
now: () => Date.now(),
|
|
67737
67878
|
onFlushError: (err) => logger.error("dispatch store flush failed", {
|
|
67738
67879
|
reason: err instanceof Error ? err.message : String(err)
|
|
@@ -67741,7 +67882,7 @@ async function startDaemon(config) {
|
|
|
67741
67882
|
await dispatchStore.load();
|
|
67742
67883
|
dispatchStore.markInterruptedAsFailed((/* @__PURE__ */ new Date()).toISOString());
|
|
67743
67884
|
const channelStore = createChannelStore({
|
|
67744
|
-
filePath:
|
|
67885
|
+
filePath: import_node_path75.default.join(config.dataDir, "channels.json"),
|
|
67745
67886
|
now: () => Date.now(),
|
|
67746
67887
|
genId: () => `ch-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
|
|
67747
67888
|
onFlushError: (err) => logger.error("channel store flush failed", {
|
|
@@ -67750,7 +67891,7 @@ async function startDaemon(config) {
|
|
|
67750
67891
|
});
|
|
67751
67892
|
await channelStore.load();
|
|
67752
67893
|
const topicStore = createTopicStore({
|
|
67753
|
-
filePath:
|
|
67894
|
+
filePath: import_node_path75.default.join(config.dataDir, "topics.json"),
|
|
67754
67895
|
now: () => Date.now(),
|
|
67755
67896
|
genId: () => `tp-${(0, import_node_crypto22.randomUUID)().slice(0, 8)}`,
|
|
67756
67897
|
onFlushError: (err) => logger.error("topic store flush failed", {
|
|
@@ -67777,18 +67918,18 @@ async function startDaemon(config) {
|
|
|
67777
67918
|
});
|
|
67778
67919
|
}
|
|
67779
67920
|
});
|
|
67780
|
-
const here = typeof __dirname === "string" ? __dirname :
|
|
67921
|
+
const here = typeof __dirname === "string" ? __dirname : import_node_path75.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
|
|
67781
67922
|
const mcpConfigs = [];
|
|
67782
67923
|
const mcpDaemonUrl = `http://127.0.0.1:${config.port}`;
|
|
67783
67924
|
const dispatchServerCandidates = [
|
|
67784
|
-
|
|
67925
|
+
import_node_path75.default.join(here, "dispatch", "mcp-server.cjs"),
|
|
67785
67926
|
// 生产 dist/index → dist/dispatch/mcp-server.cjs
|
|
67786
|
-
|
|
67927
|
+
import_node_path75.default.join(here, "..", "dist", "dispatch", "mcp-server.cjs")
|
|
67787
67928
|
// dev tsx src/index → ../dist/dispatch/mcp-server.cjs
|
|
67788
67929
|
];
|
|
67789
|
-
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) =>
|
|
67930
|
+
const dispatchServerScriptPath = dispatchServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
67790
67931
|
if (dispatchServerScriptPath) {
|
|
67791
|
-
const dispatchLogPath =
|
|
67932
|
+
const dispatchLogPath = import_node_path75.default.join(logDir, "dispatch-mcp-server.log");
|
|
67792
67933
|
const dispatchCfgPath = writeDispatchMcpConfig({
|
|
67793
67934
|
dataDir: config.dataDir,
|
|
67794
67935
|
serverScriptPath: dispatchServerScriptPath,
|
|
@@ -67808,12 +67949,12 @@ async function startDaemon(config) {
|
|
|
67808
67949
|
});
|
|
67809
67950
|
}
|
|
67810
67951
|
const ticketServerCandidates = [
|
|
67811
|
-
|
|
67812
|
-
|
|
67952
|
+
import_node_path75.default.join(here, "ticket", "mcp-server.cjs"),
|
|
67953
|
+
import_node_path75.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
|
|
67813
67954
|
];
|
|
67814
|
-
const ticketServerScriptPath = ticketServerCandidates.find((p2) =>
|
|
67955
|
+
const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
67815
67956
|
if (ticketServerScriptPath) {
|
|
67816
|
-
const ticketLogPath =
|
|
67957
|
+
const ticketLogPath = import_node_path75.default.join(logDir, "ticket-mcp-server.log");
|
|
67817
67958
|
const ticketCfgPath = writeTicketMcpConfig({
|
|
67818
67959
|
dataDir: config.dataDir,
|
|
67819
67960
|
serverScriptPath: ticketServerScriptPath,
|
|
@@ -67835,12 +67976,12 @@ async function startDaemon(config) {
|
|
|
67835
67976
|
});
|
|
67836
67977
|
}
|
|
67837
67978
|
const shiftServerCandidates = [
|
|
67838
|
-
|
|
67839
|
-
|
|
67979
|
+
import_node_path75.default.join(here, "shift", "mcp-server.cjs"),
|
|
67980
|
+
import_node_path75.default.join(here, "..", "dist", "shift", "mcp-server.cjs")
|
|
67840
67981
|
];
|
|
67841
|
-
const shiftServerScriptPath = shiftServerCandidates.find((p2) =>
|
|
67982
|
+
const shiftServerScriptPath = shiftServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
67842
67983
|
if (shiftServerScriptPath) {
|
|
67843
|
-
const shiftLogPath =
|
|
67984
|
+
const shiftLogPath = import_node_path75.default.join(logDir, "shift-mcp-server.log");
|
|
67844
67985
|
const shiftCfgPath = await writeShiftMcpConfig({
|
|
67845
67986
|
dataDir: config.dataDir,
|
|
67846
67987
|
serverScriptPath: shiftServerScriptPath,
|
|
@@ -67861,12 +68002,12 @@ async function startDaemon(config) {
|
|
|
67861
68002
|
);
|
|
67862
68003
|
}
|
|
67863
68004
|
const inboxServerCandidates = [
|
|
67864
|
-
|
|
67865
|
-
|
|
68005
|
+
import_node_path75.default.join(here, "inbox", "mcp-server.cjs"),
|
|
68006
|
+
import_node_path75.default.join(here, "..", "dist", "inbox", "mcp-server.cjs")
|
|
67866
68007
|
];
|
|
67867
|
-
const inboxServerScriptPath = inboxServerCandidates.find((p2) =>
|
|
68008
|
+
const inboxServerScriptPath = inboxServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
67868
68009
|
if (inboxServerScriptPath) {
|
|
67869
|
-
const inboxLogPath =
|
|
68010
|
+
const inboxLogPath = import_node_path75.default.join(logDir, "inbox-mcp-server.log");
|
|
67870
68011
|
const inboxCfgPath = await writeInboxMcpConfig({
|
|
67871
68012
|
dataDir: config.dataDir,
|
|
67872
68013
|
serverScriptPath: inboxServerScriptPath,
|
|
@@ -67887,10 +68028,10 @@ async function startDaemon(config) {
|
|
|
67887
68028
|
);
|
|
67888
68029
|
}
|
|
67889
68030
|
const peerOpsServerCandidates = [
|
|
67890
|
-
|
|
67891
|
-
|
|
68031
|
+
import_node_path75.default.join(here, "peer-ops", "mcp-server.cjs"),
|
|
68032
|
+
import_node_path75.default.join(here, "..", "dist", "peer-ops", "mcp-server.cjs")
|
|
67892
68033
|
];
|
|
67893
|
-
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) =>
|
|
68034
|
+
const peerOpsServerScriptPath = peerOpsServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
67894
68035
|
if (peerOpsServerScriptPath) {
|
|
67895
68036
|
const peerOpsCfgPath = writePeerOpsMcpConfig({
|
|
67896
68037
|
dataDir: config.dataDir,
|
|
@@ -67910,12 +68051,12 @@ async function startDaemon(config) {
|
|
|
67910
68051
|
);
|
|
67911
68052
|
}
|
|
67912
68053
|
const rpcToolServerCandidates = [
|
|
67913
|
-
|
|
67914
|
-
|
|
68054
|
+
import_node_path75.default.join(here, "rpc-tool", "mcp-server.cjs"),
|
|
68055
|
+
import_node_path75.default.join(here, "..", "dist", "rpc-tool", "mcp-server.cjs")
|
|
67915
68056
|
];
|
|
67916
|
-
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) =>
|
|
68057
|
+
const rpcToolServerScriptPath = rpcToolServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
67917
68058
|
if (rpcToolServerScriptPath) {
|
|
67918
|
-
const rpcToolLogPath =
|
|
68059
|
+
const rpcToolLogPath = import_node_path75.default.join(logDir, "rpc-tool-mcp-server.log");
|
|
67919
68060
|
const rpcToolCfgPath = writeRpcToolMcpConfig({
|
|
67920
68061
|
dataDir: config.dataDir,
|
|
67921
68062
|
serverScriptPath: rpcToolServerScriptPath,
|
|
@@ -67935,8 +68076,35 @@ async function startDaemon(config) {
|
|
|
67935
68076
|
{ tried: rpcToolServerCandidates }
|
|
67936
68077
|
);
|
|
67937
68078
|
}
|
|
68079
|
+
const appBuilderServerCandidates = [
|
|
68080
|
+
import_node_path75.default.join(here, "app-builder-plugin", "mcp-server.cjs"),
|
|
68081
|
+
import_node_path75.default.join(here, "..", "dist", "app-builder-plugin", "mcp-server.cjs")
|
|
68082
|
+
];
|
|
68083
|
+
const appBuilderServerScriptPath = appBuilderServerCandidates.find((p2) => import_node_fs54.default.existsSync(p2));
|
|
68084
|
+
if (appBuilderServerScriptPath) {
|
|
68085
|
+
const appBuilderLogPath = import_node_path75.default.join(logDir, "app-builder-mcp-server.log");
|
|
68086
|
+
const appBuilderCfgPath = writeAppBuilderMcpConfig({
|
|
68087
|
+
dataDir: config.dataDir,
|
|
68088
|
+
serverScriptPath: appBuilderServerScriptPath,
|
|
68089
|
+
daemonToken: resolvedAuthToken,
|
|
68090
|
+
daemonUrl: mcpDaemonUrl,
|
|
68091
|
+
deployKitScriptsDir: import_node_path75.default.join(config.dataDir, "deploy-kit", "scripts"),
|
|
68092
|
+
logPath: appBuilderLogPath
|
|
68093
|
+
});
|
|
68094
|
+
mcpConfigs.push({ id: "app-builder", path: appBuilderCfgPath, personas: APP_BUILDER_PERSONAS });
|
|
68095
|
+
logger.info("app-builder.mcp.json written", {
|
|
68096
|
+
path: appBuilderCfgPath,
|
|
68097
|
+
server: appBuilderServerScriptPath,
|
|
68098
|
+
serverLog: appBuilderLogPath
|
|
68099
|
+
});
|
|
68100
|
+
} else {
|
|
68101
|
+
logger.warn(
|
|
68102
|
+
"app-builder-plugin/mcp-server.cjs not found; clawd-app-builder tools disabled (dev tsx \u6A21\u5F0F\u4E0B\u9700\u5148\u8DD1\u8FC7 build)",
|
|
68103
|
+
{ tried: appBuilderServerCandidates }
|
|
68104
|
+
);
|
|
68105
|
+
}
|
|
67938
68106
|
const shiftStore = createShiftStore({
|
|
67939
|
-
filePath:
|
|
68107
|
+
filePath: import_node_path75.default.join(config.dataDir, "shift.json"),
|
|
67940
68108
|
ownerIdProvider: () => ownerPrincipalId,
|
|
67941
68109
|
now: () => Date.now()
|
|
67942
68110
|
});
|
|
@@ -67958,7 +68126,7 @@ async function startDaemon(config) {
|
|
|
67958
68126
|
getAdapter,
|
|
67959
68127
|
historyReader: history,
|
|
67960
68128
|
dataDir: config.dataDir,
|
|
67961
|
-
personaRoot:
|
|
68129
|
+
personaRoot: import_node_path75.default.join(config.dataDir, "personas"),
|
|
67962
68130
|
// dispatch / shift 自动化 spawn 按 persona 绑定 tool 起 B session(codex persona 用 codex)。
|
|
67963
68131
|
// personaRegistry 声明在 manager 之后(同作用域 const,调用时机在启动完成后,无 TDZ 风险)。
|
|
67964
68132
|
getPersonaDefaults: (personaId2) => personaRegistry.get(personaId2),
|
|
@@ -68012,10 +68180,10 @@ async function startDaemon(config) {
|
|
|
68012
68180
|
// 文件可能 agent 写完又被自己删(罕见),用 size=0 / fallback mime 兜底。
|
|
68013
68181
|
attachmentGroup: {
|
|
68014
68182
|
onFileEdit: (input) => {
|
|
68015
|
-
const absPath =
|
|
68183
|
+
const absPath = import_node_path75.default.isAbsolute(input.relPath) ? input.relPath : import_node_path75.default.join(input.cwd, input.relPath);
|
|
68016
68184
|
let size = 0;
|
|
68017
68185
|
try {
|
|
68018
|
-
size =
|
|
68186
|
+
size = import_node_fs54.default.statSync(absPath).size;
|
|
68019
68187
|
} catch (err) {
|
|
68020
68188
|
logger.warn("attachment.onFileEdit stat failed", {
|
|
68021
68189
|
sessionId: input.sessionId,
|
|
@@ -68045,9 +68213,9 @@ async function startDaemon(config) {
|
|
|
68045
68213
|
logger.info("projects.seed-dropped", { dropped: droppedSeed.dropped, backup: droppedSeed.backup });
|
|
68046
68214
|
}
|
|
68047
68215
|
const projectsStore = new ProjectsStore({
|
|
68048
|
-
file:
|
|
68216
|
+
file: import_node_path75.default.join(config.dataDir, "projects.json"),
|
|
68049
68217
|
clawdDir: config.dataDir,
|
|
68050
|
-
codexStateFile:
|
|
68218
|
+
codexStateFile: import_node_path75.default.join(import_node_os26.default.homedir(), ".codex", ".codex-global-state.json"),
|
|
68051
68219
|
logger
|
|
68052
68220
|
});
|
|
68053
68221
|
const observer = new SessionObserver({
|
|
@@ -68107,13 +68275,13 @@ async function startDaemon(config) {
|
|
|
68107
68275
|
screenIdleProbeLogger
|
|
68108
68276
|
}) : new ClaudeAdapter({ logger, historyReader: new ClaudeHistoryReader() });
|
|
68109
68277
|
registerAdapter("claude", claudeAdapter);
|
|
68110
|
-
const codexIsolatedHome =
|
|
68278
|
+
const codexIsolatedHome = import_node_path75.default.join(config.dataDir, "codex-home");
|
|
68111
68279
|
try {
|
|
68112
|
-
|
|
68280
|
+
import_node_fs54.default.mkdirSync(codexIsolatedHome, { recursive: true });
|
|
68113
68281
|
for (const f of ["auth.json", "config.toml"]) {
|
|
68114
|
-
const link =
|
|
68115
|
-
const target =
|
|
68116
|
-
if (!
|
|
68282
|
+
const link = import_node_path75.default.join(codexIsolatedHome, f);
|
|
68283
|
+
const target = import_node_path75.default.join(import_node_os26.default.homedir(), ".codex", f);
|
|
68284
|
+
if (!import_node_fs54.default.existsSync(link) && import_node_fs54.default.existsSync(target)) import_node_fs54.default.symlinkSync(target, link);
|
|
68117
68285
|
}
|
|
68118
68286
|
} catch (err) {
|
|
68119
68287
|
logger.warn("codex isolated home setup failed", { err: String(err) });
|
|
@@ -68126,11 +68294,11 @@ async function startDaemon(config) {
|
|
|
68126
68294
|
// projectPaths 每次调用现取 —— 用户新建 project 后立即生效,不用重启 daemon
|
|
68127
68295
|
codexHomeFor: (cwd) => resolveCodexHome({
|
|
68128
68296
|
cwd,
|
|
68129
|
-
personaRoot:
|
|
68297
|
+
personaRoot: import_node_path75.default.join(config.dataDir, "personas"),
|
|
68130
68298
|
// 必须用 listMerged(Codex registry ∪ 叠加层):只用本地 list() 的话,用户在
|
|
68131
68299
|
// Codex 里建的 project 不在表里,在它下面开的会话会被误判成隔离 → Codex 侧看不到
|
|
68132
68300
|
projectPaths: projectsStore.listMerged().map((x) => x.path),
|
|
68133
|
-
sharedHome:
|
|
68301
|
+
sharedHome: import_node_path75.default.join(import_node_os26.default.homedir(), ".codex"),
|
|
68134
68302
|
isolatedHome: codexIsolatedHome
|
|
68135
68303
|
})
|
|
68136
68304
|
})
|
|
@@ -68312,6 +68480,7 @@ async function startDaemon(config) {
|
|
|
68312
68480
|
error: err instanceof Error ? err.message : String(err)
|
|
68313
68481
|
});
|
|
68314
68482
|
});
|
|
68483
|
+
const appBuilderPublishService = createPublishService();
|
|
68315
68484
|
const devServerSupervisor = new DevServerSupervisor();
|
|
68316
68485
|
devServerSupervisor.setLogger(logger);
|
|
68317
68486
|
const appBuilderPortRange = [];
|
|
@@ -68414,11 +68583,11 @@ async function startDaemon(config) {
|
|
|
68414
68583
|
// 'persona/<pid>/owner',default 走 'default'。
|
|
68415
68584
|
getSessionScope: (sid) => manager.findOwnedSessionScope(sid),
|
|
68416
68585
|
// guest path guard:candidate 必须在 personaRoot 子树或调用者自己的 user-dir 下
|
|
68417
|
-
personaRoot:
|
|
68586
|
+
personaRoot: import_node_path75.default.join(config.dataDir, "personas"),
|
|
68418
68587
|
usersRoot
|
|
68419
68588
|
},
|
|
68420
68589
|
// workspace/git/history/skills/agents handler 共用的 guest path guard 锚点
|
|
68421
|
-
personaRoot:
|
|
68590
|
+
personaRoot: import_node_path75.default.join(config.dataDir, "personas"),
|
|
68422
68591
|
// v2 多人 persona 隔离:handler 派生 guest user-dir 放行
|
|
68423
68592
|
usersRoot,
|
|
68424
68593
|
// v2 Phase 6: whoami handler 装在 owner principal.displayName + persona 解析
|
|
@@ -68499,6 +68668,8 @@ async function startDaemon(config) {
|
|
|
68499
68668
|
// app-builder
|
|
68500
68669
|
appBuilderStore,
|
|
68501
68670
|
getProjectStore,
|
|
68671
|
+
publishService: appBuilderPublishService,
|
|
68672
|
+
createProjectOnDisk,
|
|
68502
68673
|
devServerLifecycle: devServerSupervisor,
|
|
68503
68674
|
// 单栏 refactor §5.6.2 stage fix:appBuilder:project-updated 帧通过 wsServer broadcast。
|
|
68504
68675
|
// 推给所有 owner 连接(picker 可能没订阅特定 session,全局 broadcast 最稳)。
|
|
@@ -68517,11 +68688,11 @@ async function startDaemon(config) {
|
|
|
68517
68688
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2):
|
|
68518
68689
|
// appBuilderPersonaRoot 用于拼 publish.sh 绝对路径(persona-app-builder 安装在
|
|
68519
68690
|
// dataDir/personas/persona-app-builder 之下,extension-kit/scripts/publish.sh 是相对路径)。
|
|
68520
|
-
appBuilderPersonaRoot:
|
|
68691
|
+
appBuilderPersonaRoot: import_node_path75.default.join(config.dataDir, "personas", "persona-app-builder"),
|
|
68521
68692
|
// 共享 deploy-kit 根:scaffold/publish 脚本骨架 + 阿里云凭证单一真源。
|
|
68522
|
-
deployKitRoot:
|
|
68693
|
+
deployKitRoot: import_node_path75.default.join(config.dataDir, "deploy-kit"),
|
|
68523
68694
|
// scaffold/publish 按当前 session 的 persona 解析其安装根,让每个 persona 用自己的模板/注入配置。
|
|
68524
|
-
resolvePersonaRoot: (personaId2) =>
|
|
68695
|
+
resolvePersonaRoot: (personaId2) => import_node_path75.default.join(config.dataDir, "personas", personaId2),
|
|
68525
68696
|
// 发布上线脚手架化 (spec 2026-06-03 §5.2.2):
|
|
68526
68697
|
// 复用 SessionManagerDeps.broadcastFrame 同款 dispatch 逻辑 —— runner 调 manager.send
|
|
68527
68698
|
// 取回 broadcast 帧后逐帧 push 到 transport,跟 manager 自身的 deps 一致。
|
|
@@ -68634,12 +68805,12 @@ async function startDaemon(config) {
|
|
|
68634
68805
|
});
|
|
68635
68806
|
Object.assign(handlers, shiftHandlers);
|
|
68636
68807
|
const deployReceipts = createReceiptStore({
|
|
68637
|
-
filePath:
|
|
68808
|
+
filePath: import_node_path75.default.join(config.dataDir, "deploy.json"),
|
|
68638
68809
|
now: () => Date.now(),
|
|
68639
68810
|
onFlushError: (err) => logger.error("deploy receipts flush failed", { error: String(err) })
|
|
68640
68811
|
});
|
|
68641
68812
|
const deploySecrets = createSecretStore({
|
|
68642
|
-
filePath:
|
|
68813
|
+
filePath: import_node_path75.default.join(config.dataDir, "deploy-secrets.json"),
|
|
68643
68814
|
now: () => Date.now(),
|
|
68644
68815
|
onFlushError: (err) => logger.error("deploy secrets flush failed", { error: String(err) })
|
|
68645
68816
|
});
|
|
@@ -68653,7 +68824,7 @@ async function startDaemon(config) {
|
|
|
68653
68824
|
hasPersona: (personaId2) => personaStore.has(personaId2),
|
|
68654
68825
|
startScan: (deployId, personaId2) => {
|
|
68655
68826
|
const assetLines = SCANNABLE_ASSETS.map(
|
|
68656
|
-
(name) => ` - ${name}\uFF1A${
|
|
68827
|
+
(name) => ` - ${name}\uFF1A${import_node_path75.default.join(config.dataDir, name)}`
|
|
68657
68828
|
).join("\n");
|
|
68658
68829
|
const prompt = [
|
|
68659
68830
|
`\u626B\u63CF persona\u300C${personaId2}\u300D\u7684\u90E8\u7F72\u73AF\u5883\uFF0CdeployId=${deployId}\u3002`,
|
|
@@ -68694,7 +68865,7 @@ async function startDaemon(config) {
|
|
|
68694
68865
|
});
|
|
68695
68866
|
shiftScheduler.start();
|
|
68696
68867
|
logger.info("shift scheduler started", { shiftCount: shiftStore.list().length });
|
|
68697
|
-
const larkBotStore = createLarkBotBindingStore(
|
|
68868
|
+
const larkBotStore = createLarkBotBindingStore(import_node_path75.default.join(config.dataDir, "personas"));
|
|
68698
68869
|
const larkBotCloud = createLarkBotCloudClient({
|
|
68699
68870
|
api: config.clawosApi ?? DEFAULT_CLAWOS_API,
|
|
68700
68871
|
apiKey: resolveClawdTicketsApiKey(),
|
|
@@ -68708,7 +68879,7 @@ async function startDaemon(config) {
|
|
|
68708
68879
|
store: larkBotStore,
|
|
68709
68880
|
fetchResource: (appId, messageId, fileKey, maxBytes, type) => larkBotCloud.fetchResource(appId, messageId, fileKey, maxBytes, type),
|
|
68710
68881
|
// 图片落 guest userWorkDir 下(capId = lark-<chat_id>):CC 经 --add-dir + allowRead carve 可 Read
|
|
68711
|
-
mediaRootFor: (chatId) =>
|
|
68882
|
+
mediaRootFor: (chatId) => import_node_path75.default.join(deriveUserWorkDir(`lark-${chatId}`, usersRoot), "lark-media"),
|
|
68712
68883
|
isShuttingDown: () => larkDraining,
|
|
68713
68884
|
logger: {
|
|
68714
68885
|
warn: (msg) => logger.warn(msg),
|
|
@@ -69013,8 +69184,8 @@ async function startDaemon(config) {
|
|
|
69013
69184
|
const lines = [
|
|
69014
69185
|
`Tunnel: ${r.url}`,
|
|
69015
69186
|
...resolvedAuthToken ? [`Connect: ${connectUrl}`] : [],
|
|
69016
|
-
`Frpc config: ${
|
|
69017
|
-
`Frpc log: ${
|
|
69187
|
+
`Frpc config: ${import_node_path75.default.join(config.dataDir, "frpc.toml")}`,
|
|
69188
|
+
`Frpc log: ${import_node_path75.default.join(logDir, "frpc.log")}`
|
|
69018
69189
|
];
|
|
69019
69190
|
const width2 = Math.max(...lines.map((l) => l.length));
|
|
69020
69191
|
const bar = "\u2550".repeat(width2 + 4);
|
|
@@ -69027,8 +69198,8 @@ ${bar}
|
|
|
69027
69198
|
|
|
69028
69199
|
`);
|
|
69029
69200
|
try {
|
|
69030
|
-
const connectPath =
|
|
69031
|
-
|
|
69201
|
+
const connectPath = import_node_path75.default.join(config.dataDir, "connect.txt");
|
|
69202
|
+
import_node_fs54.default.writeFileSync(connectPath, lines.join("\n") + "\n", { mode: 384 });
|
|
69032
69203
|
} catch {
|
|
69033
69204
|
}
|
|
69034
69205
|
} catch (err) {
|
|
@@ -69117,9 +69288,9 @@ ${bar}
|
|
|
69117
69288
|
};
|
|
69118
69289
|
}
|
|
69119
69290
|
function migrateDropPersonsDir(dataDir) {
|
|
69120
|
-
const dir =
|
|
69291
|
+
const dir = import_node_path75.default.join(dataDir, "persons");
|
|
69121
69292
|
try {
|
|
69122
|
-
|
|
69293
|
+
import_node_fs54.default.rmSync(dir, { recursive: true, force: true });
|
|
69123
69294
|
} catch {
|
|
69124
69295
|
}
|
|
69125
69296
|
}
|