dsh-tiddlywiki 0.6.0 → 0.7.3
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/lib/index.js +181 -4
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/host/config.ts +7 -0
- package/src/host/routes.ts +145 -0
- package/src/host/tools.ts +1 -1
- package/src/index.ts +15 -3
package/lib/index.js
CHANGED
|
@@ -852,6 +852,151 @@ function registerRoutes(ctx, deps) {
|
|
|
852
852
|
ui: deps.uiDefaults()
|
|
853
853
|
});
|
|
854
854
|
};
|
|
855
|
+
/**
|
|
856
|
+
* GET /dsh-tiddlywiki/agent/sessions — visible ordinary sessions for the TW
|
|
857
|
+
* one-click picker (excludes subagent sessions, activity-descending).
|
|
858
|
+
*/
|
|
859
|
+
const handleAgentSessions = async (_req, res) => {
|
|
860
|
+
try {
|
|
861
|
+
const sc = deps.getSessionController();
|
|
862
|
+
if (sc === void 0) {
|
|
863
|
+
json$1(res, {
|
|
864
|
+
ok: false,
|
|
865
|
+
error: "session service unavailable"
|
|
866
|
+
}, 503);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
json$1(res, {
|
|
870
|
+
ok: true,
|
|
871
|
+
items: ((await sc.list({}, AbortSignal.timeout(1e4))).items ?? []).filter((s) => s.parentSessionId === void 0).map((s) => ({
|
|
872
|
+
sessionId: s.sessionId,
|
|
873
|
+
cwd: s.cwd ?? null,
|
|
874
|
+
running: !!s.running,
|
|
875
|
+
blank: !!s.blank,
|
|
876
|
+
updatedAt: s.updatedAt ?? 0
|
|
877
|
+
})).sort((a, b) => b.updatedAt - a.updatedAt)
|
|
878
|
+
});
|
|
879
|
+
} catch (err) {
|
|
880
|
+
json$1(res, {
|
|
881
|
+
ok: false,
|
|
882
|
+
error: err instanceof Error ? err.message : String(err)
|
|
883
|
+
}, 500);
|
|
884
|
+
}
|
|
885
|
+
};
|
|
886
|
+
/**
|
|
887
|
+
* POST /dsh-tiddlywiki/agent/send — deliver a note to one agent session as a
|
|
888
|
+
* queued user message (sessionController.prompt, the same API the GUI chat
|
|
889
|
+
* input uses). Guards: feature switch, optional shared token, body shape.
|
|
890
|
+
*/
|
|
891
|
+
const handleAgentSend = async (req, res) => {
|
|
892
|
+
try {
|
|
893
|
+
if (!deps.sendToAgentEnabled()) {
|
|
894
|
+
json$1(res, {
|
|
895
|
+
ok: false,
|
|
896
|
+
error: "send-to-agent is disabled"
|
|
897
|
+
}, 403);
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
const token = deps.sendToAgentToken().trim();
|
|
901
|
+
if (token.length > 0) {
|
|
902
|
+
const got = req.headers["x-send-to-agent-token"];
|
|
903
|
+
if ((typeof got === "string" ? got : Array.isArray(got) ? got[0] ?? "" : "") !== token) {
|
|
904
|
+
json$1(res, {
|
|
905
|
+
ok: false,
|
|
906
|
+
error: "unauthorized"
|
|
907
|
+
}, 401);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
const body = JSON.parse(await readBody$1(req));
|
|
912
|
+
const sessionId = typeof body.sessionId === "string" && body.sessionId.trim().length > 0 ? body.sessionId.trim() : "";
|
|
913
|
+
const text = typeof body.text === "string" && body.text.trim().length > 0 ? body.text.trim() : "";
|
|
914
|
+
if (sessionId.length === 0 || text.length === 0) {
|
|
915
|
+
json$1(res, {
|
|
916
|
+
ok: false,
|
|
917
|
+
error: "sessionId and text are required"
|
|
918
|
+
}, 400);
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const sc = deps.getSessionController();
|
|
922
|
+
if (sc === void 0) {
|
|
923
|
+
json$1(res, {
|
|
924
|
+
ok: false,
|
|
925
|
+
error: "session service unavailable"
|
|
926
|
+
}, 503);
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const requestId = `tw-send-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
930
|
+
await sc.prompt({
|
|
931
|
+
requestId,
|
|
932
|
+
sessionId,
|
|
933
|
+
mode: "queue",
|
|
934
|
+
content: [{
|
|
935
|
+
type: "text",
|
|
936
|
+
text
|
|
937
|
+
}]
|
|
938
|
+
}, AbortSignal.timeout(2e4));
|
|
939
|
+
json$1(res, {
|
|
940
|
+
ok: true,
|
|
941
|
+
requestId,
|
|
942
|
+
sessionId
|
|
943
|
+
});
|
|
944
|
+
} catch (err) {
|
|
945
|
+
json$1(res, {
|
|
946
|
+
ok: false,
|
|
947
|
+
error: err instanceof Error ? err.message : String(err)
|
|
948
|
+
}, 500);
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* POST /dsh-tiddlywiki/agent/create — create (or adopt) one ordinary session,
|
|
953
|
+
* optionally inside a workspace path. The picker uses it for "new workspace /
|
|
954
|
+
* new session"; the created session's cwd becomes its workspace. The directory
|
|
955
|
+
* is materialised so a brand-new workspace actually exists on disk.
|
|
956
|
+
*/
|
|
957
|
+
const handleAgentCreate = async (req, res) => {
|
|
958
|
+
try {
|
|
959
|
+
if (!deps.sendToAgentEnabled()) {
|
|
960
|
+
json$1(res, {
|
|
961
|
+
ok: false,
|
|
962
|
+
error: "send-to-agent is disabled"
|
|
963
|
+
}, 403);
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
966
|
+
const token = deps.sendToAgentToken().trim();
|
|
967
|
+
if (token.length > 0) {
|
|
968
|
+
const got = req.headers["x-send-to-agent-token"];
|
|
969
|
+
if ((typeof got === "string" ? got : Array.isArray(got) ? got[0] ?? "" : "") !== token) {
|
|
970
|
+
json$1(res, {
|
|
971
|
+
ok: false,
|
|
972
|
+
error: "unauthorized"
|
|
973
|
+
}, 401);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
const body = JSON.parse(await readBody$1(req));
|
|
978
|
+
const cwd = typeof body.cwd === "string" ? body.cwd.trim() : "";
|
|
979
|
+
const sc = deps.getSessionController();
|
|
980
|
+
if (sc === void 0) {
|
|
981
|
+
json$1(res, {
|
|
982
|
+
ok: false,
|
|
983
|
+
error: "session service unavailable"
|
|
984
|
+
}, 503);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (cwd.length > 0) await mkdir(cwd, { recursive: true });
|
|
988
|
+
json$1(res, {
|
|
989
|
+
ok: true,
|
|
990
|
+
sessionId: (await sc.create({ cwd: cwd.length > 0 ? cwd : void 0 })).sessionId,
|
|
991
|
+
cwd: cwd || null
|
|
992
|
+
});
|
|
993
|
+
} catch (err) {
|
|
994
|
+
json$1(res, {
|
|
995
|
+
ok: false,
|
|
996
|
+
error: err instanceof Error ? err.message : String(err)
|
|
997
|
+
}, 500);
|
|
998
|
+
}
|
|
999
|
+
};
|
|
855
1000
|
const handleNote = async (req, res) => {
|
|
856
1001
|
try {
|
|
857
1002
|
const body = JSON.parse(await readBody$1(req));
|
|
@@ -1311,6 +1456,27 @@ function registerRoutes(ctx, deps) {
|
|
|
1311
1456
|
handleRestart(req, res);
|
|
1312
1457
|
}
|
|
1313
1458
|
}),
|
|
1459
|
+
ctx.webServer.register({
|
|
1460
|
+
kind: "exact",
|
|
1461
|
+
path: `${ROUTE_PREFIX}/agent/sessions`,
|
|
1462
|
+
handler: (req, res) => {
|
|
1463
|
+
handleAgentSessions(req, res);
|
|
1464
|
+
}
|
|
1465
|
+
}),
|
|
1466
|
+
ctx.webServer.register({
|
|
1467
|
+
kind: "exact",
|
|
1468
|
+
path: `${ROUTE_PREFIX}/agent/send`,
|
|
1469
|
+
handler: (req, res) => {
|
|
1470
|
+
handleAgentSend(req, res);
|
|
1471
|
+
}
|
|
1472
|
+
}),
|
|
1473
|
+
ctx.webServer.register({
|
|
1474
|
+
kind: "exact",
|
|
1475
|
+
path: `${ROUTE_PREFIX}/agent/create`,
|
|
1476
|
+
handler: (req, res) => {
|
|
1477
|
+
handleAgentCreate(req, res);
|
|
1478
|
+
}
|
|
1479
|
+
}),
|
|
1314
1480
|
ctx.webServer.register({
|
|
1315
1481
|
kind: "prefix",
|
|
1316
1482
|
path: `${ROUTE_PREFIX}/api`,
|
|
@@ -2640,7 +2806,10 @@ function registerTiddlywikiTools(ctx, deps) {
|
|
|
2640
2806
|
}
|
|
2641
2807
|
}
|
|
2642
2808
|
}
|
|
2643
|
-
await wiki.put(
|
|
2809
|
+
await wiki.put({
|
|
2810
|
+
...cleanTiddler(existing),
|
|
2811
|
+
title: newTitle
|
|
2812
|
+
});
|
|
2644
2813
|
await wiki.delete(oldTitle);
|
|
2645
2814
|
if (refsTiddlers === 0) warning = "未找到任何其他 tiddler 引用旧标题;如确实需要,可手动补充链接。";
|
|
2646
2815
|
deps.autoCommit();
|
|
@@ -2924,7 +3093,8 @@ const DEFAULTS = {
|
|
|
2924
3093
|
ui: {
|
|
2925
3094
|
showQuickNote: true,
|
|
2926
3095
|
showPanelStatus: true,
|
|
2927
|
-
showSyncButton: true
|
|
3096
|
+
showSyncButton: true,
|
|
3097
|
+
sendToAgent: { enabled: true }
|
|
2928
3098
|
},
|
|
2929
3099
|
auth: {
|
|
2930
3100
|
username: "",
|
|
@@ -3164,6 +3334,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3164
3334
|
})();
|
|
3165
3335
|
ctx.inject(["webServer"], (webCtx) => {
|
|
3166
3336
|
const ws = webCtx.webServer;
|
|
3337
|
+
const getSessionController = () => ctx.get("sessionController");
|
|
3167
3338
|
const disposeRoutes = registerRoutes({ webServer: ws }, {
|
|
3168
3339
|
server,
|
|
3169
3340
|
getClient: client,
|
|
@@ -3171,7 +3342,13 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3171
3342
|
autoCommit: () => committer?.touch(),
|
|
3172
3343
|
noteDefaults: () => ({ tag: effectiveNoteTag() }),
|
|
3173
3344
|
uiDefaults: () => effectiveUi(),
|
|
3174
|
-
getWikiPath: () => wikiPath
|
|
3345
|
+
getWikiPath: () => wikiPath,
|
|
3346
|
+
getSessionController,
|
|
3347
|
+
sendToAgentEnabled: () => eff().ui?.sendToAgent?.enabled !== false,
|
|
3348
|
+
sendToAgentToken: () => {
|
|
3349
|
+
const token = eff().ui?.sendToAgent?.token;
|
|
3350
|
+
return typeof token === "string" ? token : "";
|
|
3351
|
+
}
|
|
3175
3352
|
});
|
|
3176
3353
|
const disposeAdmin = registerAdminRoutes({ webServer: ws }, {
|
|
3177
3354
|
server,
|
|
@@ -3196,6 +3373,6 @@ function apply(ctx, rawConfig = {}) {
|
|
|
3196
3373
|
}, "dsh-tiddlywiki: host teardown");
|
|
3197
3374
|
}
|
|
3198
3375
|
//#endregion
|
|
3199
|
-
export { AutoCommitter, ConfigStore, DOC_NOTE_TAG, DOC_NOTE_TEXT, DOC_NOTE_TITLE, GitFace, PATH_PREFIX, TW_PROXY_PATH, TW_PROXY_PREFIX, TW_WEB_HOST_TIDDLER, TiddlyWebClient, WikiServer, apply, bundledCatalog, deepMerge, defineTool, dshHomePath, ensureLanguage, ensureTwWebHost, inject, name, normalizeThemes, openInTwEditor, readWikiInfo, registerAdminRoutes, registerRoutes, resolveTwRoot, seedDocNote, writeWikiInfo };
|
|
3376
|
+
export { AutoCommitter, ConfigStore, DOC_NOTE_TAG, DOC_NOTE_TEXT, DOC_NOTE_TITLE, GitFace, PATH_PREFIX, TW_PROXY_PATH, TW_PROXY_PREFIX, TW_WEB_HOST_TIDDLER, TiddlyWebClient, WikiServer, apply, bundledCatalog, deepMerge, defineTool, dshHomePath, ensureLanguage, ensureTwWebHost, inject, name, normalizeThemes, openInTwEditor, readWikiInfo, registerAdminRoutes, registerRoutes, registerTiddlywikiTools, resolveTwRoot, seedDocNote, writeWikiInfo };
|
|
3200
3377
|
|
|
3201
3378
|
//# sourceMappingURL=index.js.map
|