@halofy/agent-connect 0.2.0 → 0.3.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 +3 -2
- package/package.json +1 -1
- package/src/client-registry.mjs +16 -0
- package/src/host-config.mjs +62 -0
- package/src/installer-cli.mjs +10 -8
- package/src/runtime.mjs +2 -1
- package/src/version.mjs +2 -2
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ agent connections:
|
|
|
19
19
|
There is one setup path for every packaged client:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
npx --yes @halofy/agent-connect@0.
|
|
22
|
+
npx --yes @halofy/agent-connect@0.3.0 install <client-kind> \
|
|
23
23
|
--server https://app.halofy.ai \
|
|
24
24
|
--claim '<one-time-claim>'
|
|
25
25
|
```
|
|
@@ -32,6 +32,7 @@ permits only these reviewed client kinds:
|
|
|
32
32
|
| `claude-code` | complete for declared text/tool lifecycle hooks | image bodies, artifact bodies, context-use evidence |
|
|
33
33
|
| `cursor` | complete for declared text/tool lifecycle hooks | image bodies, artifact bodies, context-use evidence |
|
|
34
34
|
| `gemini-cli` | complete for declared text/tool lifecycle hooks | image bodies, artifact bodies, subagents, context-use evidence |
|
|
35
|
+
| `kimi-cli` | partial | assistant responses, image and artifact bodies, context-use evidence |
|
|
35
36
|
| `codex` | partial | assistant responses, tool failures, session end, binary bodies |
|
|
36
37
|
| `vscode` | partial | assistant responses, binary bodies, context-use evidence |
|
|
37
38
|
| `cline` | partial | assistant responses, tool failures, subagents, compaction, session end, binary bodies |
|
|
@@ -60,7 +61,7 @@ and query rules. Publication is fail-closed until the package tarball, current
|
|
|
60
61
|
Claude fixtures, cross-implementation signature fixtures, and deployed server
|
|
61
62
|
protocol have all passed for the exact version. Server versions configured
|
|
62
63
|
with the Claude-only `0.1.x` artifact keep every additional client fenced as
|
|
63
|
-
`Not supported yet
|
|
64
|
+
`Not supported yet`; `0.2.x` keeps Kimi fenced until its `0.3.x` adapter.
|
|
64
65
|
|
|
65
66
|
Every packaged adapter advertises archive protocol v1 explicitly. The Claude
|
|
66
67
|
adapter's current
|
package/package.json
CHANGED
package/src/client-registry.mjs
CHANGED
|
@@ -5,6 +5,7 @@ export const CLIENT_KINDS = Object.freeze([
|
|
|
5
5
|
"vscode",
|
|
6
6
|
"cline",
|
|
7
7
|
"gemini-cli",
|
|
8
|
+
"kimi-cli",
|
|
8
9
|
]);
|
|
9
10
|
|
|
10
11
|
const BASE_CAPABILITIES = Object.freeze({
|
|
@@ -80,6 +81,21 @@ export const CLIENT_REGISTRY = Object.freeze({
|
|
|
80
81
|
compactionCheckpoints: true, contextRecalled: true,
|
|
81
82
|
}),
|
|
82
83
|
}),
|
|
84
|
+
"kimi-cli": Object.freeze({
|
|
85
|
+
clientKind: "kimi-cli",
|
|
86
|
+
label: "Kimi Code CLI",
|
|
87
|
+
command: "kimi",
|
|
88
|
+
coverage: "partial",
|
|
89
|
+
reason: "assistant_message_hook_unavailable",
|
|
90
|
+
capabilities: capabilities({
|
|
91
|
+
sessionStart: true, userPromptSubmit: true, stop: true, preCompact: true,
|
|
92
|
+
sessionEnd: true, subagentStart: true, subagentStop: true,
|
|
93
|
+
postToolUse: true, postToolUseFailure: true, userMessages: true,
|
|
94
|
+
toolInputs: true, toolOutputs: true, toolFailures: true,
|
|
95
|
+
artifactReferences: true, subagents: true, compactionCheckpoints: true,
|
|
96
|
+
contextRecalled: true,
|
|
97
|
+
}),
|
|
98
|
+
}),
|
|
83
99
|
vscode: Object.freeze({
|
|
84
100
|
clientKind: "vscode",
|
|
85
101
|
label: "VS Code",
|
package/src/host-config.mjs
CHANGED
|
@@ -137,6 +137,68 @@ export async function configureGemini({
|
|
|
137
137
|
return { configuredPaths: [settingsPath], hookEvents: Object.keys(GEMINI_HOOKS), replacedLegacyMcpEntries };
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
const KIMI_HOOKS = Object.freeze({
|
|
141
|
+
SessionStart: "SessionStart",
|
|
142
|
+
UserPromptSubmit: "UserPromptSubmit",
|
|
143
|
+
Stop: "Stop",
|
|
144
|
+
PostToolUse: "PostToolUse",
|
|
145
|
+
PostToolUseFailure: "PostToolUseFailure",
|
|
146
|
+
PreCompact: "PreCompact",
|
|
147
|
+
SessionEnd: "SessionEnd",
|
|
148
|
+
SubagentStart: "SubagentStart",
|
|
149
|
+
SubagentStop: "SubagentStop",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const KIMI_MANAGED_BEGIN = "# BEGIN HALOFY LIFECYCLE";
|
|
153
|
+
const KIMI_MANAGED_END = "# END HALOFY LIFECYCLE";
|
|
154
|
+
|
|
155
|
+
function replaceKimiManagedHooks(source, replacement) {
|
|
156
|
+
const text = String(source || "");
|
|
157
|
+
const start = text.indexOf(KIMI_MANAGED_BEGIN);
|
|
158
|
+
const end = text.indexOf(KIMI_MANAGED_END);
|
|
159
|
+
if ((start === -1) !== (end === -1) || (start !== -1 && end < start)) {
|
|
160
|
+
throw new Error("existing Halofy Kimi hook configuration is malformed");
|
|
161
|
+
}
|
|
162
|
+
const withoutManaged = start === -1
|
|
163
|
+
? text
|
|
164
|
+
: `${text.slice(0, start)}${text.slice(end + KIMI_MANAGED_END.length)}`;
|
|
165
|
+
const body = withoutManaged.trimEnd();
|
|
166
|
+
return `${body ? `${body}\n\n` : ""}${replacement}\n`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export async function configureKimi({
|
|
170
|
+
installationId,
|
|
171
|
+
nodePath = process.execPath,
|
|
172
|
+
runtimePath,
|
|
173
|
+
kimiRoot = process.env.KIMI_CODE_HOME || join(homedir(), ".kimi-code"),
|
|
174
|
+
}) {
|
|
175
|
+
validateInputs({ installationId, runtimePath });
|
|
176
|
+
const configPath = join(kimiRoot, "config.toml");
|
|
177
|
+
let source = "";
|
|
178
|
+
try { source = await readFile(configPath, "utf8"); } catch (error) { if (error?.code !== "ENOENT") throw error; }
|
|
179
|
+
const hookBlock = [
|
|
180
|
+
KIMI_MANAGED_BEGIN,
|
|
181
|
+
...Object.entries(KIMI_HOOKS).flatMap(([hostEvent, runtimeEvent]) => [
|
|
182
|
+
"[[hooks]]",
|
|
183
|
+
`event = ${JSON.stringify(hostEvent)}`,
|
|
184
|
+
`command = ${JSON.stringify(managedCommand(nodePath, runtimePath, runtimeEvent, installationId))}`,
|
|
185
|
+
"timeout = 20",
|
|
186
|
+
"",
|
|
187
|
+
]),
|
|
188
|
+
KIMI_MANAGED_END,
|
|
189
|
+
].join("\n");
|
|
190
|
+
const mcpPath = join(kimiRoot, "mcp.json");
|
|
191
|
+
const mcp = await readJson(mcpPath, {});
|
|
192
|
+
mcp.mcpServers = mcp.mcpServers && typeof mcp.mcpServers === "object" ? mcp.mcpServers : {};
|
|
193
|
+
const replacedLegacyMcpEntries = replaceHalofyMcpEntries(
|
|
194
|
+
mcp.mcpServers,
|
|
195
|
+
managedMcp(nodePath, runtimePath, installationId),
|
|
196
|
+
);
|
|
197
|
+
await writePrivateFile(configPath, replaceKimiManagedHooks(source, hookBlock));
|
|
198
|
+
await writePrivateFile(mcpPath, `${JSON.stringify(mcp, null, 2)}\n`);
|
|
199
|
+
return { configuredPaths: [configPath, mcpPath], hookEvents: Object.keys(KIMI_HOOKS), replacedLegacyMcpEntries };
|
|
200
|
+
}
|
|
201
|
+
|
|
140
202
|
const VSCODE_HOOKS = Object.freeze({
|
|
141
203
|
SessionStart: "SessionStart",
|
|
142
204
|
UserPromptSubmit: "UserPromptSubmit",
|
package/src/installer-cli.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
localMcpSnippet,
|
|
11
11
|
} from "./install.mjs";
|
|
12
12
|
import { configureClaudeProject } from "./claude-config.mjs";
|
|
13
|
-
import { configureCline, configureCodex, configureCursor, configureGemini, configureVscode } from "./host-config.mjs";
|
|
13
|
+
import { configureCline, configureCodex, configureCursor, configureGemini, configureKimi, configureVscode } from "./host-config.mjs";
|
|
14
14
|
import { CLIENT_KINDS, lifecycleClient } from "./client-registry.mjs";
|
|
15
15
|
import { defaultRuntimeDirectory } from "./storage.mjs";
|
|
16
16
|
import { DISCLOSURE_VERSION, INSTALLER_VERSION } from "./version.mjs";
|
|
@@ -172,13 +172,15 @@ export async function runInstaller(argv, {
|
|
|
172
172
|
? await configureCursor(common)
|
|
173
173
|
: input.clientKind === "gemini-cli"
|
|
174
174
|
? await configureGemini(common)
|
|
175
|
-
: input.clientKind === "
|
|
176
|
-
? await
|
|
177
|
-
: input.clientKind === "
|
|
178
|
-
? await
|
|
179
|
-
: input.clientKind === "
|
|
180
|
-
? await
|
|
181
|
-
:
|
|
175
|
+
: input.clientKind === "kimi-cli"
|
|
176
|
+
? await configureKimi(common)
|
|
177
|
+
: input.clientKind === "vscode"
|
|
178
|
+
? await configureVscode(common)
|
|
179
|
+
: input.clientKind === "codex"
|
|
180
|
+
? await configureCodex(common)
|
|
181
|
+
: input.clientKind === "cline"
|
|
182
|
+
? await configureCline(common)
|
|
183
|
+
: (() => { throw new Error("the selected adapter is not packaged yet"); })();
|
|
182
184
|
let heartbeat = false;
|
|
183
185
|
try {
|
|
184
186
|
heartbeat = await heartbeatInstalledConnection({
|
package/src/runtime.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { BoundedEncryptedQueue } from "./queue.mjs";
|
|
|
4
4
|
import { CursorStore, deriveSessionHash, readClaudeTranscriptSuffix } from "./session.mjs";
|
|
5
5
|
import { SignedRuntimeTransport } from "./transport.mjs";
|
|
6
6
|
import { withFileLock } from "./storage.mjs";
|
|
7
|
+
import { RUNTIME_VERSION } from "./version.mjs";
|
|
7
8
|
|
|
8
9
|
export class LifecycleRuntime {
|
|
9
10
|
constructor(connection, {
|
|
@@ -255,7 +256,7 @@ export class LifecycleRuntime {
|
|
|
255
256
|
async heartbeat(capabilities) {
|
|
256
257
|
const queue = await this.queue.diagnostics();
|
|
257
258
|
return this.transport.heartbeat(capabilities, {
|
|
258
|
-
pluginVersion: this.connection.pluginVersion ||
|
|
259
|
+
pluginVersion: this.connection.pluginVersion || `${RUNTIME_VERSION}-local`,
|
|
259
260
|
proofStorage: this.connection.proofStorage || "unknown",
|
|
260
261
|
diagnostics: {
|
|
261
262
|
queueDepth: queue.depth,
|
package/src/version.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export const PACKAGE_NAME = "@halofy/agent-connect";
|
|
2
|
-
export const INSTALLER_VERSION = "0.
|
|
3
|
-
export const RUNTIME_VERSION = "0.
|
|
2
|
+
export const INSTALLER_VERSION = "0.3.0";
|
|
3
|
+
export const RUNTIME_VERSION = "0.3.0";
|
|
4
4
|
export const DISCLOSURE_VERSION = "halofy-agent-lifecycle-2026-08-29";
|