@docyrus/docyrus 0.0.63 → 0.0.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/agent-loader.js +1 -1
- package/agent-loader.js.map +2 -2
- package/main.js +268 -105
- package/main.js.map +4 -4
- package/package.json +1 -1
- package/resources/pi-agent/extensions/soul.ts +183 -0
- package/resources/pi-agent/skills/grill-me/SKILL.md +11 -8
- package/resources/pi-agent/skills/release-manager/SKILL.md +469 -30
- package/resources/pi-agent/souls/boomer-parent.md +23 -0
- package/resources/pi-agent/souls/bro.md +22 -0
- package/resources/pi-agent/souls/catalog.ts +79 -0
- package/resources/pi-agent/souls/caveman.md +21 -0
- package/resources/pi-agent/souls/linkedin-influencer.md +60 -0
- package/resources/pi-agent/souls/master-yoda.md +22 -0
- package/resources/pi-agent/souls/noir-detective.md +24 -0
- package/resources/pi-agent/souls/nonsense-engineer.md +23 -0
- package/resources/pi-agent/souls/pirate.md +24 -0
- package/resources/pi-agent/souls/shakespeare.md +24 -0
- package/server-loader.js +678 -69
- package/server-loader.js.map +4 -4
- package/resources/pi-agent/skills/changelog-generator/SKILL.md +0 -461
package/server-loader.js
CHANGED
|
@@ -2218,8 +2218,8 @@ var require_lib = __commonJS({
|
|
|
2218
2218
|
}
|
|
2219
2219
|
};
|
|
2220
2220
|
var walk2 = (opts, callback) => {
|
|
2221
|
-
const p = new Promise((
|
|
2222
|
-
new Walker(opts).on("done",
|
|
2221
|
+
const p = new Promise((resolve5, reject) => {
|
|
2222
|
+
new Walker(opts).on("done", resolve5).on("error", reject).start();
|
|
2223
2223
|
});
|
|
2224
2224
|
return callback ? p.then((res) => callback(null, res), callback) : p;
|
|
2225
2225
|
};
|
|
@@ -5393,10 +5393,10 @@ function resolveAll(constructs2, events, context) {
|
|
|
5393
5393
|
const called = [];
|
|
5394
5394
|
let index2 = -1;
|
|
5395
5395
|
while (++index2 < constructs2.length) {
|
|
5396
|
-
const
|
|
5397
|
-
if (
|
|
5398
|
-
events =
|
|
5399
|
-
called.push(
|
|
5396
|
+
const resolve5 = constructs2[index2].resolveAll;
|
|
5397
|
+
if (resolve5 && !called.includes(resolve5)) {
|
|
5398
|
+
events = resolve5(events, context);
|
|
5399
|
+
called.push(resolve5);
|
|
5400
5400
|
}
|
|
5401
5401
|
}
|
|
5402
5402
|
return events;
|
|
@@ -10705,9 +10705,9 @@ var init_lib9 = __esm({
|
|
|
10705
10705
|
* @returns {undefined}
|
|
10706
10706
|
* Nothing.
|
|
10707
10707
|
*/
|
|
10708
|
-
set dirname(
|
|
10708
|
+
set dirname(dirname12) {
|
|
10709
10709
|
assertPath(this.basename, "dirname");
|
|
10710
|
-
this.path = import_node_path6.default.join(
|
|
10710
|
+
this.path = import_node_path6.default.join(dirname12 || "", this.basename);
|
|
10711
10711
|
}
|
|
10712
10712
|
/**
|
|
10713
10713
|
* Get the extname (including dot) (example: `'.js'`).
|
|
@@ -11354,7 +11354,7 @@ var init_lib10 = __esm({
|
|
|
11354
11354
|
assertParser("process", this.parser || this.Parser);
|
|
11355
11355
|
assertCompiler("process", this.compiler || this.Compiler);
|
|
11356
11356
|
return done ? executor(void 0, done) : new Promise(executor);
|
|
11357
|
-
function executor(
|
|
11357
|
+
function executor(resolve5, reject) {
|
|
11358
11358
|
const realFile = vfile(file2);
|
|
11359
11359
|
const parseTree = (
|
|
11360
11360
|
/** @type {HeadTree extends undefined ? Node : HeadTree} */
|
|
@@ -11385,8 +11385,8 @@ var init_lib10 = __esm({
|
|
|
11385
11385
|
function realDone(error48, file3) {
|
|
11386
11386
|
if (error48 || !file3) {
|
|
11387
11387
|
reject(error48);
|
|
11388
|
-
} else if (
|
|
11389
|
-
|
|
11388
|
+
} else if (resolve5) {
|
|
11389
|
+
resolve5(file3);
|
|
11390
11390
|
} else {
|
|
11391
11391
|
ok(done, "`done` is defined if `resolve` is not");
|
|
11392
11392
|
done(void 0, file3);
|
|
@@ -11488,7 +11488,7 @@ var init_lib10 = __esm({
|
|
|
11488
11488
|
file2 = void 0;
|
|
11489
11489
|
}
|
|
11490
11490
|
return done ? executor(void 0, done) : new Promise(executor);
|
|
11491
|
-
function executor(
|
|
11491
|
+
function executor(resolve5, reject) {
|
|
11492
11492
|
ok(
|
|
11493
11493
|
typeof file2 !== "function",
|
|
11494
11494
|
"`file` can\u2019t be a `done` anymore, we checked"
|
|
@@ -11502,8 +11502,8 @@ var init_lib10 = __esm({
|
|
|
11502
11502
|
);
|
|
11503
11503
|
if (error48) {
|
|
11504
11504
|
reject(error48);
|
|
11505
|
-
} else if (
|
|
11506
|
-
|
|
11505
|
+
} else if (resolve5) {
|
|
11506
|
+
resolve5(resultingTree);
|
|
11507
11507
|
} else {
|
|
11508
11508
|
ok(done, "`done` is defined if `resolve` is not");
|
|
11509
11509
|
done(void 0, resultingTree, file3);
|
|
@@ -12590,8 +12590,8 @@ var require_dist = __commonJS({
|
|
|
12590
12590
|
const header = report.header;
|
|
12591
12591
|
return typeof header === "object" && !!header && "glibcVersionRuntime" in header;
|
|
12592
12592
|
}
|
|
12593
|
-
function load(
|
|
12594
|
-
const m = path6.join(
|
|
12593
|
+
function load(dirname12) {
|
|
12594
|
+
const m = path6.join(dirname12, "index.node");
|
|
12595
12595
|
return fs7.existsSync(m) ? require(m) : null;
|
|
12596
12596
|
}
|
|
12597
12597
|
exports2.load = load;
|
|
@@ -12621,12 +12621,12 @@ var require_filesystem = __commonJS({
|
|
|
12621
12621
|
var fs7 = require("fs");
|
|
12622
12622
|
var LDD_PATH = "/usr/bin/ldd";
|
|
12623
12623
|
var readFileSync5 = (path6) => fs7.readFileSync(path6, "utf-8");
|
|
12624
|
-
var readFile15 = (path6) => new Promise((
|
|
12624
|
+
var readFile15 = (path6) => new Promise((resolve5, reject) => {
|
|
12625
12625
|
fs7.readFile(path6, "utf-8", (err2, data) => {
|
|
12626
12626
|
if (err2) {
|
|
12627
12627
|
reject(err2);
|
|
12628
12628
|
} else {
|
|
12629
|
-
|
|
12629
|
+
resolve5(data);
|
|
12630
12630
|
}
|
|
12631
12631
|
});
|
|
12632
12632
|
});
|
|
@@ -12651,10 +12651,10 @@ var require_detect_libc = __commonJS({
|
|
|
12651
12651
|
var commandOut = "";
|
|
12652
12652
|
var safeCommand = () => {
|
|
12653
12653
|
if (!commandOut) {
|
|
12654
|
-
return new Promise((
|
|
12654
|
+
return new Promise((resolve5) => {
|
|
12655
12655
|
childProcess.exec(command, (err2, out2) => {
|
|
12656
12656
|
commandOut = err2 ? " " : out2;
|
|
12657
|
-
|
|
12657
|
+
resolve5(commandOut);
|
|
12658
12658
|
});
|
|
12659
12659
|
});
|
|
12660
12660
|
}
|
|
@@ -16571,7 +16571,7 @@ var require_websocket = __commonJS({
|
|
|
16571
16571
|
var http = require("http");
|
|
16572
16572
|
var net = require("net");
|
|
16573
16573
|
var tls = require("tls");
|
|
16574
|
-
var { randomBytes, createHash:
|
|
16574
|
+
var { randomBytes, createHash: createHash6 } = require("crypto");
|
|
16575
16575
|
var { Duplex, Readable: Readable2 } = require("stream");
|
|
16576
16576
|
var { URL: URL2 } = require("url");
|
|
16577
16577
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -17231,7 +17231,7 @@ var require_websocket = __commonJS({
|
|
|
17231
17231
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
17232
17232
|
return;
|
|
17233
17233
|
}
|
|
17234
|
-
const digest =
|
|
17234
|
+
const digest = createHash6("sha1").update(key + GUID).digest("base64");
|
|
17235
17235
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
17236
17236
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
17237
17237
|
return;
|
|
@@ -17598,7 +17598,7 @@ var require_websocket_server = __commonJS({
|
|
|
17598
17598
|
var EventEmitter = require("events");
|
|
17599
17599
|
var http = require("http");
|
|
17600
17600
|
var { Duplex } = require("stream");
|
|
17601
|
-
var { createHash:
|
|
17601
|
+
var { createHash: createHash6 } = require("crypto");
|
|
17602
17602
|
var extension3 = require_extension();
|
|
17603
17603
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
17604
17604
|
var subprotocol2 = require_subprotocol();
|
|
@@ -17899,7 +17899,7 @@ var require_websocket_server = __commonJS({
|
|
|
17899
17899
|
);
|
|
17900
17900
|
}
|
|
17901
17901
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
17902
|
-
const digest =
|
|
17902
|
+
const digest = createHash6("sha1").update(key + GUID).digest("base64");
|
|
17903
17903
|
const headers = [
|
|
17904
17904
|
"HTTP/1.1 101 Switching Protocols",
|
|
17905
17905
|
"Upgrade: websocket",
|
|
@@ -18467,7 +18467,7 @@ var init_dist = __esm({
|
|
|
18467
18467
|
});
|
|
18468
18468
|
if (!chunk) {
|
|
18469
18469
|
if (i2 === 1) {
|
|
18470
|
-
await new Promise((
|
|
18470
|
+
await new Promise((resolve5) => setTimeout(resolve5));
|
|
18471
18471
|
maxReadCount = 3;
|
|
18472
18472
|
continue;
|
|
18473
18473
|
}
|
|
@@ -18617,7 +18617,7 @@ var init_dist = __esm({
|
|
|
18617
18617
|
});
|
|
18618
18618
|
|
|
18619
18619
|
// src/server/server-loader.ts
|
|
18620
|
-
var
|
|
18620
|
+
var import_node_fs14 = require("node:fs");
|
|
18621
18621
|
var import_node_url3 = require("node:url");
|
|
18622
18622
|
var import_node_path23 = require("node:path");
|
|
18623
18623
|
var import_picocolors2 = __toESM(require_picocolors());
|
|
@@ -18743,7 +18743,7 @@ function resolvePackagedExtensionPaths(resourceRoot, runtime = "terminal") {
|
|
|
18743
18743
|
|
|
18744
18744
|
// src/server/agentServer.ts
|
|
18745
18745
|
var import_node_child_process3 = require("node:child_process");
|
|
18746
|
-
var
|
|
18746
|
+
var import_node_crypto7 = require("node:crypto");
|
|
18747
18747
|
var import_promises18 = require("node:fs/promises");
|
|
18748
18748
|
var import_node_path22 = require("node:path");
|
|
18749
18749
|
|
|
@@ -32612,7 +32612,8 @@ var EnvironmentConfigStateSchema = external_exports.object({
|
|
|
32612
32612
|
version: external_exports.literal(1),
|
|
32613
32613
|
activeEnvironmentId: external_exports.string().min(1),
|
|
32614
32614
|
environments: external_exports.array(EnvironmentConfigItemSchema).min(1),
|
|
32615
|
-
defaultClientId: external_exports.string().min(1).optional()
|
|
32615
|
+
defaultClientId: external_exports.string().min(1).optional(),
|
|
32616
|
+
activeSoulId: external_exports.string().min(1).optional()
|
|
32616
32617
|
});
|
|
32617
32618
|
var LegacyAuthSessionSchema = external_exports.object({
|
|
32618
32619
|
apiBaseUrl: external_exports.string().min(1),
|
|
@@ -32982,6 +32983,76 @@ var AuthStore = class {
|
|
|
32982
32983
|
// src/services/environmentConfig.ts
|
|
32983
32984
|
var import_promises3 = require("node:fs/promises");
|
|
32984
32985
|
var import_node_path5 = require("node:path");
|
|
32986
|
+
|
|
32987
|
+
// resources/pi-agent/souls/catalog.ts
|
|
32988
|
+
var DEFAULT_SOUL_ID = "default";
|
|
32989
|
+
var SOULS = [
|
|
32990
|
+
{
|
|
32991
|
+
id: "default",
|
|
32992
|
+
name: "Default",
|
|
32993
|
+
description: "Standard Docyrus operator voice. No style overlay.",
|
|
32994
|
+
promptFile: null
|
|
32995
|
+
},
|
|
32996
|
+
{
|
|
32997
|
+
id: "caveman",
|
|
32998
|
+
name: "Caveman",
|
|
32999
|
+
description: "Short grunts. Agent talk simple. Fire good.",
|
|
33000
|
+
promptFile: "caveman.md"
|
|
33001
|
+
},
|
|
33002
|
+
{
|
|
33003
|
+
id: "boomer-parent",
|
|
33004
|
+
name: "Boomer Parent",
|
|
33005
|
+
description: "Overly proud dad-jokes energy with 'back in my day' asides.",
|
|
33006
|
+
promptFile: "boomer-parent.md"
|
|
33007
|
+
},
|
|
33008
|
+
{
|
|
33009
|
+
id: "master-yoda",
|
|
33010
|
+
name: "Master Yoda",
|
|
33011
|
+
description: "Inverted syntax the agent speaks. Mystical brevity, hmm.",
|
|
33012
|
+
promptFile: "master-yoda.md"
|
|
33013
|
+
},
|
|
33014
|
+
{
|
|
33015
|
+
id: "bro",
|
|
33016
|
+
name: "Bro",
|
|
33017
|
+
description: "Pure gym-bro hype energy. 'Lit, fam, let's go.'",
|
|
33018
|
+
promptFile: "bro.md"
|
|
33019
|
+
},
|
|
33020
|
+
{
|
|
33021
|
+
id: "nonsense-engineer",
|
|
33022
|
+
name: "Nonsense Engineer",
|
|
33023
|
+
description: "Maximum jargon, minimum meaning. 'Leveraging synergistic abstractions.'",
|
|
33024
|
+
promptFile: "nonsense-engineer.md"
|
|
33025
|
+
},
|
|
33026
|
+
{
|
|
33027
|
+
id: "shakespeare",
|
|
33028
|
+
name: "Shakespeare",
|
|
33029
|
+
description: "Thee/thou, dramatic flair, iambic vibes.",
|
|
33030
|
+
promptFile: "shakespeare.md"
|
|
33031
|
+
},
|
|
33032
|
+
{
|
|
33033
|
+
id: "noir-detective",
|
|
33034
|
+
name: "Noir Detective",
|
|
33035
|
+
description: "Hard-boiled 1940s narrator. Every bug is a dame.",
|
|
33036
|
+
promptFile: "noir-detective.md"
|
|
33037
|
+
},
|
|
33038
|
+
{
|
|
33039
|
+
id: "pirate",
|
|
33040
|
+
name: "Pirate",
|
|
33041
|
+
description: "Aye matey, every task a seafaring metaphor, arrr.",
|
|
33042
|
+
promptFile: "pirate.md"
|
|
33043
|
+
},
|
|
33044
|
+
{
|
|
33045
|
+
id: "linkedin-influencer",
|
|
33046
|
+
name: "LinkedIn Influencer",
|
|
33047
|
+
description: "Every reply is a mini-post. Single-sentence paragraphs. Humble-brags. 'Agree? \u{1F447}'",
|
|
33048
|
+
promptFile: "linkedin-influencer.md"
|
|
33049
|
+
}
|
|
33050
|
+
];
|
|
33051
|
+
function findSoul(id) {
|
|
33052
|
+
return SOULS.find((soul) => soul.id === id);
|
|
33053
|
+
}
|
|
33054
|
+
|
|
33055
|
+
// src/services/environmentConfig.ts
|
|
32985
33056
|
var ENVIRONMENT_ID_ALIASES = {
|
|
32986
33057
|
"local-development": "dev",
|
|
32987
33058
|
prod: "live"
|
|
@@ -33005,9 +33076,20 @@ function createDefaultState2() {
|
|
|
33005
33076
|
name: environment.name,
|
|
33006
33077
|
apiBaseUrl: environment.apiBaseUrl
|
|
33007
33078
|
})),
|
|
33008
|
-
defaultClientId: void 0
|
|
33079
|
+
defaultClientId: void 0,
|
|
33080
|
+
activeSoulId: DEFAULT_SOUL_ID
|
|
33009
33081
|
};
|
|
33010
33082
|
}
|
|
33083
|
+
function normalizeSoulId(value2) {
|
|
33084
|
+
if (!value2) {
|
|
33085
|
+
return DEFAULT_SOUL_ID;
|
|
33086
|
+
}
|
|
33087
|
+
const trimmed = value2.trim();
|
|
33088
|
+
if (!trimmed) {
|
|
33089
|
+
return DEFAULT_SOUL_ID;
|
|
33090
|
+
}
|
|
33091
|
+
return findSoul(trimmed) ? trimmed : DEFAULT_SOUL_ID;
|
|
33092
|
+
}
|
|
33011
33093
|
function normalizeState3(state) {
|
|
33012
33094
|
const defaultsById = new Map(
|
|
33013
33095
|
DEFAULT_ENVIRONMENTS.map((environment) => [
|
|
@@ -33058,7 +33140,8 @@ function normalizeState3(state) {
|
|
|
33058
33140
|
version: 1,
|
|
33059
33141
|
activeEnvironmentId: hasActiveEnvironment ? canonicalActiveEnvironmentId : fallbackActiveEnvironment,
|
|
33060
33142
|
environments,
|
|
33061
|
-
defaultClientId: state.defaultClientId?.trim() || void 0
|
|
33143
|
+
defaultClientId: state.defaultClientId?.trim() || void 0,
|
|
33144
|
+
activeSoulId: normalizeSoulId(state.activeSoulId)
|
|
33062
33145
|
};
|
|
33063
33146
|
}
|
|
33064
33147
|
var EnvironmentConfigService = class {
|
|
@@ -33163,6 +33246,25 @@ var EnvironmentConfigService = class {
|
|
|
33163
33246
|
defaultClientId: trimmedClientId
|
|
33164
33247
|
});
|
|
33165
33248
|
}
|
|
33249
|
+
async getActiveSoulId() {
|
|
33250
|
+
const state = await this.#readStateWithDefaults();
|
|
33251
|
+
return normalizeSoulId(state.activeSoulId);
|
|
33252
|
+
}
|
|
33253
|
+
async setActiveSoulId(soulId) {
|
|
33254
|
+
const trimmed = soulId.trim();
|
|
33255
|
+
if (!trimmed) {
|
|
33256
|
+
throw new UserInputError("Soul ID cannot be empty.");
|
|
33257
|
+
}
|
|
33258
|
+
if (!findSoul(trimmed)) {
|
|
33259
|
+
throw new UserInputError(`Unknown soul '${soulId}'. Use /souls inside the pi agent or GET /api/souls to view options.`);
|
|
33260
|
+
}
|
|
33261
|
+
const state = await this.#readStateWithDefaults();
|
|
33262
|
+
await this.writeState({
|
|
33263
|
+
...state,
|
|
33264
|
+
activeSoulId: trimmed
|
|
33265
|
+
});
|
|
33266
|
+
return trimmed;
|
|
33267
|
+
}
|
|
33166
33268
|
async #readStateWithDefaults() {
|
|
33167
33269
|
const state = await this.readState();
|
|
33168
33270
|
if (state.environments.length > 0) {
|
|
@@ -33177,6 +33279,14 @@ var EnvironmentConfigService = class {
|
|
|
33177
33279
|
}
|
|
33178
33280
|
};
|
|
33179
33281
|
|
|
33282
|
+
// src/services/soulRegistry.ts
|
|
33283
|
+
function listSouls(activeSoulId) {
|
|
33284
|
+
return SOULS.map((soul) => ({
|
|
33285
|
+
...soul,
|
|
33286
|
+
isActive: soul.id === activeSoulId
|
|
33287
|
+
}));
|
|
33288
|
+
}
|
|
33289
|
+
|
|
33180
33290
|
// ../../node_modules/.pnpm/hono@4.12.14/node_modules/hono/dist/compose.js
|
|
33181
33291
|
var compose = (middleware, onError, onNotFound) => {
|
|
33182
33292
|
return (context, next) => {
|
|
@@ -35695,23 +35805,23 @@ var EXCLUDE_DIRS = ["docyrus/knowledge", ".claude"];
|
|
|
35695
35805
|
var EXCLUDE_GLOBS = ["*.md"];
|
|
35696
35806
|
var DOCYRUS_REF_RE = /(?:\/\/|#)\s*@docyrus:\s*\[\[([^\]]+)\]\]/gu;
|
|
35697
35807
|
function tryExec(command, args2, cwd) {
|
|
35698
|
-
return new Promise((
|
|
35808
|
+
return new Promise((resolve5) => {
|
|
35699
35809
|
(0, import_node_child_process.execFile)(command, args2, { cwd, maxBuffer: 50 * 1024 * 1024 }, (error48, stdout) => {
|
|
35700
35810
|
if (error48) {
|
|
35701
35811
|
const exitCode = error48.code;
|
|
35702
35812
|
const status = error48.status;
|
|
35703
35813
|
if (exitCode === "ENOENT") {
|
|
35704
|
-
|
|
35814
|
+
resolve5(null);
|
|
35705
35815
|
return;
|
|
35706
35816
|
}
|
|
35707
35817
|
if (status === 1 && stdout === "") {
|
|
35708
|
-
|
|
35818
|
+
resolve5("");
|
|
35709
35819
|
return;
|
|
35710
35820
|
}
|
|
35711
|
-
|
|
35821
|
+
resolve5(null);
|
|
35712
35822
|
return;
|
|
35713
35823
|
}
|
|
35714
|
-
|
|
35824
|
+
resolve5(stdout);
|
|
35715
35825
|
});
|
|
35716
35826
|
});
|
|
35717
35827
|
}
|
|
@@ -37917,8 +38027,8 @@ var Module2 = (() => {
|
|
|
37917
38027
|
var moduleRtn;
|
|
37918
38028
|
var Module = moduleArg;
|
|
37919
38029
|
var readyPromiseResolve, readyPromiseReject;
|
|
37920
|
-
var readyPromise = new Promise((
|
|
37921
|
-
readyPromiseResolve =
|
|
38030
|
+
var readyPromise = new Promise((resolve5, reject) => {
|
|
38031
|
+
readyPromiseResolve = resolve5;
|
|
37922
38032
|
readyPromiseReject = reject;
|
|
37923
38033
|
});
|
|
37924
38034
|
var ENVIRONMENT_IS_WEB = typeof window == "object";
|
|
@@ -38001,13 +38111,13 @@ var Module2 = (() => {
|
|
|
38001
38111
|
}
|
|
38002
38112
|
readAsync = /* @__PURE__ */ __name(async (url2) => {
|
|
38003
38113
|
if (isFileURI(url2)) {
|
|
38004
|
-
return new Promise((
|
|
38114
|
+
return new Promise((resolve5, reject) => {
|
|
38005
38115
|
var xhr = new XMLHttpRequest();
|
|
38006
38116
|
xhr.open("GET", url2, true);
|
|
38007
38117
|
xhr.responseType = "arraybuffer";
|
|
38008
38118
|
xhr.onload = () => {
|
|
38009
38119
|
if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
|
|
38010
|
-
|
|
38120
|
+
resolve5(xhr.response);
|
|
38011
38121
|
return;
|
|
38012
38122
|
}
|
|
38013
38123
|
reject(xhr.status);
|
|
@@ -38231,10 +38341,10 @@ var Module2 = (() => {
|
|
|
38231
38341
|
__name(receiveInstantiationResult, "receiveInstantiationResult");
|
|
38232
38342
|
var info2 = getWasmImports();
|
|
38233
38343
|
if (Module["instantiateWasm"]) {
|
|
38234
|
-
return new Promise((
|
|
38344
|
+
return new Promise((resolve5, reject) => {
|
|
38235
38345
|
Module["instantiateWasm"](info2, (mod, inst) => {
|
|
38236
38346
|
receiveInstance(mod, inst);
|
|
38237
|
-
|
|
38347
|
+
resolve5(mod.exports);
|
|
38238
38348
|
});
|
|
38239
38349
|
});
|
|
38240
38350
|
}
|
|
@@ -43379,8 +43489,8 @@ var OAuthFlowManager = class {
|
|
|
43379
43489
|
if (state.currentStep) {
|
|
43380
43490
|
return Promise.resolve(state.currentStep);
|
|
43381
43491
|
}
|
|
43382
|
-
return new Promise((
|
|
43383
|
-
state.waitingForStep = { resolve:
|
|
43492
|
+
return new Promise((resolve5) => {
|
|
43493
|
+
state.waitingForStep = { resolve: resolve5 };
|
|
43384
43494
|
});
|
|
43385
43495
|
}
|
|
43386
43496
|
async start(params) {
|
|
@@ -43401,8 +43511,8 @@ var OAuthFlowManager = class {
|
|
|
43401
43511
|
onPrompt: async (prompt) => {
|
|
43402
43512
|
const step = buildPromptStep({ state, type: "prompt", prompt });
|
|
43403
43513
|
this.emitStep(state, step);
|
|
43404
|
-
return await new Promise((
|
|
43405
|
-
state.pendingInput = { type: "prompt", resolve:
|
|
43514
|
+
return await new Promise((resolve5) => {
|
|
43515
|
+
state.pendingInput = { type: "prompt", resolve: resolve5 };
|
|
43406
43516
|
});
|
|
43407
43517
|
},
|
|
43408
43518
|
onManualCodeInput: async () => {
|
|
@@ -43414,8 +43524,8 @@ var OAuthFlowManager = class {
|
|
|
43414
43524
|
}
|
|
43415
43525
|
});
|
|
43416
43526
|
this.emitStep(state, step);
|
|
43417
|
-
return await new Promise((
|
|
43418
|
-
state.pendingInput = { type: "manual-code", resolve:
|
|
43527
|
+
return await new Promise((resolve5) => {
|
|
43528
|
+
state.pendingInput = { type: "manual-code", resolve: resolve5 };
|
|
43419
43529
|
});
|
|
43420
43530
|
},
|
|
43421
43531
|
onProgress: (_message) => {
|
|
@@ -43459,6 +43569,7 @@ var OAuthFlowManager = class {
|
|
|
43459
43569
|
|
|
43460
43570
|
// src/server/mcpConfigService.ts
|
|
43461
43571
|
var import_node_crypto5 = require("node:crypto");
|
|
43572
|
+
var import_node_fs12 = require("node:fs");
|
|
43462
43573
|
var import_promises16 = require("node:fs/promises");
|
|
43463
43574
|
var import_node_os2 = require("node:os");
|
|
43464
43575
|
var import_node_path20 = require("node:path");
|
|
@@ -43784,6 +43895,95 @@ async function removeMcpServer(agentDir, name2) {
|
|
|
43784
43895
|
raw2[key] = servers;
|
|
43785
43896
|
await writeUserConfig(agentDir, raw2);
|
|
43786
43897
|
}
|
|
43898
|
+
var SUPPORTED_IMPORT_KINDS = [
|
|
43899
|
+
"cursor",
|
|
43900
|
+
"claude-code",
|
|
43901
|
+
"claude-desktop",
|
|
43902
|
+
"codex",
|
|
43903
|
+
"windsurf",
|
|
43904
|
+
"vscode"
|
|
43905
|
+
];
|
|
43906
|
+
function validateMcpSettings(value2) {
|
|
43907
|
+
if (!value2 || typeof value2 !== "object" || Array.isArray(value2)) {
|
|
43908
|
+
return { ok: false, error: "settings must be an object" };
|
|
43909
|
+
}
|
|
43910
|
+
const obj = value2;
|
|
43911
|
+
const settings = {};
|
|
43912
|
+
if (obj.toolPrefix !== void 0) {
|
|
43913
|
+
if (!["server", "none", "short"].includes(obj.toolPrefix)) {
|
|
43914
|
+
return { ok: false, error: "settings.toolPrefix must be 'server', 'none', or 'short'" };
|
|
43915
|
+
}
|
|
43916
|
+
settings.toolPrefix = obj.toolPrefix;
|
|
43917
|
+
}
|
|
43918
|
+
if (obj.idleTimeout !== void 0) {
|
|
43919
|
+
if (typeof obj.idleTimeout !== "number" || !Number.isFinite(obj.idleTimeout) || obj.idleTimeout < 0) {
|
|
43920
|
+
return { ok: false, error: "settings.idleTimeout must be a non-negative number (minutes)" };
|
|
43921
|
+
}
|
|
43922
|
+
settings.idleTimeout = obj.idleTimeout;
|
|
43923
|
+
}
|
|
43924
|
+
if (obj.directTools !== void 0) {
|
|
43925
|
+
if (typeof obj.directTools !== "boolean") {
|
|
43926
|
+
return { ok: false, error: "settings.directTools must be a boolean" };
|
|
43927
|
+
}
|
|
43928
|
+
settings.directTools = obj.directTools;
|
|
43929
|
+
}
|
|
43930
|
+
return { ok: true, value: settings };
|
|
43931
|
+
}
|
|
43932
|
+
function validateImportKinds(value2) {
|
|
43933
|
+
if (!Array.isArray(value2)) {
|
|
43934
|
+
return { ok: false, error: "imports must be an array of import kinds" };
|
|
43935
|
+
}
|
|
43936
|
+
const kinds = [];
|
|
43937
|
+
for (const item of value2) {
|
|
43938
|
+
if (typeof item !== "string" || !SUPPORTED_IMPORT_KINDS.includes(item)) {
|
|
43939
|
+
return {
|
|
43940
|
+
ok: false,
|
|
43941
|
+
error: `Unsupported import kind: ${String(item)}. Allowed: ${SUPPORTED_IMPORT_KINDS.join(", ")}`
|
|
43942
|
+
};
|
|
43943
|
+
}
|
|
43944
|
+
if (!kinds.includes(item)) {
|
|
43945
|
+
kinds.push(item);
|
|
43946
|
+
}
|
|
43947
|
+
}
|
|
43948
|
+
return { ok: true, value: kinds };
|
|
43949
|
+
}
|
|
43950
|
+
function getImportPath(kind, cwd) {
|
|
43951
|
+
const raw2 = IMPORT_PATHS[kind];
|
|
43952
|
+
return raw2.startsWith(".") ? (0, import_node_path20.resolve)(cwd, raw2) : raw2;
|
|
43953
|
+
}
|
|
43954
|
+
async function updateMcpSettings(agentDir, patch) {
|
|
43955
|
+
const { raw: raw2 } = await readUserConfig(agentDir);
|
|
43956
|
+
const current = raw2.settings && typeof raw2.settings === "object" && !Array.isArray(raw2.settings) ? raw2.settings : {};
|
|
43957
|
+
const merged = { ...current, ...patch };
|
|
43958
|
+
raw2.settings = merged;
|
|
43959
|
+
await writeUserConfig(agentDir, raw2);
|
|
43960
|
+
return merged;
|
|
43961
|
+
}
|
|
43962
|
+
async function updateMcpImports(agentDir, imports) {
|
|
43963
|
+
const { raw: raw2 } = await readUserConfig(agentDir);
|
|
43964
|
+
raw2.imports = imports;
|
|
43965
|
+
await writeUserConfig(agentDir, raw2);
|
|
43966
|
+
return imports;
|
|
43967
|
+
}
|
|
43968
|
+
async function describeImports(agentDir, cwd) {
|
|
43969
|
+
const { config: config2 } = await readUserConfig(agentDir);
|
|
43970
|
+
const enabled = config2.imports ?? [];
|
|
43971
|
+
const available = await Promise.all(
|
|
43972
|
+
SUPPORTED_IMPORT_KINDS.map(async (kind) => {
|
|
43973
|
+
const path6 = getImportPath(kind, cwd);
|
|
43974
|
+
const imported = (0, import_node_fs12.existsSync)(path6) ? await readJsonFile2(path6) : null;
|
|
43975
|
+
const servers = imported ? extractServers(imported, kind) : {};
|
|
43976
|
+
return {
|
|
43977
|
+
kind,
|
|
43978
|
+
path: path6,
|
|
43979
|
+
exists: imported !== null,
|
|
43980
|
+
enabled: enabled.includes(kind),
|
|
43981
|
+
serverCount: Object.keys(servers).length
|
|
43982
|
+
};
|
|
43983
|
+
})
|
|
43984
|
+
);
|
|
43985
|
+
return { enabled, available };
|
|
43986
|
+
}
|
|
43787
43987
|
function getServerPrefix(serverName, mode) {
|
|
43788
43988
|
if (mode === "none") {
|
|
43789
43989
|
return "";
|
|
@@ -43803,8 +44003,18 @@ function formatToolName(toolName, serverName, prefix) {
|
|
|
43803
44003
|
}
|
|
43804
44004
|
|
|
43805
44005
|
// src/server/skillsService.ts
|
|
44006
|
+
var import_node_crypto6 = require("node:crypto");
|
|
43806
44007
|
var import_promises17 = require("node:fs/promises");
|
|
43807
44008
|
var import_node_path21 = require("node:path");
|
|
44009
|
+
var SKILL_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_-]*$/;
|
|
44010
|
+
var SkillError = class extends Error {
|
|
44011
|
+
code;
|
|
44012
|
+
constructor(code, message) {
|
|
44013
|
+
super(message);
|
|
44014
|
+
this.name = "SkillError";
|
|
44015
|
+
this.code = code;
|
|
44016
|
+
}
|
|
44017
|
+
};
|
|
43808
44018
|
function parseFrontmatter2(content3) {
|
|
43809
44019
|
const frontmatter2 = {};
|
|
43810
44020
|
if (!content3.startsWith("---")) {
|
|
@@ -43910,6 +44120,229 @@ async function getSkillDetail(agentDir, skillName) {
|
|
|
43910
44120
|
}
|
|
43911
44121
|
return null;
|
|
43912
44122
|
}
|
|
44123
|
+
function getSkillsLockPath(agentDir) {
|
|
44124
|
+
return (0, import_node_path21.join)(agentDir, "skills-lock.json");
|
|
44125
|
+
}
|
|
44126
|
+
function getSkillsDir(agentDir) {
|
|
44127
|
+
return (0, import_node_path21.join)(agentDir, "skills");
|
|
44128
|
+
}
|
|
44129
|
+
function createEmptyLockFile() {
|
|
44130
|
+
return { version: 1, skills: {} };
|
|
44131
|
+
}
|
|
44132
|
+
async function readSkillsLockFile(agentDir) {
|
|
44133
|
+
let content3;
|
|
44134
|
+
try {
|
|
44135
|
+
content3 = await (0, import_promises17.readFile)(getSkillsLockPath(agentDir), "utf-8");
|
|
44136
|
+
} catch (error48) {
|
|
44137
|
+
if (isErrnoException(error48) && error48.code === "ENOENT") {
|
|
44138
|
+
return createEmptyLockFile();
|
|
44139
|
+
}
|
|
44140
|
+
throw error48;
|
|
44141
|
+
}
|
|
44142
|
+
let parsed;
|
|
44143
|
+
try {
|
|
44144
|
+
parsed = JSON.parse(content3);
|
|
44145
|
+
} catch {
|
|
44146
|
+
return createEmptyLockFile();
|
|
44147
|
+
}
|
|
44148
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
44149
|
+
return createEmptyLockFile();
|
|
44150
|
+
}
|
|
44151
|
+
const obj = parsed;
|
|
44152
|
+
const skills = obj.skills;
|
|
44153
|
+
if (!skills || typeof skills !== "object" || Array.isArray(skills)) {
|
|
44154
|
+
return createEmptyLockFile();
|
|
44155
|
+
}
|
|
44156
|
+
return {
|
|
44157
|
+
version: 1,
|
|
44158
|
+
skills
|
|
44159
|
+
};
|
|
44160
|
+
}
|
|
44161
|
+
function isErrnoException(error48) {
|
|
44162
|
+
return error48 instanceof Error && "code" in error48;
|
|
44163
|
+
}
|
|
44164
|
+
async function writeSkillsLockFile(agentDir, lock) {
|
|
44165
|
+
const lockPath = getSkillsLockPath(agentDir);
|
|
44166
|
+
await (0, import_promises17.mkdir)((0, import_node_path21.dirname)(lockPath), { recursive: true });
|
|
44167
|
+
const tmpPath = `${lockPath}.${process.pid}.tmp`;
|
|
44168
|
+
await (0, import_promises17.writeFile)(tmpPath, JSON.stringify(lock, null, 2) + "\n", "utf-8");
|
|
44169
|
+
await (0, import_promises17.rename)(tmpPath, lockPath);
|
|
44170
|
+
}
|
|
44171
|
+
function validateSkillName(name2) {
|
|
44172
|
+
if (!name2) {
|
|
44173
|
+
return { ok: false, error: "Skill name is required" };
|
|
44174
|
+
}
|
|
44175
|
+
if (!SKILL_NAME_REGEX.test(name2)) {
|
|
44176
|
+
return {
|
|
44177
|
+
ok: false,
|
|
44178
|
+
error: "Skill name must start with alphanumeric and contain only alphanumeric, hyphens, and underscores"
|
|
44179
|
+
};
|
|
44180
|
+
}
|
|
44181
|
+
return { ok: true };
|
|
44182
|
+
}
|
|
44183
|
+
function validateInstallRequest(request) {
|
|
44184
|
+
if (!request.source || typeof request.source !== "string") {
|
|
44185
|
+
return { ok: false, code: "INVALID_REQUEST", error: "Missing required field: source" };
|
|
44186
|
+
}
|
|
44187
|
+
if (!request.sourceType || !["local"].includes(request.sourceType)) {
|
|
44188
|
+
return { ok: false, code: "INVALID_REQUEST", error: "sourceType must be 'local'" };
|
|
44189
|
+
}
|
|
44190
|
+
if (request.name !== void 0) {
|
|
44191
|
+
const nameCheck = validateSkillName(request.name);
|
|
44192
|
+
if (!nameCheck.ok) {
|
|
44193
|
+
return { ok: false, code: "INVALID_NAME", error: nameCheck.error };
|
|
44194
|
+
}
|
|
44195
|
+
}
|
|
44196
|
+
return { ok: true };
|
|
44197
|
+
}
|
|
44198
|
+
async function collectFiles2(dir, baseDir) {
|
|
44199
|
+
const files = [];
|
|
44200
|
+
const entries = await (0, import_promises17.readdir)(dir, { withFileTypes: true });
|
|
44201
|
+
for (const entry of entries) {
|
|
44202
|
+
const full = (0, import_node_path21.join)(dir, entry.name);
|
|
44203
|
+
if (entry.isDirectory()) {
|
|
44204
|
+
files.push(...await collectFiles2(full, baseDir));
|
|
44205
|
+
} else if (entry.isFile()) {
|
|
44206
|
+
files.push(full);
|
|
44207
|
+
}
|
|
44208
|
+
}
|
|
44209
|
+
return files;
|
|
44210
|
+
}
|
|
44211
|
+
async function computeSkillHash(skillDir) {
|
|
44212
|
+
const files = (await collectFiles2(skillDir, skillDir)).sort();
|
|
44213
|
+
const hash2 = (0, import_node_crypto6.createHash)("sha256");
|
|
44214
|
+
for (const file2 of files) {
|
|
44215
|
+
const rel = file2.slice(skillDir.length + 1).replace(/\\/g, "/");
|
|
44216
|
+
const content3 = await (0, import_promises17.readFile)(file2);
|
|
44217
|
+
hash2.update(rel);
|
|
44218
|
+
hash2.update("\0");
|
|
44219
|
+
hash2.update(content3);
|
|
44220
|
+
hash2.update("\0");
|
|
44221
|
+
}
|
|
44222
|
+
return hash2.digest("hex");
|
|
44223
|
+
}
|
|
44224
|
+
async function readSkillFrontmatterName(skillDir) {
|
|
44225
|
+
try {
|
|
44226
|
+
const content3 = await (0, import_promises17.readFile)((0, import_node_path21.join)(skillDir, "SKILL.md"), "utf-8");
|
|
44227
|
+
const parsed = parseFrontmatter2(content3);
|
|
44228
|
+
return parsed.frontmatter.name || null;
|
|
44229
|
+
} catch {
|
|
44230
|
+
return null;
|
|
44231
|
+
}
|
|
44232
|
+
}
|
|
44233
|
+
async function verifySkillDirectory(skillDir) {
|
|
44234
|
+
const skillMd = (0, import_node_path21.join)(skillDir, "SKILL.md");
|
|
44235
|
+
try {
|
|
44236
|
+
const s = await (0, import_promises17.stat)(skillMd);
|
|
44237
|
+
if (!s.isFile()) {
|
|
44238
|
+
throw new SkillError("INVALID_SOURCE", `SKILL.md at ${skillMd} is not a regular file`);
|
|
44239
|
+
}
|
|
44240
|
+
} catch (error48) {
|
|
44241
|
+
if (error48 instanceof SkillError) {
|
|
44242
|
+
throw error48;
|
|
44243
|
+
}
|
|
44244
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
44245
|
+
throw new SkillError("INVALID_SOURCE", `Invalid skill directory: ${message}`);
|
|
44246
|
+
}
|
|
44247
|
+
}
|
|
44248
|
+
async function copyLocalSkill(params) {
|
|
44249
|
+
const absoluteSource = (0, import_node_path21.isAbsolute)(params.source) ? params.source : (0, import_node_path21.resolve)(params.cwd, params.source);
|
|
44250
|
+
const s = await (0, import_promises17.stat)(absoluteSource).catch(() => null);
|
|
44251
|
+
if (!s || !s.isDirectory()) {
|
|
44252
|
+
throw new SkillError("INVALID_SOURCE", `Local skill source must be an existing directory: ${absoluteSource}`);
|
|
44253
|
+
}
|
|
44254
|
+
await verifySkillDirectory(absoluteSource);
|
|
44255
|
+
await (0, import_promises17.rm)(params.destination, { recursive: true, force: true });
|
|
44256
|
+
await (0, import_promises17.cp)(absoluteSource, params.destination, { recursive: true });
|
|
44257
|
+
}
|
|
44258
|
+
function deriveSkillName(request) {
|
|
44259
|
+
if (request.name) {
|
|
44260
|
+
return request.name;
|
|
44261
|
+
}
|
|
44262
|
+
const normalized = request.source.replace(/[\\/]+$/, "");
|
|
44263
|
+
const base = normalized.split(/[\\/]/).filter(Boolean).pop() ?? "";
|
|
44264
|
+
return base;
|
|
44265
|
+
}
|
|
44266
|
+
async function installSkill(params) {
|
|
44267
|
+
const validation = validateInstallRequest(params.request);
|
|
44268
|
+
if (!validation.ok) {
|
|
44269
|
+
throw new SkillError(validation.code, validation.error);
|
|
44270
|
+
}
|
|
44271
|
+
const skillName = params.request.name ?? deriveSkillName(params.request);
|
|
44272
|
+
if (!params.request.name) {
|
|
44273
|
+
const nameCheck = validateSkillName(skillName);
|
|
44274
|
+
if (!nameCheck.ok) {
|
|
44275
|
+
throw new SkillError(
|
|
44276
|
+
"INVALID_NAME",
|
|
44277
|
+
`Unable to derive a valid skill name from "${params.request.source}". Provide an explicit "name".`
|
|
44278
|
+
);
|
|
44279
|
+
}
|
|
44280
|
+
}
|
|
44281
|
+
const skillsDir = getSkillsDir(params.agentDir);
|
|
44282
|
+
const destination = (0, import_node_path21.join)(skillsDir, skillName);
|
|
44283
|
+
const existed = await dirExists(destination);
|
|
44284
|
+
if (existed && !params.request.overwrite) {
|
|
44285
|
+
throw new SkillError(
|
|
44286
|
+
"ALREADY_EXISTS",
|
|
44287
|
+
`Skill "${skillName}" already exists. Set overwrite=true to replace it.`
|
|
44288
|
+
);
|
|
44289
|
+
}
|
|
44290
|
+
await (0, import_promises17.mkdir)(skillsDir, { recursive: true });
|
|
44291
|
+
switch (params.request.sourceType) {
|
|
44292
|
+
case "local":
|
|
44293
|
+
await copyLocalSkill({
|
|
44294
|
+
source: params.request.source,
|
|
44295
|
+
cwd: params.cwd,
|
|
44296
|
+
destination
|
|
44297
|
+
});
|
|
44298
|
+
break;
|
|
44299
|
+
}
|
|
44300
|
+
const fmName = await readSkillFrontmatterName(destination);
|
|
44301
|
+
const computedHash = await computeSkillHash(destination);
|
|
44302
|
+
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
44303
|
+
const lock = await readSkillsLockFile(params.agentDir);
|
|
44304
|
+
lock.skills[skillName] = {
|
|
44305
|
+
source: params.request.source,
|
|
44306
|
+
sourceType: params.request.sourceType,
|
|
44307
|
+
computedHash,
|
|
44308
|
+
installedAt
|
|
44309
|
+
};
|
|
44310
|
+
await writeSkillsLockFile(params.agentDir, lock);
|
|
44311
|
+
return {
|
|
44312
|
+
name: fmName ?? skillName,
|
|
44313
|
+
directory: skillName,
|
|
44314
|
+
source: params.request.source,
|
|
44315
|
+
sourceType: params.request.sourceType,
|
|
44316
|
+
computedHash,
|
|
44317
|
+
installedAt,
|
|
44318
|
+
overwritten: existed
|
|
44319
|
+
};
|
|
44320
|
+
}
|
|
44321
|
+
async function uninstallSkill(params) {
|
|
44322
|
+
const nameCheck = validateSkillName(params.name);
|
|
44323
|
+
if (!nameCheck.ok) {
|
|
44324
|
+
throw new SkillError("INVALID_NAME", nameCheck.error);
|
|
44325
|
+
}
|
|
44326
|
+
const skillsDir = getSkillsDir(params.agentDir);
|
|
44327
|
+
let targetDir = params.name;
|
|
44328
|
+
const existed = await dirExists((0, import_node_path21.join)(skillsDir, targetDir));
|
|
44329
|
+
if (!existed) {
|
|
44330
|
+
const detail = await getSkillDetail(params.agentDir, params.name);
|
|
44331
|
+
if (!detail) {
|
|
44332
|
+
throw new SkillError("NOT_FOUND", `Skill "${params.name}" not found`);
|
|
44333
|
+
}
|
|
44334
|
+
targetDir = detail.skill.directory;
|
|
44335
|
+
}
|
|
44336
|
+
const destination = (0, import_node_path21.join)(skillsDir, targetDir);
|
|
44337
|
+
const lock = await readSkillsLockFile(params.agentDir);
|
|
44338
|
+
const lockKey = lock.skills[targetDir] ? targetDir : lock.skills[params.name] ? params.name : null;
|
|
44339
|
+
await (0, import_promises17.rm)(destination, { recursive: true, force: true });
|
|
44340
|
+
if (lockKey) {
|
|
44341
|
+
delete lock.skills[lockKey];
|
|
44342
|
+
await writeSkillsLockFile(params.agentDir, lock);
|
|
44343
|
+
}
|
|
44344
|
+
return { name: params.name, directory: targetDir, removed: true };
|
|
44345
|
+
}
|
|
43913
44346
|
|
|
43914
44347
|
// src/server/toolsService.ts
|
|
43915
44348
|
var BUILT_IN_TOOLS = {
|
|
@@ -44180,7 +44613,7 @@ var BROWSER_TOOL_SCHEMAS = [
|
|
|
44180
44613
|
];
|
|
44181
44614
|
|
|
44182
44615
|
// src/server/sessionConfig.ts
|
|
44183
|
-
var
|
|
44616
|
+
var import_node_fs13 = require("node:fs");
|
|
44184
44617
|
var path5 = __toESM(require("node:path"));
|
|
44185
44618
|
var DEFAULT_CONFIG = { autoCommit: false };
|
|
44186
44619
|
function configPath(agentDir, sessionId) {
|
|
@@ -44188,7 +44621,7 @@ function configPath(agentDir, sessionId) {
|
|
|
44188
44621
|
}
|
|
44189
44622
|
async function readSessionConfig(agentDir, sessionId) {
|
|
44190
44623
|
try {
|
|
44191
|
-
const raw2 = await
|
|
44624
|
+
const raw2 = await import_node_fs13.promises.readFile(configPath(agentDir, sessionId), "utf-8");
|
|
44192
44625
|
return { ...DEFAULT_CONFIG, ...JSON.parse(raw2) };
|
|
44193
44626
|
} catch {
|
|
44194
44627
|
return { ...DEFAULT_CONFIG };
|
|
@@ -44196,14 +44629,28 @@ async function readSessionConfig(agentDir, sessionId) {
|
|
|
44196
44629
|
}
|
|
44197
44630
|
async function writeSessionConfig(agentDir, sessionId, patch) {
|
|
44198
44631
|
const dir = path5.join(agentDir, "session-config");
|
|
44199
|
-
await
|
|
44632
|
+
await import_node_fs13.promises.mkdir(dir, { recursive: true });
|
|
44200
44633
|
const current = await readSessionConfig(agentDir, sessionId);
|
|
44201
44634
|
const next = { ...current, ...patch };
|
|
44202
|
-
await
|
|
44635
|
+
await import_node_fs13.promises.writeFile(configPath(agentDir, sessionId), JSON.stringify(next, null, 2), "utf-8");
|
|
44203
44636
|
return next;
|
|
44204
44637
|
}
|
|
44205
44638
|
|
|
44206
44639
|
// src/server/agentServer.ts
|
|
44640
|
+
var SKILL_ERROR_STATUS = {
|
|
44641
|
+
INVALID_REQUEST: 400,
|
|
44642
|
+
INVALID_NAME: 400,
|
|
44643
|
+
INVALID_SOURCE: 404,
|
|
44644
|
+
ALREADY_EXISTS: 409,
|
|
44645
|
+
NOT_FOUND: 404
|
|
44646
|
+
};
|
|
44647
|
+
function skillErrorResponse(c, error48) {
|
|
44648
|
+
if (error48 instanceof SkillError) {
|
|
44649
|
+
return c.json({ error: error48.message, code: error48.code }, SKILL_ERROR_STATUS[error48.code]);
|
|
44650
|
+
}
|
|
44651
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
44652
|
+
return c.json({ error: message }, 500);
|
|
44653
|
+
}
|
|
44207
44654
|
function generateMessageId() {
|
|
44208
44655
|
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
44209
44656
|
}
|
|
@@ -44271,7 +44718,7 @@ async function waitForIdle(session, timeoutMs = 3e4) {
|
|
|
44271
44718
|
if (!session.isStreaming) {
|
|
44272
44719
|
return;
|
|
44273
44720
|
}
|
|
44274
|
-
return new Promise((
|
|
44721
|
+
return new Promise((resolve5, reject) => {
|
|
44275
44722
|
const timer = setTimeout(() => {
|
|
44276
44723
|
unsubscribe();
|
|
44277
44724
|
reject(new Error("Timed out waiting for session to become idle"));
|
|
@@ -44280,13 +44727,13 @@ async function waitForIdle(session, timeoutMs = 3e4) {
|
|
|
44280
44727
|
if (event.type === "agent_end") {
|
|
44281
44728
|
clearTimeout(timer);
|
|
44282
44729
|
unsubscribe();
|
|
44283
|
-
|
|
44730
|
+
resolve5();
|
|
44284
44731
|
}
|
|
44285
44732
|
});
|
|
44286
44733
|
if (!session.isStreaming) {
|
|
44287
44734
|
clearTimeout(timer);
|
|
44288
44735
|
unsubscribe();
|
|
44289
|
-
|
|
44736
|
+
resolve5();
|
|
44290
44737
|
}
|
|
44291
44738
|
});
|
|
44292
44739
|
}
|
|
@@ -45070,6 +45517,41 @@ async function createAgentServer(params) {
|
|
|
45070
45517
|
commands: normalizeSlashCommands(activeSession.listCommands())
|
|
45071
45518
|
});
|
|
45072
45519
|
});
|
|
45520
|
+
app.get("/api/souls", async (c) => {
|
|
45521
|
+
const configFilePath = (0, import_node_path22.join)(settingsRootPath, "config.json");
|
|
45522
|
+
const envConfigService = new EnvironmentConfigService(configFilePath);
|
|
45523
|
+
const activeSoulId = await envConfigService.getActiveSoulId();
|
|
45524
|
+
const runtimeSoulId = process.env.DOCYRUS_PI_SOUL_ID?.trim() || DEFAULT_SOUL_ID;
|
|
45525
|
+
return c.json({
|
|
45526
|
+
souls: listSouls(activeSoulId),
|
|
45527
|
+
activeSoulId,
|
|
45528
|
+
runtimeSoulId,
|
|
45529
|
+
restartRequired: activeSoulId !== runtimeSoulId
|
|
45530
|
+
});
|
|
45531
|
+
});
|
|
45532
|
+
app.post("/api/souls/select", async (c) => {
|
|
45533
|
+
const body2 = await c.req.json().catch(() => ({}));
|
|
45534
|
+
const requested = typeof body2.soulId === "string" ? body2.soulId.trim() : "";
|
|
45535
|
+
if (!requested) {
|
|
45536
|
+
return c.json({ error: "Field 'soulId' is required." }, 400);
|
|
45537
|
+
}
|
|
45538
|
+
if (!SOULS.some((soul) => soul.id === requested)) {
|
|
45539
|
+
return c.json({
|
|
45540
|
+
error: `Unknown soul '${requested}'.`,
|
|
45541
|
+
availableSoulIds: SOULS.map((soul) => soul.id)
|
|
45542
|
+
}, 400);
|
|
45543
|
+
}
|
|
45544
|
+
const configFilePath = (0, import_node_path22.join)(settingsRootPath, "config.json");
|
|
45545
|
+
const envConfigService = new EnvironmentConfigService(configFilePath);
|
|
45546
|
+
const persistedSoulId = await envConfigService.setActiveSoulId(requested);
|
|
45547
|
+
const runtimeSoulId = process.env.DOCYRUS_PI_SOUL_ID?.trim() || DEFAULT_SOUL_ID;
|
|
45548
|
+
return c.json({
|
|
45549
|
+
soulId: persistedSoulId,
|
|
45550
|
+
runtimeSoulId,
|
|
45551
|
+
restartRequired: persistedSoulId !== runtimeSoulId,
|
|
45552
|
+
message: persistedSoulId === runtimeSoulId ? "Soul persisted. Already running \u2014 no restart needed." : "Soul persisted. Restart the agent (or open a new session) for the new soul to take effect."
|
|
45553
|
+
});
|
|
45554
|
+
});
|
|
45073
45555
|
app.get("/api/knowledge/sections", async (c) => {
|
|
45074
45556
|
try {
|
|
45075
45557
|
const query = c.req.query("query")?.trim();
|
|
@@ -46420,6 +46902,69 @@ async function createAgentServer(params) {
|
|
|
46420
46902
|
return c.json({ error: message }, status);
|
|
46421
46903
|
}
|
|
46422
46904
|
});
|
|
46905
|
+
app.get("/api/mcp/settings", async (c) => {
|
|
46906
|
+
try {
|
|
46907
|
+
const config2 = await loadMcpServerConfig(context.agentDir, context.cwd);
|
|
46908
|
+
return c.json({
|
|
46909
|
+
settings: {
|
|
46910
|
+
toolPrefix: config2.settings?.toolPrefix ?? "server",
|
|
46911
|
+
idleTimeout: config2.settings?.idleTimeout ?? 10,
|
|
46912
|
+
directTools: config2.settings?.directTools ?? false
|
|
46913
|
+
},
|
|
46914
|
+
supportedToolPrefixes: ["server", "none", "short"]
|
|
46915
|
+
});
|
|
46916
|
+
} catch (error48) {
|
|
46917
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
46918
|
+
return c.json({ error: message }, 500);
|
|
46919
|
+
}
|
|
46920
|
+
});
|
|
46921
|
+
app.put("/api/mcp/settings", async (c) => {
|
|
46922
|
+
try {
|
|
46923
|
+
const body2 = await c.req.json();
|
|
46924
|
+
const result = validateMcpSettings(body2.settings);
|
|
46925
|
+
if (!result.ok) {
|
|
46926
|
+
return c.json({ error: result.error }, 400);
|
|
46927
|
+
}
|
|
46928
|
+
const merged = await updateMcpSettings(context.agentDir, result.value);
|
|
46929
|
+
return c.json({
|
|
46930
|
+
settings: {
|
|
46931
|
+
toolPrefix: merged.toolPrefix ?? "server",
|
|
46932
|
+
idleTimeout: merged.idleTimeout ?? 10,
|
|
46933
|
+
directTools: merged.directTools ?? false
|
|
46934
|
+
}
|
|
46935
|
+
});
|
|
46936
|
+
} catch (error48) {
|
|
46937
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
46938
|
+
return c.json({ error: message }, 500);
|
|
46939
|
+
}
|
|
46940
|
+
});
|
|
46941
|
+
app.get("/api/mcp/imports", async (c) => {
|
|
46942
|
+
try {
|
|
46943
|
+
const summary = await describeImports(context.agentDir, context.cwd);
|
|
46944
|
+
return c.json({
|
|
46945
|
+
enabled: summary.enabled,
|
|
46946
|
+
available: summary.available,
|
|
46947
|
+
supported: SUPPORTED_IMPORT_KINDS
|
|
46948
|
+
});
|
|
46949
|
+
} catch (error48) {
|
|
46950
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
46951
|
+
return c.json({ error: message }, 500);
|
|
46952
|
+
}
|
|
46953
|
+
});
|
|
46954
|
+
app.put("/api/mcp/imports", async (c) => {
|
|
46955
|
+
try {
|
|
46956
|
+
const body2 = await c.req.json();
|
|
46957
|
+
const result = validateImportKinds(body2.imports);
|
|
46958
|
+
if (!result.ok) {
|
|
46959
|
+
return c.json({ error: result.error }, 400);
|
|
46960
|
+
}
|
|
46961
|
+
const imports = await updateMcpImports(context.agentDir, result.value);
|
|
46962
|
+
return c.json({ imports });
|
|
46963
|
+
} catch (error48) {
|
|
46964
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
46965
|
+
return c.json({ error: message }, 500);
|
|
46966
|
+
}
|
|
46967
|
+
});
|
|
46423
46968
|
app.get("/api/skills", async (c) => {
|
|
46424
46969
|
try {
|
|
46425
46970
|
const skills = (await listSkills(context.agentDir)).filter((skill) => skill.name !== "docyrus-chrome-devtools-cli");
|
|
@@ -46445,6 +46990,56 @@ async function createAgentServer(params) {
|
|
|
46445
46990
|
return c.json({ error: message }, 500);
|
|
46446
46991
|
}
|
|
46447
46992
|
});
|
|
46993
|
+
app.get("/api/skills/lock/entries", async (c) => {
|
|
46994
|
+
try {
|
|
46995
|
+
const lock = await readSkillsLockFile(context.agentDir);
|
|
46996
|
+
return c.json({
|
|
46997
|
+
version: lock.version,
|
|
46998
|
+
skills: lock.skills,
|
|
46999
|
+
supportedSourceTypes: ["local"]
|
|
47000
|
+
});
|
|
47001
|
+
} catch (error48) {
|
|
47002
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
47003
|
+
return c.json({ error: message }, 500);
|
|
47004
|
+
}
|
|
47005
|
+
});
|
|
47006
|
+
app.post("/api/skills", async (c) => {
|
|
47007
|
+
try {
|
|
47008
|
+
const body2 = await c.req.json();
|
|
47009
|
+
if (!body2.source || typeof body2.source !== "string") {
|
|
47010
|
+
return c.json({ error: "Missing required field: source" }, 400);
|
|
47011
|
+
}
|
|
47012
|
+
if (!body2.sourceType || typeof body2.sourceType !== "string") {
|
|
47013
|
+
return c.json({ error: "Missing required field: sourceType" }, 400);
|
|
47014
|
+
}
|
|
47015
|
+
const request = {
|
|
47016
|
+
source: body2.source,
|
|
47017
|
+
sourceType: body2.sourceType,
|
|
47018
|
+
name: body2.name,
|
|
47019
|
+
overwrite: body2.overwrite === true
|
|
47020
|
+
};
|
|
47021
|
+
const result = await installSkill({
|
|
47022
|
+
agentDir: context.agentDir,
|
|
47023
|
+
cwd: context.cwd,
|
|
47024
|
+
request
|
|
47025
|
+
});
|
|
47026
|
+
return c.json({ ok: true, skill: result }, result.overwritten ? 200 : 201);
|
|
47027
|
+
} catch (error48) {
|
|
47028
|
+
return skillErrorResponse(c, error48);
|
|
47029
|
+
}
|
|
47030
|
+
});
|
|
47031
|
+
app.delete("/api/skills/:skillName", async (c) => {
|
|
47032
|
+
const skillName = c.req.param("skillName");
|
|
47033
|
+
try {
|
|
47034
|
+
const result = await uninstallSkill({
|
|
47035
|
+
agentDir: context.agentDir,
|
|
47036
|
+
name: skillName
|
|
47037
|
+
});
|
|
47038
|
+
return c.json({ ok: true, ...result });
|
|
47039
|
+
} catch (error48) {
|
|
47040
|
+
return skillErrorResponse(c, error48);
|
|
47041
|
+
}
|
|
47042
|
+
});
|
|
46448
47043
|
app.post("/api/extension-ui-response", async (c) => {
|
|
46449
47044
|
if (!extensionUIBridge) {
|
|
46450
47045
|
return c.json({ error: "Extension UI bridge not available" }, 404);
|
|
@@ -46692,10 +47287,24 @@ async function createAgentServer(params) {
|
|
|
46692
47287
|
process.stderr.write(` PUT /api/mcp/servers/:name \u2014 update MCP server
|
|
46693
47288
|
`);
|
|
46694
47289
|
process.stderr.write(` DEL /api/mcp/servers/:name \u2014 remove MCP server
|
|
47290
|
+
`);
|
|
47291
|
+
process.stderr.write(` GET /api/mcp/settings \u2014 MCP global settings
|
|
47292
|
+
`);
|
|
47293
|
+
process.stderr.write(` PUT /api/mcp/settings \u2014 update MCP global settings
|
|
47294
|
+
`);
|
|
47295
|
+
process.stderr.write(` GET /api/mcp/imports \u2014 available and enabled MCP imports
|
|
47296
|
+
`);
|
|
47297
|
+
process.stderr.write(` PUT /api/mcp/imports \u2014 update enabled MCP imports
|
|
46695
47298
|
`);
|
|
46696
47299
|
process.stderr.write(` GET /api/skills \u2014 list skills
|
|
46697
47300
|
`);
|
|
46698
47301
|
process.stderr.write(` GET /api/skills/:name \u2014 skill details
|
|
47302
|
+
`);
|
|
47303
|
+
process.stderr.write(` POST /api/skills \u2014 install a skill from local source
|
|
47304
|
+
`);
|
|
47305
|
+
process.stderr.write(` DEL /api/skills/:name \u2014 uninstall a skill
|
|
47306
|
+
`);
|
|
47307
|
+
process.stderr.write(` GET /api/skills/lock/entries \u2014 skills-lock.json entries
|
|
46699
47308
|
`);
|
|
46700
47309
|
process.stderr.write(` GET /api/tools \u2014 list all tools
|
|
46701
47310
|
`);
|
|
@@ -46756,7 +47365,7 @@ function extractBearerToken(authorizationHeader) {
|
|
|
46756
47365
|
return token;
|
|
46757
47366
|
}
|
|
46758
47367
|
function hashToken(token) {
|
|
46759
|
-
return (0,
|
|
47368
|
+
return (0, import_node_crypto7.createHash)("sha256").update(token).digest();
|
|
46760
47369
|
}
|
|
46761
47370
|
function isBearerTokenAuthorized(actualToken, expectedToken) {
|
|
46762
47371
|
if (!expectedToken) {
|
|
@@ -46767,7 +47376,7 @@ function isBearerTokenAuthorized(actualToken, expectedToken) {
|
|
|
46767
47376
|
}
|
|
46768
47377
|
const actualHash = hashToken(actualToken);
|
|
46769
47378
|
const expectedHash = hashToken(expectedToken);
|
|
46770
|
-
return (0,
|
|
47379
|
+
return (0, import_node_crypto7.timingSafeEqual)(actualHash, expectedHash);
|
|
46771
47380
|
}
|
|
46772
47381
|
function createUnauthorizedResponse() {
|
|
46773
47382
|
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
@@ -46901,7 +47510,7 @@ function createServerSessionAdapter(params) {
|
|
|
46901
47510
|
}
|
|
46902
47511
|
|
|
46903
47512
|
// src/server/extensionUIBridge.ts
|
|
46904
|
-
var
|
|
47513
|
+
var import_node_crypto8 = require("node:crypto");
|
|
46905
47514
|
var ExtensionUIBridge = class {
|
|
46906
47515
|
pending = /* @__PURE__ */ new Map();
|
|
46907
47516
|
requestHandler;
|
|
@@ -46945,9 +47554,9 @@ var ExtensionUIBridge = class {
|
|
|
46945
47554
|
if (opts?.signal?.aborted) {
|
|
46946
47555
|
return Promise.resolve(defaultValue);
|
|
46947
47556
|
}
|
|
46948
|
-
const id = (0,
|
|
47557
|
+
const id = (0, import_node_crypto8.randomUUID)();
|
|
46949
47558
|
const timeout = opts?.timeout ?? this.defaultTimeout;
|
|
46950
|
-
return new Promise((
|
|
47559
|
+
return new Promise((resolve5, reject) => {
|
|
46951
47560
|
const cleanup = () => {
|
|
46952
47561
|
if (timer) {
|
|
46953
47562
|
clearTimeout(timer);
|
|
@@ -46957,17 +47566,17 @@ var ExtensionUIBridge = class {
|
|
|
46957
47566
|
};
|
|
46958
47567
|
const onAbort = () => {
|
|
46959
47568
|
cleanup();
|
|
46960
|
-
|
|
47569
|
+
resolve5(defaultValue);
|
|
46961
47570
|
};
|
|
46962
47571
|
opts?.signal?.addEventListener("abort", onAbort, { once: true });
|
|
46963
47572
|
const timer = timeout > 0 ? setTimeout(() => {
|
|
46964
47573
|
cleanup();
|
|
46965
|
-
|
|
47574
|
+
resolve5(defaultValue);
|
|
46966
47575
|
}, timeout) : void 0;
|
|
46967
47576
|
this.pending.set(id, {
|
|
46968
47577
|
resolve: (response) => {
|
|
46969
47578
|
cleanup();
|
|
46970
|
-
|
|
47579
|
+
resolve5(parseResponse(response));
|
|
46971
47580
|
},
|
|
46972
47581
|
reject: (error48) => {
|
|
46973
47582
|
cleanup();
|
|
@@ -47008,23 +47617,23 @@ var ExtensionUIBridge = class {
|
|
|
47008
47617
|
opts
|
|
47009
47618
|
),
|
|
47010
47619
|
notify: (message, notifyType) => {
|
|
47011
|
-
const id = (0,
|
|
47620
|
+
const id = (0, import_node_crypto8.randomUUID)();
|
|
47012
47621
|
this.requestHandler({ type: "extension_ui_request", id, method: "notify", message, placeholder: notifyType });
|
|
47013
47622
|
},
|
|
47014
47623
|
setStatus: (statusKey, statusText) => {
|
|
47015
|
-
const id = (0,
|
|
47624
|
+
const id = (0, import_node_crypto8.randomUUID)();
|
|
47016
47625
|
this.requestHandler({ type: "extension_ui_request", id, method: "setStatus", title: statusKey, message: statusText });
|
|
47017
47626
|
},
|
|
47018
47627
|
setWidget: (widgetKey, widgetLines) => {
|
|
47019
|
-
const id = (0,
|
|
47628
|
+
const id = (0, import_node_crypto8.randomUUID)();
|
|
47020
47629
|
this.requestHandler({ type: "extension_ui_request", id, method: "setWidget", title: widgetKey, options: widgetLines });
|
|
47021
47630
|
},
|
|
47022
47631
|
setTitle: (title) => {
|
|
47023
|
-
const id = (0,
|
|
47632
|
+
const id = (0, import_node_crypto8.randomUUID)();
|
|
47024
47633
|
this.requestHandler({ type: "extension_ui_request", id, method: "setTitle", title });
|
|
47025
47634
|
},
|
|
47026
47635
|
setEditorText: (text3) => {
|
|
47027
|
-
const id = (0,
|
|
47636
|
+
const id = (0, import_node_crypto8.randomUUID)();
|
|
47028
47637
|
this.requestHandler({ type: "extension_ui_request", id, method: "set_editor_text", message: text3 });
|
|
47029
47638
|
},
|
|
47030
47639
|
// No-op methods for server mode (not applicable without TUI)
|
|
@@ -47105,7 +47714,7 @@ function resolvePackagedPiResourceRoot() {
|
|
|
47105
47714
|
(0, import_node_path23.resolve)(__dirname, "resources/pi-agent"),
|
|
47106
47715
|
(0, import_node_path23.resolve)(process.cwd(), "dist/apps/api-cli/resources/pi-agent")
|
|
47107
47716
|
];
|
|
47108
|
-
const resolved = candidates.find((candidate) => (0,
|
|
47717
|
+
const resolved = candidates.find((candidate) => (0, import_node_fs14.existsSync)(candidate));
|
|
47109
47718
|
if (!resolved) {
|
|
47110
47719
|
throw new Error(`Unable to locate pi agent resources. Checked: ${candidates.join(", ")}`);
|
|
47111
47720
|
}
|
|
@@ -47237,7 +47846,7 @@ async function main() {
|
|
|
47237
47846
|
skills: skills.filter((skill) => skill.name !== "docyrus-chrome-devtools-cli"),
|
|
47238
47847
|
diagnostics
|
|
47239
47848
|
}),
|
|
47240
|
-
systemPrompt: (0, import_node_path23.join)(
|
|
47849
|
+
systemPrompt: process.env.DOCYRUS_PI_SYSTEM_PROMPT_PATH ?? (0, import_node_path23.join)(
|
|
47241
47850
|
resourceRoot,
|
|
47242
47851
|
"prompts",
|
|
47243
47852
|
request.profile === "agent" ? "agent-system.md" : "coder-system.md"
|