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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cofluxd",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Coflux 无界面宿主(cofluxd)与统一操作工具(coflux)",
5
5
  "type": "module",
6
6
  "bin": {
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 (component !== "worker" && component !== "supervisor") {
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 !== 2 ||
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 = [];
@@ -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