termdock 1.4.4 → 1.4.6
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/client/assets/{abnfDiagram-VRR7QNED-l1RHVwtV.js → abnfDiagram-VRR7QNED-TJWKds8h.js} +1 -1
- package/dist/client/assets/{arc-DO19HDpA.js → arc-Bwq4gJDN.js} +1 -1
- package/dist/client/assets/{architectureDiagram-ZJ3FMSHR-CwkysCpv.js → architectureDiagram-ZJ3FMSHR-C_PaIGsp.js} +1 -1
- package/dist/client/assets/{blockDiagram-677ZJIJ3-BRctjbx4.js → blockDiagram-677ZJIJ3-DIQ1s4RG.js} +1 -1
- package/dist/client/assets/{c4Diagram-LMCZKHZV-CL1FBbko.js → c4Diagram-LMCZKHZV-Cw3HxHgb.js} +1 -1
- package/dist/client/assets/channel-DwhPbxV3.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-Csh7Imvj.js → chunk-2Q5K7J3B-LMScDiKF.js} +1 -1
- package/dist/client/assets/{chunk-32BRIVSS-BbMLiuF9.js → chunk-32BRIVSS-Cgcdv9a_.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-D48bXYje.js → chunk-5VM5RSS4-BN4q0bFP.js} +1 -1
- package/dist/client/assets/{chunk-EX3LRPZG-CZe-cckf.js → chunk-EX3LRPZG-f7v2lPuo.js} +1 -1
- package/dist/client/assets/{chunk-JWPE2WC7-Ciaj8hAC.js → chunk-JWPE2WC7-qRGfWvPl.js} +1 -1
- package/dist/client/assets/{chunk-MOJQB5TN-CBfP6hIj.js → chunk-MOJQB5TN-CcRVcjNk.js} +1 -1
- package/dist/client/assets/{chunk-RYQCIY6F-H-dwX8-8.js → chunk-RYQCIY6F-CiStzedH.js} +1 -1
- package/dist/client/assets/{chunk-V7JOEXUC-UyB55Fb4.js → chunk-V7JOEXUC-By8l1Yd1.js} +1 -1
- package/dist/client/assets/{chunk-VR4S4FIN-C-xnKkZn.js → chunk-VR4S4FIN-Cs9MYsyB.js} +1 -1
- package/dist/client/assets/{chunk-XXDRQBXY-DwM4iNfy.js → chunk-XXDRQBXY-BqymfWtI.js} +1 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-C5oIvoR8.js +1 -0
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-C5oIvoR8.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-DQ6wrpJd.js → cose-bilkent-JH36ORCC-D_ATAEN1.js} +1 -1
- package/dist/client/assets/{cynefin-VYW2F7L2-Du46UaXb.js → cynefin-VYW2F7L2-nMKGdMLr.js} +1 -1
- package/dist/client/assets/{cynefinDiagram-TSTJHNR4-BJmwLYq0.js → cynefinDiagram-TSTJHNR4-88CGto9V.js} +1 -1
- package/dist/client/assets/{dagre-VKFMJZFB-BKJvvyPu.js → dagre-VKFMJZFB-DbSHMc1E.js} +1 -1
- package/dist/client/assets/{diagram-FQU43EPY-BOVDpQ4_.js → diagram-FQU43EPY-CJ_zBTrl.js} +1 -1
- package/dist/client/assets/{diagram-G47NLZAW-D2kIGl0J.js → diagram-G47NLZAW-DBtAAmF_.js} +1 -1
- package/dist/client/assets/{diagram-NH7WQ7WH-wJmqwi0p.js → diagram-NH7WQ7WH-Bx0uckWy.js} +1 -1
- package/dist/client/assets/{diagram-OA4YK3LP-DUT1bEEW.js → diagram-OA4YK3LP-D5hbO3ke.js} +1 -1
- package/dist/client/assets/{diagram-WEI45ONY-Hzq15wub.js → diagram-WEI45ONY-DpBP-0oQ.js} +1 -1
- package/dist/client/assets/{ebnfDiagram-CCIWWBDH-BAywDP6W.js → ebnfDiagram-CCIWWBDH-DlWAndW4.js} +1 -1
- package/dist/client/assets/{erDiagram-Q63AITRT-B48EkAYi.js → erDiagram-Q63AITRT-Bigvvv40.js} +1 -1
- package/dist/client/assets/{flowDiagram-23GEKE2U-DMm-ZzDO.js → flowDiagram-23GEKE2U-HJ2jxf9M.js} +1 -1
- package/dist/client/assets/{ganttDiagram-NO4QXBWP-BQ-7Srcw.js → ganttDiagram-NO4QXBWP-ipKqpn0t.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-IHSO6WYX-BFmdjMso.js → gitGraphDiagram-IHSO6WYX-DBkaSbhB.js} +1 -1
- package/dist/client/assets/{index-uR9bCvK3.js → index-BH2cm4bW.js} +32 -32
- package/dist/client/assets/index-DF1hQ7NF.css +1 -0
- package/dist/client/assets/{infoDiagram-FWYZ7A6U-Bq5fgLNO.js → infoDiagram-FWYZ7A6U-DV7Vstzf.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-DmLvJJcG.js → ishikawaDiagram-FXEZZL3T-Doar0fdM.js} +1 -1
- package/dist/client/assets/{journeyDiagram-5HDEW3XC-BEiSOBlj.js → journeyDiagram-5HDEW3XC-DJF-AHMR.js} +1 -1
- package/dist/client/assets/{kanban-definition-HUTT4EX6-tMWJSPAz.js → kanban-definition-HUTT4EX6-DOMPu4eG.js} +1 -1
- package/dist/client/assets/{linear-OUqi4t3W.js → linear-CncZrcBd.js} +1 -1
- package/dist/client/assets/{mermaid.core-D4Ax3qLz.js → mermaid.core-BGdwVdTT.js} +4 -4
- package/dist/client/assets/{mindmap-definition-LN4V7U3C-Dvz7Ium8.js → mindmap-definition-LN4V7U3C-Dx2SDF8J.js} +1 -1
- package/dist/client/assets/{pegDiagram-2B236MQR-Bkq7I7zD.js → pegDiagram-2B236MQR-CHGsPWYg.js} +1 -1
- package/dist/client/assets/{pieDiagram-ENE6RG2P-BbeI6TNI.js → pieDiagram-ENE6RG2P-CqsHXeDH.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-BuzU3JxG.js → quadrantDiagram-ABIIQ3AL-Db61n-HD.js} +1 -1
- package/dist/client/assets/{railroadDiagram-RFXS5EU6-Bh48nt62.js → railroadDiagram-RFXS5EU6-DJH0mG1M.js} +1 -1
- package/dist/client/assets/{requirementDiagram-TGXJPOKE-D6K-3boL.js → requirementDiagram-TGXJPOKE-BZ_At6m6.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-HTMAVEWB-xJQM56y0.js → sankeyDiagram-HTMAVEWB-CsNxLNrA.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-CkiaqqKF.js → sequenceDiagram-DBY2YBRQ-qnZzQ6rT.js} +1 -1
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-BRq8N0Fv.js → sizeCapture-X5ZJPWSS-BMeAZbXl.js} +1 -1
- package/dist/client/assets/{stateDiagram-2N3HPSRC-O9EoMMzY.js → stateDiagram-2N3HPSRC-BlnkxwAF.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-D7FRP5LD.js +1 -0
- package/dist/client/assets/{swimlanes-5IMT3BWC-BD_Or2Wo.js → swimlanes-5IMT3BWC-BcKd981V.js} +2 -2
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-6XCfgXZ4.js +8 -0
- package/dist/client/assets/{timeline-definition-FHXFAJF6-Dmdy1Wn0.js → timeline-definition-FHXFAJF6-m8_M9iJb.js} +1 -1
- package/dist/client/assets/{vennDiagram-L72KCM5P-BnaYCKIs.js → vennDiagram-L72KCM5P-QUhrT66B.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-EHGQE667-Vmk5-bqO.js → wardleyDiagram-EHGQE667-Bkj5mPbW.js} +1 -1
- package/dist/client/assets/{xychartDiagram-FW5EYKEG-B4t6sTC6.js → xychartDiagram-FW5EYKEG-CJTY9c9m.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/client/sw.js +1 -1
- package/dist/server/cli.js +348 -1
- package/dist/server/routes/terminal.js +8 -2
- package/package.json +1 -1
- package/dist/client/assets/channel-CD9EYHvd.js +0 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-D46YHcok.js +0 -1
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-D46YHcok.js +0 -1
- package/dist/client/assets/index-DgG9nafK.css +0 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-B8vFTMC3.js +0 -1
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-Bs0H1_c3.js +0 -8
package/dist/server/cli.js
CHANGED
|
@@ -147,10 +147,22 @@ Options:
|
|
|
147
147
|
Print one hunk's diff/context by Termdock hunk ID.
|
|
148
148
|
--change-audit-explain <id> [cwd]
|
|
149
149
|
Read a natural-language explanation from stdin and inject
|
|
150
|
-
|
|
150
|
+
it for the specified Termdock hunk ID.
|
|
151
|
+
--plugin-init Print the agent plugin manifest schema reference
|
|
152
|
+
--plugin-create <file>
|
|
153
|
+
Create a plugin from a manifest JSON file
|
|
154
|
+
--plugin-list List installed agent plugins
|
|
155
|
+
--plugin-remove <slug>
|
|
156
|
+
Remove an installed agent plugin
|
|
151
157
|
-h, --help Show this help message
|
|
152
158
|
|
|
153
159
|
Short commands:
|
|
160
|
+
pi Same as --plugin-init
|
|
161
|
+
plugin-create <file>
|
|
162
|
+
Same as --plugin-create <file>
|
|
163
|
+
plugin-list Same as --plugin-list
|
|
164
|
+
plugin-remove <slug>
|
|
165
|
+
Same as --plugin-remove <slug>
|
|
154
166
|
s Same as --status
|
|
155
167
|
st Same as --status
|
|
156
168
|
x Same as --stop
|
|
@@ -466,6 +478,10 @@ function parseArgs(argv) {
|
|
|
466
478
|
let changeAuditList;
|
|
467
479
|
let changeAuditShow;
|
|
468
480
|
let injectChangeAuditHunk;
|
|
481
|
+
let pluginInit = false;
|
|
482
|
+
let pluginCreate;
|
|
483
|
+
let pluginList = false;
|
|
484
|
+
let pluginRemove;
|
|
469
485
|
// Short command aliases for the common path. Keep these positional-only so
|
|
470
486
|
// long-form flags remain the single source of truth for option semantics.
|
|
471
487
|
if (argv[0] && !argv[0].startsWith('-')) {
|
|
@@ -561,6 +577,34 @@ function parseArgs(argv) {
|
|
|
561
577
|
injectChangeAuditHunk = { id: next, cwd };
|
|
562
578
|
argv = argv.slice(cwd ? 3 : 2);
|
|
563
579
|
}
|
|
580
|
+
else if (command === 'pi' || command === 'plugin-init') {
|
|
581
|
+
pluginInit = true;
|
|
582
|
+
argv = argv.slice(1);
|
|
583
|
+
}
|
|
584
|
+
else if (command === 'pcreate' || command === 'plugin-create') {
|
|
585
|
+
if (next && !next.startsWith('-')) {
|
|
586
|
+
pluginCreate = next;
|
|
587
|
+
argv = argv.slice(2);
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
pluginCreate = undefined;
|
|
591
|
+
argv = argv.slice(1);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
else if (command === 'pinfo' || command === 'plugin-list') {
|
|
595
|
+
pluginList = true;
|
|
596
|
+
argv = argv.slice(1);
|
|
597
|
+
}
|
|
598
|
+
else if (command === 'premove' || command === 'plugin-remove') {
|
|
599
|
+
if (next && !next.startsWith('-')) {
|
|
600
|
+
pluginRemove = next;
|
|
601
|
+
argv = argv.slice(2);
|
|
602
|
+
}
|
|
603
|
+
else {
|
|
604
|
+
pluginRemove = undefined;
|
|
605
|
+
argv = argv.slice(1);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
564
608
|
}
|
|
565
609
|
for (let index = 0; index < argv.length; index += 1) {
|
|
566
610
|
const arg = argv[index];
|
|
@@ -737,6 +781,36 @@ function parseArgs(argv) {
|
|
|
737
781
|
index += cwd ? 2 : 1;
|
|
738
782
|
continue;
|
|
739
783
|
}
|
|
784
|
+
if (arg === '--plugin-init') {
|
|
785
|
+
pluginInit = true;
|
|
786
|
+
continue;
|
|
787
|
+
}
|
|
788
|
+
if (arg === '--plugin-create') {
|
|
789
|
+
const next = argv[index + 1];
|
|
790
|
+
if (next && !next.startsWith('-')) {
|
|
791
|
+
pluginCreate = next;
|
|
792
|
+
index += 1;
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
pluginCreate = undefined;
|
|
796
|
+
}
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
if (arg === '--plugin-list') {
|
|
800
|
+
pluginList = true;
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
if (arg === '--plugin-remove') {
|
|
804
|
+
const next = argv[index + 1];
|
|
805
|
+
if (next && !next.startsWith('-')) {
|
|
806
|
+
pluginRemove = next;
|
|
807
|
+
index += 1;
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
pluginRemove = undefined;
|
|
811
|
+
}
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
740
814
|
if (!arg.startsWith('-')) {
|
|
741
815
|
if (attachTmux && !attachTmuxName) {
|
|
742
816
|
attachTmuxName = arg;
|
|
@@ -778,6 +852,10 @@ function parseArgs(argv) {
|
|
|
778
852
|
changeAuditList,
|
|
779
853
|
changeAuditShow,
|
|
780
854
|
injectChangeAuditHunk,
|
|
855
|
+
pluginInit,
|
|
856
|
+
pluginCreate,
|
|
857
|
+
pluginList,
|
|
858
|
+
pluginRemove,
|
|
781
859
|
};
|
|
782
860
|
}
|
|
783
861
|
// Reads a single line from stdin without echoing keystrokes. Used for password
|
|
@@ -936,6 +1014,32 @@ async function postLocalJson(baseUrl, token, endpoint, payload) {
|
|
|
936
1014
|
req.end();
|
|
937
1015
|
});
|
|
938
1016
|
}
|
|
1017
|
+
async function getLocalJson(baseUrl, token, endpoint) {
|
|
1018
|
+
const url = new URL(endpoint, baseUrl);
|
|
1019
|
+
const isHttps = url.protocol === 'https:';
|
|
1020
|
+
const requestImpl = isHttps ? https.request : http.request;
|
|
1021
|
+
const ca = isHttps && fs.existsSync(defaultHttpsCaPath) ? fs.readFileSync(defaultHttpsCaPath) : undefined;
|
|
1022
|
+
return new Promise((resolve, reject) => {
|
|
1023
|
+
const req = requestImpl({
|
|
1024
|
+
protocol: url.protocol,
|
|
1025
|
+
hostname: url.hostname,
|
|
1026
|
+
port: url.port,
|
|
1027
|
+
path: `${url.pathname}${url.search}`,
|
|
1028
|
+
method: 'GET',
|
|
1029
|
+
ca,
|
|
1030
|
+
headers: {
|
|
1031
|
+
'X-Termdock-Local-Token': token,
|
|
1032
|
+
},
|
|
1033
|
+
}, (res) => {
|
|
1034
|
+
let responseBody = '';
|
|
1035
|
+
res.setEncoding('utf8');
|
|
1036
|
+
res.on('data', (chunk) => { responseBody += chunk; });
|
|
1037
|
+
res.on('end', () => resolve({ statusCode: res.statusCode ?? 0, body: responseBody }));
|
|
1038
|
+
});
|
|
1039
|
+
req.on('error', reject);
|
|
1040
|
+
req.end();
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
939
1043
|
async function runInjectChangeAudit(source) {
|
|
940
1044
|
const raw = source === true
|
|
941
1045
|
? await readStdinText()
|
|
@@ -1476,6 +1580,225 @@ async function runInjectChangeAuditHunk(request) {
|
|
|
1476
1580
|
};
|
|
1477
1581
|
await postChangeAuditPayload(payload);
|
|
1478
1582
|
}
|
|
1583
|
+
// ── Agent plugin CLI commands ──
|
|
1584
|
+
function resolveServerBaseUrl(state) {
|
|
1585
|
+
return state.localUrl ?? `${state.scheme ?? 'http'}://${state.host === '0.0.0.0' ? 'localhost' : state.host}:${state.port}`;
|
|
1586
|
+
}
|
|
1587
|
+
function requireRunningServer() {
|
|
1588
|
+
const state = getRunningState();
|
|
1589
|
+
if (!state) {
|
|
1590
|
+
console.error(`${ICON.err} ${c.red('Termdock is not running. Start it first: td')}`);
|
|
1591
|
+
process.exit(1);
|
|
1592
|
+
}
|
|
1593
|
+
const token = state.localApiToken;
|
|
1594
|
+
if (!token) {
|
|
1595
|
+
console.error(`${ICON.err} ${c.red('Running server has no local API token. Restart Termdock first.')}`);
|
|
1596
|
+
process.exit(1);
|
|
1597
|
+
}
|
|
1598
|
+
return { baseUrl: resolveServerBaseUrl(state), token };
|
|
1599
|
+
}
|
|
1600
|
+
function runPluginInit() {
|
|
1601
|
+
console.log(`\
|
|
1602
|
+
${c.bold('Agent Plugin Reference')}
|
|
1603
|
+
${c.dim('─────────────────────')}
|
|
1604
|
+
|
|
1605
|
+
A plugin is a directory under ${c.cyan('~/.termdock/agent-plugins/<slug>/')} containing:
|
|
1606
|
+
|
|
1607
|
+
${c.cyan('manifest.json')} required – agent identity, hooks, and resume config
|
|
1608
|
+
${c.cyan('icon.svg')} optional – brand icon (rendered as mask silhouette or native)
|
|
1609
|
+
|
|
1610
|
+
${c.bold('manifest.json schema')}
|
|
1611
|
+
${c.dim('───────────────────')}
|
|
1612
|
+
|
|
1613
|
+
{
|
|
1614
|
+
${c.dim('// Manifest version. Must be')} ${c.green('1')}${c.dim('.')}
|
|
1615
|
+
"version": 1,
|
|
1616
|
+
|
|
1617
|
+
${c.dim('// Unique slug (lowercase alphanum + hyphens, max 40 chars).')}
|
|
1618
|
+
${c.dim('// Must not collide with built-in agent slugs.')}
|
|
1619
|
+
"slug": "trae",
|
|
1620
|
+
|
|
1621
|
+
${c.dim('// Human-readable label shown in tabs and settings.')}
|
|
1622
|
+
"displayName": "Trae Agent",
|
|
1623
|
+
|
|
1624
|
+
${c.dim('// Command names that identify this agent at runtime.')}
|
|
1625
|
+
${c.dim('// First alias is the primary binary name; extras match npm/pip wrappers.')}
|
|
1626
|
+
"aliases": ["trae", "traecli"],
|
|
1627
|
+
|
|
1628
|
+
${c.dim('// Brand accent color as 6-digit hex. Used for avatar background in mask mode,')}
|
|
1629
|
+
${c.dim('// and as the status-dot color. Must be Flexoki-family or brand theme-safe.')}
|
|
1630
|
+
"accentColor": "#4385BE",
|
|
1631
|
+
|
|
1632
|
+
${c.dim('// ── optional ──')}
|
|
1633
|
+
${c.dim('// Icon rendering mode (default "mask"):')}
|
|
1634
|
+
${c.dim('// "mask" - SVG is a white-on-accent silhouette (CSS mask). Mono-color.')}
|
|
1635
|
+
${c.dim('// "native" - SVG rendered directly, preserving original fills/gradients.')}
|
|
1636
|
+
"iconMode": "native",
|
|
1637
|
+
|
|
1638
|
+
${c.dim('// ── optional: hook installation (bring your own hooks.json surface) ──')}
|
|
1639
|
+
"hooks": {
|
|
1640
|
+
${c.dim("// Path to the agent's hooks config file (~-abbreviated).")}
|
|
1641
|
+
${c.dim('// termdock inserts marker-carrying entries; leaves user entries untouched.')}
|
|
1642
|
+
"target": "~/.trae/settings.json",
|
|
1643
|
+
|
|
1644
|
+
${c.dim('// Event mappings: agent-native hook name → termdock sentinel event.')}
|
|
1645
|
+
${c.dim('// Optional matcher narrows the subscription (e.g. permission type).')}
|
|
1646
|
+
"events": [
|
|
1647
|
+
{ "hook": "SessionStart", "event": "session-start" },
|
|
1648
|
+
{ "hook": "UserPromptSubmit", "event": "prompt-submit" },
|
|
1649
|
+
{ "hook": "Notification", "event": "notification", "matcher": "elicitation_dialog" },
|
|
1650
|
+
{ "hook": "PostToolUse", "event": "tool-complete" },
|
|
1651
|
+
{ "hook": "Stop", "event": "stop" },
|
|
1652
|
+
{ "hook": "SessionEnd", "event": "session-end" }
|
|
1653
|
+
]
|
|
1654
|
+
},
|
|
1655
|
+
|
|
1656
|
+
${c.dim('// ── optional: resume command (for session picker re-entry) ──')}
|
|
1657
|
+
"resume": {
|
|
1658
|
+
${c.dim('// Shell command template. {sessionId} is replaced with the native session id.')}
|
|
1659
|
+
"command": "trae --resume {sessionId}",
|
|
1660
|
+
${c.dim('// Flags to strip from the original launch argv when replaying the resume.')}
|
|
1661
|
+
"staleFlags": ["--resume", "-r", "--session-id", "--continue"]
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
${c.bold('Sentinel event kinds')}
|
|
1666
|
+
${c.dim('─────────────────────')}
|
|
1667
|
+
|
|
1668
|
+
session-start Agent session opened (binary started / first prompt)
|
|
1669
|
+
prompt-submit A new prompt/turn was submitted
|
|
1670
|
+
permission-request Agent is blocked waiting for a tool-permission grant
|
|
1671
|
+
question-asked Agent asked the user a question (elicitation dialog)
|
|
1672
|
+
tool-complete A tool execution completed (unblocks waiting state)
|
|
1673
|
+
notification Generic notification from the agent (heuristic gated)
|
|
1674
|
+
stop Agent turn finished / went idle
|
|
1675
|
+
session-end Agent session closed / binary exited
|
|
1676
|
+
|
|
1677
|
+
${c.bold('Creating a plugin')}
|
|
1678
|
+
${c.dim('──────────────────')}
|
|
1679
|
+
|
|
1680
|
+
# 1. Create the plugin directory with manifest + icon
|
|
1681
|
+
mkdir -p ~/.termdock/agent-plugins/trae
|
|
1682
|
+
cp manifest.json icon.svg ~/.termdock/agent-plugins/trae/
|
|
1683
|
+
|
|
1684
|
+
${c.dim('# 2. Install the plugin via CLI (needs running server)')}
|
|
1685
|
+
td plugin-create ~/.termdock/agent-plugins/trae/manifest.json
|
|
1686
|
+
|
|
1687
|
+
${c.dim('# 3. Or create directly from the manifest JSON')}
|
|
1688
|
+
td plugin-create ./trae-manifest.json
|
|
1689
|
+
|
|
1690
|
+
${c.dim('# 4. List installed plugins')}
|
|
1691
|
+
td plugin-list
|
|
1692
|
+
|
|
1693
|
+
${c.dim('# 5. Remove a plugin')}
|
|
1694
|
+
td plugin-remove trae
|
|
1695
|
+
|
|
1696
|
+
${c.bold('Manifest validation at startup')}
|
|
1697
|
+
${c.dim('───────────────────────────────')}
|
|
1698
|
+
|
|
1699
|
+
Termdock validates every plugin manifest on server start. Errors are logged
|
|
1700
|
+
to ${c.cyan('~/.termdock/server.log')} and visible via ${c.cyan('td plugin-list')}${c.dim('.')}
|
|
1701
|
+
Slugs/aliases that collide with built-in agents are skipped.
|
|
1702
|
+
`);
|
|
1703
|
+
}
|
|
1704
|
+
async function runPluginCreate(manifestPath) {
|
|
1705
|
+
const resolved = path.resolve(manifestPath);
|
|
1706
|
+
let raw;
|
|
1707
|
+
try {
|
|
1708
|
+
raw = fs.readFileSync(resolved, 'utf8');
|
|
1709
|
+
}
|
|
1710
|
+
catch {
|
|
1711
|
+
console.error(`${ICON.err} ${c.red(`Cannot read manifest file: ${resolved}`)}`);
|
|
1712
|
+
process.exit(1);
|
|
1713
|
+
}
|
|
1714
|
+
let manifest;
|
|
1715
|
+
try {
|
|
1716
|
+
manifest = JSON.parse(raw);
|
|
1717
|
+
}
|
|
1718
|
+
catch (error) {
|
|
1719
|
+
console.error(`${ICON.err} ${c.red(`Invalid JSON in ${resolved}: ${error.message}`)}`);
|
|
1720
|
+
process.exit(1);
|
|
1721
|
+
}
|
|
1722
|
+
const { baseUrl, token } = requireRunningServer();
|
|
1723
|
+
const response = await postLocalJson(baseUrl, token, '/api/terminal/agent-plugins', manifest);
|
|
1724
|
+
const body = JSON.parse(response.body || '{}');
|
|
1725
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
1726
|
+
console.error(`${ICON.err} ${c.red(body.error || 'Failed to create plugin')}`);
|
|
1727
|
+
process.exit(1);
|
|
1728
|
+
}
|
|
1729
|
+
console.log(`${ICON.ok} ${c.green(`Plugin "${body.slug}" created.`)}`);
|
|
1730
|
+
console.log(` ${c.dim('Directory:')} ${c.cyan(body.dir ?? resolved)}`);
|
|
1731
|
+
console.log(` ${c.dim('Restart Termdock to activate:')} ${c.cyan('td --stop && td')}`);
|
|
1732
|
+
}
|
|
1733
|
+
async function runPluginList() {
|
|
1734
|
+
const { baseUrl, token } = requireRunningServer();
|
|
1735
|
+
const response = await getLocalJson(baseUrl, token, '/api/terminal/agent-plugins');
|
|
1736
|
+
const body = JSON.parse(response.body || '{}');
|
|
1737
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
1738
|
+
console.error(`${ICON.err} ${c.red('Failed to list plugins')}`);
|
|
1739
|
+
process.exit(1);
|
|
1740
|
+
}
|
|
1741
|
+
const plugins = body.plugins ?? [];
|
|
1742
|
+
if (plugins.length === 0) {
|
|
1743
|
+
console.log(`${c.dim('No plugins installed.')}`);
|
|
1744
|
+
console.log(` ${c.dim('See:')} ${c.cyan('td plugin-init')}`);
|
|
1745
|
+
}
|
|
1746
|
+
else {
|
|
1747
|
+
console.log(`${c.bold('Installed plugins')} ${c.dim(`(${plugins.length})`)}`);
|
|
1748
|
+
console.log('');
|
|
1749
|
+
for (const p of plugins) {
|
|
1750
|
+
const flags = [];
|
|
1751
|
+
if (p.hasIcon)
|
|
1752
|
+
flags.push('icon');
|
|
1753
|
+
if (p.hasHooks)
|
|
1754
|
+
flags.push('hooks');
|
|
1755
|
+
if (p.hasResume)
|
|
1756
|
+
flags.push('resume');
|
|
1757
|
+
if (p.iconMode !== 'mask')
|
|
1758
|
+
flags.push(p.iconMode);
|
|
1759
|
+
console.log(` ${c.cyan(p.slug)} ${c.dim(p.displayName)} ${c.gray(p.accentColor)} ${c.dim(flags.length > 0 ? `[${flags.join(', ')}]` : '')}`);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
const errors = body.errors ?? [];
|
|
1763
|
+
if (errors.length > 0) {
|
|
1764
|
+
console.log('');
|
|
1765
|
+
console.log(`${c.yellow('Validation errors')}`);
|
|
1766
|
+
for (const e of errors) {
|
|
1767
|
+
console.log(` ${c.red('✗')} ${c.cyan(e.slug)}${c.dim(':')} ${e.errors.join('; ')}`);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
async function runPluginRemove(slug) {
|
|
1772
|
+
const { baseUrl, token } = requireRunningServer();
|
|
1773
|
+
const response = await new Promise((resolve, reject) => {
|
|
1774
|
+
const url = new URL(`/api/terminal/agent-plugins/${encodeURIComponent(slug)}`, baseUrl);
|
|
1775
|
+
const isHttps = url.protocol === 'https:';
|
|
1776
|
+
const requestImpl = isHttps ? https.request : http.request;
|
|
1777
|
+
const ca = isHttps && fs.existsSync(defaultHttpsCaPath) ? fs.readFileSync(defaultHttpsCaPath) : undefined;
|
|
1778
|
+
const req = requestImpl({
|
|
1779
|
+
protocol: url.protocol,
|
|
1780
|
+
hostname: url.hostname,
|
|
1781
|
+
port: url.port,
|
|
1782
|
+
path: url.pathname,
|
|
1783
|
+
method: 'DELETE',
|
|
1784
|
+
ca,
|
|
1785
|
+
headers: { 'X-Termdock-Local-Token': token },
|
|
1786
|
+
}, (res) => {
|
|
1787
|
+
let responseBody = '';
|
|
1788
|
+
res.setEncoding('utf8');
|
|
1789
|
+
res.on('data', (chunk) => { responseBody += chunk; });
|
|
1790
|
+
res.on('end', () => resolve({ statusCode: res.statusCode ?? 0, body: responseBody }));
|
|
1791
|
+
});
|
|
1792
|
+
req.on('error', reject);
|
|
1793
|
+
req.end();
|
|
1794
|
+
});
|
|
1795
|
+
const body = JSON.parse(response.body || '{}');
|
|
1796
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
1797
|
+
console.error(`${ICON.err} ${c.red(body.error || `Failed to remove plugin "${slug}"`)}`);
|
|
1798
|
+
process.exit(1);
|
|
1799
|
+
}
|
|
1800
|
+
console.log(`${ICON.ok} ${c.green(`Plugin "${body.slug ?? slug}" removed.`)}`);
|
|
1801
|
+
}
|
|
1479
1802
|
const options = parseArgs(process.argv.slice(2));
|
|
1480
1803
|
if (options.setPassword && options.clearPassword) {
|
|
1481
1804
|
console.error(`${ICON.err} ${c.red('Cannot use --set-password and --clear-password together.')}`);
|
|
@@ -2375,6 +2698,30 @@ async function main() {
|
|
|
2375
2698
|
runClearPassword();
|
|
2376
2699
|
process.exit(0);
|
|
2377
2700
|
}
|
|
2701
|
+
if (options.pluginInit) {
|
|
2702
|
+
runPluginInit();
|
|
2703
|
+
process.exit(0);
|
|
2704
|
+
}
|
|
2705
|
+
if (options.pluginCreate !== undefined) {
|
|
2706
|
+
if (!options.pluginCreate) {
|
|
2707
|
+
console.error(`${ICON.err} ${c.red('plugin-create requires a manifest file path')}`);
|
|
2708
|
+
process.exit(1);
|
|
2709
|
+
}
|
|
2710
|
+
await runPluginCreate(options.pluginCreate);
|
|
2711
|
+
process.exit(0);
|
|
2712
|
+
}
|
|
2713
|
+
if (options.pluginList) {
|
|
2714
|
+
await runPluginList();
|
|
2715
|
+
process.exit(0);
|
|
2716
|
+
}
|
|
2717
|
+
if (options.pluginRemove !== undefined) {
|
|
2718
|
+
if (!options.pluginRemove) {
|
|
2719
|
+
console.error(`${ICON.err} ${c.red('plugin-remove requires a plugin slug')}`);
|
|
2720
|
+
process.exit(1);
|
|
2721
|
+
}
|
|
2722
|
+
await runPluginRemove(options.pluginRemove);
|
|
2723
|
+
process.exit(0);
|
|
2724
|
+
}
|
|
2378
2725
|
const localApiToken = getOrCreateLocalApiToken();
|
|
2379
2726
|
await refreshDefaultHttpsCertificateSafely();
|
|
2380
2727
|
const https = resolveHttpsOptions(options);
|
|
@@ -4573,8 +4573,14 @@ router.get('/:sessionId/health', (req, res) => {
|
|
|
4573
4573
|
const { sessionId } = req.params;
|
|
4574
4574
|
const session = terminalSessions.get(sessionId);
|
|
4575
4575
|
if (!session) {
|
|
4576
|
-
|
|
4577
|
-
|
|
4576
|
+
// TD 重启后 terminalSessions 清空,但从 globalSessionState(持久化到磁盘)
|
|
4577
|
+
// 可恢复 mode / tmuxSessionName,避免前端把 tmux 会话误重建为 shell。
|
|
4578
|
+
const persistedRecord = globalSessionState.sessions.find((s) => s.backendSessionId === sessionId) ?? null;
|
|
4579
|
+
const recovered = persistedRecord
|
|
4580
|
+
? { mode: persistedRecord.mode, tmuxSessionName: persistedRecord.tmuxSessionName }
|
|
4581
|
+
: {};
|
|
4582
|
+
console.log(`Health check: session ${sessionId} not found${persistedRecord ? `, recovered mode=${persistedRecord.mode} from persisted state` : ''}`);
|
|
4583
|
+
return res.status(404).json({ healthy: false, error: 'Session not found', ...recovered });
|
|
4578
4584
|
}
|
|
4579
4585
|
console.log(`Health check: session ${sessionId} healthy, cwd=${session.cwd}, clients=${getTotalClients(sessionId)}, lastActivity=${Date.now() - session.lastActivity}ms ago`);
|
|
4580
4586
|
res.json({
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,C as n}from"./mermaid.core-D4Ax3qLz.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as t,C as e}from"./chunk-V7JOEXUC-UyB55Fb4.js";import{b as i}from"./mermaid.core-D4Ax3qLz.js";import"./chunk-5VM5RSS4-D48bXYje.js";import"./chunk-XXDRQBXY-DwM4iNfy.js";import"./chunk-VR4S4FIN-C-xnKkZn.js";import"./chunk-32BRIVSS-BbMLiuF9.js";import"./purify.es-CC4Brkr_.js";import"./index-uR9bCvK3.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as t,C as e}from"./chunk-V7JOEXUC-UyB55Fb4.js";import{b as i}from"./mermaid.core-D4Ax3qLz.js";import"./chunk-5VM5RSS4-D48bXYje.js";import"./chunk-XXDRQBXY-DwM4iNfy.js";import"./chunk-VR4S4FIN-C-xnKkZn.js";import"./chunk-32BRIVSS-BbMLiuF9.js";import"./purify.es-CC4Brkr_.js";import"./index-uR9bCvK3.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
|