@ken-jo/agent-connector 0.4.0 → 0.4.1
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 +8 -8
- package/dist/{action-PLZW5BGX.js → action-WT7GVRCC.js} +11 -10
- package/dist/{action-PLZW5BGX.js.map → action-WT7GVRCC.js.map} +1 -1
- package/dist/amazon-q-COAL3764.js +276 -0
- package/dist/amazon-q-COAL3764.js.map +1 -0
- package/dist/{amp-B524U6LO.js → amp-4U33CU7E.js} +3 -3
- package/dist/{antigravity-ANDKF3K7.js → antigravity-AMKKKHS4.js} +4 -4
- package/dist/{antigravity-cli-LLRPDDOT.js → antigravity-cli-XERXEH5W.js} +4 -4
- package/dist/{chunk-KGJWE6A2.js → chunk-24IDL5RW.js} +2 -2
- package/dist/{chunk-CIRDOY2V.js → chunk-2AVLX7GH.js} +3 -3
- package/dist/{chunk-ADTHT2FN.js → chunk-4ENJK5S2.js} +10 -173
- package/dist/chunk-4ENJK5S2.js.map +1 -0
- package/dist/{chunk-BHUCB6LY.js → chunk-5OWS5CMA.js} +8 -7
- package/dist/{chunk-BHUCB6LY.js.map → chunk-5OWS5CMA.js.map} +1 -1
- package/dist/{chunk-IW77FFNX.js → chunk-CPLK7GTE.js} +41 -5
- package/dist/chunk-CPLK7GTE.js.map +1 -0
- package/dist/chunk-DCKFYWGM.js +237 -0
- package/dist/chunk-DCKFYWGM.js.map +1 -0
- package/dist/{chunk-J3D5W5T2.js → chunk-EGCBZ2DC.js} +2 -2
- package/dist/{chunk-22Y24V7O.js → chunk-F5RX62T7.js} +2 -2
- package/dist/chunk-FAHIMJRU.js +177 -0
- package/dist/chunk-FAHIMJRU.js.map +1 -0
- package/dist/{chunk-BXGFUENQ.js → chunk-I5MLE6S7.js} +14 -1
- package/dist/{chunk-BXGFUENQ.js.map → chunk-I5MLE6S7.js.map} +1 -1
- package/dist/{chunk-LL4OBGRU.js → chunk-LQRAPXS4.js} +3 -3
- package/dist/{chunk-KGXDYGNJ.js → chunk-O5TWCIJN.js} +19 -19
- package/dist/{chunk-KGXDYGNJ.js.map → chunk-O5TWCIJN.js.map} +1 -1
- package/dist/{chunk-MAH6QQTO.js → chunk-QREL7LZJ.js} +5 -4
- package/dist/chunk-QREL7LZJ.js.map +1 -0
- package/dist/{chunk-G3ER4SY5.js → chunk-RIMVWCZY.js} +9 -9
- package/dist/{chunk-6XHB6BE3.js → chunk-SCVBYSF7.js} +1 -1
- package/dist/{chunk-KGGBNKI4.js → chunk-URHQMFB3.js} +90 -13
- package/dist/chunk-URHQMFB3.js.map +1 -0
- package/dist/chunk-WZA4CSGJ.js +28 -0
- package/dist/chunk-WZA4CSGJ.js.map +1 -0
- package/dist/{chunk-76FUSVIA.js → chunk-XJ4S47CT.js} +6 -5
- package/dist/chunk-XJ4S47CT.js.map +1 -0
- package/dist/{claude-code-MLWS7CW6.js → claude-code-W4PUFZL5.js} +20 -30
- package/dist/claude-code-W4PUFZL5.js.map +1 -0
- package/dist/cli/sdk.js +5 -4
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cline-WRYMNS7Z.js +442 -0
- package/dist/cline-WRYMNS7Z.js.map +1 -0
- package/dist/{codebuff-SH2S3QAN.js → codebuff-DH5Y7GAT.js} +8 -4
- package/dist/codebuff-DH5Y7GAT.js.map +1 -0
- package/dist/{codex-BXA4FIF4.js → codex-DDHIV767.js} +43 -11
- package/dist/codex-DDHIV767.js.map +1 -0
- package/dist/continue-K43SUHLQ.js +790 -0
- package/dist/continue-K43SUHLQ.js.map +1 -0
- package/dist/{copilot-cli-ROIBTTDT.js → copilot-cli-Q3SSPT4V.js} +70 -12
- package/dist/copilot-cli-Q3SSPT4V.js.map +1 -0
- package/dist/{crush-QLEFLHUC.js → crush-MBEH2R3I.js} +130 -6
- package/dist/crush-MBEH2R3I.js.map +1 -0
- package/dist/{cursor-ASJPWZ4R.js → cursor-TMBXDYR4.js} +119 -19
- package/dist/cursor-TMBXDYR4.js.map +1 -0
- package/dist/{detect-ZIIS55LD.js → detect-KG5FG3EV.js} +5 -4
- package/dist/{detect-ZIIS55LD.js.map → detect-KG5FG3EV.js.map} +1 -1
- package/dist/{doctor-TJUGSQ5C.js → doctor-FLZF34Y3.js} +221 -95
- package/dist/doctor-FLZF34Y3.js.map +1 -0
- package/dist/{droid-NCSS3B5Y.js → droid-JC2NT6S4.js} +135 -13
- package/dist/droid-JC2NT6S4.js.map +1 -0
- package/dist/{gemini-cli-SLVWLXJW.js → gemini-cli-ILR7M5X3.js} +62 -10
- package/dist/gemini-cli-ILR7M5X3.js.map +1 -0
- package/dist/{goose-PBA7KTE5.js → goose-SFO5BBGW.js} +15 -8
- package/dist/goose-SFO5BBGW.js.map +1 -0
- package/dist/{hermes-ONDCECP2.js → hermes-3N7WN4WS.js} +329 -15
- package/dist/hermes-3N7WN4WS.js.map +1 -0
- package/dist/{hook-OU522ABV.js → hook-XR3Z45FB.js} +14 -11
- package/dist/hook-XR3Z45FB.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -2
- package/dist/{install-UDCBL7HP.js → install-BSR62UHJ.js} +11 -10
- package/dist/{install-UDCBL7HP.js.map → install-BSR62UHJ.js.map} +1 -1
- package/dist/{introspect-DuZSPSHB.d.ts → introspect-Nw8hTReX.d.ts} +1 -1
- package/dist/{jetbrains-copilot-YABZ3HFA.js → jetbrains-copilot-NRZHI5PC.js} +85 -18
- package/dist/jetbrains-copilot-NRZHI5PC.js.map +1 -0
- package/dist/{kilo-F3ZDZKCT.js → kilo-5NWOXVSD.js} +16 -16
- package/dist/kilo-5NWOXVSD.js.map +1 -0
- package/dist/{kilo-cli-3HWPWBY4.js → kilo-cli-UZ7R5UOP.js} +3 -3
- package/dist/{kimi-NV72FVAO.js → kimi-2YFK2GBA.js} +87 -25
- package/dist/kimi-2YFK2GBA.js.map +1 -0
- package/dist/{kiro-C5W6AGDR.js → kiro-YL6AWUYG.js} +3 -3
- package/dist/{leaderboard-TIBVONVT.js → leaderboard-MJG24O35.js} +3 -3
- package/dist/{mimo-code-IMM5YM3M.js → mimo-code-FTMGSKMQ.js} +41 -5
- package/dist/mimo-code-FTMGSKMQ.js.map +1 -0
- package/dist/{mux-DSSH4AFS.js → mux-5XZFB44C.js} +156 -6
- package/dist/mux-5XZFB44C.js.map +1 -0
- package/dist/{nemoclaw-3EVNKD3I.js → nemoclaw-W5KEJ3WX.js} +4 -4
- package/dist/{omp-Z6FRNDPN.js → omp-2QMEY6HD.js} +138 -18
- package/dist/omp-2QMEY6HD.js.map +1 -0
- package/dist/{openclaw-7G437NT7.js → openclaw-EXJEFNZI.js} +4 -4
- package/dist/{opencode-Q6KBSAKW.js → opencode-WNXYJR4X.js} +84 -27
- package/dist/opencode-WNXYJR4X.js.map +1 -0
- package/dist/{package-RMPN57YZ.js → package-ACZXJHWB.js} +8 -7
- package/dist/{package-RMPN57YZ.js.map → package-ACZXJHWB.js.map} +1 -1
- package/dist/{pi-LZT6WWAZ.js → pi-PVVPVWKG.js} +3 -2
- package/dist/{pi-LZT6WWAZ.js.map → pi-PVVPVWKG.js.map} +1 -1
- package/dist/{qwen-code-WQBKRPWJ.js → qwen-code-G4CXKUHR.js} +426 -10
- package/dist/qwen-code-G4CXKUHR.js.map +1 -0
- package/dist/{roo-code-GWSNU3OW.js → roo-code-67TYJIQR.js} +3 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +9 -8
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.js +4 -3
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +6 -5
- package/dist/sdk/test.js.map +1 -1
- package/dist/{serve-D3GO36UT.js → serve-GER7URPR.js} +11 -10
- package/dist/{serve-D3GO36UT.js.map → serve-GER7URPR.js.map} +1 -1
- package/dist/{status-KOSKCETC.js → status-LAJE3BM5.js} +7 -6
- package/dist/{status-KOSKCETC.js.map → status-LAJE3BM5.js.map} +1 -1
- package/dist/{statusline-ZNTCL5YC.js → statusline-L376ZPZU.js} +10 -9
- package/dist/{statusline-ZNTCL5YC.js.map → statusline-L376ZPZU.js.map} +1 -1
- package/dist/{telemetry-XIKUUGTQ.js → telemetry-B3DX3PWU.js} +6 -5
- package/dist/{telemetry-XIKUUGTQ.js.map → telemetry-B3DX3PWU.js.map} +1 -1
- package/dist/{trae-NWT3TMSZ.js → trae-7CZZGOGI.js} +3 -3
- package/dist/{types-BEKsAium.d.ts → types-CRVrFWeU.d.ts} +64 -22
- package/dist/{uninstall-2LBLQVFA.js → uninstall-ZYTW7YMZ.js} +11 -10
- package/dist/{uninstall-2LBLQVFA.js.map → uninstall-ZYTW7YMZ.js.map} +1 -1
- package/dist/{upgrade-ZC2S7VRN.js → upgrade-4LUEEOZW.js} +11 -10
- package/dist/{upgrade-ZC2S7VRN.js.map → upgrade-4LUEEOZW.js.map} +1 -1
- package/dist/{usage-E2A4O2CY.js → usage-ZFBVQF3H.js} +3 -3
- package/dist/{usage-event-JKMC4QC4.js → usage-event-GZ32AGEB.js} +10 -9
- package/dist/{usage-event-JKMC4QC4.js.map → usage-event-GZ32AGEB.js.map} +1 -1
- package/dist/{vscode-copilot-ALV45XF6.js → vscode-copilot-MF2CDNMT.js} +23 -10
- package/dist/vscode-copilot-MF2CDNMT.js.map +1 -0
- package/dist/{warp-H6IX4U3J.js → warp-VKG55TAT.js} +55 -4
- package/dist/warp-VKG55TAT.js.map +1 -0
- package/dist/windsurf-FU5G4SHF.js +443 -0
- package/dist/windsurf-FU5G4SHF.js.map +1 -0
- package/dist/{zed-RH34TNSW.js → zed-SFUHL3GS.js} +3 -3
- package/package.json +2 -2
- package/dist/chunk-3PFFTFCU.js +0 -190
- package/dist/chunk-3PFFTFCU.js.map +0 -1
- package/dist/chunk-76FUSVIA.js.map +0 -1
- package/dist/chunk-ADTHT2FN.js.map +0 -1
- package/dist/chunk-IW77FFNX.js.map +0 -1
- package/dist/chunk-KGGBNKI4.js.map +0 -1
- package/dist/chunk-MAH6QQTO.js.map +0 -1
- package/dist/claude-code-MLWS7CW6.js.map +0 -1
- package/dist/codebuff-SH2S3QAN.js.map +0 -1
- package/dist/codex-BXA4FIF4.js.map +0 -1
- package/dist/copilot-cli-ROIBTTDT.js.map +0 -1
- package/dist/crush-QLEFLHUC.js.map +0 -1
- package/dist/cursor-ASJPWZ4R.js.map +0 -1
- package/dist/doctor-TJUGSQ5C.js.map +0 -1
- package/dist/droid-NCSS3B5Y.js.map +0 -1
- package/dist/gemini-cli-SLVWLXJW.js.map +0 -1
- package/dist/goose-PBA7KTE5.js.map +0 -1
- package/dist/hermes-ONDCECP2.js.map +0 -1
- package/dist/hook-OU522ABV.js.map +0 -1
- package/dist/jetbrains-copilot-YABZ3HFA.js.map +0 -1
- package/dist/kilo-F3ZDZKCT.js.map +0 -1
- package/dist/kimi-NV72FVAO.js.map +0 -1
- package/dist/mimo-code-IMM5YM3M.js.map +0 -1
- package/dist/mux-DSSH4AFS.js.map +0 -1
- package/dist/omp-Z6FRNDPN.js.map +0 -1
- package/dist/opencode-Q6KBSAKW.js.map +0 -1
- package/dist/qwen-code-WQBKRPWJ.js.map +0 -1
- package/dist/vscode-copilot-ALV45XF6.js.map +0 -1
- package/dist/warp-H6IX4U3J.js.map +0 -1
- /package/dist/{amp-B524U6LO.js.map → amp-4U33CU7E.js.map} +0 -0
- /package/dist/{antigravity-ANDKF3K7.js.map → antigravity-AMKKKHS4.js.map} +0 -0
- /package/dist/{antigravity-cli-LLRPDDOT.js.map → antigravity-cli-XERXEH5W.js.map} +0 -0
- /package/dist/{chunk-KGJWE6A2.js.map → chunk-24IDL5RW.js.map} +0 -0
- /package/dist/{chunk-CIRDOY2V.js.map → chunk-2AVLX7GH.js.map} +0 -0
- /package/dist/{chunk-J3D5W5T2.js.map → chunk-EGCBZ2DC.js.map} +0 -0
- /package/dist/{chunk-22Y24V7O.js.map → chunk-F5RX62T7.js.map} +0 -0
- /package/dist/{chunk-LL4OBGRU.js.map → chunk-LQRAPXS4.js.map} +0 -0
- /package/dist/{chunk-G3ER4SY5.js.map → chunk-RIMVWCZY.js.map} +0 -0
- /package/dist/{chunk-6XHB6BE3.js.map → chunk-SCVBYSF7.js.map} +0 -0
- /package/dist/{kilo-cli-3HWPWBY4.js.map → kilo-cli-UZ7R5UOP.js.map} +0 -0
- /package/dist/{kiro-C5W6AGDR.js.map → kiro-YL6AWUYG.js.map} +0 -0
- /package/dist/{leaderboard-TIBVONVT.js.map → leaderboard-MJG24O35.js.map} +0 -0
- /package/dist/{nemoclaw-3EVNKD3I.js.map → nemoclaw-W5KEJ3WX.js.map} +0 -0
- /package/dist/{openclaw-7G437NT7.js.map → openclaw-EXJEFNZI.js.map} +0 -0
- /package/dist/{roo-code-GWSNU3OW.js.map → roo-code-67TYJIQR.js.map} +0 -0
- /package/dist/{trae-NWT3TMSZ.js.map → trae-7CZZGOGI.js.map} +0 -0
- /package/dist/{usage-E2A4O2CY.js.map → usage-ZFBVQF3H.js.map} +0 -0
- /package/dist/{zed-RH34TNSW.js.map → zed-SFUHL3GS.js.map} +0 -0
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
addLedgerOwner,
|
|
4
|
+
createLedgerEntry,
|
|
5
|
+
describeJsonValue,
|
|
6
|
+
dropLedgerEntry,
|
|
7
|
+
findLedgerEntry,
|
|
8
|
+
hashJsonValue,
|
|
9
|
+
jsonDeepEquals,
|
|
10
|
+
ledgerEntriesOwnedBy,
|
|
11
|
+
loadConfigPatchLedger,
|
|
12
|
+
removeLedgerOwner,
|
|
13
|
+
saveConfigPatchLedger
|
|
14
|
+
} from "./chunk-FAHIMJRU.js";
|
|
2
15
|
import {
|
|
3
16
|
writeTomlString
|
|
4
17
|
} from "./chunk-OPXAP3AC.js";
|
|
@@ -7,16 +20,18 @@ import {
|
|
|
7
20
|
} from "./chunk-DBQMX75U.js";
|
|
8
21
|
import {
|
|
9
22
|
BaseAdapter
|
|
10
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-CPLK7GTE.js";
|
|
11
24
|
import {
|
|
12
25
|
renderSkillMd
|
|
13
26
|
} from "./chunk-7L6ITC4T.js";
|
|
14
27
|
import {
|
|
15
28
|
buildHomeBinHookCommand,
|
|
29
|
+
buildHomeBinStatuslineCommand,
|
|
16
30
|
buildServeWrapperCommand,
|
|
17
31
|
isHomeBinHookCommand,
|
|
32
|
+
isHomeBinStatuslineCommand,
|
|
18
33
|
shouldWrapForTelemetry
|
|
19
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-I5MLE6S7.js";
|
|
20
35
|
import "./chunk-N6HH7K6P.js";
|
|
21
36
|
import "./chunk-TRQKHP7D.js";
|
|
22
37
|
|
|
@@ -26,6 +41,7 @@ import { homedir } from "os";
|
|
|
26
41
|
import { join } from "path";
|
|
27
42
|
var HOST = "qwen-code";
|
|
28
43
|
var MCP_ROOT_KEY = "mcpServers";
|
|
44
|
+
var STATUSLINE_KEY = "ui.statusLine";
|
|
29
45
|
var QwenCodeAdapter = class extends BaseAdapter {
|
|
30
46
|
id = HOST;
|
|
31
47
|
name = "Qwen CLI";
|
|
@@ -39,6 +55,10 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
39
55
|
preToolUse: true,
|
|
40
56
|
postToolUse: true,
|
|
41
57
|
preCompact: true,
|
|
58
|
+
// Qwen fires PostCompact natively (observe-only — "not in the decision mode
|
|
59
|
+
// supported events list"; QwenLM/qwen-code docs/users/features/hooks.md
|
|
60
|
+
// "#### PostCompact", trigger + compact_summary payload).
|
|
61
|
+
postCompact: true,
|
|
42
62
|
sessionStart: true,
|
|
43
63
|
sessionEnd: true,
|
|
44
64
|
userPromptSubmit: true,
|
|
@@ -63,7 +83,22 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
63
83
|
// Ground truth: kilo-pi-ground-truth.md § "Already-known skills gaps".
|
|
64
84
|
supportsCommands: true,
|
|
65
85
|
supportsSkills: true,
|
|
66
|
-
supportsSubagents: true
|
|
86
|
+
supportsSubagents: true,
|
|
87
|
+
// Statusline surface: qwen-code is the 2nd v1 host (after claude-code).
|
|
88
|
+
// installStatusline wires settings.json `ui.statusLine` = {type:"command",
|
|
89
|
+
// command:<home-bin statusline cmd>} through the SAME refcounted ownership
|
|
90
|
+
// ledger as configPatch (never clobbers a ui.statusLine agent-connector does
|
|
91
|
+
// not own). The key is NESTED here (`ui.statusLine`), unlike claude-code's
|
|
92
|
+
// top-level `statusLine`. Confirmed config key + stdin payload against the
|
|
93
|
+
// qwen-code status-line docs (shipped v0.14.3, PR #2923).
|
|
94
|
+
supportsStatusline: true,
|
|
95
|
+
// Native passthrough: Qwen's 16-event surface includes 3 host-specific events
|
|
96
|
+
// with NO canonical HookEventName analog — TodoCreated / TodoCompleted /
|
|
97
|
+
// StopFailure (QwenLM/qwen-code docs/users/features/hooks.md). A connector
|
|
98
|
+
// reaches them via platforms["qwen-code"].nativeHooks; installHooks files the
|
|
99
|
+
// PascalCase event key VERBATIM into settings.json hooks, and the generic
|
|
100
|
+
// uninstall reverses it.
|
|
101
|
+
supportsNativeHooks: true
|
|
67
102
|
};
|
|
68
103
|
// ── Detection ────────────────────────────────────────────────────────────
|
|
69
104
|
detectInstalled(projectDir) {
|
|
@@ -198,18 +233,26 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
198
233
|
// ── Hook install / uninstall ─────────────────────────────────────────────
|
|
199
234
|
installHooks(ctx) {
|
|
200
235
|
const { connector } = ctx;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
236
|
+
const override = connector.platforms[HOST];
|
|
237
|
+
const hooksDisabled = override?.hooks === false;
|
|
238
|
+
const normalizedEvents = hooksDisabled ? [] : connector.hookEvents;
|
|
239
|
+
const nativeHooks = override?.nativeHooks ?? {};
|
|
240
|
+
const nativeEvents = Object.keys(nativeHooks);
|
|
241
|
+
if (normalizedEvents.length === 0 && nativeEvents.length === 0) {
|
|
242
|
+
return [
|
|
243
|
+
{
|
|
244
|
+
platform: this.id,
|
|
245
|
+
action: "skip",
|
|
246
|
+
detail: hooksDisabled ? "hooks disabled for qwen-code" : "connector declares no hooks"
|
|
247
|
+
}
|
|
248
|
+
];
|
|
206
249
|
}
|
|
207
250
|
const settingsPath = this.getHookConfigPath(ctx);
|
|
208
251
|
const settings = this.readJson(settingsPath) ?? {};
|
|
209
252
|
const hooks = settings.hooks ??= {};
|
|
210
253
|
const changes = [];
|
|
211
254
|
let mutated = false;
|
|
212
|
-
for (const event of
|
|
255
|
+
for (const event of normalizedEvents) {
|
|
213
256
|
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
|
|
214
257
|
const matcher = connector.hooks[event]?.matcher ?? "";
|
|
215
258
|
const entry = {
|
|
@@ -246,6 +289,32 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
246
289
|
}
|
|
247
290
|
mutated = true;
|
|
248
291
|
}
|
|
292
|
+
for (const nativeEvent of nativeEvents) {
|
|
293
|
+
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, nativeEvent, connector.id);
|
|
294
|
+
const entry = {
|
|
295
|
+
matcher: nativeHooks[nativeEvent]?.matcher ?? "",
|
|
296
|
+
hooks: [{ type: "command", command }]
|
|
297
|
+
};
|
|
298
|
+
const bucket = hooks[nativeEvent] ??= [];
|
|
299
|
+
const existingIdx = bucket.findIndex((e) => e.hooks?.[0]?.command === command);
|
|
300
|
+
if (existingIdx >= 0) {
|
|
301
|
+
if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
|
|
302
|
+
changes.push({
|
|
303
|
+
platform: this.id,
|
|
304
|
+
action: "skip",
|
|
305
|
+
path: settingsPath,
|
|
306
|
+
detail: `hooks.${nativeEvent} (native) already registered`
|
|
307
|
+
});
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
bucket[existingIdx] = entry;
|
|
311
|
+
changes.push({ platform: this.id, action: "update", path: settingsPath, detail: `hooks.${nativeEvent} (native)` });
|
|
312
|
+
} else {
|
|
313
|
+
bucket.push(entry);
|
|
314
|
+
changes.push({ platform: this.id, action: "create", path: settingsPath, detail: `hooks.${nativeEvent} (native)` });
|
|
315
|
+
}
|
|
316
|
+
mutated = true;
|
|
317
|
+
}
|
|
249
318
|
if (mutated) this.writeJson(settingsPath, settings, ctx.dryRun);
|
|
250
319
|
return changes;
|
|
251
320
|
}
|
|
@@ -307,6 +376,282 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
307
376
|
isOurCommand(command, ctx) {
|
|
308
377
|
return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
|
|
309
378
|
}
|
|
379
|
+
// ── Statusline surface (a HUD/status line) ────────────────────────────────
|
|
380
|
+
// Wires settings.json `ui.statusLine` = { type:"command", command:<home-bin
|
|
381
|
+
// statusline cmd> } through the SAME refcounted ownership ledger as configPatch
|
|
382
|
+
// (the ledger primitives are surface-agnostic). qwen-code does NOT advertise
|
|
383
|
+
// supportsConfigPatch, so — unlike claude-code, which routes the statusline
|
|
384
|
+
// through its private applyConfigPatches loop — this adapter performs the nested
|
|
385
|
+
// set-if-absent write directly with the exported ledger primitives. Semantics
|
|
386
|
+
// are identical: never clobber a ui.statusLine agent-connector does not own
|
|
387
|
+
// (skip-warn), record prior state + owner (refcounted across connectors),
|
|
388
|
+
// reversible by uninstallStatusline (last-owner-verified delete). The key is
|
|
389
|
+
// NESTED (`ui.statusLine`), so we own the `ui.statusLine` leaf — if the user
|
|
390
|
+
// already has it, we skip-warn and never touch their value.
|
|
391
|
+
//
|
|
392
|
+
// The home-bin command makes Qwen exec
|
|
393
|
+
// `<homeBin> statusline qwen-code --connector <id>` for every status refresh,
|
|
394
|
+
// which re-imports the connector module and renders the line (runtime/
|
|
395
|
+
// statusline-entrypoint). No telemetry in v1.
|
|
396
|
+
/** The statusLine config object value agent-connector writes at `ui.statusLine`. */
|
|
397
|
+
statuslineValue(ctx) {
|
|
398
|
+
const command = buildHomeBinStatuslineCommand(ctx.homeBinPath, HOST, ctx.connector.id);
|
|
399
|
+
return { type: "command", command };
|
|
400
|
+
}
|
|
401
|
+
installStatusline(ctx) {
|
|
402
|
+
const { connector } = ctx;
|
|
403
|
+
if (connector.statusline == null) {
|
|
404
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no statusline" }];
|
|
405
|
+
}
|
|
406
|
+
if (connector.platforms[HOST]?.statusline === false) {
|
|
407
|
+
return [{ platform: this.id, action: "skip", detail: "statusline disabled for qwen-code" }];
|
|
408
|
+
}
|
|
409
|
+
const filePath = this.getServerConfigPath(ctx);
|
|
410
|
+
if (this.isPresentButUnparseable(filePath)) {
|
|
411
|
+
return [
|
|
412
|
+
{
|
|
413
|
+
platform: this.id,
|
|
414
|
+
action: "warn",
|
|
415
|
+
path: filePath,
|
|
416
|
+
detail: `existing ${filePath} is not parseable; statusline left unapplied (back it up / fix it, then re-run)`
|
|
417
|
+
}
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
const settings = this.readJson(filePath) ?? {};
|
|
421
|
+
if (typeof settings !== "object" || Array.isArray(settings)) {
|
|
422
|
+
return [
|
|
423
|
+
{
|
|
424
|
+
platform: this.id,
|
|
425
|
+
action: "warn",
|
|
426
|
+
path: filePath,
|
|
427
|
+
detail: `existing ${filePath} is not a JSON object; statusline left unapplied`
|
|
428
|
+
}
|
|
429
|
+
];
|
|
430
|
+
}
|
|
431
|
+
const ledger = loadConfigPatchLedger(ctx.dataRoot);
|
|
432
|
+
const desired = this.statuslineValue(ctx);
|
|
433
|
+
const segments = STATUSLINE_KEY.split(".");
|
|
434
|
+
const leaf = readJsonLeaf(settings, segments);
|
|
435
|
+
const entry = findLedgerEntry(ledger, HOST, filePath, STATUSLINE_KEY);
|
|
436
|
+
const changes = [];
|
|
437
|
+
if (leaf.kind === "blocked") {
|
|
438
|
+
return [
|
|
439
|
+
{
|
|
440
|
+
platform: this.id,
|
|
441
|
+
action: "warn",
|
|
442
|
+
path: filePath,
|
|
443
|
+
detail: `statusline ${STATUSLINE_KEY} skipped: "${leaf.atPath}" exists but is not an object \u2014 set ${STATUSLINE_KEY} manually if wanted`
|
|
444
|
+
}
|
|
445
|
+
];
|
|
446
|
+
}
|
|
447
|
+
if (leaf.kind === "absent") {
|
|
448
|
+
writeJsonLeaf(settings, segments, desired);
|
|
449
|
+
this.writeJson(filePath, settings, ctx.dryRun);
|
|
450
|
+
if (entry) {
|
|
451
|
+
entry.writtenValue = desired;
|
|
452
|
+
entry.writtenValueHash = hashJsonValue(desired);
|
|
453
|
+
addLedgerOwner(entry, connector.id, connector.version);
|
|
454
|
+
} else {
|
|
455
|
+
createLedgerEntry(ledger, {
|
|
456
|
+
platform: HOST,
|
|
457
|
+
file: filePath,
|
|
458
|
+
key: STATUSLINE_KEY,
|
|
459
|
+
value: desired,
|
|
460
|
+
connectorId: connector.id,
|
|
461
|
+
connectorVersion: connector.version
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
if (!ctx.dryRun) saveConfigPatchLedger(ctx.dataRoot, ledger);
|
|
465
|
+
changes.push({
|
|
466
|
+
platform: this.id,
|
|
467
|
+
action: "create",
|
|
468
|
+
path: filePath,
|
|
469
|
+
detail: `statusline ${STATUSLINE_KEY}: <absent> \u2192 ${describeJsonValue(desired)}`
|
|
470
|
+
});
|
|
471
|
+
return changes;
|
|
472
|
+
}
|
|
473
|
+
if (!entry) {
|
|
474
|
+
return [
|
|
475
|
+
{
|
|
476
|
+
platform: this.id,
|
|
477
|
+
action: "warn",
|
|
478
|
+
path: filePath,
|
|
479
|
+
detail: `statusline ${STATUSLINE_KEY} skipped: already set to ${describeJsonValue(leaf.value)} (not created by agent-connector) \u2014 left untouched`
|
|
480
|
+
}
|
|
481
|
+
];
|
|
482
|
+
}
|
|
483
|
+
if (!jsonDeepEquals(leaf.value, entry.writtenValue)) {
|
|
484
|
+
return [
|
|
485
|
+
{
|
|
486
|
+
platform: this.id,
|
|
487
|
+
action: "warn",
|
|
488
|
+
path: filePath,
|
|
489
|
+
detail: `statusline ${STATUSLINE_KEY}: value changed since install (current ${describeJsonValue(leaf.value)}, wrote ${describeJsonValue(entry.writtenValue)}); leaving in place`
|
|
490
|
+
}
|
|
491
|
+
];
|
|
492
|
+
}
|
|
493
|
+
if (jsonDeepEquals(desired, leaf.value)) {
|
|
494
|
+
const owners = entry.owners.map((o) => o.connectorId);
|
|
495
|
+
if (addLedgerOwner(entry, connector.id, connector.version)) {
|
|
496
|
+
if (!ctx.dryRun) saveConfigPatchLedger(ctx.dataRoot, ledger);
|
|
497
|
+
return [
|
|
498
|
+
{
|
|
499
|
+
platform: this.id,
|
|
500
|
+
action: "skip",
|
|
501
|
+
path: filePath,
|
|
502
|
+
detail: `statusline ${STATUSLINE_KEY} already installed; registered as co-owner (co-owned with ${owners.join(", ")})`
|
|
503
|
+
}
|
|
504
|
+
];
|
|
505
|
+
}
|
|
506
|
+
return [
|
|
507
|
+
{
|
|
508
|
+
platform: this.id,
|
|
509
|
+
action: "skip",
|
|
510
|
+
path: filePath,
|
|
511
|
+
detail: `statusline ${STATUSLINE_KEY} already installed`
|
|
512
|
+
}
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
return [
|
|
516
|
+
{
|
|
517
|
+
platform: this.id,
|
|
518
|
+
action: "warn",
|
|
519
|
+
path: filePath,
|
|
520
|
+
detail: `statusline ${STATUSLINE_KEY} skipped: already owned by ${entry.owners.map((o) => o.connectorId).join(", ")} with a different value \u2014 left untouched`
|
|
521
|
+
}
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
uninstallStatusline(ctx) {
|
|
525
|
+
const ledger = loadConfigPatchLedger(ctx.dataRoot);
|
|
526
|
+
const owned = ledgerEntriesOwnedBy(ledger, HOST, ctx.connector.id).filter(
|
|
527
|
+
(e) => e.key === STATUSLINE_KEY
|
|
528
|
+
);
|
|
529
|
+
if (owned.length === 0) {
|
|
530
|
+
return [
|
|
531
|
+
{
|
|
532
|
+
platform: this.id,
|
|
533
|
+
action: "skip",
|
|
534
|
+
detail: "statusline: no ownership recorded; left untouched"
|
|
535
|
+
}
|
|
536
|
+
];
|
|
537
|
+
}
|
|
538
|
+
const changes = [];
|
|
539
|
+
let ledgerMutated = false;
|
|
540
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
541
|
+
for (const entry of owned) {
|
|
542
|
+
const bucket = byFile.get(entry.file) ?? [];
|
|
543
|
+
bucket.push(entry);
|
|
544
|
+
byFile.set(entry.file, bucket);
|
|
545
|
+
}
|
|
546
|
+
for (const [filePath, entries] of byFile) {
|
|
547
|
+
const unparseable = this.isPresentButUnparseable(filePath);
|
|
548
|
+
const settings = unparseable ? null : this.readJson(filePath);
|
|
549
|
+
let fileMutated = false;
|
|
550
|
+
for (const entry of entries) {
|
|
551
|
+
const { lastOwner } = removeLedgerOwner(entry, ctx.connector.id);
|
|
552
|
+
ledgerMutated = true;
|
|
553
|
+
if (!lastOwner) {
|
|
554
|
+
changes.push({
|
|
555
|
+
platform: this.id,
|
|
556
|
+
action: "skip",
|
|
557
|
+
path: filePath,
|
|
558
|
+
detail: `statusline ${entry.key} retained: still owned by ${entry.owners.map((o) => o.connectorId).join(", ")}`
|
|
559
|
+
});
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
dropLedgerEntry(ledger, entry);
|
|
563
|
+
if (unparseable) {
|
|
564
|
+
changes.push({
|
|
565
|
+
platform: this.id,
|
|
566
|
+
action: "warn",
|
|
567
|
+
path: filePath,
|
|
568
|
+
detail: `statusline ${entry.key}: ${filePath} is not parseable; key left in place (ownership released)`
|
|
569
|
+
});
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings)) {
|
|
573
|
+
changes.push({
|
|
574
|
+
platform: this.id,
|
|
575
|
+
action: "skip",
|
|
576
|
+
path: filePath,
|
|
577
|
+
detail: `statusline ${entry.key} already absent (no settings file); ownership record dropped`
|
|
578
|
+
});
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const leaf = readJsonLeaf(settings, entry.key.split("."));
|
|
582
|
+
if (leaf.kind !== "present") {
|
|
583
|
+
changes.push({
|
|
584
|
+
platform: this.id,
|
|
585
|
+
action: "skip",
|
|
586
|
+
path: filePath,
|
|
587
|
+
detail: `statusline ${entry.key} already absent; ownership record dropped`
|
|
588
|
+
});
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (entry.prior?.present !== false || !jsonDeepEquals(leaf.value, entry.writtenValue)) {
|
|
592
|
+
changes.push({
|
|
593
|
+
platform: this.id,
|
|
594
|
+
action: "warn",
|
|
595
|
+
path: filePath,
|
|
596
|
+
detail: `statusline ${entry.key}: value changed since install (current ${describeJsonValue(leaf.value)}, wrote ${describeJsonValue(entry.writtenValue)}); left in place`
|
|
597
|
+
});
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
deleteJsonLeaf(settings, entry.key.split("."));
|
|
601
|
+
fileMutated = true;
|
|
602
|
+
changes.push({
|
|
603
|
+
platform: this.id,
|
|
604
|
+
action: "remove",
|
|
605
|
+
path: filePath,
|
|
606
|
+
detail: `statusline ${entry.key} removed (was ${describeJsonValue(entry.writtenValue)})`
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
if (fileMutated && settings) this.writeJson(filePath, settings, ctx.dryRun);
|
|
610
|
+
}
|
|
611
|
+
if (ledgerMutated && !ctx.dryRun) saveConfigPatchLedger(ctx.dataRoot, ledger);
|
|
612
|
+
return changes;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Parse Qwen's statusLine stdin JSON into the normalized
|
|
616
|
+
* {@link StatuslineContext}. Qwen pipes a JSON object to the statusLine command
|
|
617
|
+
* on stdin (model, context_window, workspace, git, …); fields the payload omits
|
|
618
|
+
* stay undefined. `raw` keeps the verbatim payload (incl. version/git/metrics/
|
|
619
|
+
* vim). NOTE: Qwen has NO cost analog (no cost field in the payload), so
|
|
620
|
+
* `ctx.cost` is intentionally left undefined. Sources: qwen-code status-line
|
|
621
|
+
* docs, QwenLM/qwen-code settings.md.
|
|
622
|
+
*/
|
|
623
|
+
parseStatusInput(raw) {
|
|
624
|
+
const input = raw ?? {};
|
|
625
|
+
const ctx = {
|
|
626
|
+
host: HOST,
|
|
627
|
+
capabilities: this.capabilities,
|
|
628
|
+
raw
|
|
629
|
+
};
|
|
630
|
+
if (typeof input.session_id === "string" && input.session_id !== "") {
|
|
631
|
+
ctx.sessionId = input.session_id;
|
|
632
|
+
}
|
|
633
|
+
if (typeof input.workspace?.current_dir === "string") {
|
|
634
|
+
ctx.cwd = input.workspace.current_dir;
|
|
635
|
+
}
|
|
636
|
+
if (typeof input.model?.display_name === "string") {
|
|
637
|
+
ctx.model = { displayName: input.model.display_name };
|
|
638
|
+
}
|
|
639
|
+
const cw = input.context_window;
|
|
640
|
+
if (cw) {
|
|
641
|
+
const context = {};
|
|
642
|
+
if (typeof cw.context_window_size === "number") context.maxTokens = cw.context_window_size;
|
|
643
|
+
if (typeof cw.current_usage === "number") context.usedTokens = cw.current_usage;
|
|
644
|
+
if (typeof cw.used_percentage === "number") context.percent = cw.used_percentage;
|
|
645
|
+
if (context.usedTokens !== void 0 || context.maxTokens !== void 0 || context.percent !== void 0) {
|
|
646
|
+
ctx.context = context;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return ctx;
|
|
650
|
+
}
|
|
651
|
+
/** Format the rendered status line into Qwen's native reply: stdout = line, exit 0. */
|
|
652
|
+
formatStatusOutput(rendered) {
|
|
653
|
+
return { exitCode: 0, stdout: rendered };
|
|
654
|
+
}
|
|
310
655
|
// ── Content surfaces: commands / subagents ───────────────────────────────
|
|
311
656
|
// CONTENT-ONLY: pure native-file writers under <qwenDir>/{commands,agents}. No
|
|
312
657
|
// runtime dispatch, no home-bin pointer, no telemetry wrap. Each method is
|
|
@@ -513,6 +858,32 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
513
858
|
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
514
859
|
});
|
|
515
860
|
}
|
|
861
|
+
const statuslineLedgerOwned = ledgerEntriesOwnedBy(
|
|
862
|
+
loadConfigPatchLedger(ctx.dataRoot),
|
|
863
|
+
HOST,
|
|
864
|
+
connectorId
|
|
865
|
+
).some((e) => e.key === STATUSLINE_KEY);
|
|
866
|
+
if ((ctx.connector.statusline != null || statuslineLedgerOwned) && ctx.connector.platforms[HOST]?.statusline !== false) {
|
|
867
|
+
checks.push({
|
|
868
|
+
name: `${this.name}: statusline wired`,
|
|
869
|
+
check: () => {
|
|
870
|
+
const settings = this.readJson(
|
|
871
|
+
settingsPath
|
|
872
|
+
);
|
|
873
|
+
const command = settings?.ui?.statusLine?.command;
|
|
874
|
+
if (command === void 0) {
|
|
875
|
+
return { status: "FAIL", detail: `ui.statusLine not set in ${settingsPath}` };
|
|
876
|
+
}
|
|
877
|
+
if (typeof command === "string" && isHomeBinStatuslineCommand(command, homeBin, connectorId)) {
|
|
878
|
+
return { status: "OK", detail: "ui.statusLine command present" };
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
status: "FAIL",
|
|
882
|
+
detail: `ui.statusLine in ${settingsPath} is not agent-connector's (left untouched)`
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
}
|
|
516
887
|
return checks;
|
|
517
888
|
}
|
|
518
889
|
// ── Runtime: parse Qwen stdin JSON → normalized event ────────────────────
|
|
@@ -574,6 +945,13 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
574
945
|
};
|
|
575
946
|
return ev;
|
|
576
947
|
}
|
|
948
|
+
case "PostCompact": {
|
|
949
|
+
const ev = {
|
|
950
|
+
...base,
|
|
951
|
+
...input.trigger === "auto" || input.trigger === "manual" ? { trigger: input.trigger } : {}
|
|
952
|
+
};
|
|
953
|
+
return ev;
|
|
954
|
+
}
|
|
577
955
|
case "Stop": {
|
|
578
956
|
const ev = {
|
|
579
957
|
...base,
|
|
@@ -713,6 +1091,44 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
713
1091
|
return { exitCode: 0, stdout: JSON.stringify(payload) };
|
|
714
1092
|
}
|
|
715
1093
|
};
|
|
1094
|
+
function readJsonLeaf(root, segments) {
|
|
1095
|
+
let node = root;
|
|
1096
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1097
|
+
const next = node[segments[i]];
|
|
1098
|
+
if (next === void 0) return { kind: "absent" };
|
|
1099
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) {
|
|
1100
|
+
return { kind: "blocked", atPath: segments.slice(0, i + 1).join(".") };
|
|
1101
|
+
}
|
|
1102
|
+
node = next;
|
|
1103
|
+
}
|
|
1104
|
+
const leaf = node[segments[segments.length - 1]];
|
|
1105
|
+
if (leaf === void 0) return { kind: "absent" };
|
|
1106
|
+
return { kind: "present", value: leaf };
|
|
1107
|
+
}
|
|
1108
|
+
function writeJsonLeaf(root, segments, value) {
|
|
1109
|
+
let node = root;
|
|
1110
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1111
|
+
const seg = segments[i];
|
|
1112
|
+
const next = node[seg];
|
|
1113
|
+
if (next === void 0) {
|
|
1114
|
+
const created = {};
|
|
1115
|
+
node[seg] = created;
|
|
1116
|
+
node = created;
|
|
1117
|
+
} else {
|
|
1118
|
+
node = next;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
node[segments[segments.length - 1]] = value;
|
|
1122
|
+
}
|
|
1123
|
+
function deleteJsonLeaf(root, segments) {
|
|
1124
|
+
let node = root;
|
|
1125
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1126
|
+
const next = node[segments[i]];
|
|
1127
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) return;
|
|
1128
|
+
node = next;
|
|
1129
|
+
}
|
|
1130
|
+
delete node[segments[segments.length - 1]];
|
|
1131
|
+
}
|
|
716
1132
|
function extractSessionId(input) {
|
|
717
1133
|
if (typeof input.session_id === "string" && input.session_id !== "") {
|
|
718
1134
|
return input.session_id;
|
|
@@ -751,4 +1167,4 @@ export {
|
|
|
751
1167
|
adapter,
|
|
752
1168
|
qwen_code_default as default
|
|
753
1169
|
};
|
|
754
|
-
//# sourceMappingURL=qwen-code-
|
|
1170
|
+
//# sourceMappingURL=qwen-code-G4CXKUHR.js.map
|