cofluxd 1.0.0 → 1.1.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/coflux.mjs +13 -0
- package/cofluxd.mjs +4 -4
- package/package.json +1 -1
- package/release-trust.mjs +10 -4
- package/skills/coflux/SKILL.md +14 -0
package/coflux.mjs
CHANGED
|
@@ -2,9 +2,22 @@
|
|
|
2
2
|
// coflux:账号与本地、跨设备业务操作;不负责宿主生命周期。
|
|
3
3
|
import { handlesAccountCommand, runAccountCommand } from "./account-client.mjs";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
5
7
|
import { homedir } from "node:os";
|
|
6
8
|
import { join } from "node:path";
|
|
7
9
|
const HOME = process.env.COFLUX_HOME || join(homedir(), ".coflux");
|
|
10
|
+
// Delegate integration to the native CLI shipped with this device's runtime.
|
|
11
|
+
if (process.argv[2] === "agent") {
|
|
12
|
+
const native = join(HOME, "bin", "coflux");
|
|
13
|
+
if (!existsSync(native)) {
|
|
14
|
+
console.error("Coflux integration is unavailable. Update this device with cofluxd update.");
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
const result = spawnSync(native, process.argv.slice(2), { stdio: "inherit" });
|
|
18
|
+
if (result.error) console.error(result.error.message);
|
|
19
|
+
process.exit(result.status ?? 1);
|
|
20
|
+
}
|
|
8
21
|
const DEFAULT_LOCAL_GATEWAY_PORT = 8788;
|
|
9
22
|
const die = (message) => { console.error("✗ " + message); process.exit(1); };
|
|
10
23
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
package/cofluxd.mjs
CHANGED
|
@@ -254,7 +254,7 @@ async function resolveLatestTag() {
|
|
|
254
254
|
async function ensureBinaries({ version, binDir, skipIfPresent }) {
|
|
255
255
|
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
256
256
|
if (binDir) {
|
|
257
|
-
const localArtifacts = ["coflux-supervisor", "coflux-worker"].map((name) => ({
|
|
257
|
+
const localArtifacts = ["coflux-supervisor", "coflux-worker", ...(fs.existsSync(join(binDir, "coflux")) ? ["coflux"] : [])].map((name) => ({
|
|
258
258
|
name,
|
|
259
259
|
path: join(binDir, name),
|
|
260
260
|
}));
|
|
@@ -336,7 +336,7 @@ async function ensureBinaries({ version, binDir, skipIfPresent }) {
|
|
|
336
336
|
}
|
|
337
337
|
const publicKey = loadReleasePublicKey();
|
|
338
338
|
const staged = [];
|
|
339
|
-
for (const component of ["supervisor", "worker"]) {
|
|
339
|
+
for (const component of ["supervisor", "worker", ...(manifest.cli ? ["cli"] : [])]) {
|
|
340
340
|
const entry = parseReleaseManifestEntry(manifest, component, releaseVersion, target);
|
|
341
341
|
const artifactName = `coflux-${component}-${target}`;
|
|
342
342
|
process.stdout.write(`下载并验签 ${artifactName} … `);
|
|
@@ -346,12 +346,12 @@ async function ensureBinaries({ version, binDir, skipIfPresent }) {
|
|
|
346
346
|
artifactName,
|
|
347
347
|
);
|
|
348
348
|
verifyReleaseArtifact({ component, version: releaseVersion, entry, data, publicKey });
|
|
349
|
-
const source = join(stageDir, `coflux-${component}`);
|
|
349
|
+
const source = join(stageDir, component === "cli" ? "coflux" : `coflux-${component}`);
|
|
350
350
|
fs.writeFileSync(source, data, { mode: 0o755 });
|
|
351
351
|
fs.chmodSync(source, 0o755);
|
|
352
352
|
staged.push({
|
|
353
353
|
source,
|
|
354
|
-
destination: component === "supervisor" ? SUP_BIN : WRK_BIN,
|
|
354
|
+
destination: component === "cli" ? join(BIN_DIR, "coflux") : component === "supervisor" ? SUP_BIN : WRK_BIN,
|
|
355
355
|
});
|
|
356
356
|
console.log("✓");
|
|
357
357
|
}
|
package/package.json
CHANGED
package/release-trust.mjs
CHANGED
|
@@ -11,6 +11,8 @@ export const SUPERVISOR_RELEASE_STATEMENT_DOMAIN = Buffer.from(
|
|
|
11
11
|
"utf8",
|
|
12
12
|
);
|
|
13
13
|
|
|
14
|
+
export const CLI_RELEASE_STATEMENT_DOMAIN = Buffer.from("coflux-cli-release-v1\0", "utf8");
|
|
15
|
+
|
|
14
16
|
const STRICT_RELEASE_VERSION = /^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
15
17
|
const SHA256_HEX = /^[0-9a-f]{64}$/i;
|
|
16
18
|
const ED25519_SIGNATURE_HEX = /^[0-9a-f]{128}$/i;
|
|
@@ -111,6 +113,10 @@ export function supervisorReleaseStatement(metadata) {
|
|
|
111
113
|
return artifactReleaseStatement(SUPERVISOR_RELEASE_STATEMENT_DOMAIN, metadata);
|
|
112
114
|
}
|
|
113
115
|
|
|
116
|
+
export function cliReleaseStatement(metadata) {
|
|
117
|
+
return artifactReleaseStatement(CLI_RELEASE_STATEMENT_DOMAIN, metadata);
|
|
118
|
+
}
|
|
119
|
+
|
|
114
120
|
export function createReleasePublicKey(publicKeyHex) {
|
|
115
121
|
const normalized = typeof publicKeyHex === "string" ? publicKeyHex.trim() : "";
|
|
116
122
|
if (!ED25519_PUBLIC_KEY_HEX.test(normalized)) {
|
|
@@ -136,7 +142,7 @@ function isRecord(value) {
|
|
|
136
142
|
*/
|
|
137
143
|
export function parseReleaseManifestEntry(manifest, component, version, target) {
|
|
138
144
|
assertReleaseVersion(version);
|
|
139
|
-
if (
|
|
145
|
+
if (!["worker", "supervisor", "cli"].includes(component)) {
|
|
140
146
|
throw new Error(`未知 release component: ${JSON.stringify(component)}`);
|
|
141
147
|
}
|
|
142
148
|
if (!isRecord(manifest) || manifest.schemaVersion !== 2 || manifest.version !== version) {
|
|
@@ -192,7 +198,7 @@ export function verifyReleaseArtifact({ component, version, entry, data, publicK
|
|
|
192
198
|
const metadata = { version, target: entry.target, sha256, size: data.byteLength };
|
|
193
199
|
const statement = component === "worker"
|
|
194
200
|
? workerReleaseStatement(metadata)
|
|
195
|
-
: supervisorReleaseStatement(metadata);
|
|
201
|
+
: component === "cli" ? cliReleaseStatement(metadata) : supervisorReleaseStatement(metadata);
|
|
196
202
|
if (!crypto.verify(null, statement, publicKey, Buffer.from(entry.releaseSignature, "hex"))) {
|
|
197
203
|
throw new Error(`${component} 产物 release Ed25519 签名无效`);
|
|
198
204
|
}
|
|
@@ -205,11 +211,11 @@ export function verifyReleaseArtifact({ component, version, entry, data, publicK
|
|
|
205
211
|
export function installStagedPair(staged) {
|
|
206
212
|
if (
|
|
207
213
|
!Array.isArray(staged) ||
|
|
208
|
-
staged.length
|
|
214
|
+
![2, 3].includes(staged.length) ||
|
|
209
215
|
staged.some(({ source, destination }) =>
|
|
210
216
|
typeof source !== "string" || !source || typeof destination !== "string" || !destination)
|
|
211
217
|
) {
|
|
212
|
-
throw new Error("daemon
|
|
218
|
+
throw new Error("daemon installation requires two or three valid staged artifacts");
|
|
213
219
|
}
|
|
214
220
|
const installed = [];
|
|
215
221
|
const backups = [];
|
package/skills/coflux/SKILL.md
CHANGED
|
@@ -22,6 +22,20 @@ local daemon and never touch the center; `new`/`list`/`ports` are relayed to the
|
|
|
22
22
|
daemon on your behalf (terminals must appear in the user's sidebar, preview URLs are minted by
|
|
23
23
|
the center). You only ever talk to the local daemon.
|
|
24
24
|
|
|
25
|
+
## Managed terminal integration
|
|
26
|
+
|
|
27
|
+
Coflux terminals automatically load this capability for Claude Code and Codex. Use
|
|
28
|
+
`coflux agent status` to inspect this terminal's integration acknowledgements; an
|
|
29
|
+
unconfirmed run has not successfully executed its context hook. It does not prove
|
|
30
|
+
that approval is pending. Codex asks for native hook review when needed; use `/hooks`
|
|
31
|
+
to review it. Do not edit trust hashes or the user's global configuration.
|
|
32
|
+
|
|
33
|
+
Each agent keeps its own immutable CLI and skill files. Relaunching the agent selects
|
|
34
|
+
the installed device version, including from an already-open supported shell. Use
|
|
35
|
+
`COFLUX_AGENT_INTEGRATION=off claude` or `COFLUX_AGENT_INTEGRATION=off codex` to bypass
|
|
36
|
+
managed integration for one invocation. Use `coflux agent run <claude|codex> -- ...`
|
|
37
|
+
when a custom shell alias takes precedence over automatic integration.
|
|
38
|
+
|
|
25
39
|
## Figure out where you are first
|
|
26
40
|
|
|
27
41
|
With the coflux plugin installed, Claude Code and Codex receive a `<coflux-session>` block at
|