lark-coding-assistant 0.1.2 → 0.2.0
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/README.md +68 -46
- package/bin/lca.mjs +2 -0
- package/dist/cli.js +187 -35
- package/dist/cli.js.map +1 -1
- package/dist/daemon-entry.js +1786 -181
- package/dist/daemon-entry.js.map +1 -1
- package/dist/hook-entry.js +22 -3
- package/dist/hook-entry.js.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/cli.ts
|
|
2
2
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
3
|
-
import {
|
|
3
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
4
4
|
import { spawn as spawn3 } from "child_process";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { resolve } from "path";
|
|
@@ -64,6 +64,14 @@ async function writeJsonAtomic(path, value, mode = 384) {
|
|
|
64
64
|
await chmod(path, mode);
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
// src/agents/types.ts
|
|
68
|
+
var AGENT_IDS = ["codex", "traex", "claude"];
|
|
69
|
+
function normalizeAgentId(value) {
|
|
70
|
+
if (value === "trae-cli") return "traex";
|
|
71
|
+
if (value === "claude-code") return "claude";
|
|
72
|
+
return AGENT_IDS.includes(value) ? value : void 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
// src/core/store.ts
|
|
68
76
|
var AppStore = class {
|
|
69
77
|
constructor(paths2) {
|
|
@@ -80,8 +88,21 @@ var AppStore = class {
|
|
|
80
88
|
chmod2(this.paths.logsDir, 448)
|
|
81
89
|
]);
|
|
82
90
|
}
|
|
83
|
-
loadConfig() {
|
|
84
|
-
|
|
91
|
+
async loadConfig() {
|
|
92
|
+
const config = await readJson(this.paths.config);
|
|
93
|
+
if (!config) return void 0;
|
|
94
|
+
const binaries = config.agentBinaries ?? {};
|
|
95
|
+
return {
|
|
96
|
+
tenant: config.tenant,
|
|
97
|
+
appId: config.appId,
|
|
98
|
+
tmuxBinary: config.tmuxBinary,
|
|
99
|
+
agentBinaries: {
|
|
100
|
+
codex: binaries.codex ?? "codex",
|
|
101
|
+
traex: binaries.traex ?? binaries["trae-cli"] ?? "trae-cli",
|
|
102
|
+
claude: binaries.claude ?? binaries["claude-code"] ?? "claude"
|
|
103
|
+
},
|
|
104
|
+
pollIntervalMs: config.pollIntervalMs
|
|
105
|
+
};
|
|
85
106
|
}
|
|
86
107
|
saveConfig(config) {
|
|
87
108
|
return writeJsonAtomic(this.paths.config, config);
|
|
@@ -93,7 +114,13 @@ var AppStore = class {
|
|
|
93
114
|
return writeJsonAtomic(this.paths.secrets, secrets);
|
|
94
115
|
}
|
|
95
116
|
async loadState() {
|
|
96
|
-
|
|
117
|
+
const state = await readJson(this.paths.state);
|
|
118
|
+
if (!state) return emptyState();
|
|
119
|
+
const sessions = Object.fromEntries(Object.entries(state.sessions ?? {}).flatMap(([id, session]) => {
|
|
120
|
+
const agent = normalizeAgentId(session.agent);
|
|
121
|
+
return agent ? [[id, { ...session, agent }]] : [];
|
|
122
|
+
}));
|
|
123
|
+
return { ...state, sessions };
|
|
97
124
|
}
|
|
98
125
|
saveState(state) {
|
|
99
126
|
return writeJsonAtomic(this.paths.state, state);
|
|
@@ -198,7 +225,7 @@ function resolveResumeOption(options) {
|
|
|
198
225
|
const modes = [options.resume !== void 0, options.resumeLast, options.resumeAll].filter(Boolean).length;
|
|
199
226
|
if (modes > 1) {
|
|
200
227
|
throw new AppError(
|
|
201
|
-
"
|
|
228
|
+
"INVALID_RESUME",
|
|
202
229
|
"--resume, --resume-last, and --resume-all cannot be used together",
|
|
203
230
|
{ reason: "--resume\u3001--resume-last \u548C --resume-all \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528" }
|
|
204
231
|
);
|
|
@@ -252,12 +279,12 @@ var CODEX_DIALECT = {
|
|
|
252
279
|
};
|
|
253
280
|
var TRAE_DIALECT = {
|
|
254
281
|
...CODEX_DIALECT,
|
|
255
|
-
id: "
|
|
282
|
+
id: "traex",
|
|
256
283
|
headerPatterns: [...commonHeaders, /^\s*Question\s+\d+\/\d+/i],
|
|
257
284
|
customInputControls: [/^(?:other|none of the above|add notes)$/i]
|
|
258
285
|
};
|
|
259
286
|
var CLAUDE_DIALECT = {
|
|
260
|
-
id: "claude
|
|
287
|
+
id: "claude",
|
|
261
288
|
headerPatterns: [
|
|
262
289
|
...commonHeaders,
|
|
263
290
|
/^\s*(?:←\s*)?[☐☑☒]\s+.+?(?:\s+✔\s+Submit\s*→)?\s*$/i,
|
|
@@ -591,11 +618,18 @@ function lastMatchingIndex(lines, pattern) {
|
|
|
591
618
|
// src/agents/stop-hook.ts
|
|
592
619
|
function codexStyleStopHookArgs(command) {
|
|
593
620
|
const hook = `{hooks=[{type="command",command=${JSON.stringify(command)},timeout=5}]}`;
|
|
594
|
-
return [
|
|
621
|
+
return [
|
|
622
|
+
"--dangerously-bypass-hook-trust",
|
|
623
|
+
"-c",
|
|
624
|
+
`hooks.SessionStart=[${hook}]`,
|
|
625
|
+
"-c",
|
|
626
|
+
`hooks.Stop=[${hook}]`
|
|
627
|
+
];
|
|
595
628
|
}
|
|
596
629
|
function claudeStopHookArgs(command) {
|
|
597
630
|
return ["--settings", JSON.stringify({
|
|
598
631
|
hooks: {
|
|
632
|
+
SessionStart: [{ hooks: [{ type: "command", command, timeout: 5 }] }],
|
|
599
633
|
Stop: [{ hooks: [{ type: "command", command, timeout: 5 }] }]
|
|
600
634
|
}
|
|
601
635
|
})];
|
|
@@ -604,7 +638,7 @@ function claudeStopHookArgs(command) {
|
|
|
604
638
|
// src/agents/codex.ts
|
|
605
639
|
var codexAdapter = {
|
|
606
640
|
id: "codex",
|
|
607
|
-
displayName: "
|
|
641
|
+
displayName: "codex",
|
|
608
642
|
groupOrder: 10,
|
|
609
643
|
binary: (config) => config.agentBinaries.codex,
|
|
610
644
|
versionArgs: ["--version"],
|
|
@@ -617,10 +651,10 @@ var codexAdapter = {
|
|
|
617
651
|
|
|
618
652
|
// src/agents/trae-cli.ts
|
|
619
653
|
var traeCliAdapter = {
|
|
620
|
-
id: "
|
|
621
|
-
displayName: "
|
|
654
|
+
id: "traex",
|
|
655
|
+
displayName: "traex",
|
|
622
656
|
groupOrder: 20,
|
|
623
|
-
binary: (config) => config.agentBinaries
|
|
657
|
+
binary: (config) => config.agentBinaries.traex,
|
|
624
658
|
versionArgs: ["--version"],
|
|
625
659
|
buildLaunchArgs: ({ resume, stopHookCommand }) => [
|
|
626
660
|
...codexStyleStopHookArgs(stopHookCommand),
|
|
@@ -631,10 +665,10 @@ var traeCliAdapter = {
|
|
|
631
665
|
|
|
632
666
|
// src/agents/claude-code.ts
|
|
633
667
|
var claudeCodeAdapter = {
|
|
634
|
-
id: "claude
|
|
635
|
-
displayName: "
|
|
668
|
+
id: "claude",
|
|
669
|
+
displayName: "claude",
|
|
636
670
|
groupOrder: 30,
|
|
637
|
-
binary: (config) => config.agentBinaries
|
|
671
|
+
binary: (config) => config.agentBinaries.claude,
|
|
638
672
|
versionArgs: ["--version"],
|
|
639
673
|
buildLaunchArgs: ({ resume, stopHookCommand }) => [
|
|
640
674
|
...claudeStopHookArgs(stopHookCommand),
|
|
@@ -643,9 +677,6 @@ var claudeCodeAdapter = {
|
|
|
643
677
|
detectScreen: detectClaudeScreen
|
|
644
678
|
};
|
|
645
679
|
|
|
646
|
-
// src/agents/types.ts
|
|
647
|
-
var AGENT_IDS = ["codex", "trae-cli", "claude-code"];
|
|
648
|
-
|
|
649
680
|
// src/agents/registry.ts
|
|
650
681
|
var adapters = /* @__PURE__ */ new Map([
|
|
651
682
|
[codexAdapter.id, codexAdapter],
|
|
@@ -657,9 +688,6 @@ function getAgentAdapter(id) {
|
|
|
657
688
|
if (!adapter) throw new Error(`unsupported coding agent: ${id}`);
|
|
658
689
|
return adapter;
|
|
659
690
|
}
|
|
660
|
-
function isAgentId(value) {
|
|
661
|
-
return AGENT_IDS.includes(value);
|
|
662
|
-
}
|
|
663
691
|
|
|
664
692
|
// src/daemon/lifecycle.ts
|
|
665
693
|
import { mkdir as mkdir3, open as open2, readFile as readFile2 } from "fs/promises";
|
|
@@ -676,6 +704,13 @@ async function daemonInfo(paths2, timeoutMs = 500) {
|
|
|
676
704
|
async function startDaemonProcess(paths2, daemonEntry, readyTimeoutMs = 5e3) {
|
|
677
705
|
const existing = await daemonInfo(paths2);
|
|
678
706
|
if (existing) return existing;
|
|
707
|
+
const health = await daemonHealth(paths2);
|
|
708
|
+
if (health.status === "running") return health.info;
|
|
709
|
+
if (health.status === "unresponsive") {
|
|
710
|
+
throw new AppError("DAEMON_UNRESPONSIVE", "daemon process is alive but its control socket is unresponsive", {
|
|
711
|
+
pid: health.pid
|
|
712
|
+
});
|
|
713
|
+
}
|
|
679
714
|
await Promise.all([
|
|
680
715
|
mkdir3(paths2.runtimeDir, { recursive: true, mode: 448 }),
|
|
681
716
|
mkdir3(paths2.logsDir, { recursive: true, mode: 448 })
|
|
@@ -701,6 +736,25 @@ async function startDaemonProcess(paths2, daemonEntry, readyTimeoutMs = 5e3) {
|
|
|
701
736
|
}
|
|
702
737
|
throw new Error("daemon did not become ready");
|
|
703
738
|
}
|
|
739
|
+
async function daemonHealth(paths2, probe = defaultHealthProbe) {
|
|
740
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
741
|
+
const info = await probe.ping(paths2, 400);
|
|
742
|
+
if (info) return { status: "running", info };
|
|
743
|
+
if (attempt < 2) await probe.wait(80);
|
|
744
|
+
}
|
|
745
|
+
const pid = await probe.readPid(paths2);
|
|
746
|
+
if (validPid(pid) && probe.processIsAlive(pid) && await probe.isCurrentDaemonProcess(pid)) {
|
|
747
|
+
return { status: "unresponsive", pid };
|
|
748
|
+
}
|
|
749
|
+
return { status: "stopped" };
|
|
750
|
+
}
|
|
751
|
+
var defaultHealthProbe = {
|
|
752
|
+
ping: daemonInfo,
|
|
753
|
+
readPid: async (paths2) => Number.parseInt(await readFile2(paths2.pid, "utf8").catch(() => ""), 10),
|
|
754
|
+
processIsAlive,
|
|
755
|
+
isCurrentDaemonProcess,
|
|
756
|
+
wait: delay
|
|
757
|
+
};
|
|
704
758
|
async function stopDaemonProcess(paths2) {
|
|
705
759
|
const info = await daemonInfo(paths2);
|
|
706
760
|
if (!info) return stopDaemonByPid(paths2);
|
|
@@ -794,6 +848,37 @@ function formatKnownError(error, context) {
|
|
|
794
848
|
` lark-coding-assistant attach ${sessionId}`,
|
|
795
849
|
" lark-coding-assistant start --name <\u65B0\u540D\u79F0>"
|
|
796
850
|
];
|
|
851
|
+
case "AGENT_SESSION_IN_USE": {
|
|
852
|
+
const ownerSessionId = safeValue(context.ownerSessionId, "\u73B0\u6709 session");
|
|
853
|
+
return [
|
|
854
|
+
`\u65E0\u6CD5\u542F\u52A8 session\u300C${sessionId}\u300D\uFF1A\u5BF9\u5E94\u7684 Agent \u539F\u751F session \u5DF2\u7531\u300C${ownerSessionId}\u300D\u8FDE\u63A5\u3002`,
|
|
855
|
+
"",
|
|
856
|
+
"\u8BF7\u76F4\u63A5\u8FDE\u63A5\u73B0\u6709 session\uFF1A",
|
|
857
|
+
` lark-coding-assistant attach ${ownerSessionId}`
|
|
858
|
+
];
|
|
859
|
+
}
|
|
860
|
+
case "AGENT_EXITED_DURING_STARTUP": {
|
|
861
|
+
const exitStatus = typeof context.exitStatus === "number" ? `\uFF08\u9000\u51FA\u7801 ${context.exitStatus}\uFF09` : "";
|
|
862
|
+
return [
|
|
863
|
+
`Agent \u542F\u52A8\u540E\u7ACB\u5373\u9000\u51FA${exitStatus}\uFF0Csession\u300C${sessionId}\u300D\u672A\u521B\u5EFA\u3002`,
|
|
864
|
+
"",
|
|
865
|
+
"\u539F\u59CB\u9519\u8BEF\uFF1A",
|
|
866
|
+
safeValue(context.terminalExcerpt, "Agent \u672A\u8F93\u51FA\u53EF\u7528\u9519\u8BEF\u4FE1\u606F\u3002"),
|
|
867
|
+
"",
|
|
868
|
+
"\u53EF\u67E5\u770B\u65E5\u5FD7\u6216\u6539\u4E3A\u542F\u52A8\u65B0\u4F1A\u8BDD\uFF1A",
|
|
869
|
+
" lark-coding-assistant logs",
|
|
870
|
+
` lark-coding-assistant start --name ${sessionId} --agent ${safeValue(context.agent, "codex")}`
|
|
871
|
+
];
|
|
872
|
+
}
|
|
873
|
+
case "AGENT_IDENTITY_TIMEOUT":
|
|
874
|
+
return [
|
|
875
|
+
`\u65E0\u6CD5\u786E\u8BA4\u6062\u590D\u76EE\u6807\uFF0Csession\u300C${sessionId}\u300D\u672A\u521B\u5EFA\u3002`,
|
|
876
|
+
"Agent \u4ECD\u5728\u8FD0\u884C\uFF0C\u4F46 LCA \u672A\u80FD\u8BC6\u522B\u539F\u751F session ID\u3002",
|
|
877
|
+
"",
|
|
878
|
+
"\u4E34\u65F6 tmux \u5DF2\u6E05\u7406\uFF0C\u8BF7\u67E5\u770B\u65E5\u5FD7\u540E\u91CD\u8BD5\u6216\u542F\u52A8\u65B0\u4F1A\u8BDD\uFF1A",
|
|
879
|
+
" lark-coding-assistant logs",
|
|
880
|
+
` lark-coding-assistant start --name ${sessionId} --agent ${safeValue(context.agent, "codex")}`
|
|
881
|
+
];
|
|
797
882
|
case "SESSION_NOT_FOUND":
|
|
798
883
|
return [
|
|
799
884
|
`\u627E\u4E0D\u5230 session\u300C${sessionId}\u300D\u3002`,
|
|
@@ -827,6 +912,19 @@ function formatKnownError(error, context) {
|
|
|
827
912
|
"",
|
|
828
913
|
"\u8BF7\u8FD0\u884C lark-coding-assistant --help \u67E5\u770B\u53EF\u7528\u53C2\u6570\u3002"
|
|
829
914
|
];
|
|
915
|
+
case "INVALID_RESUME":
|
|
916
|
+
return [
|
|
917
|
+
`\u6062\u590D\u53C2\u6570\u65E0\u6548\uFF1A${safeValue(context.reason, error.message)}`,
|
|
918
|
+
"",
|
|
919
|
+
"\u8BF7\u53EA\u9009\u62E9\u4E00\u79CD\u6062\u590D\u65B9\u5F0F\uFF0C\u5E76\u68C0\u67E5\u5386\u53F2 session ID\u3002"
|
|
920
|
+
];
|
|
921
|
+
case "START_FAILED":
|
|
922
|
+
return [
|
|
923
|
+
`\u65E0\u6CD5\u542F\u52A8 session\u300C${sessionId}\u300D\u3002`,
|
|
924
|
+
"",
|
|
925
|
+
"\u8BF7\u68C0\u67E5\u5DE5\u4F5C\u76EE\u5F55\u3001Agent \u5B89\u88C5\u548C daemon \u65E5\u5FD7\uFF1A",
|
|
926
|
+
" lark-coding-assistant logs"
|
|
927
|
+
];
|
|
830
928
|
case "DAEMON_UNAVAILABLE":
|
|
831
929
|
return [
|
|
832
930
|
"\u65E0\u6CD5\u8FDE\u63A5 bridge daemon\u3002",
|
|
@@ -835,6 +933,13 @@ function formatKnownError(error, context) {
|
|
|
835
933
|
" lark-coding-assistant daemon restart",
|
|
836
934
|
" lark-coding-assistant logs"
|
|
837
935
|
];
|
|
936
|
+
case "DAEMON_UNRESPONSIVE":
|
|
937
|
+
return [
|
|
938
|
+
"bridge daemon \u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF0C\u4F46\u63A7\u5236\u901A\u9053\u65E0\u54CD\u5E94\u3002",
|
|
939
|
+
"",
|
|
940
|
+
"\u8BF7\u91CD\u542F daemon\uFF1B\u73B0\u6709 coding-agent/tmux sessions \u4F1A\u4FDD\u7559\uFF1A",
|
|
941
|
+
" lark-coding-assistant daemon restart"
|
|
942
|
+
];
|
|
838
943
|
case "REQUEST_TIMEOUT":
|
|
839
944
|
return [
|
|
840
945
|
"bridge daemon \u672A\u53CA\u65F6\u54CD\u5E94\u3002",
|
|
@@ -888,6 +993,37 @@ function debugStack(error) {
|
|
|
888
993
|
return values.join("\nCaused by:\n");
|
|
889
994
|
}
|
|
890
995
|
|
|
996
|
+
// src/session/start-request.ts
|
|
997
|
+
import { stat } from "fs/promises";
|
|
998
|
+
import { isAbsolute } from "path";
|
|
999
|
+
async function validateStartSessionRequest(request) {
|
|
1000
|
+
if (!validSessionId(request.sessionId)) {
|
|
1001
|
+
throw new AppError(
|
|
1002
|
+
"INVALID_SESSION_NAME",
|
|
1003
|
+
"session name must use letters, digits, underscore, or dash",
|
|
1004
|
+
{ sessionId: request.sessionId }
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
if (!isAbsolute(request.cwd)) {
|
|
1008
|
+
throw new AppError("INVALID_CWD", "working directory must be absolute", { cwd: request.cwd });
|
|
1009
|
+
}
|
|
1010
|
+
const info = await stat(request.cwd).catch((error) => {
|
|
1011
|
+
throw new AppError("INVALID_CWD", `working directory is unavailable: ${request.cwd}`, { cwd: request.cwd }, { cause: error });
|
|
1012
|
+
});
|
|
1013
|
+
if (!info.isDirectory()) {
|
|
1014
|
+
throw new AppError("INVALID_CWD", `working directory is not a directory: ${request.cwd}`, { cwd: request.cwd });
|
|
1015
|
+
}
|
|
1016
|
+
if (request.resume?.mode === "session" && !request.resume.sessionId.trim()) {
|
|
1017
|
+
throw new AppError("INVALID_RESUME", "resume session id must not be empty", {
|
|
1018
|
+
reason: "\u6062\u590D\u5386\u53F2\u4F1A\u8BDD\u65F6\u5FC5\u987B\u63D0\u4F9B session ID"
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
return request;
|
|
1022
|
+
}
|
|
1023
|
+
function validSessionId(value) {
|
|
1024
|
+
return /^[a-zA-Z0-9_-]{1,40}$/.test(value);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
891
1027
|
// src/cli.ts
|
|
892
1028
|
var program = new Command();
|
|
893
1029
|
var paths = resolveAppPaths();
|
|
@@ -897,14 +1033,14 @@ var packageInfo = JSON.parse(
|
|
|
897
1033
|
);
|
|
898
1034
|
program.name("lark-coding-assistant").version(packageInfo.version);
|
|
899
1035
|
program.command("init").description("Configure Feishu/Lark PersonalAgent").action(runInit);
|
|
900
|
-
program.command("start").option("-n, --name <name>", "Session name", "default").option("--agent <agent>", "Coding agent (codex,
|
|
1036
|
+
program.command("start").option("-n, --name <name>", "Session name", "default").option("--agent <agent>", "Coding agent (codex, traex, or claude)", parseAgentId, "codex").option("--cwd <path>", "Coding agent working directory").option("--resume [session-id]", "Resume agent session; omit the ID to open the picker").option("--resume-last", "Resume the most recent agent session in this working directory").option("--resume-all", "Show all agent sessions in the resume picker").action(runStart);
|
|
901
1037
|
program.command("attach").argument("[name]", "Session name", "default").description("Attach local terminal to coding-agent tmux session").action(runAttach);
|
|
902
1038
|
program.command("bind-code").description("Generate a new one-time Lark binding code").action(runBindCode);
|
|
903
1039
|
program.command("status").argument("[name]", "Session name").description("Show daemon and session status").action(runStatus);
|
|
904
1040
|
program.command("stop").argument("[name]", "Session name").description("Stop managed coding-agent/tmux session").action(runStop);
|
|
905
1041
|
program.command("logs").option("-n, --lines <count>", "Number of lines", "100").action(runLogs);
|
|
906
1042
|
program.command("reset-owner").description("Clear persistent Lark owner").action(runResetOwner);
|
|
907
|
-
var daemonCommand = program.command("daemon").description("
|
|
1043
|
+
var daemonCommand = program.command("daemon").description("Start or manage the Lark bridge daemon").action(runDaemonStart);
|
|
908
1044
|
daemonCommand.command("start").description("Start the bridge daemon").action(runDaemonStart);
|
|
909
1045
|
daemonCommand.command("stop").description("Stop the bridge daemon without stopping coding-agent sessions").action(runDaemonStop);
|
|
910
1046
|
daemonCommand.command("restart").description("Restart the bridge daemon without stopping coding-agent sessions").action(runDaemonRestart);
|
|
@@ -956,7 +1092,7 @@ ${url}
|
|
|
956
1092
|
tenant: registeredTenant,
|
|
957
1093
|
appId: registration.client_id,
|
|
958
1094
|
tmuxBinary: "tmux",
|
|
959
|
-
agentBinaries: { codex: "codex",
|
|
1095
|
+
agentBinaries: { codex: "codex", traex: "trae-cli", claude: "claude" },
|
|
960
1096
|
pollIntervalMs: 650
|
|
961
1097
|
};
|
|
962
1098
|
const previousState = await store.loadState();
|
|
@@ -983,18 +1119,18 @@ ${url}
|
|
|
983
1119
|
async function runStart(options) {
|
|
984
1120
|
const cwd = resolve(options.cwd ?? process.cwd());
|
|
985
1121
|
const resume = resolveResumeOption(options);
|
|
986
|
-
await
|
|
987
|
-
|
|
1122
|
+
const request = await validateStartSessionRequest({
|
|
1123
|
+
sessionId: options.name,
|
|
1124
|
+
agent: options.agent,
|
|
1125
|
+
cwd,
|
|
1126
|
+
resume
|
|
988
1127
|
});
|
|
989
1128
|
await ensureInitialized();
|
|
990
1129
|
await preflight(options.agent);
|
|
991
1130
|
await ensureDaemon();
|
|
992
1131
|
const value = await daemonValue({
|
|
993
1132
|
method: "start",
|
|
994
|
-
|
|
995
|
-
sessionId: options.name,
|
|
996
|
-
agent: options.agent,
|
|
997
|
-
resume
|
|
1133
|
+
...request
|
|
998
1134
|
});
|
|
999
1135
|
if (value.binding.mode === "reused") {
|
|
1000
1136
|
console.log("\n\u5DF2\u81EA\u52A8\u6CBF\u7528\u539F\u6709\u98DE\u4E66/Lark \u79C1\u804A\u7ED1\u5B9A\u3002\n");
|
|
@@ -1062,7 +1198,12 @@ async function runStatus(name) {
|
|
|
1062
1198
|
console.log(JSON.stringify(response.value, null, 2));
|
|
1063
1199
|
} catch {
|
|
1064
1200
|
const state = await store.loadState();
|
|
1065
|
-
|
|
1201
|
+
const health = await daemonHealth(paths);
|
|
1202
|
+
console.log(JSON.stringify({
|
|
1203
|
+
daemon: health.status,
|
|
1204
|
+
...health.status === "unresponsive" ? { daemonPid: health.pid } : {},
|
|
1205
|
+
state
|
|
1206
|
+
}, null, 2));
|
|
1066
1207
|
}
|
|
1067
1208
|
}
|
|
1068
1209
|
async function runStop(name) {
|
|
@@ -1100,12 +1241,22 @@ async function runDaemonRestart() {
|
|
|
1100
1241
|
console.log(`Bridge daemon restarted (PID ${info.pid}, version ${info.version}). Coding-agent/tmux sessions were preserved.`);
|
|
1101
1242
|
}
|
|
1102
1243
|
async function runDaemonStatus() {
|
|
1103
|
-
const
|
|
1104
|
-
if (
|
|
1244
|
+
const health = await daemonHealth(paths);
|
|
1245
|
+
if (health.status === "stopped") {
|
|
1105
1246
|
console.log(`Bridge daemon: stopped
|
|
1106
1247
|
CLI version: ${packageInfo.version}`);
|
|
1107
1248
|
return;
|
|
1108
1249
|
}
|
|
1250
|
+
if (health.status === "unresponsive") {
|
|
1251
|
+
console.log([
|
|
1252
|
+
"Bridge daemon: unresponsive",
|
|
1253
|
+
`PID: ${health.pid}`,
|
|
1254
|
+
`CLI version: ${packageInfo.version}`,
|
|
1255
|
+
"\u5EFA\u8BAE\u8FD0\u884C\uFF1Alark-coding-assistant daemon restart"
|
|
1256
|
+
].join("\n"));
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
const info = health.info;
|
|
1109
1260
|
console.log([
|
|
1110
1261
|
"Bridge daemon: running",
|
|
1111
1262
|
`PID: ${info.pid}`,
|
|
@@ -1128,12 +1279,13 @@ async function preflight(agentId) {
|
|
|
1128
1279
|
]);
|
|
1129
1280
|
}
|
|
1130
1281
|
function parseAgentId(value) {
|
|
1131
|
-
|
|
1282
|
+
const agent = normalizeAgentId(value);
|
|
1283
|
+
if (!agent) {
|
|
1132
1284
|
throw new AppError("INVALID_OPTIONS", `unsupported coding agent: ${value}`, {
|
|
1133
1285
|
reason: `\u4E0D\u652F\u6301 coding agent\u300C${value}\u300D`
|
|
1134
1286
|
});
|
|
1135
1287
|
}
|
|
1136
|
-
return
|
|
1288
|
+
return agent;
|
|
1137
1289
|
}
|
|
1138
1290
|
async function ensureDaemon() {
|
|
1139
1291
|
const info = await daemonInfo(paths);
|