sparkecoder 0.1.111 → 0.1.112
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/agent/index.js +10 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +261 -88
- package/dist/cli.js.map +1 -1
- package/dist/index.js +261 -88
- package/dist/index.js.map +1 -1
- package/dist/server/index.js +261 -88
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__6097da17._.js +3 -3
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_page_tsx_5ac4794b._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_settings_page_tsx_eb320e07._.js +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/web/.next/static/chunks/{ae4bb24474ff1ed0.js → a189cacf6d83cf0b.js} +5 -5
- package/web/.next/standalone/web/.next/static/chunks/bef6931fdd8428c8.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/c1f73b3fa4353c31.css +1 -0
- package/web/.next/standalone/web/.next/static/chunks/c5dd884b71007965.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{ae4bb24474ff1ed0.js → a189cacf6d83cf0b.js} +5 -5
- package/web/.next/standalone/web/.next/static/static/chunks/bef6931fdd8428c8.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/c1f73b3fa4353c31.css +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/c5dd884b71007965.js +1 -0
- package/web/.next/standalone/web/src/app/(main)/page.tsx +36 -2
- package/web/.next/standalone/web/src/app/(main)/settings/page.tsx +40 -7
- package/web/.next/standalone/web/src/components/chat-interface.tsx +34 -0
- package/web/.next/static/chunks/{ae4bb24474ff1ed0.js → a189cacf6d83cf0b.js} +5 -5
- package/web/.next/static/chunks/bef6931fdd8428c8.js +1 -0
- package/web/.next/static/chunks/c1f73b3fa4353c31.css +1 -0
- package/web/.next/static/chunks/c5dd884b71007965.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/344be859c2c8600b.css +0 -1
- package/web/.next/standalone/web/.next/static/chunks/f5fe518b79d1bf41.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/f6e2bbd3014e1fc9.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/344be859c2c8600b.css +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/f5fe518b79d1bf41.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/f6e2bbd3014e1fc9.js +0 -1
- package/web/.next/static/chunks/344be859c2c8600b.css +0 -1
- package/web/.next/static/chunks/f5fe518b79d1bf41.js +0 -1
- package/web/.next/static/chunks/f6e2bbd3014e1fc9.js +0 -1
- /package/web/.next/standalone/web/.next/static/{Tm_6r8b-tCAfCBoIt-U0X → static/x3G1ePtJHSb_uWa9Qs8dN}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{Tm_6r8b-tCAfCBoIt-U0X → static/x3G1ePtJHSb_uWa9Qs8dN}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{Tm_6r8b-tCAfCBoIt-U0X → static/x3G1ePtJHSb_uWa9Qs8dN}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/Tm_6r8b-tCAfCBoIt-U0X → x3G1ePtJHSb_uWa9Qs8dN}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/Tm_6r8b-tCAfCBoIt-U0X → x3G1ePtJHSb_uWa9Qs8dN}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/Tm_6r8b-tCAfCBoIt-U0X → x3G1ePtJHSb_uWa9Qs8dN}/_ssgManifest.js +0 -0
- /package/web/.next/static/{Tm_6r8b-tCAfCBoIt-U0X → x3G1ePtJHSb_uWa9Qs8dN}/_buildManifest.js +0 -0
- /package/web/.next/static/{Tm_6r8b-tCAfCBoIt-U0X → x3G1ePtJHSb_uWa9Qs8dN}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{Tm_6r8b-tCAfCBoIt-U0X → x3G1ePtJHSb_uWa9Qs8dN}/_ssgManifest.js +0 -0
package/dist/server/index.js
CHANGED
|
@@ -1339,9 +1339,10 @@ function createDefaultConfig() {
|
|
|
1339
1339
|
}
|
|
1340
1340
|
function loadStoredAuthKey() {
|
|
1341
1341
|
const locations = [
|
|
1342
|
+
process.env.SPARKECODER_AUTH_KEY_PATH,
|
|
1342
1343
|
join(process.cwd(), ".sparkecoder", AUTH_KEY_FILE),
|
|
1343
1344
|
join(getAppDataDirectory(), AUTH_KEY_FILE)
|
|
1344
|
-
];
|
|
1345
|
+
].filter((p) => !!p);
|
|
1345
1346
|
for (const keysPath of locations) {
|
|
1346
1347
|
if (!existsSync(keysPath)) continue;
|
|
1347
1348
|
try {
|
|
@@ -1360,15 +1361,44 @@ function saveAuthKey(authKey3, userId) {
|
|
|
1360
1361
|
userId
|
|
1361
1362
|
};
|
|
1362
1363
|
const json = JSON.stringify(data, null, 2);
|
|
1363
|
-
const
|
|
1364
|
-
|
|
1364
|
+
const targets = [];
|
|
1365
|
+
if (process.env.SPARKECODER_AUTH_KEY_PATH) {
|
|
1366
|
+
targets.push({
|
|
1367
|
+
label: "SPARKECODER_AUTH_KEY_PATH",
|
|
1368
|
+
path: process.env.SPARKECODER_AUTH_KEY_PATH
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1365
1371
|
try {
|
|
1366
|
-
const
|
|
1367
|
-
|
|
1368
|
-
|
|
1372
|
+
const appDir = ensureAppDataDirectory();
|
|
1373
|
+
targets.push({ label: "app-data", path: join(appDir, AUTH_KEY_FILE) });
|
|
1374
|
+
} catch (err) {
|
|
1375
|
+
console.warn(`[auth-key] could not ensure app data dir: ${err?.message ?? err}`);
|
|
1376
|
+
}
|
|
1377
|
+
targets.push({
|
|
1378
|
+
label: "workspace",
|
|
1379
|
+
path: join(process.cwd(), ".sparkecoder", AUTH_KEY_FILE)
|
|
1380
|
+
});
|
|
1381
|
+
const successes = [];
|
|
1382
|
+
const failures = [];
|
|
1383
|
+
for (const { label, path } of targets) {
|
|
1384
|
+
try {
|
|
1385
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
1386
|
+
writeFileSync(path, json, { mode: 384 });
|
|
1387
|
+
successes.push(`${label}:${path}`);
|
|
1388
|
+
} catch (err) {
|
|
1389
|
+
failures.push({ label, path, error: err?.message ?? String(err) });
|
|
1369
1390
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1391
|
+
}
|
|
1392
|
+
if (successes.length === 0) {
|
|
1393
|
+
const detail = failures.map((f) => `${f.label} (${f.path}): ${f.error}`).join("; ");
|
|
1394
|
+
throw new Error(`Failed to persist auth-key.json to any location. ${detail}`);
|
|
1395
|
+
}
|
|
1396
|
+
if (failures.length > 0) {
|
|
1397
|
+
console.warn(
|
|
1398
|
+
`[auth-key] wrote to ${successes.length}/${targets.length} locations. Success: ${successes.join(", ")}. Failed: ${failures.map((f) => `${f.label} (${f.path}): ${f.error}`).join("; ")}`
|
|
1399
|
+
);
|
|
1400
|
+
} else if (process.env.SPARKECODER_VERBOSE_CONFIG) {
|
|
1401
|
+
console.log(`[auth-key] saved to: ${successes.join(", ")}`);
|
|
1372
1402
|
}
|
|
1373
1403
|
}
|
|
1374
1404
|
function getStoredAuthKeyInfo() {
|
|
@@ -8278,15 +8308,30 @@ var init_client3 = __esm({
|
|
|
8278
8308
|
});
|
|
8279
8309
|
|
|
8280
8310
|
// src/integrations/channels/slack.ts
|
|
8311
|
+
function threadKey(channel, threadTs) {
|
|
8312
|
+
return `${channel}\u241F${threadTs}`;
|
|
8313
|
+
}
|
|
8314
|
+
function markThreadOwned(channel, threadTs) {
|
|
8315
|
+
ownedThreads.add(threadKey(channel, threadTs));
|
|
8316
|
+
}
|
|
8317
|
+
function isThreadOwned(channel, threadTs) {
|
|
8318
|
+
return ownedThreads.has(threadKey(channel, threadTs));
|
|
8319
|
+
}
|
|
8281
8320
|
function stripMention(text) {
|
|
8282
8321
|
return String(text || "").replace(/<@[^>]+>/g, "").trim();
|
|
8283
8322
|
}
|
|
8284
8323
|
function slackEventToInboundResult(event) {
|
|
8285
8324
|
if (!event) return { event: null, dropReason: "empty_text" };
|
|
8286
|
-
if (event.bot_id
|
|
8325
|
+
if (event.bot_id) return { event: null, dropReason: "bot_message" };
|
|
8326
|
+
if (event.type === "message" && event.subtype && IGNORED_MESSAGE_SUBTYPES.has(event.subtype)) {
|
|
8327
|
+
return { event: null, dropReason: "bot_message" };
|
|
8328
|
+
}
|
|
8287
8329
|
const isDm = event.type === "message" && event.channel_type === "im";
|
|
8288
|
-
|
|
8289
|
-
|
|
8330
|
+
const isThreadReply = event.type === "message" && !isDm && typeof event.thread_ts === "string" && event.thread_ts !== event.ts;
|
|
8331
|
+
if (event.type !== "app_mention" && !isDm && !isThreadReply) {
|
|
8332
|
+
return { event: null, dropReason: "unsupported_type" };
|
|
8333
|
+
}
|
|
8334
|
+
const text = event.type === "app_mention" ? stripMention(event.text) : (event.text ?? "").trim();
|
|
8290
8335
|
if (!text) return { event: null, dropReason: "empty_text" };
|
|
8291
8336
|
const policy = getSlackAllowlistPolicy();
|
|
8292
8337
|
const userAllowlistActive = policy.allowedUsers.length > 0;
|
|
@@ -8321,11 +8366,12 @@ function slackEventToInboundResult(event) {
|
|
|
8321
8366
|
}
|
|
8322
8367
|
};
|
|
8323
8368
|
}
|
|
8324
|
-
var slackChannel;
|
|
8369
|
+
var ownedThreads, slackChannel, IGNORED_MESSAGE_SUBTYPES;
|
|
8325
8370
|
var init_slack = __esm({
|
|
8326
8371
|
"src/integrations/channels/slack.ts"() {
|
|
8327
8372
|
"use strict";
|
|
8328
8373
|
init_client3();
|
|
8374
|
+
ownedThreads = /* @__PURE__ */ new Set();
|
|
8329
8375
|
slackChannel = {
|
|
8330
8376
|
id: "slack",
|
|
8331
8377
|
canSend: () => isSlackConfigured(),
|
|
@@ -8339,6 +8385,9 @@ var init_slack = __esm({
|
|
|
8339
8385
|
threadTs: r.threadTs
|
|
8340
8386
|
});
|
|
8341
8387
|
if (!result.ok) throw new Error(`slack post failed: ${result.error}`);
|
|
8388
|
+
if (r.slackChannel && r.threadTs) {
|
|
8389
|
+
markThreadOwned(r.slackChannel, r.threadTs);
|
|
8390
|
+
}
|
|
8342
8391
|
},
|
|
8343
8392
|
displayLabel(ref) {
|
|
8344
8393
|
const r = ref;
|
|
@@ -8349,6 +8398,29 @@ var init_slack = __esm({
|
|
|
8349
8398
|
return parts.join(" ");
|
|
8350
8399
|
}
|
|
8351
8400
|
};
|
|
8401
|
+
IGNORED_MESSAGE_SUBTYPES = /* @__PURE__ */ new Set([
|
|
8402
|
+
"bot_message",
|
|
8403
|
+
"message_changed",
|
|
8404
|
+
"message_deleted",
|
|
8405
|
+
"channel_join",
|
|
8406
|
+
"channel_leave",
|
|
8407
|
+
"channel_topic",
|
|
8408
|
+
"channel_purpose",
|
|
8409
|
+
"channel_name",
|
|
8410
|
+
"channel_archive",
|
|
8411
|
+
"channel_unarchive",
|
|
8412
|
+
"pinned_item",
|
|
8413
|
+
"unpinned_item",
|
|
8414
|
+
"thread_broadcast",
|
|
8415
|
+
// also-broadcast-to-channel replies; the regular thread reply already fires
|
|
8416
|
+
"message_replied",
|
|
8417
|
+
// legacy parent-thread bump
|
|
8418
|
+
"file_share",
|
|
8419
|
+
// we'd handle these later; for now skip to avoid double-handling
|
|
8420
|
+
"reply_broadcast",
|
|
8421
|
+
"tombstone",
|
|
8422
|
+
"huddle_thread"
|
|
8423
|
+
]);
|
|
8352
8424
|
}
|
|
8353
8425
|
});
|
|
8354
8426
|
|
|
@@ -10650,6 +10722,81 @@ var init_session_lock = __esm({
|
|
|
10650
10722
|
}
|
|
10651
10723
|
});
|
|
10652
10724
|
|
|
10725
|
+
// src/orchestrator/daemon.ts
|
|
10726
|
+
var daemon_exports = {};
|
|
10727
|
+
__export(daemon_exports, {
|
|
10728
|
+
startOrchestratorDaemon: () => startOrchestratorDaemon,
|
|
10729
|
+
subscribeToDaemonOutput: () => subscribeToDaemonOutput
|
|
10730
|
+
});
|
|
10731
|
+
function subscribeToDaemonOutput(sessionId, fn) {
|
|
10732
|
+
let set = listeners.get(sessionId);
|
|
10733
|
+
if (!set) {
|
|
10734
|
+
set = /* @__PURE__ */ new Set();
|
|
10735
|
+
listeners.set(sessionId, set);
|
|
10736
|
+
}
|
|
10737
|
+
set.add(fn);
|
|
10738
|
+
return () => {
|
|
10739
|
+
const s = listeners.get(sessionId);
|
|
10740
|
+
if (!s) return;
|
|
10741
|
+
s.delete(fn);
|
|
10742
|
+
if (s.size === 0) listeners.delete(sessionId);
|
|
10743
|
+
};
|
|
10744
|
+
}
|
|
10745
|
+
function broadcast(out) {
|
|
10746
|
+
const set = listeners.get(out.sessionId);
|
|
10747
|
+
if (!set) return;
|
|
10748
|
+
for (const fn of set) {
|
|
10749
|
+
try {
|
|
10750
|
+
fn(out);
|
|
10751
|
+
} catch (err) {
|
|
10752
|
+
console.error("[daemon] listener threw:", err?.message || err);
|
|
10753
|
+
}
|
|
10754
|
+
}
|
|
10755
|
+
}
|
|
10756
|
+
function startOrchestratorDaemon() {
|
|
10757
|
+
setFlushHandler(async (sessionId, events) => {
|
|
10758
|
+
await runDaemonTurn(sessionId, events);
|
|
10759
|
+
});
|
|
10760
|
+
}
|
|
10761
|
+
async function runDaemonTurn(sessionId, events) {
|
|
10762
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
10763
|
+
const session = await sessionQueries.getById(sessionId).catch(() => void 0);
|
|
10764
|
+
if (!session) {
|
|
10765
|
+
console.warn(`[daemon] flush for unknown session ${sessionId}; dropping ${events.length} event(s)`);
|
|
10766
|
+
return;
|
|
10767
|
+
}
|
|
10768
|
+
const prompt = events.map((e) => e.content).join("\n\n");
|
|
10769
|
+
let text = "";
|
|
10770
|
+
let error;
|
|
10771
|
+
await withSessionLock(sessionId, async () => {
|
|
10772
|
+
try {
|
|
10773
|
+
const agent = await Agent.create({ sessionId });
|
|
10774
|
+
const result = await agent.stream({ prompt });
|
|
10775
|
+
for await (const part of result.stream.fullStream) {
|
|
10776
|
+
if (part.type === "text-delta") text += part.text || "";
|
|
10777
|
+
}
|
|
10778
|
+
await result.saveResponseMessages();
|
|
10779
|
+
} catch (err) {
|
|
10780
|
+
error = err?.message || String(err);
|
|
10781
|
+
console.error(`[daemon] turn failed for ${sessionId}:`, error);
|
|
10782
|
+
}
|
|
10783
|
+
});
|
|
10784
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
10785
|
+
const trimmed = text.trim();
|
|
10786
|
+
broadcast({ sessionId, text: trimmed, triggeredBy: events, startedAt, finishedAt, error });
|
|
10787
|
+
}
|
|
10788
|
+
var listeners;
|
|
10789
|
+
var init_daemon = __esm({
|
|
10790
|
+
"src/orchestrator/daemon.ts"() {
|
|
10791
|
+
"use strict";
|
|
10792
|
+
init_agent();
|
|
10793
|
+
init_session_lock();
|
|
10794
|
+
init_db();
|
|
10795
|
+
init_inbox();
|
|
10796
|
+
listeners = /* @__PURE__ */ new Map();
|
|
10797
|
+
}
|
|
10798
|
+
});
|
|
10799
|
+
|
|
10653
10800
|
// src/tasks/boot-recovery.ts
|
|
10654
10801
|
var boot_recovery_exports = {};
|
|
10655
10802
|
__export(boot_recovery_exports, {
|
|
@@ -10737,81 +10884,6 @@ var init_ensure_orchestrator = __esm({
|
|
|
10737
10884
|
}
|
|
10738
10885
|
});
|
|
10739
10886
|
|
|
10740
|
-
// src/orchestrator/daemon.ts
|
|
10741
|
-
var daemon_exports = {};
|
|
10742
|
-
__export(daemon_exports, {
|
|
10743
|
-
startOrchestratorDaemon: () => startOrchestratorDaemon,
|
|
10744
|
-
subscribeToDaemonOutput: () => subscribeToDaemonOutput
|
|
10745
|
-
});
|
|
10746
|
-
function subscribeToDaemonOutput(sessionId, fn) {
|
|
10747
|
-
let set = listeners.get(sessionId);
|
|
10748
|
-
if (!set) {
|
|
10749
|
-
set = /* @__PURE__ */ new Set();
|
|
10750
|
-
listeners.set(sessionId, set);
|
|
10751
|
-
}
|
|
10752
|
-
set.add(fn);
|
|
10753
|
-
return () => {
|
|
10754
|
-
const s = listeners.get(sessionId);
|
|
10755
|
-
if (!s) return;
|
|
10756
|
-
s.delete(fn);
|
|
10757
|
-
if (s.size === 0) listeners.delete(sessionId);
|
|
10758
|
-
};
|
|
10759
|
-
}
|
|
10760
|
-
function broadcast(out) {
|
|
10761
|
-
const set = listeners.get(out.sessionId);
|
|
10762
|
-
if (!set) return;
|
|
10763
|
-
for (const fn of set) {
|
|
10764
|
-
try {
|
|
10765
|
-
fn(out);
|
|
10766
|
-
} catch (err) {
|
|
10767
|
-
console.error("[daemon] listener threw:", err?.message || err);
|
|
10768
|
-
}
|
|
10769
|
-
}
|
|
10770
|
-
}
|
|
10771
|
-
function startOrchestratorDaemon() {
|
|
10772
|
-
setFlushHandler(async (sessionId, events) => {
|
|
10773
|
-
await runDaemonTurn(sessionId, events);
|
|
10774
|
-
});
|
|
10775
|
-
}
|
|
10776
|
-
async function runDaemonTurn(sessionId, events) {
|
|
10777
|
-
const startedAt = /* @__PURE__ */ new Date();
|
|
10778
|
-
const session = await sessionQueries.getById(sessionId).catch(() => void 0);
|
|
10779
|
-
if (!session) {
|
|
10780
|
-
console.warn(`[daemon] flush for unknown session ${sessionId}; dropping ${events.length} event(s)`);
|
|
10781
|
-
return;
|
|
10782
|
-
}
|
|
10783
|
-
const prompt = events.map((e) => e.content).join("\n\n");
|
|
10784
|
-
let text = "";
|
|
10785
|
-
let error;
|
|
10786
|
-
await withSessionLock(sessionId, async () => {
|
|
10787
|
-
try {
|
|
10788
|
-
const agent = await Agent.create({ sessionId });
|
|
10789
|
-
const result = await agent.stream({ prompt });
|
|
10790
|
-
for await (const part of result.stream.fullStream) {
|
|
10791
|
-
if (part.type === "text-delta") text += part.text || "";
|
|
10792
|
-
}
|
|
10793
|
-
await result.saveResponseMessages();
|
|
10794
|
-
} catch (err) {
|
|
10795
|
-
error = err?.message || String(err);
|
|
10796
|
-
console.error(`[daemon] turn failed for ${sessionId}:`, error);
|
|
10797
|
-
}
|
|
10798
|
-
});
|
|
10799
|
-
const finishedAt = /* @__PURE__ */ new Date();
|
|
10800
|
-
const trimmed = text.trim();
|
|
10801
|
-
broadcast({ sessionId, text: trimmed, triggeredBy: events, startedAt, finishedAt, error });
|
|
10802
|
-
}
|
|
10803
|
-
var listeners;
|
|
10804
|
-
var init_daemon = __esm({
|
|
10805
|
-
"src/orchestrator/daemon.ts"() {
|
|
10806
|
-
"use strict";
|
|
10807
|
-
init_agent();
|
|
10808
|
-
init_session_lock();
|
|
10809
|
-
init_db();
|
|
10810
|
-
init_inbox();
|
|
10811
|
-
listeners = /* @__PURE__ */ new Map();
|
|
10812
|
-
}
|
|
10813
|
-
});
|
|
10814
|
-
|
|
10815
10887
|
// src/tasks/scheduler.ts
|
|
10816
10888
|
var scheduler_exports = {};
|
|
10817
10889
|
__export(scheduler_exports, {
|
|
@@ -10940,6 +11012,7 @@ function deriveAgentStatus(input) {
|
|
|
10940
11012
|
|
|
10941
11013
|
// src/server/routes/sessions.ts
|
|
10942
11014
|
init_pending_input();
|
|
11015
|
+
init_daemon();
|
|
10943
11016
|
|
|
10944
11017
|
// src/server/devtools-store.ts
|
|
10945
11018
|
var devtoolsContextStore = /* @__PURE__ */ new Map();
|
|
@@ -11082,6 +11155,63 @@ sessions2.post(
|
|
|
11082
11155
|
}, 201);
|
|
11083
11156
|
}
|
|
11084
11157
|
);
|
|
11158
|
+
sessions2.get("/:id/updates", async (c) => {
|
|
11159
|
+
const id = c.req.param("id");
|
|
11160
|
+
const session = await sessionQueries.getById(id);
|
|
11161
|
+
if (!session) return c.json({ error: "Session not found" }, 404);
|
|
11162
|
+
const stream = new ReadableStream({
|
|
11163
|
+
start(controller) {
|
|
11164
|
+
const encoder = new TextEncoder();
|
|
11165
|
+
const send = (data) => {
|
|
11166
|
+
try {
|
|
11167
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
11168
|
+
|
|
11169
|
+
`));
|
|
11170
|
+
} catch {
|
|
11171
|
+
}
|
|
11172
|
+
};
|
|
11173
|
+
send({ type: "ready", sessionId: id });
|
|
11174
|
+
const unsubscribe = subscribeToDaemonOutput(id, (output) => {
|
|
11175
|
+
send({
|
|
11176
|
+
type: "turn-complete",
|
|
11177
|
+
sessionId: id,
|
|
11178
|
+
finishedAt: output.finishedAt.toISOString(),
|
|
11179
|
+
triggeredBy: output.triggeredBy.map((e) => e.content?.slice(0, 80)),
|
|
11180
|
+
error: output.error ?? null
|
|
11181
|
+
});
|
|
11182
|
+
});
|
|
11183
|
+
let cleaned = false;
|
|
11184
|
+
const cleanup2 = () => {
|
|
11185
|
+
if (cleaned) return;
|
|
11186
|
+
cleaned = true;
|
|
11187
|
+
clearInterval(keepalive);
|
|
11188
|
+
unsubscribe();
|
|
11189
|
+
try {
|
|
11190
|
+
controller.close();
|
|
11191
|
+
} catch {
|
|
11192
|
+
}
|
|
11193
|
+
};
|
|
11194
|
+
const keepalive = setInterval(() => {
|
|
11195
|
+
try {
|
|
11196
|
+
controller.enqueue(encoder.encode(`: keepalive
|
|
11197
|
+
|
|
11198
|
+
`));
|
|
11199
|
+
} catch {
|
|
11200
|
+
cleanup2();
|
|
11201
|
+
}
|
|
11202
|
+
}, 25e3);
|
|
11203
|
+
c.req.raw.signal?.addEventListener("abort", cleanup2);
|
|
11204
|
+
}
|
|
11205
|
+
});
|
|
11206
|
+
return new Response(stream, {
|
|
11207
|
+
headers: {
|
|
11208
|
+
"Content-Type": "text/event-stream",
|
|
11209
|
+
"Cache-Control": "no-cache",
|
|
11210
|
+
Connection: "keep-alive",
|
|
11211
|
+
"X-Accel-Buffering": "no"
|
|
11212
|
+
}
|
|
11213
|
+
});
|
|
11214
|
+
});
|
|
11085
11215
|
sessions2.get("/:id", async (c) => {
|
|
11086
11216
|
const id = c.req.param("id");
|
|
11087
11217
|
const session = await sessionQueries.getById(id);
|
|
@@ -13829,6 +13959,19 @@ function verifySlackSignature(opts) {
|
|
|
13829
13959
|
init_client3();
|
|
13830
13960
|
init_slack();
|
|
13831
13961
|
init_inbox();
|
|
13962
|
+
var recentlyHandled = /* @__PURE__ */ new Map();
|
|
13963
|
+
var MAX_RECENT = 1e3;
|
|
13964
|
+
function alreadyHandled(channel, ts) {
|
|
13965
|
+
if (!channel || !ts) return false;
|
|
13966
|
+
const key2 = `${channel}\u241F${ts}`;
|
|
13967
|
+
if (recentlyHandled.has(key2)) return true;
|
|
13968
|
+
recentlyHandled.set(key2, Date.now());
|
|
13969
|
+
if (recentlyHandled.size > MAX_RECENT) {
|
|
13970
|
+
const oldest = recentlyHandled.keys().next().value;
|
|
13971
|
+
if (oldest) recentlyHandled.delete(oldest);
|
|
13972
|
+
}
|
|
13973
|
+
return false;
|
|
13974
|
+
}
|
|
13832
13975
|
var slack = new Hono6();
|
|
13833
13976
|
slack.post("/events", async (c) => {
|
|
13834
13977
|
const signingSecret = getSlackSigningSecret();
|
|
@@ -13854,8 +13997,26 @@ slack.post("/events", async (c) => {
|
|
|
13854
13997
|
return c.json({ challenge: payload.challenge });
|
|
13855
13998
|
}
|
|
13856
13999
|
if (payload?.type === "event_callback" && payload?.event) {
|
|
13857
|
-
const
|
|
14000
|
+
const ev = payload.event;
|
|
14001
|
+
if (alreadyHandled(ev.channel, ev.ts)) {
|
|
14002
|
+
return c.json({ ok: true });
|
|
14003
|
+
}
|
|
14004
|
+
const { event: inbound, dropReason } = slackEventToInboundResult(ev);
|
|
13858
14005
|
if (inbound) {
|
|
14006
|
+
const isThreadReply = ev.type === "message" && ev.channel_type !== "im" && typeof ev.thread_ts === "string" && ev.thread_ts !== ev.ts;
|
|
14007
|
+
if (isThreadReply) {
|
|
14008
|
+
const ours = isThreadOwned(ev.channel, ev.thread_ts) || await threadBelongsToUs(ev.channel, ev.thread_ts);
|
|
14009
|
+
if (!ours) {
|
|
14010
|
+
console.log(`[slack] dropping thread reply in unknown thread: channel=${ev.channel} thread=${ev.thread_ts}`);
|
|
14011
|
+
return c.json({ ok: true });
|
|
14012
|
+
}
|
|
14013
|
+
}
|
|
14014
|
+
if (ev.type === "app_mention" && ev.channel && (ev.thread_ts || ev.ts)) {
|
|
14015
|
+
markThreadOwned(ev.channel, ev.thread_ts || ev.ts);
|
|
14016
|
+
}
|
|
14017
|
+
if (ev.type === "message" && ev.channel_type === "im" && ev.channel && (ev.thread_ts || ev.ts)) {
|
|
14018
|
+
markThreadOwned(ev.channel, ev.thread_ts || ev.ts);
|
|
14019
|
+
}
|
|
13859
14020
|
const orchestratorId = await findOrCreateOrchestratorId();
|
|
13860
14021
|
if (orchestratorId) {
|
|
13861
14022
|
pushToInbox(orchestratorId, inbound);
|
|
@@ -13872,6 +14033,18 @@ slack.post("/events", async (c) => {
|
|
|
13872
14033
|
}
|
|
13873
14034
|
return c.json({ ok: true });
|
|
13874
14035
|
});
|
|
14036
|
+
async function threadBelongsToUs(channel, threadTs) {
|
|
14037
|
+
try {
|
|
14038
|
+
const sessions3 = await sessionQueries.list(500, 0);
|
|
14039
|
+
return sessions3.some((s) => {
|
|
14040
|
+
const slack2 = s.config?.slack;
|
|
14041
|
+
return slack2?.channel === channel && slack2?.threadTs === threadTs;
|
|
14042
|
+
});
|
|
14043
|
+
} catch (err) {
|
|
14044
|
+
console.warn("[slack] threadBelongsToUs lookup failed:", err?.message ?? err);
|
|
14045
|
+
return false;
|
|
14046
|
+
}
|
|
14047
|
+
}
|
|
13875
14048
|
async function findOrCreateOrchestratorId() {
|
|
13876
14049
|
try {
|
|
13877
14050
|
const all = await sessionQueries.list(500, 0);
|