negotium 0.2.24 → 0.2.26
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-helpers.js +82 -29
- package/dist/agent-helpers.js.map +5 -5
- package/dist/hosted-agent.js +2 -2
- package/dist/hosted-agent.js.map +2 -2
- package/dist/main.js +167 -364
- package/dist/main.js.map +26 -27
- package/dist/mcp-factories.js +84 -30
- package/dist/mcp-factories.js.map +6 -6
- package/dist/registry.js +2 -2
- package/dist/registry.js.map +2 -2
- package/dist/runtime/src/index.ts +3 -7
- package/dist/runtime/src/mcp/session-comm/default-host.ts +6 -1
- package/dist/runtime/src/mcp/session-comm/topic-catalog.ts +17 -1
- package/dist/runtime/src/mcp/session-comm/topics.ts +23 -1
- package/dist/runtime/src/node-host.ts +2 -3
- package/dist/runtime/src/storage/api-topics.ts +164 -52
- package/dist/runtime/src/storage/storage-public.ts +0 -1
- package/dist/runtime/src/topics/create.ts +12 -6
- package/dist/runtime/src/topics/derive.ts +20 -11
- package/dist/runtime/src/types/api.ts +8 -4
- package/dist/runtime/src/version.ts +1 -1
- package/dist/storage.js +92 -38
- package/dist/storage.js.map +3 -3
- package/dist/types/packages/core/src/mcp/session-comm/topic-catalog.d.ts +7 -0
- package/dist/types/packages/core/src/storage/api-topics.d.ts +34 -19
- package/dist/types/packages/core/src/storage/storage-public.d.ts +1 -1
- package/dist/types/packages/core/src/topics/derive.d.ts +13 -4
- package/dist/types/packages/core/src/types/api.d.ts +8 -4
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/runtime/src/application/switch-topic-access-mode.ts +0 -110
package/dist/main.js
CHANGED
|
@@ -1868,7 +1868,7 @@ var exports_version = {};
|
|
|
1868
1868
|
__export(exports_version, {
|
|
1869
1869
|
NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
|
|
1870
1870
|
});
|
|
1871
|
-
var NEGOTIUM_VERSION = "0.2.
|
|
1871
|
+
var NEGOTIUM_VERSION = "0.2.26";
|
|
1872
1872
|
|
|
1873
1873
|
// ../../packages/core/src/agents/codex-native-multi-agent.ts
|
|
1874
1874
|
import { spawn } from "child_process";
|
|
@@ -7506,21 +7506,20 @@ var init_constants = __esm(() => {
|
|
|
7506
7506
|
var exports_api_topics = {};
|
|
7507
7507
|
__export(exports_api_topics, {
|
|
7508
7508
|
upsertTopic: () => upsertTopic,
|
|
7509
|
+
setTopicSurfaces: () => setTopicSurfaces,
|
|
7509
7510
|
setTopicSessionId: () => setTopicSessionId,
|
|
7510
|
-
setTopicAccessModes: () => setTopicAccessModes,
|
|
7511
7511
|
setApiTopicAgent: () => setApiTopicAgent,
|
|
7512
7512
|
revokeSubagentTellTarget: () => revokeSubagentTellTarget,
|
|
7513
7513
|
reparentTopicChildren: () => reparentTopicChildren,
|
|
7514
7514
|
removeParticipantFromDB: () => removeParticipantFromDB,
|
|
7515
7515
|
normalizeTopicVisibility: () => normalizeTopicVisibility,
|
|
7516
|
+
normalizeTopicSurface: () => normalizeTopicSurface,
|
|
7516
7517
|
normalizeTopicState: () => normalizeTopicState,
|
|
7517
7518
|
normalizeTopicKind: () => normalizeTopicKind,
|
|
7518
|
-
normalizeTopicAccessMode: () => normalizeTopicAccessMode,
|
|
7519
7519
|
normalizeAiMode: () => normalizeAiMode,
|
|
7520
7520
|
listTopics: () => listTopics,
|
|
7521
7521
|
listSubagentTellTargetIds: () => listSubagentTellTargetIds,
|
|
7522
7522
|
isTopicVisible: () => isTopicVisible,
|
|
7523
|
-
isTopicShared: () => isTopicShared,
|
|
7524
7523
|
inferTopicKind: () => inferTopicKind,
|
|
7525
7524
|
inferAiMode: () => inferAiMode,
|
|
7526
7525
|
grantSubagentTellTarget: () => grantSubagentTellTarget,
|
|
@@ -7533,10 +7532,17 @@ __export(exports_api_topics, {
|
|
|
7533
7532
|
getManagerTopicForUser: () => getManagerTopicForUser,
|
|
7534
7533
|
findTopicTitleConflict: () => findTopicTitleConflict,
|
|
7535
7534
|
deleteTopic: () => deleteTopic,
|
|
7535
|
+
defaultTopicSurface: () => defaultTopicSurface,
|
|
7536
7536
|
clearTopicSessionId: () => clearTopicSessionId,
|
|
7537
7537
|
aiMentionFromMode: () => aiMentionFromMode,
|
|
7538
7538
|
addParticipantToDB: () => addParticipantToDB
|
|
7539
7539
|
});
|
|
7540
|
+
function defaultTopicSurface() {
|
|
7541
|
+
return normalizeTopicSurface(process.env.NEGOTIUM_DEFAULT_SURFACE);
|
|
7542
|
+
}
|
|
7543
|
+
function normalizeTopicSurface(value) {
|
|
7544
|
+
return value === "telegram" || value === "otium" || value === "terminal" ? value : "terminal";
|
|
7545
|
+
}
|
|
7540
7546
|
function tableColumns2(table) {
|
|
7541
7547
|
const rows = db.query(`PRAGMA table_info(${table})`).all();
|
|
7542
7548
|
return new Set(rows.map((row) => row.name));
|
|
@@ -7667,7 +7673,7 @@ function initializeApiTopicsSchema() {
|
|
|
7667
7673
|
is_fork INTEGER NOT NULL DEFAULT 0 CHECK (is_fork IN (0,1)),
|
|
7668
7674
|
is_subagent INTEGER NOT NULL DEFAULT 0 CHECK (is_subagent IN (0,1)),
|
|
7669
7675
|
visibility TEXT NOT NULL DEFAULT 'visible' CHECK (visibility IN ('visible','hidden')),
|
|
7670
|
-
|
|
7676
|
+
surface TEXT NOT NULL DEFAULT 'terminal' CHECK (surface IN ('terminal','telegram','otium')),
|
|
7671
7677
|
browser_profile TEXT NOT NULL DEFAULT 'default',
|
|
7672
7678
|
browser_profile_owner TEXT,
|
|
7673
7679
|
session_id TEXT,
|
|
@@ -7713,8 +7719,8 @@ function initializeApiTopicsSchema() {
|
|
|
7713
7719
|
const legacyBaseEffort = row.base_effort ?? row.default_effort;
|
|
7714
7720
|
db.query(`INSERT INTO api_topics_next
|
|
7715
7721
|
(id,title,kind,description,agent,base_model,base_effort,response_policy,
|
|
7716
|
-
created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,
|
|
7717
|
-
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(String(row.id), String(row.title), normalized.kind, typeof row.description === "string" ? row.description : null, normalized.agent ?? null, typeof legacyBaseModel === "string" ? legacyBaseModel : null, typeof legacyBaseEffort === "string" ? legacyBaseEffort : null, normalized.aiMode, String(row.created_at), typeof row.last_message_at === "string" ? row.last_message_at : null, typeof row.parent_topic_id === "string" ? row.parent_topic_id : null, typeof row.memory_topic_id === "string" ? row.memory_topic_id : null, typeof row.memory_key === "string" ? row.memory_key : null, Number(row.is_fork ?? 0) !== 0 ? 1 : 0, Number(row.is_subagent ?? 0) !== 0 ? 1 : 0, row.visibility === "hidden" ? "hidden" : "visible", row.
|
|
7722
|
+
created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,surface,session_id)
|
|
7723
|
+
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(String(row.id), String(row.title), normalized.kind, typeof row.description === "string" ? row.description : null, normalized.agent ?? null, typeof legacyBaseModel === "string" ? legacyBaseModel : null, typeof legacyBaseEffort === "string" ? legacyBaseEffort : null, normalized.aiMode, String(row.created_at), typeof row.last_message_at === "string" ? row.last_message_at : null, typeof row.parent_topic_id === "string" ? row.parent_topic_id : null, typeof row.memory_topic_id === "string" ? row.memory_topic_id : null, typeof row.memory_key === "string" ? row.memory_key : null, Number(row.is_fork ?? 0) !== 0 ? 1 : 0, Number(row.is_subagent ?? 0) !== 0 ? 1 : 0, row.visibility === "hidden" ? "hidden" : "visible", row.surface === undefined ? defaultTopicSurface() : normalizeTopicSurface(row.surface), typeof row.session_id === "string" ? row.session_id : null);
|
|
7718
7724
|
}
|
|
7719
7725
|
db.exec("DROP TABLE IF EXISTS topic_members");
|
|
7720
7726
|
db.exec("DROP TABLE api_topics");
|
|
@@ -7768,8 +7774,15 @@ function initializeApiTopicsSchema() {
|
|
|
7768
7774
|
if (!tableColumns2("api_topics").has("visibility")) {
|
|
7769
7775
|
db.exec("ALTER TABLE api_topics ADD COLUMN visibility TEXT NOT NULL DEFAULT 'visible'");
|
|
7770
7776
|
}
|
|
7771
|
-
if (!tableColumns2("api_topics").has("
|
|
7772
|
-
db.exec("ALTER TABLE api_topics ADD COLUMN
|
|
7777
|
+
if (!tableColumns2("api_topics").has("surface")) {
|
|
7778
|
+
db.exec("ALTER TABLE api_topics ADD COLUMN surface TEXT NOT NULL DEFAULT 'terminal'");
|
|
7779
|
+
}
|
|
7780
|
+
if (tableColumns2("api_topics").has("access_mode")) {
|
|
7781
|
+
try {
|
|
7782
|
+
db.exec("ALTER TABLE api_topics DROP COLUMN access_mode");
|
|
7783
|
+
} catch (err) {
|
|
7784
|
+
logger.warn({ err }, "api_topics: could not drop the retired access_mode column");
|
|
7785
|
+
}
|
|
7773
7786
|
}
|
|
7774
7787
|
if (!tableColumns2("api_topics").has("browser_profile")) {
|
|
7775
7788
|
db.exec("ALTER TABLE api_topics ADD COLUMN browser_profile TEXT NOT NULL DEFAULT 'default'");
|
|
@@ -7796,7 +7809,48 @@ function initializeApiTopicsSchema() {
|
|
|
7796
7809
|
)
|
|
7797
7810
|
WHERE browser_profile_owner IS NULL
|
|
7798
7811
|
`);
|
|
7812
|
+
backfillTopicSurfaces();
|
|
7799
7813
|
db.exec("CREATE INDEX IF NOT EXISTS idx_api_topics_last_message ON api_topics(last_message_at DESC)");
|
|
7814
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_api_topics_surface ON api_topics(surface)");
|
|
7815
|
+
}
|
|
7816
|
+
function backfillTopicSurfaces() {
|
|
7817
|
+
db.exec(`
|
|
7818
|
+
CREATE TABLE IF NOT EXISTS api_schema_migrations (
|
|
7819
|
+
key TEXT PRIMARY KEY,
|
|
7820
|
+
applied_at TEXT NOT NULL
|
|
7821
|
+
)
|
|
7822
|
+
`);
|
|
7823
|
+
const applied = db.query("SELECT key FROM api_schema_migrations WHERE key = ?").get(SURFACE_BACKFILL_MIGRATION);
|
|
7824
|
+
if (applied)
|
|
7825
|
+
return;
|
|
7826
|
+
const surface = defaultTopicSurface();
|
|
7827
|
+
db.transaction(() => {
|
|
7828
|
+
db.query("UPDATE api_topics SET surface = ?").run(surface);
|
|
7829
|
+
renameSurfaceTitleCollisions();
|
|
7830
|
+
db.query("INSERT INTO api_schema_migrations (key, applied_at) VALUES (?, ?)").run(SURFACE_BACKFILL_MIGRATION, new Date().toISOString());
|
|
7831
|
+
})();
|
|
7832
|
+
logger.info({ surface }, "api_topics: surface backfilled");
|
|
7833
|
+
}
|
|
7834
|
+
function renameSurfaceTitleCollisions() {
|
|
7835
|
+
const rows = db.query("SELECT id, title, kind, surface FROM api_topics ORDER BY created_at ASC, rowid ASC").all();
|
|
7836
|
+
const taken = new Set;
|
|
7837
|
+
const update = db.query("UPDATE api_topics SET title = ? WHERE id = ?");
|
|
7838
|
+
for (const row of rows) {
|
|
7839
|
+
const key = (title) => [row.surface, row.kind, normalizedTitle(title)].join("\x00");
|
|
7840
|
+
if (!taken.has(key(row.title))) {
|
|
7841
|
+
taken.add(key(row.title));
|
|
7842
|
+
continue;
|
|
7843
|
+
}
|
|
7844
|
+
let suffix = 2;
|
|
7845
|
+
let candidate = `${row.title} (${suffix})`;
|
|
7846
|
+
while (taken.has(key(candidate))) {
|
|
7847
|
+
suffix += 1;
|
|
7848
|
+
candidate = `${row.title} (${suffix})`;
|
|
7849
|
+
}
|
|
7850
|
+
taken.add(key(candidate));
|
|
7851
|
+
update.run(candidate, row.id);
|
|
7852
|
+
logger.warn({ topicId: row.id, surface: row.surface, from: row.title, to: candidate }, "api_topics: renamed a duplicate title for surface-scoped uniqueness");
|
|
7853
|
+
}
|
|
7800
7854
|
}
|
|
7801
7855
|
function shortSessionId(sessionId) {
|
|
7802
7856
|
return sessionId ? sessionId.slice(0, 8) : null;
|
|
@@ -7856,15 +7910,9 @@ function rowToDto2(r, participants = getTopicParticipants(r.id), tellTargets) {
|
|
|
7856
7910
|
subagentReportMode: r.subagent_report_mode === "tell" || r.subagent_report_mode === "status-only" ? r.subagent_report_mode : "auto"
|
|
7857
7911
|
} : {},
|
|
7858
7912
|
visibility: normalizeTopicVisibility(r.visibility),
|
|
7859
|
-
|
|
7913
|
+
surface: normalizeTopicSurface(r.surface)
|
|
7860
7914
|
};
|
|
7861
7915
|
}
|
|
7862
|
-
function normalizeTopicAccessMode(value) {
|
|
7863
|
-
return value === "shared" ? "shared" : "private";
|
|
7864
|
-
}
|
|
7865
|
-
function isTopicShared(topic) {
|
|
7866
|
-
return topic.accessMode === "shared";
|
|
7867
|
-
}
|
|
7868
7916
|
function normalizeTopicVisibility(value) {
|
|
7869
7917
|
return value === "hidden" ? "hidden" : "visible";
|
|
7870
7918
|
}
|
|
@@ -7941,7 +7989,7 @@ function upsertTopic(t) {
|
|
|
7941
7989
|
db.transaction(() => {
|
|
7942
7990
|
db.query(`INSERT INTO api_topics
|
|
7943
7991
|
(id,title,kind,description,agent,base_model,base_effort,response_policy,
|
|
7944
|
-
created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,
|
|
7992
|
+
created_at,last_message_at,parent_topic_id,memory_topic_id,memory_key,is_fork,is_subagent,visibility,surface,
|
|
7945
7993
|
subagent_report_mode)
|
|
7946
7994
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
7947
7995
|
ON CONFLICT(id) DO UPDATE SET
|
|
@@ -7960,8 +8008,8 @@ function upsertTopic(t) {
|
|
|
7960
8008
|
is_fork = excluded.is_fork,
|
|
7961
8009
|
is_subagent = excluded.is_subagent,
|
|
7962
8010
|
visibility = excluded.visibility,
|
|
7963
|
-
|
|
7964
|
-
subagent_report_mode = excluded.subagent_report_mode`).run(t.id, t.title, normalized.kind, t.description ?? null, normalized.agent ?? null, t.defaultModel ?? null, t.defaultEffort ?? null, normalized.aiMode, t.createdAt, t.lastMessageAt ?? null, t.parentTopicId ?? null, t.memoryTopicId ?? null, t.memoryKey ?? null, t.isFork ? 1 : 0, t.isSubagent ? 1 : 0, normalizeTopicVisibility(t.visibility),
|
|
8011
|
+
surface = excluded.surface,
|
|
8012
|
+
subagent_report_mode = excluded.subagent_report_mode`).run(t.id, t.title, normalized.kind, t.description ?? null, normalized.agent ?? null, t.defaultModel ?? null, t.defaultEffort ?? null, normalized.aiMode, t.createdAt, t.lastMessageAt ?? null, t.parentTopicId ?? null, t.memoryTopicId ?? null, t.memoryKey ?? null, t.isFork ? 1 : 0, t.isSubagent ? 1 : 0, normalizeTopicVisibility(t.visibility), normalizeTopicSurface(t.surface ?? defaultTopicSurface()), t.subagentReportMode ?? "auto");
|
|
7965
8013
|
db.query("DELETE FROM topic_members WHERE topic_id = ?").run(t.id);
|
|
7966
8014
|
for (const participant of t.participants) {
|
|
7967
8015
|
db.query("INSERT INTO topic_members (topic_id,user_id,role) VALUES (?,?,?)").run(t.id, participant.userId, participant.role);
|
|
@@ -7974,18 +8022,8 @@ function upsertTopic(t) {
|
|
|
7974
8022
|
}
|
|
7975
8023
|
})();
|
|
7976
8024
|
}
|
|
7977
|
-
function
|
|
7978
|
-
|
|
7979
|
-
return;
|
|
7980
|
-
const normalized = normalizeTopicAccessMode(accessMode);
|
|
7981
|
-
db.transaction(() => {
|
|
7982
|
-
const update = db.query("UPDATE api_topics SET access_mode = ? WHERE id = ?");
|
|
7983
|
-
for (const topicId of topicIds)
|
|
7984
|
-
update.run(normalized, topicId);
|
|
7985
|
-
})();
|
|
7986
|
-
}
|
|
7987
|
-
function listTopics() {
|
|
7988
|
-
const rows = db.query("SELECT * FROM api_topics ORDER BY last_message_at DESC").all();
|
|
8025
|
+
function listTopics(opts = {}) {
|
|
8026
|
+
const rows = opts.surface ? db.query("SELECT * FROM api_topics WHERE surface = ? ORDER BY last_message_at DESC").all(normalizeTopicSurface(opts.surface)) : db.query("SELECT * FROM api_topics ORDER BY last_message_at DESC").all();
|
|
7989
8027
|
const participants = getAllTopicParticipants();
|
|
7990
8028
|
const tellTargets = rows.some((row) => row.is_subagent !== 0) ? getAllSubagentTellTargets() : undefined;
|
|
7991
8029
|
return rows.map((row) => rowToDto2(row, participants.get(row.id) ?? [], tellTargets));
|
|
@@ -8036,14 +8074,15 @@ function getTopicByNameAndKind(title, kind) {
|
|
|
8036
8074
|
}
|
|
8037
8075
|
function findTopicTitleConflict(title, kind, opts = {}) {
|
|
8038
8076
|
const wanted = normalizedTitle(title);
|
|
8077
|
+
const surface = normalizeTopicSurface(opts.surface ?? defaultTopicSurface());
|
|
8039
8078
|
const generalTitleRequested = wanted === normalizedTitle(GENERAL_TOPIC_ID);
|
|
8040
8079
|
if (generalTitleRequested && opts.excludeTopicId !== GENERAL_TOPIC_ID) {
|
|
8041
8080
|
const general = db.query("SELECT * FROM api_topics WHERE id = ?").get(GENERAL_TOPIC_ID);
|
|
8042
8081
|
if (general)
|
|
8043
8082
|
return rowToDto2(general);
|
|
8044
8083
|
}
|
|
8045
|
-
const params = [wanted];
|
|
8046
|
-
let sql = "SELECT * FROM api_topics WHERE LOWER(TRIM(title)) = ?";
|
|
8084
|
+
const params = [wanted, surface];
|
|
8085
|
+
let sql = "SELECT * FROM api_topics WHERE LOWER(TRIM(title)) = ? AND surface = ?";
|
|
8047
8086
|
if (kind !== "manager") {
|
|
8048
8087
|
sql += " AND (kind = ? OR id = ?)";
|
|
8049
8088
|
params.push(kind, GENERAL_TOPIC_ID);
|
|
@@ -8056,7 +8095,20 @@ function findTopicTitleConflict(title, kind, opts = {}) {
|
|
|
8056
8095
|
const row = db.query(sql).get(...params);
|
|
8057
8096
|
return row ? rowToDto2(row) : null;
|
|
8058
8097
|
}
|
|
8059
|
-
function
|
|
8098
|
+
function setTopicSurfaces(topicIds, surface) {
|
|
8099
|
+
if (topicIds.length === 0)
|
|
8100
|
+
return 0;
|
|
8101
|
+
const normalized = normalizeTopicSurface(surface);
|
|
8102
|
+
let changed = 0;
|
|
8103
|
+
db.transaction(() => {
|
|
8104
|
+
const update = db.query("UPDATE api_topics SET surface = ? WHERE id = ? AND surface != ?");
|
|
8105
|
+
for (const topicId of topicIds) {
|
|
8106
|
+
changed += Number(update.run(normalized, topicId, normalized).changes ?? 0);
|
|
8107
|
+
}
|
|
8108
|
+
})();
|
|
8109
|
+
return changed;
|
|
8110
|
+
}
|
|
8111
|
+
function getTopicByNameForUser(title, userId, opts = {}) {
|
|
8060
8112
|
const trimmed = title.trim();
|
|
8061
8113
|
const qualified = /^(agent|channel|manager):(.+)$/i.exec(trimmed);
|
|
8062
8114
|
const requestedKind = qualified ? normalizeTopicKind(qualified[1]?.toLowerCase()) : null;
|
|
@@ -8065,9 +8117,10 @@ function getTopicByNameForUser(title, userId) {
|
|
|
8065
8117
|
WHERE LOWER(t.title) = LOWER(?)
|
|
8066
8118
|
AND t.id != ?
|
|
8067
8119
|
AND t.visibility != 'hidden'
|
|
8120
|
+
AND (? IS NULL OR t.surface = ?)
|
|
8068
8121
|
AND EXISTS (
|
|
8069
8122
|
SELECT 1 FROM topic_members m WHERE m.topic_id = t.id AND m.user_id = ?
|
|
8070
|
-
)`).all(requestedTitle, GENERAL_TOPIC_ID, userId);
|
|
8123
|
+
)`).all(requestedTitle, GENERAL_TOPIC_ID, opts.surface ?? null, opts.surface ?? null, userId);
|
|
8071
8124
|
const matches = requestedKind ? rows.filter((row) => row.kind === requestedKind) : rows;
|
|
8072
8125
|
return matches.length === 1 ? rowToDto2(matches[0]) : null;
|
|
8073
8126
|
}
|
|
@@ -8155,7 +8208,7 @@ function removeParticipantFromDB(topicId, userId) {
|
|
|
8155
8208
|
db.query("DELETE FROM topic_members WHERE topic_id = ? AND user_id = ?").run(topicId, userId);
|
|
8156
8209
|
return true;
|
|
8157
8210
|
}
|
|
8158
|
-
var DEFAULT_AGENT_ROOM_AGENT = "maestro";
|
|
8211
|
+
var DEFAULT_AGENT_ROOM_AGENT = "maestro", SURFACE_BACKFILL_MIGRATION = "api_topics_surface_backfill_20260808";
|
|
8159
8212
|
var init_api_topics = __esm(async () => {
|
|
8160
8213
|
init_constants();
|
|
8161
8214
|
init_logger();
|
|
@@ -14241,11 +14294,11 @@ __export(exports_derive, {
|
|
|
14241
14294
|
});
|
|
14242
14295
|
import { createHash as createHash5, randomUUID as randomUUID12 } from "crypto";
|
|
14243
14296
|
import { mkdirSync as mkdirSync13, rmSync as rmSync5, unlinkSync as unlinkSync13 } from "fs";
|
|
14244
|
-
function getTopics() {
|
|
14245
|
-
return listTopics().filter((topic) => !isLegacySharedGeneral(topic.id));
|
|
14297
|
+
function getTopics(opts = {}) {
|
|
14298
|
+
return listTopics(opts).filter((topic) => !isLegacySharedGeneral(topic.id));
|
|
14246
14299
|
}
|
|
14247
|
-
function getVisibleTopics() {
|
|
14248
|
-
return getTopics().filter(isTopicVisible).map((topic) => {
|
|
14300
|
+
function getVisibleTopics(opts = {}) {
|
|
14301
|
+
return getTopics(opts).filter(isTopicVisible).map((topic) => {
|
|
14249
14302
|
if (!topic.agent)
|
|
14250
14303
|
return topic;
|
|
14251
14304
|
const registry = getRegistry(topic.agent);
|
|
@@ -14270,8 +14323,8 @@ function updateTopic(topicId, patch) {
|
|
|
14270
14323
|
function isParticipant(topic, userId) {
|
|
14271
14324
|
return topic.participants.some((p) => p.userId === userId);
|
|
14272
14325
|
}
|
|
14273
|
-
function nextDerivedTopicTitle(sourceTitle, kind, suffix) {
|
|
14274
|
-
const visibleTitles = new Set(listTopics().filter((topic) => topic.kind === kind).map((topic) => topic.title.toLowerCase()));
|
|
14326
|
+
function nextDerivedTopicTitle(sourceTitle, kind, suffix, surface) {
|
|
14327
|
+
const visibleTitles = new Set(listTopics(surface ? { surface } : {}).filter((topic) => topic.kind === kind).map((topic) => topic.title.toLowerCase()));
|
|
14275
14328
|
let n = 1;
|
|
14276
14329
|
let title = `${sourceTitle}-${suffix}-${n}`;
|
|
14277
14330
|
while (visibleTitles.has(title.toLowerCase())) {
|
|
@@ -14335,8 +14388,9 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
|
|
|
14335
14388
|
{ userId, role: "owner" }
|
|
14336
14389
|
] : [{ userId, role: "owner" }];
|
|
14337
14390
|
const kind = topic.kind ?? inferTopicKind(topic);
|
|
14338
|
-
const
|
|
14339
|
-
const
|
|
14391
|
+
const surface = topic.surface ?? defaultTopicSurface();
|
|
14392
|
+
const title = opts?.name?.trim() || nextDerivedTopicTitle(topic.title, kind, suffix, surface);
|
|
14393
|
+
const conflict = findTopicTitleConflict(title, kind, { surface });
|
|
14340
14394
|
if (conflict) {
|
|
14341
14395
|
logger.info({ sourceTopicId, title, kind, conflictTopicId: conflict.id }, "createDerivedTopic: title conflict");
|
|
14342
14396
|
throw new TopicTitleConflictError(title);
|
|
@@ -14359,7 +14413,7 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
|
|
|
14359
14413
|
isFork: copyHistory,
|
|
14360
14414
|
...subagent ? { isSubagent: true } : {},
|
|
14361
14415
|
visibility: topic.visibility,
|
|
14362
|
-
|
|
14416
|
+
surface
|
|
14363
14417
|
};
|
|
14364
14418
|
let sessionId;
|
|
14365
14419
|
let rollbackHandle;
|
|
@@ -14467,7 +14521,7 @@ async function createDerivedTopicImpl(topic, sourceTopicId, userId, copyHistory,
|
|
|
14467
14521
|
if (!currentSource || currentSource.kind === "manager" || !isParticipant(currentSource, userId) || subagent && isRuntimeTopicMaintenance(sourceTopicId)) {
|
|
14468
14522
|
throw new TopicDeriveBusyError("Source topic changed while deriving; try again");
|
|
14469
14523
|
}
|
|
14470
|
-
const transactionalConflict = findTopicTitleConflict(title, kind);
|
|
14524
|
+
const transactionalConflict = findTopicTitleConflict(title, kind, { surface });
|
|
14471
14525
|
if (transactionalConflict)
|
|
14472
14526
|
throw new TopicTitleConflictError(title);
|
|
14473
14527
|
upsertTopic(derived);
|
|
@@ -20358,74 +20412,6 @@ var init_submit_user_message = __esm(async () => {
|
|
|
20358
20412
|
await init_api_messages();
|
|
20359
20413
|
});
|
|
20360
20414
|
|
|
20361
|
-
// ../../packages/core/src/application/switch-topic-access-mode.ts
|
|
20362
|
-
function collectSubagentDescendants(rootTopicId) {
|
|
20363
|
-
const all = listTopics();
|
|
20364
|
-
const childrenByParent = new Map;
|
|
20365
|
-
for (const topic of all) {
|
|
20366
|
-
if (!topic.isSubagent || !topic.parentTopicId)
|
|
20367
|
-
continue;
|
|
20368
|
-
const siblings = childrenByParent.get(topic.parentTopicId);
|
|
20369
|
-
if (siblings)
|
|
20370
|
-
siblings.push(topic);
|
|
20371
|
-
else
|
|
20372
|
-
childrenByParent.set(topic.parentTopicId, [topic]);
|
|
20373
|
-
}
|
|
20374
|
-
const descendants = [];
|
|
20375
|
-
const seen = new Set([rootTopicId]);
|
|
20376
|
-
const queue = [rootTopicId];
|
|
20377
|
-
while (queue.length > 0) {
|
|
20378
|
-
const parentId = queue.shift();
|
|
20379
|
-
for (const child of childrenByParent.get(parentId) ?? []) {
|
|
20380
|
-
if (seen.has(child.id))
|
|
20381
|
-
continue;
|
|
20382
|
-
seen.add(child.id);
|
|
20383
|
-
descendants.push(child);
|
|
20384
|
-
queue.push(child.id);
|
|
20385
|
-
}
|
|
20386
|
-
}
|
|
20387
|
-
return descendants;
|
|
20388
|
-
}
|
|
20389
|
-
function switchTopicAccessMode(params) {
|
|
20390
|
-
const topic = getTopic(params.topicId);
|
|
20391
|
-
if (!topic)
|
|
20392
|
-
return { ok: false, error: "Topic not found" };
|
|
20393
|
-
const owner = topic.participants.some((participant) => participant.userId === params.userId && participant.role === "owner");
|
|
20394
|
-
if (!owner)
|
|
20395
|
-
return { ok: false, error: "Only topic owners can change privacy" };
|
|
20396
|
-
if (topic.isSubagent) {
|
|
20397
|
-
return {
|
|
20398
|
-
ok: false,
|
|
20399
|
-
error: "Subagent rooms inherit privacy from their parent topic"
|
|
20400
|
-
};
|
|
20401
|
-
}
|
|
20402
|
-
const descendants = collectSubagentDescendants(topic.id);
|
|
20403
|
-
const changed = [topic, ...descendants].filter((candidate) => (candidate.accessMode ?? "private") !== params.accessMode);
|
|
20404
|
-
if (changed.length === 0) {
|
|
20405
|
-
return {
|
|
20406
|
-
ok: true,
|
|
20407
|
-
accessMode: params.accessMode,
|
|
20408
|
-
text: params.accessMode === "shared" ? `"${topic.title}" is already public to the connected Otium Hub.` : `"${topic.title}" is already private to this worker.`,
|
|
20409
|
-
topicIds: []
|
|
20410
|
-
};
|
|
20411
|
-
}
|
|
20412
|
-
setTopicAccessModes(changed.map((candidate) => candidate.id), params.accessMode);
|
|
20413
|
-
for (const candidate of changed)
|
|
20414
|
-
WsHub.get().broadcastTopicUpdated(candidate.id);
|
|
20415
|
-
const subagentCount = changed.filter((candidate) => candidate.id !== topic.id).length;
|
|
20416
|
-
const suffix = subagentCount > 0 ? ` (${subagentCount} subagent room${subagentCount === 1 ? "" : "s"} updated)` : "";
|
|
20417
|
-
return {
|
|
20418
|
-
ok: true,
|
|
20419
|
-
accessMode: params.accessMode,
|
|
20420
|
-
topicIds: changed.map((candidate) => candidate.id),
|
|
20421
|
-
text: (params.accessMode === "shared" ? `"${topic.title}" is public to the connected Otium Hub.` : `"${topic.title}" is private to this worker.`) + suffix
|
|
20422
|
-
};
|
|
20423
|
-
}
|
|
20424
|
-
var init_switch_topic_access_mode = __esm(async () => {
|
|
20425
|
-
await init_bus();
|
|
20426
|
-
await init_api_topics();
|
|
20427
|
-
});
|
|
20428
|
-
|
|
20429
20415
|
// ../../packages/core/src/application/switch-topic-effort.ts
|
|
20430
20416
|
function switchTopicEffort(params) {
|
|
20431
20417
|
const topic = getTopic(params.topicId);
|
|
@@ -20539,9 +20525,10 @@ function registerTopic(opts) {
|
|
|
20539
20525
|
if (requestedKind === "manager") {
|
|
20540
20526
|
throw new TopicValidationError("Manager rooms are system-managed");
|
|
20541
20527
|
}
|
|
20542
|
-
const
|
|
20528
|
+
const surface = normalizeTopicSurface(opts.surface ?? defaultTopicSurface());
|
|
20529
|
+
const conflict = findTopicTitleConflict(title, requestedKind, { surface });
|
|
20543
20530
|
if (conflict) {
|
|
20544
|
-
throw new TopicValidationError(`A topic named "${title}" already exists`);
|
|
20531
|
+
throw new TopicValidationError(`A topic named "${title}" already exists on ${surface}`);
|
|
20545
20532
|
}
|
|
20546
20533
|
const rawAgent = opts.agent;
|
|
20547
20534
|
if (requestedKind === "agent" && rawAgent === "none") {
|
|
@@ -20575,7 +20562,7 @@ function registerTopic(opts) {
|
|
|
20575
20562
|
defaultEffort: defaultEffort ?? "medium",
|
|
20576
20563
|
aiMode,
|
|
20577
20564
|
participants: [{ userId: opts.userId, role: "owner" }],
|
|
20578
|
-
|
|
20565
|
+
surface,
|
|
20579
20566
|
createdAt: now,
|
|
20580
20567
|
lastMessageAt: now
|
|
20581
20568
|
};
|
|
@@ -22414,7 +22401,6 @@ __export(exports_src, {
|
|
|
22414
22401
|
textResult: () => textResult,
|
|
22415
22402
|
switchTopicModel: () => switchTopicModel,
|
|
22416
22403
|
switchTopicEffort: () => switchTopicEffort,
|
|
22417
|
-
switchTopicAccessMode: () => switchTopicAccessMode,
|
|
22418
22404
|
sweepStaleSubagentCards: () => sweepStaleSubagentCards,
|
|
22419
22405
|
submitUserMessage: () => submitUserMessage,
|
|
22420
22406
|
submitRuntimeGatewayTurn: () => submitRuntimeGatewayTurn,
|
|
@@ -22427,6 +22413,7 @@ __export(exports_src, {
|
|
|
22427
22413
|
startBashrsCompletionsWorker: () => startBashrsCompletionsWorker,
|
|
22428
22414
|
startAskUserQuestionGateOwner: () => startAskUserQuestionGateOwner,
|
|
22429
22415
|
startAiTurn: () => startAiTurn,
|
|
22416
|
+
setTopicSurfaces: () => setTopicSurfaces,
|
|
22430
22417
|
setTopicSessionId: () => setTopicSessionId,
|
|
22431
22418
|
setRuntimeMcpPort: () => setRuntimeMcpPort,
|
|
22432
22419
|
setRuntimeBus: () => setRuntimeBus,
|
|
@@ -22473,6 +22460,7 @@ __export(exports_src, {
|
|
|
22473
22460
|
prepareDeliveryAck: () => prepareDeliveryAck,
|
|
22474
22461
|
onShutdown: () => onShutdown,
|
|
22475
22462
|
normalizeVaultKey: () => normalizeVaultKey,
|
|
22463
|
+
normalizeTopicSurface: () => normalizeTopicSurface,
|
|
22476
22464
|
nodeRequestHandlerNames: () => nodeRequestHandlerNames,
|
|
22477
22465
|
modelOwner: () => modelOwner,
|
|
22478
22466
|
markPlaywrightUnavailable: () => markPlaywrightUnavailable,
|
|
@@ -22499,7 +22487,6 @@ __export(exports_src, {
|
|
|
22499
22487
|
isVaultCommandLine: () => isVaultCommandLine,
|
|
22500
22488
|
isTranscriptionConfigured: () => isTranscriptionConfigured,
|
|
22501
22489
|
isTopicVisible: () => isTopicVisible,
|
|
22502
|
-
isTopicShared: () => isTopicShared,
|
|
22503
22490
|
isTopicRunning: () => isTopicRunning,
|
|
22504
22491
|
isSensitivePath: () => isSensitivePath,
|
|
22505
22492
|
isParticipant: () => isParticipant,
|
|
@@ -22549,6 +22536,7 @@ __export(exports_src, {
|
|
|
22549
22536
|
deliverAskCallbackToCaller: () => deliverAskCallbackToCaller,
|
|
22550
22537
|
deleteVaultEntry: () => deleteVaultEntry,
|
|
22551
22538
|
deleteTopicCascade: () => deleteTopicCascade,
|
|
22539
|
+
defaultTopicSurface: () => defaultTopicSurface,
|
|
22552
22540
|
db: () => db,
|
|
22553
22541
|
createSubagentManagementToolDefinitions: () => createSubagentManagementToolDefinitions,
|
|
22554
22542
|
createSpawnSubagentToolDefinition: () => createSpawnSubagentToolDefinition,
|
|
@@ -22640,7 +22628,6 @@ var init_src = __esm(async () => {
|
|
|
22640
22628
|
await init_execute_external_user_turn();
|
|
22641
22629
|
await init_submit_runtime_gateway_turn();
|
|
22642
22630
|
await init_submit_user_message();
|
|
22643
|
-
await init_switch_topic_access_mode();
|
|
22644
22631
|
await init_switch_topic_effort();
|
|
22645
22632
|
await init_switch_topic_model();
|
|
22646
22633
|
await init_topic_service();
|
|
@@ -22810,7 +22797,6 @@ __export(exports_node_host, {
|
|
|
22810
22797
|
topicService: () => topicService,
|
|
22811
22798
|
switchTopicModel: () => switchTopicModel,
|
|
22812
22799
|
switchTopicEffort: () => switchTopicEffort,
|
|
22813
|
-
switchTopicAccessMode: () => switchTopicAccessMode,
|
|
22814
22800
|
sweepStaleSubagentCards: () => sweepStaleSubagentCards,
|
|
22815
22801
|
submitUserMessage: () => submitUserMessage,
|
|
22816
22802
|
submitRuntimeGatewayTurn: () => submitRuntimeGatewayTurn,
|
|
@@ -22844,7 +22830,6 @@ __export(exports_node_host, {
|
|
|
22844
22830
|
killOwnedCodexTreesForShutdown: () => killOwnedCodexTreesForShutdown,
|
|
22845
22831
|
killAllPlaywright: () => killAllPlaywright,
|
|
22846
22832
|
killAllBgBash: () => killAllBgBash,
|
|
22847
|
-
isTopicShared: () => isTopicShared,
|
|
22848
22833
|
isParticipant: () => isParticipant,
|
|
22849
22834
|
getVisibleTopics: () => getVisibleTopics,
|
|
22850
22835
|
getTopicStats: () => getTopicStats,
|
|
@@ -22878,7 +22863,6 @@ var init_node_host = __esm(async () => {
|
|
|
22878
22863
|
await init_spawn_subagent();
|
|
22879
22864
|
await init_submit_runtime_gateway_turn();
|
|
22880
22865
|
await init_submit_user_message();
|
|
22881
|
-
await init_switch_topic_access_mode();
|
|
22882
22866
|
await init_switch_topic_effort();
|
|
22883
22867
|
await init_switch_topic_model();
|
|
22884
22868
|
await init_topic_service();
|
|
@@ -24154,7 +24138,8 @@ var init_session_comm = __esm(async () => {
|
|
|
24154
24138
|
function createSessionTargetCatalog(host2) {
|
|
24155
24139
|
const { currentTopicId, currentTopicName, isAgent, listRows } = host2;
|
|
24156
24140
|
function listTargets() {
|
|
24157
|
-
const
|
|
24141
|
+
const currentSurface = host2.currentSurface;
|
|
24142
|
+
const eligibleRows = listRows().filter((row) => row.kind !== "manager" && (!currentSurface || (row.surface ?? currentSurface) === currentSurface));
|
|
24158
24143
|
const titleCounts = new Map;
|
|
24159
24144
|
const qualifiedCounts = new Map;
|
|
24160
24145
|
for (const row of eligibleRows) {
|
|
@@ -24270,9 +24255,11 @@ function currentTopic(context) {
|
|
|
24270
24255
|
return topic;
|
|
24271
24256
|
}
|
|
24272
24257
|
function targetCatalog(context) {
|
|
24258
|
+
const surface = (context.currentTopicId ? getTopic(context.currentTopicId)?.surface : undefined) ?? defaultTopicSurface();
|
|
24273
24259
|
return createSessionTargetCatalog({
|
|
24274
24260
|
currentTopicId: context.currentTopicId,
|
|
24275
24261
|
currentTopicName: context.currentTopic,
|
|
24262
|
+
currentSurface: surface,
|
|
24276
24263
|
isAgent: isAgentKind,
|
|
24277
24264
|
listRows: () => listTopics().filter((topic) => topic.participants.some((p) => p.userId === context.userId)).map((topic) => ({
|
|
24278
24265
|
id: topic.id,
|
|
@@ -24280,7 +24267,8 @@ function targetCatalog(context) {
|
|
|
24280
24267
|
kind: topic.kind ?? null,
|
|
24281
24268
|
agent: topic.agent ?? null,
|
|
24282
24269
|
sessionId: null,
|
|
24283
|
-
description: topic.description ?? null
|
|
24270
|
+
description: topic.description ?? null,
|
|
24271
|
+
surface: topic.surface ?? null
|
|
24284
24272
|
}))
|
|
24285
24273
|
});
|
|
24286
24274
|
}
|
|
@@ -27516,6 +27504,7 @@ __export(exports_storage_public, {
|
|
|
27516
27504
|
softDeleteApiMessagesByIdPrefix: () => softDeleteApiMessagesByIdPrefix,
|
|
27517
27505
|
softDeleteApiMessage: () => softDeleteApiMessage,
|
|
27518
27506
|
settleTopicArchiveJob: () => settleTopicArchiveJob,
|
|
27507
|
+
setTopicSurfaces: () => setTopicSurfaces,
|
|
27519
27508
|
setTopicSessionId: () => setTopicSessionId,
|
|
27520
27509
|
setTopicMcpExtra: () => setTopicMcpExtra,
|
|
27521
27510
|
setTopicMcpEnabled: () => setTopicMcpEnabled,
|
|
@@ -27526,7 +27515,6 @@ __export(exports_storage_public, {
|
|
|
27526
27515
|
setTopicAgentAndSession: () => setTopicAgentAndSession,
|
|
27527
27516
|
setTopicAgentAndClearSession: () => setTopicAgentAndClearSession,
|
|
27528
27517
|
setTopicAgent: () => setTopicAgent,
|
|
27529
|
-
setTopicAccessModes: () => setTopicAccessModes,
|
|
27530
27518
|
setSessionForTopic: () => setSessionForTopic,
|
|
27531
27519
|
setLastShownConfig: () => setLastShownConfig,
|
|
27532
27520
|
setGlobalAiName: () => setGlobalAiName,
|
|
@@ -27560,9 +27548,9 @@ __export(exports_storage_public, {
|
|
|
27560
27548
|
quarantineAskUserGate: () => quarantineAskUserGate,
|
|
27561
27549
|
prepareAskUserGate: () => prepareAskUserGate,
|
|
27562
27550
|
normalizeTopicVisibility: () => normalizeTopicVisibility,
|
|
27551
|
+
normalizeTopicSurface: () => normalizeTopicSurface,
|
|
27563
27552
|
normalizeTopicState: () => normalizeTopicState,
|
|
27564
27553
|
normalizeTopicKind: () => normalizeTopicKind,
|
|
27565
|
-
normalizeTopicAccessMode: () => normalizeTopicAccessMode,
|
|
27566
27554
|
normalizeAiMode: () => normalizeAiMode,
|
|
27567
27555
|
markPendingAskState: () => markPendingAskState,
|
|
27568
27556
|
markPendingAskSources: () => markPendingAskSources,
|
|
@@ -27577,7 +27565,6 @@ __export(exports_storage_public, {
|
|
|
27577
27565
|
listApiMessages: () => listApiMessages,
|
|
27578
27566
|
isTopicVisible: () => isTopicVisible,
|
|
27579
27567
|
isTopicSummaryFile: () => isTopicSummaryFile,
|
|
27580
|
-
isTopicShared: () => isTopicShared,
|
|
27581
27568
|
isTopicBriefFile: () => isTopicBriefFile,
|
|
27582
27569
|
isRuntimeProcessLeaseAlive: () => isRuntimeProcessLeaseAlive,
|
|
27583
27570
|
inferTopicKind: () => inferTopicKind,
|
|
@@ -27638,6 +27625,7 @@ __export(exports_storage_public, {
|
|
|
27638
27625
|
deletePendingAsksForTopic: () => deletePendingAsksForTopic,
|
|
27639
27626
|
deleteMessagesForTopic: () => deleteMessagesForTopic,
|
|
27640
27627
|
deleteApiTopicConfig: () => deleteApiTopicConfig,
|
|
27628
|
+
defaultTopicSurface: () => defaultTopicSurface,
|
|
27641
27629
|
db: () => db2,
|
|
27642
27630
|
createTasks: () => createTasks,
|
|
27643
27631
|
createPendingAsk: () => createPendingAsk,
|
|
@@ -29351,13 +29339,19 @@ function requiredText(value, name) {
|
|
|
29351
29339
|
}
|
|
29352
29340
|
return value.trim();
|
|
29353
29341
|
}
|
|
29354
|
-
function topicsForUser(userId) {
|
|
29342
|
+
function topicsForUser(userId, surface) {
|
|
29355
29343
|
const runningTopics = listRunningTopicQueries();
|
|
29356
|
-
return getVisibleTopics().filter((topic) => isParticipant(topic, userId)).map((topic) => {
|
|
29344
|
+
return getVisibleTopics(surface ? { surface } : {}).filter((topic) => isParticipant(topic, userId)).map((topic) => {
|
|
29357
29345
|
const runningQueryId = runningTopics.get(topic.id);
|
|
29358
29346
|
return { ...topic, running: Boolean(runningQueryId), runningQueryId };
|
|
29359
29347
|
});
|
|
29360
29348
|
}
|
|
29349
|
+
function requestedSurface(url) {
|
|
29350
|
+
const raw = url.searchParams.get("surface")?.trim();
|
|
29351
|
+
if (!raw)
|
|
29352
|
+
return;
|
|
29353
|
+
return raw === "terminal" || raw === "telegram" || raw === "otium" ? raw : undefined;
|
|
29354
|
+
}
|
|
29361
29355
|
function topicForUser(topicId, userId) {
|
|
29362
29356
|
const topic = getTopic(topicId);
|
|
29363
29357
|
return topic && isParticipant(topic, userId) ? topic : null;
|
|
@@ -29514,11 +29508,7 @@ function createNodeControlHandler(options) {
|
|
|
29514
29508
|
return Response.json({ ok: true, v: NODE_RUNTIME_CONTRACT_VERSION, ...result });
|
|
29515
29509
|
}
|
|
29516
29510
|
if (req.method === "GET" && runtimePath === "/topics") {
|
|
29517
|
-
const
|
|
29518
|
-
if (accessMode && accessMode !== "shared" && accessMode !== "private") {
|
|
29519
|
-
return jsonError(400, "accessMode must be 'shared' or 'private'");
|
|
29520
|
-
}
|
|
29521
|
-
const topics = getVisibleTopics().filter((topic) => accessMode === "shared" ? isTopicShared(topic) : accessMode === "private" ? !isTopicShared(topic) : true);
|
|
29511
|
+
const topics = getVisibleTopics({ surface: "otium" });
|
|
29522
29512
|
return Response.json({
|
|
29523
29513
|
ok: true,
|
|
29524
29514
|
v: NODE_RUNTIME_CONTRACT_VERSION,
|
|
@@ -29540,7 +29530,7 @@ function createNodeControlHandler(options) {
|
|
|
29540
29530
|
title,
|
|
29541
29531
|
userId,
|
|
29542
29532
|
kind: "agent",
|
|
29543
|
-
|
|
29533
|
+
surface: "otium",
|
|
29544
29534
|
...agent ? { agent } : {}
|
|
29545
29535
|
});
|
|
29546
29536
|
return Response.json({ ok: true, v: NODE_RUNTIME_CONTRACT_VERSION, topic }, { status: 201 });
|
|
@@ -29625,13 +29615,13 @@ function createNodeControlHandler(options) {
|
|
|
29625
29615
|
ok: true,
|
|
29626
29616
|
protocolVersion: NODE_CONTROL_PROTOCOL_VERSION,
|
|
29627
29617
|
nodeVersion: NODE_VERSION,
|
|
29628
|
-
topics: topicsForUser(userId),
|
|
29618
|
+
topics: topicsForUser(userId, requestedSurface(url)),
|
|
29629
29619
|
cursor: latestRuntimeEventSeq()
|
|
29630
29620
|
});
|
|
29631
29621
|
}
|
|
29632
29622
|
if (req.method === "GET" && path === "/topics") {
|
|
29633
29623
|
const userId = requiredText(url.searchParams.get("user"), "user");
|
|
29634
|
-
return Response.json({ ok: true, topics: topicsForUser(userId) });
|
|
29624
|
+
return Response.json({ ok: true, topics: topicsForUser(userId, requestedSurface(url)) });
|
|
29635
29625
|
}
|
|
29636
29626
|
if (req.method === "GET" && path === "/background-sessions") {
|
|
29637
29627
|
const userId = requiredText(url.searchParams.get("user"), "user");
|
|
@@ -29762,24 +29752,6 @@ function createNodeControlHandler(options) {
|
|
|
29762
29752
|
return jsonError(400, result.error);
|
|
29763
29753
|
return Response.json({ ok: true, model: result.model, result: result.text });
|
|
29764
29754
|
}
|
|
29765
|
-
const accessModeMatch = path.match(/^\/topics\/([^/]+)\/access-mode$/);
|
|
29766
|
-
if (accessModeMatch && req.method === "POST") {
|
|
29767
|
-
const topicId = decodeURIComponent(accessModeMatch[1]);
|
|
29768
|
-
const body = await bodyRecord(req);
|
|
29769
|
-
const userId = requiredText(body.userId, "userId");
|
|
29770
|
-
const accessMode = requiredText(body.accessMode, "accessMode");
|
|
29771
|
-
if (accessMode !== "private" && accessMode !== "shared") {
|
|
29772
|
-
return jsonError(400, `Unknown access mode: ${accessMode}`);
|
|
29773
|
-
}
|
|
29774
|
-
const result = switchTopicAccessMode({ topicId, userId, accessMode });
|
|
29775
|
-
if (!result.ok)
|
|
29776
|
-
return jsonError(400, result.error);
|
|
29777
|
-
return Response.json({
|
|
29778
|
-
ok: true,
|
|
29779
|
-
accessMode: result.accessMode,
|
|
29780
|
-
result: result.text
|
|
29781
|
-
});
|
|
29782
|
-
}
|
|
29783
29755
|
const effortMatch = path.match(/^\/topics\/([^/]+)\/effort$/);
|
|
29784
29756
|
if (effortMatch && req.method === "POST") {
|
|
29785
29757
|
const topicId = decodeURIComponent(effortMatch[1]);
|
|
@@ -32124,8 +32096,6 @@ var init_commands = __esm(() => {
|
|
|
32124
32096
|
{ name: "model", usage: "/model", description: "choose the model" },
|
|
32125
32097
|
{ name: "effort", usage: "/effort", description: "choose reasoning effort" },
|
|
32126
32098
|
{ name: "topics", usage: "/topics", description: "open topic picker" },
|
|
32127
|
-
{ name: "public", usage: "/public", description: "share this topic with Otium Hub" },
|
|
32128
|
-
{ name: "private", usage: "/private", description: "make this topic local-only" },
|
|
32129
32099
|
{
|
|
32130
32100
|
name: "fork",
|
|
32131
32101
|
usage: "/fork [name]",
|
|
@@ -32471,8 +32441,7 @@ function topicPickerItems(state) {
|
|
|
32471
32441
|
const indexedTopics = state.topics.map((topic, index) => ({ topic, index })).filter(({ topic }) => visible.has(topic.id));
|
|
32472
32442
|
return [
|
|
32473
32443
|
...indexedTopics.filter(({ topic }) => topic.kind === "manager").map(({ topic, index }) => ({ kind: "topic", id: topic.id, index })),
|
|
32474
|
-
...indexedTopics.filter(({ topic }) => topic.kind !== "manager"
|
|
32475
|
-
...indexedTopics.filter(({ topic }) => topic.kind !== "manager" && topic.accessMode === "shared").map(({ topic, index }) => ({ kind: "topic", id: topic.id, index })),
|
|
32444
|
+
...indexedTopics.filter(({ topic }) => topic.kind !== "manager").map(({ topic, index }) => ({ kind: "topic", id: topic.id, index })),
|
|
32476
32445
|
...visibleBackgroundSessions(state).map((session) => ({
|
|
32477
32446
|
kind: "background",
|
|
32478
32447
|
id: session.id
|
|
@@ -32551,7 +32520,7 @@ function setTopics(state, topics, preferredTitle) {
|
|
|
32551
32520
|
activeTopicId: nextActive,
|
|
32552
32521
|
scrollOffset: nextActive === state.activeTopicId ? state.scrollOffset : 0,
|
|
32553
32522
|
askChoiceIndex: nextActive === state.activeTopicId ? state.askChoiceIndex : 0,
|
|
32554
|
-
topicPickerIndex: state.overlay === "topics"
|
|
32523
|
+
topicPickerIndex: state.overlay === "topics" ? pickedTopicIndex : Math.max(0, orderedTopics.findIndex((topic) => topic.id === nextActive)),
|
|
32555
32524
|
topicPickerBackgroundId: state.topicPickerBackgroundId
|
|
32556
32525
|
});
|
|
32557
32526
|
}
|
|
@@ -34089,7 +34058,7 @@ function helpLines() {
|
|
|
34089
34058
|
line(""),
|
|
34090
34059
|
line(" Commands", { fg: theme.cyan, bold: true }),
|
|
34091
34060
|
line(" /new /model /effort /status /context"),
|
|
34092
|
-
line(" /topics /
|
|
34061
|
+
line(" /topics /fork /spawn"),
|
|
34093
34062
|
line(" /del /copy /abort /help /quit", { fg: theme.muted })
|
|
34094
34063
|
];
|
|
34095
34064
|
}
|
|
@@ -34212,8 +34181,8 @@ function topicPickerHints(topicPickerRoot) {
|
|
|
34212
34181
|
const exit = topicPickerRoot ? "Esc/Ctrl-C exit" : "Esc close \xB7 Ctrl-C exit; work continues";
|
|
34213
34182
|
const shortExit = topicPickerRoot ? "Esc/Ctrl-C exit" : "Esc close";
|
|
34214
34183
|
const candidates = [
|
|
34215
|
-
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7
|
|
34216
|
-
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7
|
|
34184
|
+
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7 ${exit}`,
|
|
34185
|
+
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7 ${shortExit}`,
|
|
34217
34186
|
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete \xB7 ${exit}`,
|
|
34218
34187
|
`\u2191\u2193 select \xB7 Enter open \xB7 type to filter \xB7 Ctrl-N/D/P \xB7 ${shortExit}`,
|
|
34219
34188
|
"\u2191\u2193 \xB7 Enter \xB7 type to filter \xB7 Ctrl-N/D/P",
|
|
@@ -34235,13 +34204,11 @@ function topicOverlayLines(state, width, height, animationFrame = 0) {
|
|
|
34235
34204
|
const visibleIds = visibleTopicPickerIds(state);
|
|
34236
34205
|
const indexedTopics = state.topics.map((topic, topicIndex) => ({ topic, topicIndex })).filter(({ topic }) => visibleIds.has(topic.id));
|
|
34237
34206
|
const managerTopics = indexedTopics.filter(({ topic }) => topic.kind === "manager");
|
|
34238
|
-
const
|
|
34239
|
-
const publicTopics = indexedTopics.filter(({ topic }) => topic.kind !== "manager" && topic.accessMode === "shared");
|
|
34207
|
+
const regularTopics = indexedTopics.filter(({ topic }) => topic.kind !== "manager");
|
|
34240
34208
|
const entries = [];
|
|
34241
34209
|
for (const [label, topics] of [
|
|
34242
34210
|
["Manager", managerTopics],
|
|
34243
|
-
["
|
|
34244
|
-
["Public", publicTopics]
|
|
34211
|
+
["Topics", regularTopics]
|
|
34245
34212
|
]) {
|
|
34246
34213
|
if (topics.length === 0)
|
|
34247
34214
|
continue;
|
|
@@ -34576,34 +34543,6 @@ function conversationLines(state, width, height, animationFrame = 0, nowMs = ter
|
|
|
34576
34543
|
line(" Press y to delete or n to cancel.", { fg: theme.amber })
|
|
34577
34544
|
].slice(0, height);
|
|
34578
34545
|
}
|
|
34579
|
-
if (state.overlay === "confirm-share") {
|
|
34580
|
-
const topic = state.topics.find((candidate) => candidate.id === state.pendingShareTopicId);
|
|
34581
|
-
const subagents = (() => {
|
|
34582
|
-
if (!topic)
|
|
34583
|
-
return 0;
|
|
34584
|
-
const reached = new Set([topic.id]);
|
|
34585
|
-
for (;; ) {
|
|
34586
|
-
const next = state.topics.filter((candidate) => candidate.isSubagent && !reached.has(candidate.id) && candidate.parentTopicId !== undefined && reached.has(candidate.parentTopicId));
|
|
34587
|
-
if (next.length === 0)
|
|
34588
|
-
break;
|
|
34589
|
-
for (const candidate of next)
|
|
34590
|
-
reached.add(candidate.id);
|
|
34591
|
-
}
|
|
34592
|
-
return reached.size - 1;
|
|
34593
|
-
})();
|
|
34594
|
-
const scope = subagents > 0 ? ` Its ${subagents} subagent room${subagents === 1 ? "" : "s"} become public too.` : " Subagent rooms spawned from it will be public too.";
|
|
34595
|
-
return [
|
|
34596
|
-
line(""),
|
|
34597
|
-
line(` Make \u201C${topic?.title ?? "this topic"}\u201D public?`, {
|
|
34598
|
-
fg: theme.amber,
|
|
34599
|
-
bold: true
|
|
34600
|
-
}),
|
|
34601
|
-
line(""),
|
|
34602
|
-
line(" The transcript becomes visible to the connected Otium Hub."),
|
|
34603
|
-
line(scope),
|
|
34604
|
-
line(" Press y to publish or n to cancel.", { fg: theme.amber })
|
|
34605
|
-
].slice(0, height);
|
|
34606
|
-
}
|
|
34607
34546
|
const all = conversationContentLines(state, width, animationFrame, nowMs, includeTasks);
|
|
34608
34547
|
const { contentHeight, maxOffset, offset } = conversationViewport(all.length, height, state.scrollOffset);
|
|
34609
34548
|
const end = all.length - offset;
|
|
@@ -34871,9 +34810,6 @@ function footerHintText(state) {
|
|
|
34871
34810
|
}
|
|
34872
34811
|
return state.topicPickerRoot ? ["Esc/Ctrl-C exit ", "Esc exit "] : ["Esc close \xB7 Ctrl-C exit; work continues ", "Esc close \xB7 Ctrl-C exit ", "Esc "];
|
|
34873
34812
|
}
|
|
34874
|
-
if (state.overlay === "confirm-share") {
|
|
34875
|
-
return ["Y make public \xB7 N cancel ", "Y/N "];
|
|
34876
|
-
}
|
|
34877
34813
|
if (state.overlay === "background-session") {
|
|
34878
34814
|
return [
|
|
34879
34815
|
"wheel/PgUp/PgDn scroll \xB7 Esc back \xB7 read-only ",
|
|
@@ -35477,7 +35413,7 @@ class EmbeddedNegotiumClient {
|
|
|
35477
35413
|
}
|
|
35478
35414
|
listTopics() {
|
|
35479
35415
|
const runningTopics = listRunningTopicQueries();
|
|
35480
|
-
return getVisibleTopics().filter((topic) => topic.participants.some((participant) => participant.userId === this.#userId)).map((topic) => {
|
|
35416
|
+
return getVisibleTopics({ surface: "terminal" }).filter((topic) => topic.participants.some((participant) => participant.userId === this.#userId)).map((topic) => {
|
|
35481
35417
|
const runningQueryId = runningTopics.get(topic.id);
|
|
35482
35418
|
return { ...topic, running: Boolean(runningQueryId), runningQueryId };
|
|
35483
35419
|
});
|
|
@@ -35556,16 +35492,6 @@ class EmbeddedNegotiumClient {
|
|
|
35556
35492
|
throw new Error(result.error);
|
|
35557
35493
|
return result.text;
|
|
35558
35494
|
}
|
|
35559
|
-
setAccessMode(topic, accessMode) {
|
|
35560
|
-
const result = switchTopicAccessMode({
|
|
35561
|
-
topicId: topic.id,
|
|
35562
|
-
userId: this.#userId,
|
|
35563
|
-
accessMode
|
|
35564
|
-
});
|
|
35565
|
-
if (!result.ok)
|
|
35566
|
-
throw new Error(result.error);
|
|
35567
|
-
return result.text;
|
|
35568
|
-
}
|
|
35569
35495
|
async deleteTopic(topic) {
|
|
35570
35496
|
await topicService.delete({ topicId: topic.id, userId: this.#userId });
|
|
35571
35497
|
}
|
|
@@ -35650,7 +35576,7 @@ class RemoteNegotiumClient {
|
|
|
35650
35576
|
async start(onEvent) {
|
|
35651
35577
|
if (this.#started)
|
|
35652
35578
|
return;
|
|
35653
|
-
const session = await this.#request(`/session?user=${encodeURIComponent(this.#userId)}`);
|
|
35579
|
+
const session = await this.#request(`/session?user=${encodeURIComponent(this.#userId)}&surface=terminal`);
|
|
35654
35580
|
if (session.protocolVersion !== NODE_CONTROL_PROTOCOL_VERSION) {
|
|
35655
35581
|
throw new Error(`Node protocol ${String(session.protocolVersion)} is incompatible with terminal protocol ${NODE_CONTROL_PROTOCOL_VERSION}`);
|
|
35656
35582
|
}
|
|
@@ -35676,7 +35602,7 @@ class RemoteNegotiumClient {
|
|
|
35676
35602
|
this.#onEvent = null;
|
|
35677
35603
|
}
|
|
35678
35604
|
async listTopics() {
|
|
35679
|
-
const result = await this.#request(`/topics?user=${encodeURIComponent(this.#userId)}`);
|
|
35605
|
+
const result = await this.#request(`/topics?user=${encodeURIComponent(this.#userId)}&surface=terminal`);
|
|
35680
35606
|
return result.topics ?? [];
|
|
35681
35607
|
}
|
|
35682
35608
|
async listBackgroundSessions() {
|
|
@@ -35748,13 +35674,6 @@ class RemoteNegotiumClient {
|
|
|
35748
35674
|
});
|
|
35749
35675
|
return String(result.result ?? `Effort set to '${effort}'.`);
|
|
35750
35676
|
}
|
|
35751
|
-
async setAccessMode(topic, accessMode) {
|
|
35752
|
-
const result = await this.#request(`/topics/${encodeURIComponent(topic.id)}/access-mode`, {
|
|
35753
|
-
method: "POST",
|
|
35754
|
-
body: JSON.stringify({ userId: this.#userId, accessMode })
|
|
35755
|
-
});
|
|
35756
|
-
return String(result.result ?? `Access mode set to '${accessMode}'.`);
|
|
35757
|
-
}
|
|
35758
35677
|
async deleteTopic(topic) {
|
|
35759
35678
|
await this.#request(`/topics/${encodeURIComponent(topic.id)}?user=${encodeURIComponent(this.#userId)}`, { method: "DELETE" });
|
|
35760
35679
|
}
|
|
@@ -36232,32 +36151,6 @@ async function runTerminalCommand(commandLine, context) {
|
|
|
36232
36151
|
context.queueRender();
|
|
36233
36152
|
return;
|
|
36234
36153
|
}
|
|
36235
|
-
if (command === "public" || command === "private") {
|
|
36236
|
-
if (args.length > 0) {
|
|
36237
|
-
context.state = { ...context.state, notice: `Usage: /${command}`, noticeLevel: "warn" };
|
|
36238
|
-
context.queueRender();
|
|
36239
|
-
return;
|
|
36240
|
-
}
|
|
36241
|
-
const topic = activeTopic(context.state);
|
|
36242
|
-
if (!topic) {
|
|
36243
|
-
context.state = { ...context.state, notice: "No topic selected", noticeLevel: "warn" };
|
|
36244
|
-
context.queueRender();
|
|
36245
|
-
return;
|
|
36246
|
-
}
|
|
36247
|
-
try {
|
|
36248
|
-
const notice = await context.client.setAccessMode(topic, command === "public" ? "shared" : "private");
|
|
36249
|
-
await context.refreshTopics(topic.title);
|
|
36250
|
-
context.state = { ...context.state, notice, noticeLevel: "success" };
|
|
36251
|
-
} catch (error2) {
|
|
36252
|
-
context.state = {
|
|
36253
|
-
...context.state,
|
|
36254
|
-
notice: error2 instanceof Error ? error2.message : String(error2),
|
|
36255
|
-
noticeLevel: "error"
|
|
36256
|
-
};
|
|
36257
|
-
}
|
|
36258
|
-
context.queueRender();
|
|
36259
|
-
return;
|
|
36260
|
-
}
|
|
36261
36154
|
if (command === "compact") {
|
|
36262
36155
|
const topic = activeTopic(context.state);
|
|
36263
36156
|
if (!topic) {
|
|
@@ -37822,16 +37715,6 @@ class TerminalApp {
|
|
|
37822
37715
|
}
|
|
37823
37716
|
return;
|
|
37824
37717
|
}
|
|
37825
|
-
if (this.#state.overlay === "confirm-share") {
|
|
37826
|
-
const key = chunk.toLowerCase();
|
|
37827
|
-
if (CONFIRM_KEYS.has(key))
|
|
37828
|
-
this.#confirmTopicShare();
|
|
37829
|
-
else if (CANCEL_KEYS.has(key) || chunk === "\x1B") {
|
|
37830
|
-
this.#state = { ...this.#state, overlay: "topics", pendingShareTopicId: undefined };
|
|
37831
|
-
this.#queueRender();
|
|
37832
|
-
}
|
|
37833
|
-
return;
|
|
37834
|
-
}
|
|
37835
37718
|
if (this.#state.overlay === "background-session") {
|
|
37836
37719
|
if (chunk === "\x1B") {
|
|
37837
37720
|
this.#state = { ...this.#state, overlay: "topics" };
|
|
@@ -38140,22 +38023,6 @@ class TerminalApp {
|
|
|
38140
38023
|
this.#queueRender();
|
|
38141
38024
|
return;
|
|
38142
38025
|
}
|
|
38143
|
-
if (chunk === TOGGLE_ACCESS_MODE_KEY) {
|
|
38144
|
-
const topic = pickedTopic(this.#state);
|
|
38145
|
-
if (topic) {
|
|
38146
|
-
this.#requestAccessModeToggle(topic);
|
|
38147
|
-
return;
|
|
38148
|
-
}
|
|
38149
|
-
if (!this.#state.topicPickerBackgroundId)
|
|
38150
|
-
return;
|
|
38151
|
-
this.#state = {
|
|
38152
|
-
...this.#state,
|
|
38153
|
-
notice: "Background sessions are read-only",
|
|
38154
|
-
noticeLevel: "warn"
|
|
38155
|
-
};
|
|
38156
|
-
this.#queueRender();
|
|
38157
|
-
return;
|
|
38158
|
-
}
|
|
38159
38026
|
if (FILTER_BACKSPACE_KEYS.has(chunk)) {
|
|
38160
38027
|
if (this.#state.topicFilter.length === 0)
|
|
38161
38028
|
return;
|
|
@@ -38598,65 +38465,6 @@ class TerminalApp {
|
|
|
38598
38465
|
};
|
|
38599
38466
|
this.#queueRender();
|
|
38600
38467
|
}
|
|
38601
|
-
async#requestAccessModeToggle(topic) {
|
|
38602
|
-
if (topic.kind !== "agent") {
|
|
38603
|
-
this.#state = {
|
|
38604
|
-
...this.#state,
|
|
38605
|
-
notice: `${topic.kind === "manager" ? "Manager" : "Channel"} topics cannot be published`,
|
|
38606
|
-
noticeLevel: "warn"
|
|
38607
|
-
};
|
|
38608
|
-
this.#queueRender();
|
|
38609
|
-
return;
|
|
38610
|
-
}
|
|
38611
|
-
if (topic.isSubagent) {
|
|
38612
|
-
this.#state = {
|
|
38613
|
-
...this.#state,
|
|
38614
|
-
notice: "Subagent rooms inherit privacy from their parent topic",
|
|
38615
|
-
noticeLevel: "warn"
|
|
38616
|
-
};
|
|
38617
|
-
this.#queueRender();
|
|
38618
|
-
return;
|
|
38619
|
-
}
|
|
38620
|
-
if (topic.accessMode === "shared") {
|
|
38621
|
-
await this.#applyAccessMode(topic, "private");
|
|
38622
|
-
return;
|
|
38623
|
-
}
|
|
38624
|
-
this.#state = {
|
|
38625
|
-
...this.#state,
|
|
38626
|
-
overlay: "confirm-share",
|
|
38627
|
-
pendingShareTopicId: topic.id
|
|
38628
|
-
};
|
|
38629
|
-
this.#queueRender();
|
|
38630
|
-
}
|
|
38631
|
-
async#confirmTopicShare() {
|
|
38632
|
-
const topic = this.#state.topics.find((candidate) => candidate.id === this.#state.pendingShareTopicId);
|
|
38633
|
-
this.#state = { ...this.#state, overlay: "topics", pendingShareTopicId: undefined };
|
|
38634
|
-
if (!topic) {
|
|
38635
|
-
this.#state = {
|
|
38636
|
-
...this.#state,
|
|
38637
|
-
notice: "That topic no longer exists",
|
|
38638
|
-
noticeLevel: "warn"
|
|
38639
|
-
};
|
|
38640
|
-
this.#queueRender();
|
|
38641
|
-
return;
|
|
38642
|
-
}
|
|
38643
|
-
await this.#applyAccessMode(topic, "shared");
|
|
38644
|
-
}
|
|
38645
|
-
async#applyAccessMode(topic, accessMode) {
|
|
38646
|
-
this.#state = { ...this.#state, overlay: "topics" };
|
|
38647
|
-
try {
|
|
38648
|
-
const notice = await this.#client.setAccessMode(topic, accessMode);
|
|
38649
|
-
await this.#refreshTopics();
|
|
38650
|
-
this.#state = { ...this.#state, notice, noticeLevel: "success" };
|
|
38651
|
-
} catch (error2) {
|
|
38652
|
-
this.#state = {
|
|
38653
|
-
...this.#state,
|
|
38654
|
-
notice: error2 instanceof Error ? error2.message : String(error2),
|
|
38655
|
-
noticeLevel: "error"
|
|
38656
|
-
};
|
|
38657
|
-
}
|
|
38658
|
-
this.#queueRender();
|
|
38659
|
-
}
|
|
38660
38468
|
#requestTopicDelete(topic) {
|
|
38661
38469
|
if (!topic)
|
|
38662
38470
|
return;
|
|
@@ -38935,7 +38743,6 @@ class TerminalApp {
|
|
|
38935
38743
|
...this.#state,
|
|
38936
38744
|
overlay: null,
|
|
38937
38745
|
pendingDeleteTopicId: undefined,
|
|
38938
|
-
pendingShareTopicId: undefined,
|
|
38939
38746
|
creatingTopic: false,
|
|
38940
38747
|
notice: "Input cleared",
|
|
38941
38748
|
noticeLevel: "info"
|
|
@@ -38998,7 +38805,7 @@ class TerminalApp {
|
|
|
38998
38805
|
await this.#client.stop();
|
|
38999
38806
|
}
|
|
39000
38807
|
}
|
|
39001
|
-
var KITTY_KEYBOARD_PUSH = "\x1B[>1u", KITTY_KEYBOARD_POP = "\x1B[<u", CANVAS_RGB, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, ABORT_ENTER_ALT_SCREEN, NEW_TOPIC_KEY = "\x0E", DELETE_TOPIC_KEY = "\x04",
|
|
38808
|
+
var KITTY_KEYBOARD_PUSH = "\x1B[>1u", KITTY_KEYBOARD_POP = "\x1B[<u", CANVAS_RGB, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, ABORT_ENTER_ALT_SCREEN, NEW_TOPIC_KEY = "\x0E", DELETE_TOPIC_KEY = "\x04", FILTER_BACKSPACE_KEYS, CONFIRM_KEYS, CANCEL_KEYS, INPUT_CARRY_FLUSH_MS = 15;
|
|
39002
38809
|
var init_app = __esm(async () => {
|
|
39003
38810
|
await init_src();
|
|
39004
38811
|
await init_app_helpers();
|
|
@@ -39476,7 +39283,7 @@ function createTelegramCommandRouter(context) {
|
|
|
39476
39283
|
return;
|
|
39477
39284
|
}
|
|
39478
39285
|
case "/topics": {
|
|
39479
|
-
const topics = listTopics().filter((topic) => isTopicVisible(topic) && topic.participants.some((person) => person.userId === userId));
|
|
39286
|
+
const topics = listTopics({ surface: "telegram" }).filter((topic) => isTopicVisible(topic) && topic.participants.some((person) => person.userId === userId));
|
|
39480
39287
|
reply(chatId, threadId, topics.length ? topics.map((topic) => `- ${topic.title}${topic.agent ? ` (${topic.agent})` : ""}`).join(`
|
|
39481
39288
|
`) : "no topics");
|
|
39482
39289
|
return;
|
|
@@ -39506,6 +39313,7 @@ function createTelegramCommandRouter(context) {
|
|
|
39506
39313
|
title: argument,
|
|
39507
39314
|
userId,
|
|
39508
39315
|
kind: "agent",
|
|
39316
|
+
surface: "telegram",
|
|
39509
39317
|
...context.defaultAgent ? { agent: context.defaultAgent } : {}
|
|
39510
39318
|
};
|
|
39511
39319
|
const fromForumGeneral = context.forum?.enabled === true && chatId === context.forum.chatId && threadId === undefined;
|
|
@@ -39724,6 +39532,15 @@ function openMappingStore(path) {
|
|
|
39724
39532
|
clearForumChatId() {
|
|
39725
39533
|
db4.run("DELETE FROM settings WHERE key = 'forum_chat_id'");
|
|
39726
39534
|
},
|
|
39535
|
+
isFlagSet(key) {
|
|
39536
|
+
return db4.query("SELECT 1 FROM settings WHERE key = ?").get(key) !== null;
|
|
39537
|
+
},
|
|
39538
|
+
setFlag(key) {
|
|
39539
|
+
db4.run("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)", [
|
|
39540
|
+
key,
|
|
39541
|
+
new Date().toISOString()
|
|
39542
|
+
]);
|
|
39543
|
+
},
|
|
39727
39544
|
outboxEnqueue(entry) {
|
|
39728
39545
|
db4.run(`INSERT INTO outbox
|
|
39729
39546
|
(chat_id, thread_id, runtime_message_id, footer, html, plain, attempts, next_try_at, last_error)
|
|
@@ -40293,6 +40110,14 @@ function startTelegramAdapter(opts) {
|
|
|
40293
40110
|
bindMapping(chatId, threadId, topic.id);
|
|
40294
40111
|
return true;
|
|
40295
40112
|
}
|
|
40113
|
+
if (!store.isFlagSet(SURFACE_BACKFILL_FLAG)) {
|
|
40114
|
+
const mappedIds = [...new Set(store.load().map((mapping) => mapping.topicId))];
|
|
40115
|
+
const moved = setTopicSurfaces(mappedIds, "telegram");
|
|
40116
|
+
store.setFlag(SURFACE_BACKFILL_FLAG);
|
|
40117
|
+
if (moved > 0) {
|
|
40118
|
+
logger.info({ moved, mapped: mappedIds.length }, "telegram adapter: moved mapped topics onto the telegram surface");
|
|
40119
|
+
}
|
|
40120
|
+
}
|
|
40296
40121
|
for (const persisted of store.load()) {
|
|
40297
40122
|
const topic = getTopic(persisted.topicId);
|
|
40298
40123
|
if (topic?.participants.some((participant) => participant.userId === userId)) {
|
|
@@ -40313,13 +40138,13 @@ function startTelegramAdapter(opts) {
|
|
|
40313
40138
|
function registerTopicLocal(options) {
|
|
40314
40139
|
suppressMaterialize++;
|
|
40315
40140
|
try {
|
|
40316
|
-
return topicService.create(options);
|
|
40141
|
+
return topicService.create({ ...options, surface: "telegram" });
|
|
40317
40142
|
} finally {
|
|
40318
40143
|
suppressMaterialize--;
|
|
40319
40144
|
}
|
|
40320
40145
|
}
|
|
40321
40146
|
function getOrCreateTopic(title, agent) {
|
|
40322
|
-
return getTopicByNameForUser(title, userId) ?? registerTopicLocal({ title, userId, kind: "agent", ...agent ? { agent } : {} });
|
|
40147
|
+
return getTopicByNameForUser(title, userId, { surface: "telegram" }) ?? registerTopicLocal({ title, userId, kind: "agent", ...agent ? { agent } : {} });
|
|
40323
40148
|
}
|
|
40324
40149
|
function resolveMapping(chatId, threadId) {
|
|
40325
40150
|
const cached = byKey.get(mappingKey(chatId, threadId));
|
|
@@ -40910,7 +40735,7 @@ ${suffix}`;
|
|
|
40910
40735
|
function materializeVisibleTopics() {
|
|
40911
40736
|
if (!forumMode || !forumManageTopicsAvailable)
|
|
40912
40737
|
return;
|
|
40913
|
-
for (const topic of listTopics()) {
|
|
40738
|
+
for (const topic of listTopics({ surface: "telegram" })) {
|
|
40914
40739
|
if (isTopicVisible(topic) && topic.participants.some((participant) => participant.userId === userId)) {
|
|
40915
40740
|
materializeTopic(topic);
|
|
40916
40741
|
}
|
|
@@ -41331,7 +41156,7 @@ Warning: enable the bot administrator permission "Manage Topics" before creating
|
|
|
41331
41156
|
}
|
|
41332
41157
|
};
|
|
41333
41158
|
}
|
|
41334
|
-
var FORUM_TOPIC_NAME_MAX = 128, MAX_PARENT_HOPS = 5, DEFAULT_SEND_TIMEOUT_MS = 60000, PHOTO_EXTS;
|
|
41159
|
+
var SURFACE_BACKFILL_FLAG = "surface_backfill_20260808", FORUM_TOPIC_NAME_MAX = 128, MAX_PARENT_HOPS = 5, DEFAULT_SEND_TIMEOUT_MS = 60000, PHOTO_EXTS;
|
|
41335
41160
|
var init_adapter = __esm(async () => {
|
|
41336
41161
|
await init_src();
|
|
41337
41162
|
await init_commands2();
|
|
@@ -43989,7 +43814,7 @@ function requirePrimaryOrigin(peer) {
|
|
|
43989
43814
|
return peer.verified.fromIsPrimary ? null : jsonError2("only the workspace hub may call this endpoint", 403);
|
|
43990
43815
|
}
|
|
43991
43816
|
function peerAddressable(topic) {
|
|
43992
|
-
return
|
|
43817
|
+
return topic.surface === "otium";
|
|
43993
43818
|
}
|
|
43994
43819
|
function localCapabilities() {
|
|
43995
43820
|
const agents = SUPPORTED_AGENTS.map((kind) => {
|
|
@@ -44159,7 +43984,7 @@ async function handleSessions(req) {
|
|
|
44159
43984
|
const userId = str(body, "userId");
|
|
44160
43985
|
if (!userId)
|
|
44161
43986
|
return jsonError2("userId is required", 400);
|
|
44162
|
-
const topics = listTopics().filter((topic) => topic.kind !== "manager" && !topic.isSubagent && peerAddressable(topic) && topic.participants.some((p) => p.userId === userId));
|
|
43987
|
+
const topics = listTopics({ surface: "otium" }).filter((topic) => topic.kind !== "manager" && !topic.isSubagent && peerAddressable(topic) && topic.participants.some((p) => p.userId === userId));
|
|
44163
43988
|
const titleCounts = new Map;
|
|
44164
43989
|
for (const topic of topics) {
|
|
44165
43990
|
const normalized = topic.title.toLowerCase();
|
|
@@ -44875,26 +44700,8 @@ async function runOtiumCli(args = process.argv.slice(2)) {
|
|
|
44875
44700
|
const { loadJoin: loadJoin2, removeJoin: removeJoin2 } = await init_join().then(() => exports_join);
|
|
44876
44701
|
if (!loadJoin2())
|
|
44877
44702
|
throw new Error("not joined to an Otium workspace");
|
|
44878
|
-
const { getVisibleTopics: getVisibleTopics2, isTopicShared: isTopicShared2, switchTopicAccessMode: switchTopicAccessMode2 } = await init_src().then(() => exports_src);
|
|
44879
|
-
let downgraded = 0;
|
|
44880
|
-
for (const topic of getVisibleTopics2()) {
|
|
44881
|
-
if (!isTopicShared2(topic))
|
|
44882
|
-
continue;
|
|
44883
|
-
const owner = topic.participants.find((participant) => participant.role === "owner");
|
|
44884
|
-
if (!owner)
|
|
44885
|
-
continue;
|
|
44886
|
-
if (topic.isSubagent)
|
|
44887
|
-
continue;
|
|
44888
|
-
const switched = switchTopicAccessMode2({
|
|
44889
|
-
topicId: topic.id,
|
|
44890
|
-
userId: owner.userId,
|
|
44891
|
-
accessMode: "private"
|
|
44892
|
-
});
|
|
44893
|
-
if (switched.ok)
|
|
44894
|
-
downgraded += switched.topicIds.length;
|
|
44895
|
-
}
|
|
44896
44703
|
removeJoin2();
|
|
44897
|
-
console.log(
|
|
44704
|
+
console.log("disconnected from Otium; workspace credentials removed");
|
|
44898
44705
|
break;
|
|
44899
44706
|
}
|
|
44900
44707
|
case "serve": {
|
|
@@ -44968,11 +44775,7 @@ function topicsCommand() {
|
|
|
44968
44775
|
}
|
|
44969
44776
|
for (const t of topics) {
|
|
44970
44777
|
const model = t.effectiveModel ?? t.defaultModel;
|
|
44971
|
-
const flags = [
|
|
44972
|
-
t.accessMode ?? "private",
|
|
44973
|
-
t.isSubagent ? "subagent" : null,
|
|
44974
|
-
t.isFork ? "fork" : null
|
|
44975
|
-
].filter(Boolean).join(",");
|
|
44778
|
+
const flags = [t.isSubagent ? "subagent" : null, t.isFork ? "fork" : null].filter(Boolean).join(",");
|
|
44976
44779
|
console.log(`${t.title} ${t.agent ?? "no-ai"}${model ? `/${model}` : ""}` + `${flags ? ` [${flags}]` : ""} ${t.id}`);
|
|
44977
44780
|
}
|
|
44978
44781
|
}
|
|
@@ -45620,4 +45423,4 @@ switch (command) {
|
|
|
45620
45423
|
}
|
|
45621
45424
|
}
|
|
45622
45425
|
|
|
45623
|
-
//# debugId=
|
|
45426
|
+
//# debugId=50D62D73CF0EE2E064756E2164756E21
|