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/index.js
CHANGED
|
@@ -826,9 +826,10 @@ function createDefaultConfig() {
|
|
|
826
826
|
}
|
|
827
827
|
function loadStoredAuthKey() {
|
|
828
828
|
const locations = [
|
|
829
|
+
process.env.SPARKECODER_AUTH_KEY_PATH,
|
|
829
830
|
join(process.cwd(), ".sparkecoder", AUTH_KEY_FILE),
|
|
830
831
|
join(getAppDataDirectory(), AUTH_KEY_FILE)
|
|
831
|
-
];
|
|
832
|
+
].filter((p) => !!p);
|
|
832
833
|
for (const keysPath of locations) {
|
|
833
834
|
if (!existsSync(keysPath)) continue;
|
|
834
835
|
try {
|
|
@@ -847,15 +848,44 @@ function saveAuthKey(authKey3, userId) {
|
|
|
847
848
|
userId
|
|
848
849
|
};
|
|
849
850
|
const json = JSON.stringify(data, null, 2);
|
|
850
|
-
const
|
|
851
|
-
|
|
851
|
+
const targets = [];
|
|
852
|
+
if (process.env.SPARKECODER_AUTH_KEY_PATH) {
|
|
853
|
+
targets.push({
|
|
854
|
+
label: "SPARKECODER_AUTH_KEY_PATH",
|
|
855
|
+
path: process.env.SPARKECODER_AUTH_KEY_PATH
|
|
856
|
+
});
|
|
857
|
+
}
|
|
852
858
|
try {
|
|
853
|
-
const
|
|
854
|
-
|
|
855
|
-
|
|
859
|
+
const appDir = ensureAppDataDirectory();
|
|
860
|
+
targets.push({ label: "app-data", path: join(appDir, AUTH_KEY_FILE) });
|
|
861
|
+
} catch (err) {
|
|
862
|
+
console.warn(`[auth-key] could not ensure app data dir: ${err?.message ?? err}`);
|
|
863
|
+
}
|
|
864
|
+
targets.push({
|
|
865
|
+
label: "workspace",
|
|
866
|
+
path: join(process.cwd(), ".sparkecoder", AUTH_KEY_FILE)
|
|
867
|
+
});
|
|
868
|
+
const successes = [];
|
|
869
|
+
const failures = [];
|
|
870
|
+
for (const { label, path } of targets) {
|
|
871
|
+
try {
|
|
872
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
873
|
+
writeFileSync(path, json, { mode: 384 });
|
|
874
|
+
successes.push(`${label}:${path}`);
|
|
875
|
+
} catch (err) {
|
|
876
|
+
failures.push({ label, path, error: err?.message ?? String(err) });
|
|
856
877
|
}
|
|
857
|
-
|
|
858
|
-
|
|
878
|
+
}
|
|
879
|
+
if (successes.length === 0) {
|
|
880
|
+
const detail = failures.map((f) => `${f.label} (${f.path}): ${f.error}`).join("; ");
|
|
881
|
+
throw new Error(`Failed to persist auth-key.json to any location. ${detail}`);
|
|
882
|
+
}
|
|
883
|
+
if (failures.length > 0) {
|
|
884
|
+
console.warn(
|
|
885
|
+
`[auth-key] wrote to ${successes.length}/${targets.length} locations. Success: ${successes.join(", ")}. Failed: ${failures.map((f) => `${f.label} (${f.path}): ${f.error}`).join("; ")}`
|
|
886
|
+
);
|
|
887
|
+
} else if (process.env.SPARKECODER_VERBOSE_CONFIG) {
|
|
888
|
+
console.log(`[auth-key] saved to: ${successes.join(", ")}`);
|
|
859
889
|
}
|
|
860
890
|
}
|
|
861
891
|
function getStoredAuthKeyInfo() {
|
|
@@ -8295,15 +8325,30 @@ var init_client3 = __esm({
|
|
|
8295
8325
|
});
|
|
8296
8326
|
|
|
8297
8327
|
// src/integrations/channels/slack.ts
|
|
8328
|
+
function threadKey(channel, threadTs) {
|
|
8329
|
+
return `${channel}\u241F${threadTs}`;
|
|
8330
|
+
}
|
|
8331
|
+
function markThreadOwned(channel, threadTs) {
|
|
8332
|
+
ownedThreads.add(threadKey(channel, threadTs));
|
|
8333
|
+
}
|
|
8334
|
+
function isThreadOwned(channel, threadTs) {
|
|
8335
|
+
return ownedThreads.has(threadKey(channel, threadTs));
|
|
8336
|
+
}
|
|
8298
8337
|
function stripMention(text) {
|
|
8299
8338
|
return String(text || "").replace(/<@[^>]+>/g, "").trim();
|
|
8300
8339
|
}
|
|
8301
8340
|
function slackEventToInboundResult(event) {
|
|
8302
8341
|
if (!event) return { event: null, dropReason: "empty_text" };
|
|
8303
|
-
if (event.bot_id
|
|
8342
|
+
if (event.bot_id) return { event: null, dropReason: "bot_message" };
|
|
8343
|
+
if (event.type === "message" && event.subtype && IGNORED_MESSAGE_SUBTYPES.has(event.subtype)) {
|
|
8344
|
+
return { event: null, dropReason: "bot_message" };
|
|
8345
|
+
}
|
|
8304
8346
|
const isDm = event.type === "message" && event.channel_type === "im";
|
|
8305
|
-
|
|
8306
|
-
|
|
8347
|
+
const isThreadReply = event.type === "message" && !isDm && typeof event.thread_ts === "string" && event.thread_ts !== event.ts;
|
|
8348
|
+
if (event.type !== "app_mention" && !isDm && !isThreadReply) {
|
|
8349
|
+
return { event: null, dropReason: "unsupported_type" };
|
|
8350
|
+
}
|
|
8351
|
+
const text = event.type === "app_mention" ? stripMention(event.text) : (event.text ?? "").trim();
|
|
8307
8352
|
if (!text) return { event: null, dropReason: "empty_text" };
|
|
8308
8353
|
const policy = getSlackAllowlistPolicy();
|
|
8309
8354
|
const userAllowlistActive = policy.allowedUsers.length > 0;
|
|
@@ -8338,11 +8383,12 @@ function slackEventToInboundResult(event) {
|
|
|
8338
8383
|
}
|
|
8339
8384
|
};
|
|
8340
8385
|
}
|
|
8341
|
-
var slackChannel;
|
|
8386
|
+
var ownedThreads, slackChannel, IGNORED_MESSAGE_SUBTYPES;
|
|
8342
8387
|
var init_slack = __esm({
|
|
8343
8388
|
"src/integrations/channels/slack.ts"() {
|
|
8344
8389
|
"use strict";
|
|
8345
8390
|
init_client3();
|
|
8391
|
+
ownedThreads = /* @__PURE__ */ new Set();
|
|
8346
8392
|
slackChannel = {
|
|
8347
8393
|
id: "slack",
|
|
8348
8394
|
canSend: () => isSlackConfigured(),
|
|
@@ -8356,6 +8402,9 @@ var init_slack = __esm({
|
|
|
8356
8402
|
threadTs: r.threadTs
|
|
8357
8403
|
});
|
|
8358
8404
|
if (!result.ok) throw new Error(`slack post failed: ${result.error}`);
|
|
8405
|
+
if (r.slackChannel && r.threadTs) {
|
|
8406
|
+
markThreadOwned(r.slackChannel, r.threadTs);
|
|
8407
|
+
}
|
|
8359
8408
|
},
|
|
8360
8409
|
displayLabel(ref) {
|
|
8361
8410
|
const r = ref;
|
|
@@ -8366,6 +8415,29 @@ var init_slack = __esm({
|
|
|
8366
8415
|
return parts.join(" ");
|
|
8367
8416
|
}
|
|
8368
8417
|
};
|
|
8418
|
+
IGNORED_MESSAGE_SUBTYPES = /* @__PURE__ */ new Set([
|
|
8419
|
+
"bot_message",
|
|
8420
|
+
"message_changed",
|
|
8421
|
+
"message_deleted",
|
|
8422
|
+
"channel_join",
|
|
8423
|
+
"channel_leave",
|
|
8424
|
+
"channel_topic",
|
|
8425
|
+
"channel_purpose",
|
|
8426
|
+
"channel_name",
|
|
8427
|
+
"channel_archive",
|
|
8428
|
+
"channel_unarchive",
|
|
8429
|
+
"pinned_item",
|
|
8430
|
+
"unpinned_item",
|
|
8431
|
+
"thread_broadcast",
|
|
8432
|
+
// also-broadcast-to-channel replies; the regular thread reply already fires
|
|
8433
|
+
"message_replied",
|
|
8434
|
+
// legacy parent-thread bump
|
|
8435
|
+
"file_share",
|
|
8436
|
+
// we'd handle these later; for now skip to avoid double-handling
|
|
8437
|
+
"reply_broadcast",
|
|
8438
|
+
"tombstone",
|
|
8439
|
+
"huddle_thread"
|
|
8440
|
+
]);
|
|
8369
8441
|
}
|
|
8370
8442
|
});
|
|
8371
8443
|
|
|
@@ -10667,6 +10739,81 @@ var init_session_lock = __esm({
|
|
|
10667
10739
|
}
|
|
10668
10740
|
});
|
|
10669
10741
|
|
|
10742
|
+
// src/orchestrator/daemon.ts
|
|
10743
|
+
var daemon_exports = {};
|
|
10744
|
+
__export(daemon_exports, {
|
|
10745
|
+
startOrchestratorDaemon: () => startOrchestratorDaemon,
|
|
10746
|
+
subscribeToDaemonOutput: () => subscribeToDaemonOutput
|
|
10747
|
+
});
|
|
10748
|
+
function subscribeToDaemonOutput(sessionId, fn) {
|
|
10749
|
+
let set = listeners.get(sessionId);
|
|
10750
|
+
if (!set) {
|
|
10751
|
+
set = /* @__PURE__ */ new Set();
|
|
10752
|
+
listeners.set(sessionId, set);
|
|
10753
|
+
}
|
|
10754
|
+
set.add(fn);
|
|
10755
|
+
return () => {
|
|
10756
|
+
const s = listeners.get(sessionId);
|
|
10757
|
+
if (!s) return;
|
|
10758
|
+
s.delete(fn);
|
|
10759
|
+
if (s.size === 0) listeners.delete(sessionId);
|
|
10760
|
+
};
|
|
10761
|
+
}
|
|
10762
|
+
function broadcast(out) {
|
|
10763
|
+
const set = listeners.get(out.sessionId);
|
|
10764
|
+
if (!set) return;
|
|
10765
|
+
for (const fn of set) {
|
|
10766
|
+
try {
|
|
10767
|
+
fn(out);
|
|
10768
|
+
} catch (err) {
|
|
10769
|
+
console.error("[daemon] listener threw:", err?.message || err);
|
|
10770
|
+
}
|
|
10771
|
+
}
|
|
10772
|
+
}
|
|
10773
|
+
function startOrchestratorDaemon() {
|
|
10774
|
+
setFlushHandler(async (sessionId, events) => {
|
|
10775
|
+
await runDaemonTurn(sessionId, events);
|
|
10776
|
+
});
|
|
10777
|
+
}
|
|
10778
|
+
async function runDaemonTurn(sessionId, events) {
|
|
10779
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
10780
|
+
const session = await sessionQueries.getById(sessionId).catch(() => void 0);
|
|
10781
|
+
if (!session) {
|
|
10782
|
+
console.warn(`[daemon] flush for unknown session ${sessionId}; dropping ${events.length} event(s)`);
|
|
10783
|
+
return;
|
|
10784
|
+
}
|
|
10785
|
+
const prompt = events.map((e) => e.content).join("\n\n");
|
|
10786
|
+
let text = "";
|
|
10787
|
+
let error;
|
|
10788
|
+
await withSessionLock(sessionId, async () => {
|
|
10789
|
+
try {
|
|
10790
|
+
const agent = await Agent.create({ sessionId });
|
|
10791
|
+
const result = await agent.stream({ prompt });
|
|
10792
|
+
for await (const part of result.stream.fullStream) {
|
|
10793
|
+
if (part.type === "text-delta") text += part.text || "";
|
|
10794
|
+
}
|
|
10795
|
+
await result.saveResponseMessages();
|
|
10796
|
+
} catch (err) {
|
|
10797
|
+
error = err?.message || String(err);
|
|
10798
|
+
console.error(`[daemon] turn failed for ${sessionId}:`, error);
|
|
10799
|
+
}
|
|
10800
|
+
});
|
|
10801
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
10802
|
+
const trimmed = text.trim();
|
|
10803
|
+
broadcast({ sessionId, text: trimmed, triggeredBy: events, startedAt, finishedAt, error });
|
|
10804
|
+
}
|
|
10805
|
+
var listeners;
|
|
10806
|
+
var init_daemon = __esm({
|
|
10807
|
+
"src/orchestrator/daemon.ts"() {
|
|
10808
|
+
"use strict";
|
|
10809
|
+
init_agent();
|
|
10810
|
+
init_session_lock();
|
|
10811
|
+
init_db();
|
|
10812
|
+
init_inbox();
|
|
10813
|
+
listeners = /* @__PURE__ */ new Map();
|
|
10814
|
+
}
|
|
10815
|
+
});
|
|
10816
|
+
|
|
10670
10817
|
// src/tasks/boot-recovery.ts
|
|
10671
10818
|
var boot_recovery_exports = {};
|
|
10672
10819
|
__export(boot_recovery_exports, {
|
|
@@ -10754,81 +10901,6 @@ var init_ensure_orchestrator = __esm({
|
|
|
10754
10901
|
}
|
|
10755
10902
|
});
|
|
10756
10903
|
|
|
10757
|
-
// src/orchestrator/daemon.ts
|
|
10758
|
-
var daemon_exports = {};
|
|
10759
|
-
__export(daemon_exports, {
|
|
10760
|
-
startOrchestratorDaemon: () => startOrchestratorDaemon,
|
|
10761
|
-
subscribeToDaemonOutput: () => subscribeToDaemonOutput
|
|
10762
|
-
});
|
|
10763
|
-
function subscribeToDaemonOutput(sessionId, fn) {
|
|
10764
|
-
let set = listeners.get(sessionId);
|
|
10765
|
-
if (!set) {
|
|
10766
|
-
set = /* @__PURE__ */ new Set();
|
|
10767
|
-
listeners.set(sessionId, set);
|
|
10768
|
-
}
|
|
10769
|
-
set.add(fn);
|
|
10770
|
-
return () => {
|
|
10771
|
-
const s = listeners.get(sessionId);
|
|
10772
|
-
if (!s) return;
|
|
10773
|
-
s.delete(fn);
|
|
10774
|
-
if (s.size === 0) listeners.delete(sessionId);
|
|
10775
|
-
};
|
|
10776
|
-
}
|
|
10777
|
-
function broadcast(out) {
|
|
10778
|
-
const set = listeners.get(out.sessionId);
|
|
10779
|
-
if (!set) return;
|
|
10780
|
-
for (const fn of set) {
|
|
10781
|
-
try {
|
|
10782
|
-
fn(out);
|
|
10783
|
-
} catch (err) {
|
|
10784
|
-
console.error("[daemon] listener threw:", err?.message || err);
|
|
10785
|
-
}
|
|
10786
|
-
}
|
|
10787
|
-
}
|
|
10788
|
-
function startOrchestratorDaemon() {
|
|
10789
|
-
setFlushHandler(async (sessionId, events) => {
|
|
10790
|
-
await runDaemonTurn(sessionId, events);
|
|
10791
|
-
});
|
|
10792
|
-
}
|
|
10793
|
-
async function runDaemonTurn(sessionId, events) {
|
|
10794
|
-
const startedAt = /* @__PURE__ */ new Date();
|
|
10795
|
-
const session = await sessionQueries.getById(sessionId).catch(() => void 0);
|
|
10796
|
-
if (!session) {
|
|
10797
|
-
console.warn(`[daemon] flush for unknown session ${sessionId}; dropping ${events.length} event(s)`);
|
|
10798
|
-
return;
|
|
10799
|
-
}
|
|
10800
|
-
const prompt = events.map((e) => e.content).join("\n\n");
|
|
10801
|
-
let text = "";
|
|
10802
|
-
let error;
|
|
10803
|
-
await withSessionLock(sessionId, async () => {
|
|
10804
|
-
try {
|
|
10805
|
-
const agent = await Agent.create({ sessionId });
|
|
10806
|
-
const result = await agent.stream({ prompt });
|
|
10807
|
-
for await (const part of result.stream.fullStream) {
|
|
10808
|
-
if (part.type === "text-delta") text += part.text || "";
|
|
10809
|
-
}
|
|
10810
|
-
await result.saveResponseMessages();
|
|
10811
|
-
} catch (err) {
|
|
10812
|
-
error = err?.message || String(err);
|
|
10813
|
-
console.error(`[daemon] turn failed for ${sessionId}:`, error);
|
|
10814
|
-
}
|
|
10815
|
-
});
|
|
10816
|
-
const finishedAt = /* @__PURE__ */ new Date();
|
|
10817
|
-
const trimmed = text.trim();
|
|
10818
|
-
broadcast({ sessionId, text: trimmed, triggeredBy: events, startedAt, finishedAt, error });
|
|
10819
|
-
}
|
|
10820
|
-
var listeners;
|
|
10821
|
-
var init_daemon = __esm({
|
|
10822
|
-
"src/orchestrator/daemon.ts"() {
|
|
10823
|
-
"use strict";
|
|
10824
|
-
init_agent();
|
|
10825
|
-
init_session_lock();
|
|
10826
|
-
init_db();
|
|
10827
|
-
init_inbox();
|
|
10828
|
-
listeners = /* @__PURE__ */ new Map();
|
|
10829
|
-
}
|
|
10830
|
-
});
|
|
10831
|
-
|
|
10832
10904
|
// src/tasks/scheduler.ts
|
|
10833
10905
|
var scheduler_exports = {};
|
|
10834
10906
|
__export(scheduler_exports, {
|
|
@@ -10960,6 +11032,7 @@ function deriveAgentStatus(input) {
|
|
|
10960
11032
|
|
|
10961
11033
|
// src/server/routes/sessions.ts
|
|
10962
11034
|
init_pending_input();
|
|
11035
|
+
init_daemon();
|
|
10963
11036
|
|
|
10964
11037
|
// src/server/devtools-store.ts
|
|
10965
11038
|
var devtoolsContextStore = /* @__PURE__ */ new Map();
|
|
@@ -11102,6 +11175,63 @@ sessions2.post(
|
|
|
11102
11175
|
}, 201);
|
|
11103
11176
|
}
|
|
11104
11177
|
);
|
|
11178
|
+
sessions2.get("/:id/updates", async (c) => {
|
|
11179
|
+
const id = c.req.param("id");
|
|
11180
|
+
const session = await sessionQueries.getById(id);
|
|
11181
|
+
if (!session) return c.json({ error: "Session not found" }, 404);
|
|
11182
|
+
const stream = new ReadableStream({
|
|
11183
|
+
start(controller) {
|
|
11184
|
+
const encoder = new TextEncoder();
|
|
11185
|
+
const send = (data) => {
|
|
11186
|
+
try {
|
|
11187
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
11188
|
+
|
|
11189
|
+
`));
|
|
11190
|
+
} catch {
|
|
11191
|
+
}
|
|
11192
|
+
};
|
|
11193
|
+
send({ type: "ready", sessionId: id });
|
|
11194
|
+
const unsubscribe = subscribeToDaemonOutput(id, (output) => {
|
|
11195
|
+
send({
|
|
11196
|
+
type: "turn-complete",
|
|
11197
|
+
sessionId: id,
|
|
11198
|
+
finishedAt: output.finishedAt.toISOString(),
|
|
11199
|
+
triggeredBy: output.triggeredBy.map((e) => e.content?.slice(0, 80)),
|
|
11200
|
+
error: output.error ?? null
|
|
11201
|
+
});
|
|
11202
|
+
});
|
|
11203
|
+
let cleaned = false;
|
|
11204
|
+
const cleanup2 = () => {
|
|
11205
|
+
if (cleaned) return;
|
|
11206
|
+
cleaned = true;
|
|
11207
|
+
clearInterval(keepalive);
|
|
11208
|
+
unsubscribe();
|
|
11209
|
+
try {
|
|
11210
|
+
controller.close();
|
|
11211
|
+
} catch {
|
|
11212
|
+
}
|
|
11213
|
+
};
|
|
11214
|
+
const keepalive = setInterval(() => {
|
|
11215
|
+
try {
|
|
11216
|
+
controller.enqueue(encoder.encode(`: keepalive
|
|
11217
|
+
|
|
11218
|
+
`));
|
|
11219
|
+
} catch {
|
|
11220
|
+
cleanup2();
|
|
11221
|
+
}
|
|
11222
|
+
}, 25e3);
|
|
11223
|
+
c.req.raw.signal?.addEventListener("abort", cleanup2);
|
|
11224
|
+
}
|
|
11225
|
+
});
|
|
11226
|
+
return new Response(stream, {
|
|
11227
|
+
headers: {
|
|
11228
|
+
"Content-Type": "text/event-stream",
|
|
11229
|
+
"Cache-Control": "no-cache",
|
|
11230
|
+
Connection: "keep-alive",
|
|
11231
|
+
"X-Accel-Buffering": "no"
|
|
11232
|
+
}
|
|
11233
|
+
});
|
|
11234
|
+
});
|
|
11105
11235
|
sessions2.get("/:id", async (c) => {
|
|
11106
11236
|
const id = c.req.param("id");
|
|
11107
11237
|
const session = await sessionQueries.getById(id);
|
|
@@ -13849,6 +13979,19 @@ function verifySlackSignature(opts) {
|
|
|
13849
13979
|
init_client3();
|
|
13850
13980
|
init_slack();
|
|
13851
13981
|
init_inbox();
|
|
13982
|
+
var recentlyHandled = /* @__PURE__ */ new Map();
|
|
13983
|
+
var MAX_RECENT = 1e3;
|
|
13984
|
+
function alreadyHandled(channel, ts) {
|
|
13985
|
+
if (!channel || !ts) return false;
|
|
13986
|
+
const key2 = `${channel}\u241F${ts}`;
|
|
13987
|
+
if (recentlyHandled.has(key2)) return true;
|
|
13988
|
+
recentlyHandled.set(key2, Date.now());
|
|
13989
|
+
if (recentlyHandled.size > MAX_RECENT) {
|
|
13990
|
+
const oldest = recentlyHandled.keys().next().value;
|
|
13991
|
+
if (oldest) recentlyHandled.delete(oldest);
|
|
13992
|
+
}
|
|
13993
|
+
return false;
|
|
13994
|
+
}
|
|
13852
13995
|
var slack = new Hono6();
|
|
13853
13996
|
slack.post("/events", async (c) => {
|
|
13854
13997
|
const signingSecret = getSlackSigningSecret();
|
|
@@ -13874,8 +14017,26 @@ slack.post("/events", async (c) => {
|
|
|
13874
14017
|
return c.json({ challenge: payload.challenge });
|
|
13875
14018
|
}
|
|
13876
14019
|
if (payload?.type === "event_callback" && payload?.event) {
|
|
13877
|
-
const
|
|
14020
|
+
const ev = payload.event;
|
|
14021
|
+
if (alreadyHandled(ev.channel, ev.ts)) {
|
|
14022
|
+
return c.json({ ok: true });
|
|
14023
|
+
}
|
|
14024
|
+
const { event: inbound, dropReason } = slackEventToInboundResult(ev);
|
|
13878
14025
|
if (inbound) {
|
|
14026
|
+
const isThreadReply = ev.type === "message" && ev.channel_type !== "im" && typeof ev.thread_ts === "string" && ev.thread_ts !== ev.ts;
|
|
14027
|
+
if (isThreadReply) {
|
|
14028
|
+
const ours = isThreadOwned(ev.channel, ev.thread_ts) || await threadBelongsToUs(ev.channel, ev.thread_ts);
|
|
14029
|
+
if (!ours) {
|
|
14030
|
+
console.log(`[slack] dropping thread reply in unknown thread: channel=${ev.channel} thread=${ev.thread_ts}`);
|
|
14031
|
+
return c.json({ ok: true });
|
|
14032
|
+
}
|
|
14033
|
+
}
|
|
14034
|
+
if (ev.type === "app_mention" && ev.channel && (ev.thread_ts || ev.ts)) {
|
|
14035
|
+
markThreadOwned(ev.channel, ev.thread_ts || ev.ts);
|
|
14036
|
+
}
|
|
14037
|
+
if (ev.type === "message" && ev.channel_type === "im" && ev.channel && (ev.thread_ts || ev.ts)) {
|
|
14038
|
+
markThreadOwned(ev.channel, ev.thread_ts || ev.ts);
|
|
14039
|
+
}
|
|
13879
14040
|
const orchestratorId = await findOrCreateOrchestratorId();
|
|
13880
14041
|
if (orchestratorId) {
|
|
13881
14042
|
pushToInbox(orchestratorId, inbound);
|
|
@@ -13892,6 +14053,18 @@ slack.post("/events", async (c) => {
|
|
|
13892
14053
|
}
|
|
13893
14054
|
return c.json({ ok: true });
|
|
13894
14055
|
});
|
|
14056
|
+
async function threadBelongsToUs(channel, threadTs) {
|
|
14057
|
+
try {
|
|
14058
|
+
const sessions3 = await sessionQueries.list(500, 0);
|
|
14059
|
+
return sessions3.some((s) => {
|
|
14060
|
+
const slack2 = s.config?.slack;
|
|
14061
|
+
return slack2?.channel === channel && slack2?.threadTs === threadTs;
|
|
14062
|
+
});
|
|
14063
|
+
} catch (err) {
|
|
14064
|
+
console.warn("[slack] threadBelongsToUs lookup failed:", err?.message ?? err);
|
|
14065
|
+
return false;
|
|
14066
|
+
}
|
|
14067
|
+
}
|
|
13895
14068
|
async function findOrCreateOrchestratorId() {
|
|
13896
14069
|
try {
|
|
13897
14070
|
const all = await sessionQueries.list(500, 0);
|