@passioncode-ai/fabric-agent-adapter 0.44.1 → 0.44.2

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.
Files changed (19) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/package.json +1 -1
  3. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  4. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +1 -1
  5. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +1 -1
  6. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +1 -1
  7. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +3 -3
  8. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-base.mjs +1 -1
  9. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +5 -7
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-paths.mjs +13 -11
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-platform.mjs +1 -1
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_base.py +1 -1
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +5 -11
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_paths.py +8 -8
  15. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_platform.py +1 -1
  16. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +135 -57
  17. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +1 -1
  18. package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +1 -1
  19. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.44.2 (2026-10-22)
4
+
5
+ ### Fixed
6
+
7
+ - **The consumed-approval file is written with the kit's private writer** (FAA-85). `FileJtiStore` in both twins
8
+ opened its file with a plain 0600 mode and set no Windows ACL, so on Windows its privacy rested on its folder alone,
9
+ and a write that failed left its temporary file behind. It now writes through `fabric_paths.atomic_write` /
10
+ `atomicWrite`: a protected owner-only ACL before the bytes on Windows (DEC-0032), 0600 elsewhere, fsynced and renamed
11
+ into place, nothing left on failure. The file holds consumed approval ids, not a secret.
12
+ - **The kit's private writer removes its temporary file whatever fails, and reports the error that caused it**
13
+ (FAA-85, found by the blind readings). Node `atomicWrite` cleaned up only when chmod or the rename failed; a failure
14
+ while setting the Windows ACL, writing or syncing left `.<name>.<pid>.<hex>` beside the real file. Python
15
+ `atomic_write` set the Windows ACL before it wrapped the file's handle, so when that step failed the handle stayed
16
+ open, Windows could not delete the file, and the delete's error replaced the ACL's. Both now close the file on every
17
+ path, remove it, and raise the original error even when the removal fails.
18
+
19
+ ### Changed
20
+
21
+ - `fabric_base`, `fabric_platform` and `fabric_paths` (and their Node twins) move from layer L3 to L1 in `kit.json`, so
22
+ the L2 modules may use them: their code and names are unchanged. `fabric_delegation` now imports `fabric_paths`, so
23
+ a service that copies `fabric_delegation` by hand copies `fabric_base`, `fabric_platform` and `fabric_paths` too
24
+ (`fabric_kit.py install` and `status` name them).
25
+
3
26
  ## 0.44.1 (2026-10-22)
4
27
 
5
28
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@passioncode-ai/fabric-agent-adapter",
3
- "version": "0.44.1",
3
+ "version": "0.44.2",
4
4
  "description": "Create Fabric-compatible agents, run them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract. This package is the installer CLI.",
5
5
  "scripts": {
6
6
  "test": "python3 test/validate.py && python3 -m unittest discover -s test -q && node --test 'test/*.test.mjs'"
@@ -3,7 +3,7 @@
3
3
  "name": "fabric-agent-adapter",
4
4
  "displayName": "Fabric Agent Adapter",
5
5
  "description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks.",
6
- "version": "0.44.1",
6
+ "version": "0.44.2",
7
7
  "author": {
8
8
  "name": "PassionCode.ai",
9
9
  "url": "https://passioncode.ai/"
@@ -5,7 +5,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
5
5
  compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode.
6
6
  metadata:
7
7
  author: PassionCode.ai
8
- version: "0.44.1"
8
+ version: "0.44.2"
9
9
  contract-version: "0.1.0"
10
10
  contract-commit: "bfa9a67aa3c6cb808c093e7d83cd59799f1ee7d0"
11
11
  ---
@@ -14,7 +14,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
14
14
  compatibility: Python 3.9+ or Node.js 20+ for the kits (Node.js 22+ for a Linux service's instance lock); the probe needs Python 3.9+. launchd steps are macOS-only; Linux services install a systemd user unit and Windows ones a per-user Scheduled Task with the kits' writers. Dashboard handoff optionally uses Fabric Dashboards MCP link/host_status/open; without it, report unresolved host capability. The contract checkout is optional.
15
15
  metadata:
16
16
  author: PassionCode.ai
17
- version: "0.44.1"
17
+ version: "0.44.2"
18
18
  contract-version: "0.1.0"
19
19
  extension: "fabric-service/0.1"
20
20
  extension-commit: "bfa9a67aa3c6cb808c093e7d83cd59799f1ee7d0"
@@ -80,7 +80,7 @@ then the grant check where there is one, then `verify_approval` / `verifyApprova
80
80
  `jti` last, then the action. Without an approval, answer `approval-required` with
81
81
  `action_digest(action)` / `actionDigest(action)` (the SHA-256 of the action's RFC 8785 form, `jcs`) so the caller
82
82
  can ask the hub. When the meter denies a grant check, answer `refusal_from_denial(denial)` /
83
- `refusalFromDenial(denial)`: the meter's code unchanged, its window and level in `error.data` (DL-21 step 6). Keep consumed ids in `FileJtiStore` (0600, survives a restart); `MemoryJtiStore` is for tests
83
+ `refusalFromDenial(denial)`: the meter's code unchanged, its window and level in `error.data` (DL-21 step 6). Keep consumed ids in `FileJtiStore` (owner-only through the kit's private writer: 0600, on Windows a protected ACL; survives a restart); `MemoryJtiStore` is for tests
84
84
  and `UNSAFE_NO_JTI_STORE` exists only by name. No store at all, or a store file that cannot be read, is
85
85
  `unknown-state`, never a pass.
86
86
 
@@ -54,15 +54,15 @@ A module imports only modules listed before it in `kit.json`, so the kit has no
54
54
  | L0 | `fabric_identifiers` | identifier equality by normal form (DEC-0076) |
55
55
  | L0 | `fabric_secrets` | the contract's one credential detector (DEC-0044) |
56
56
  | L1 | `fabric_crypto` | Ed25519 signing (a Montgomery ladder that does not branch on the key) and verification, P-256 verification, base64url, sha256 |
57
+ | L1 | `fabric_base` | the protocol name, `ServiceError`, small shared helpers |
58
+ | L1 | `fabric_platform` | Windows: named pipes, owner-only files (DEC-0032) |
59
+ | L1 | `fabric_paths` | the services directory, a service's folders, atomic and private writes (L1 since 0.44.2, so `fabric_delegation` writes its consumed approval ids with them, FAA-85) |
57
60
  | L2 | `fabric_estate` | `estate-record/1` revisions and their rules (DEC-0055) |
58
61
  | L2 | `fabric_delegation` | the callee's side of `fabric-delegation/0.1` (DEC-0039) |
59
62
  | L2 | `fabric_share` | share grants and registrations (DEC-0086) |
60
63
  | L2 | `fabric_ceremonies` | the headless join token (DEC-0084) |
61
64
  | L2 | `fabric_package_schema` | the reading of `fabric-package.schema.json` with JavaScript's pattern and format semantics (FAA-92) |
62
65
  | L2 | `fabric_package` | `fabric-package/1`: pack, sign, verify; re-exports `schema_problems` (DEC-0050, DEC-0051) |
63
- | L3 | `fabric_base` | the protocol name, `ServiceError`, small shared helpers |
64
- | L3 | `fabric_platform` | Windows: named pipes, owner-only files (DEC-0032) |
65
- | L3 | `fabric_paths` | the services directory, a service's folders, atomic and private writes |
66
66
  | L3 | `fabric_protocols` | protocol revisions (DEC-0067) and feed data (DEC-0070) |
67
67
  | L3 | `fabric_connections` | what an agent uses, `fabric-connections/0.1`: the reference reading and the declaration (DEC-0096, FAC-SEM-127) |
68
68
  | L3 | `fabric_lock` | the instance lock and the supervisor marker (LC-01, DEC-0057) |
@@ -1,5 +1,5 @@
1
1
  // What every module of the Node service kit shares: the protocol name, ServiceError, ids, nowIso and expand.
2
- // Part of the Node service kit (FAA-65, layer L3); the twin of fabric_base.py. Node 20+, no dependency.
2
+ // Part of the Node service kit (FAA-65, layer L1); the twin of fabric_base.py. Node 20+, no dependency.
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
 
@@ -13,8 +13,8 @@
13
13
  import crypto from 'node:crypto';
14
14
  import fs from 'node:fs';
15
15
  import net from 'node:net';
16
- import path from 'node:path';
17
16
  import { hubKeyCertified } from './fabric-estate.mjs';
17
+ import { atomicWrite } from './fabric-paths.mjs'; // the kit's private writer (FAA-85)
18
18
 
19
19
  export const REFUSAL_CODES = Object.freeze([
20
20
  'unauthenticated', 'token-expired', 'wrong-audience', 'scope-not-granted', 'effect-above-ceiling', 'no-grant',
@@ -347,7 +347,7 @@ export function createMemoryJtiStore() {
347
347
  export class JtiStoreError extends Error {}
348
348
 
349
349
  /**
350
- * Consumed approval ids in a 0600 JSON file, so a second use is refused across a restart (DL-18). A file that
350
+ * Consumed approval ids in an owner-only JSON file, so a second use is refused across a restart (DL-18). A file that
351
351
  * cannot be read throws JtiStoreError: forgetting every consumed id would let each approval be replayed.
352
352
  */
353
353
  export class FileJtiStore {
@@ -364,11 +364,9 @@ export class FileJtiStore {
364
364
  const seen = new Map(Object.entries(read).filter(([, until]) => typeof until === 'number' && until + LEEWAY_SECONDS >= now));
365
365
  if (seen.has(jti)) return false;
366
366
  seen.set(jti, expiresAt);
367
- fs.mkdirSync(path.dirname(this.file), { recursive: true });
368
- const temp = path.join(path.dirname(this.file), `.${path.basename(this.file)}.${crypto.randomBytes(4).toString('hex')}.tmp`);
369
- const fd = fs.openSync(temp, 'wx', 0o600);
370
- try { fs.writeSync(fd, JSON.stringify(Object.fromEntries(seen))); fs.fsyncSync(fd); } finally { fs.closeSync(fd); }
371
- fs.renameSync(temp, this.file);
367
+ // Owner-only (0600; on Windows a protected ACL before the bytes, DEC-0032), fsynced, renamed into place, and no
368
+ // temporary file left when it fails (FAA-85).
369
+ atomicWrite(this.file, JSON.stringify(Object.fromEntries(seen)));
372
370
  return true;
373
371
  }
374
372
  }
@@ -1,5 +1,5 @@
1
1
  // Where a service's things live (fabric-service/0.1): the services directory, its data, config, logs and run dirs per OS, private dirs, atomic writes.
2
- // Part of the Node service kit (FAA-65, layer L3); the twin of fabric_paths.py. Node 20+, no dependency.
2
+ // Part of the Node service kit (FAA-65, layer L1); the twin of fabric_paths.py. Node 20+, no dependency.
3
3
  import crypto from 'node:crypto';
4
4
  import fs from 'node:fs';
5
5
  import os from 'node:os';
@@ -51,19 +51,21 @@ export function atomicWrite(file, data, mode = 0o600) {
51
51
  const tmp = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${crypto.randomBytes(4).toString('hex')}`);
52
52
  const fd = fs.openSync(tmp, 'wx', mode);
53
53
  try {
54
- // On Windows the file's ACL is its privacy (DEC-0032): set explicitly and protected — before the bytes go in —
55
- // so it does not depend on what the folder hands down. A rename keeps it.
56
- if (process.platform === 'win32') windowsProtect(tmp, { folder: false });
57
- fs.writeSync(fd, data);
58
- fs.fsyncSync(fd);
59
- } finally {
60
- fs.closeSync(fd);
61
- }
62
- try {
54
+ try {
55
+ // On Windows the file's ACL is its privacy (DEC-0032): set explicitly and protected — before the bytes go in —
56
+ // so it does not depend on what the folder hands down. A rename keeps it.
57
+ if (process.platform === 'win32') windowsProtect(tmp, { folder: false });
58
+ fs.writeSync(fd, data);
59
+ fs.fsyncSync(fd);
60
+ } finally {
61
+ fs.closeSync(fd);
62
+ }
63
63
  if (process.platform !== 'win32') fs.chmodSync(tmp, mode);
64
64
  fs.renameSync(tmp, file);
65
65
  } catch (error) {
66
- fs.rmSync(tmp, { force: true });
66
+ // Whatever failed, no half-written file is left beside the real one, and a failed cleanup never replaces the
67
+ // error that caused it (FAA-85).
68
+ try { fs.rmSync(tmp, { force: true }); } catch { /* the original error is the one to report */ }
67
69
  throw error;
68
70
  }
69
71
  }
@@ -1,5 +1,5 @@
1
1
  // Windows, where the kit needs it (DEC-0032): reading a file's ACL to refuse a token file others can read.
2
- // Part of the Node service kit (FAA-65, layer L3); the twin of fabric_platform.py. Node 20+, no dependency.
2
+ // Part of the Node service kit (FAA-65, layer L1); the twin of fabric_platform.py. Node 20+, no dependency.
3
3
  import crypto from 'node:crypto';
4
4
  import fs from 'node:fs';
5
5
  import os from 'node:os';
@@ -1,4 +1,4 @@
1
- """What every module of the service kit shares (FAA-65, layer L3): the protocol name, ServiceError, the
1
+ """What every module of the service kit shares (FAA-65, layer L1): the protocol name, ServiceError, the
2
2
  platform, ids and now_iso. Standard library only."""
3
3
  from __future__ import annotations
4
4
 
@@ -21,10 +21,8 @@ import http.client
21
21
  import ipaddress
22
22
  import json
23
23
  import math
24
- import os
25
24
  from pathlib import Path
26
25
  import re
27
- import secrets
28
26
  import threading
29
27
  import time
30
28
  from typing import Any, Callable, Dict, List, Mapping, Optional, Tuple
@@ -46,6 +44,7 @@ from fabric_jsvalue import ( # noqa: E402 - the core (FAA-65)
46
44
  MISSING as _MISSING,
47
45
  jcs,
48
46
  )
47
+ from fabric_paths import atomic_write as _atomic_write # noqa: E402 - the kit's private writer (FAA-85)
49
48
 
50
49
  REFUSAL_CODES = (
51
50
  "unauthenticated", "token-expired", "wrong-audience", "scope-not-granted", "effect-above-ceiling", "no-grant",
@@ -484,7 +483,7 @@ class JtiStoreError(RuntimeError):
484
483
 
485
484
 
486
485
  class FileJtiStore:
487
- """Consumed approval ids in a 0600 JSON file, so a second use is refused across a restart (DL-18). One
486
+ """Consumed approval ids in an owner-only JSON file, so a second use is refused across a restart (DL-18). One
488
487
  service instance writes it (the kit's instance lock keeps other processes out); threads are serialised."""
489
488
 
490
489
  _locks: Dict[str, threading.Lock] = {}
@@ -511,14 +510,9 @@ class FileJtiStore:
511
510
  if jti in seen:
512
511
  return False
513
512
  seen[jti] = expires_at
514
- self.path.parent.mkdir(parents=True, exist_ok=True)
515
- temp = self.path.with_name(".%s.%s.tmp" % (self.path.name, secrets.token_hex(4)))
516
- fd = os.open(str(temp), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
517
- with os.fdopen(fd, "w") as handle:
518
- json.dump(seen, handle)
519
- handle.flush()
520
- os.fsync(handle.fileno())
521
- os.replace(str(temp), str(self.path))
513
+ # The kit's private writer: owner-only (0600; on Windows a protected ACL before the bytes, DEC-0032),
514
+ # fsynced, renamed into place, and no temporary file left when it fails (FAA-85).
515
+ _atomic_write(self.path, json.dumps(seen).encode("utf-8"))
522
516
  return True
523
517
 
524
518
 
@@ -1,5 +1,5 @@
1
1
  """Where a service's things live (fabric-service/0.1): the services directory, a service's data, config, logs and run
2
- directories per OS, private directories and atomic writes. Part of the service kit (FAA-65, layer L3)."""
2
+ directories per OS, private directories and atomic writes. Part of the service kit (FAA-65, layer L1)."""
3
3
  from __future__ import annotations
4
4
 
5
5
  import os
@@ -83,11 +83,11 @@ def atomic_write(path: Path, data: bytes, mode: int = 0o600) -> None:
83
83
  path.parent.mkdir(parents=True, exist_ok=True)
84
84
  fd, tmp = tempfile.mkstemp(prefix="." + path.name + ".", dir=str(path.parent))
85
85
  try:
86
- if WINDOWS:
87
- # The file's ACL is its privacy (DEC-0032): set explicitly and protected — before the bytes go in — so
88
- # it does not depend on what the folder hands down. A rename keeps it.
89
- _win_protect(Path(tmp), folder=False)
90
- with os.fdopen(fd, "wb") as handle:
86
+ with os.fdopen(fd, "wb") as handle: # closed on every path: Windows cannot delete a file still open
87
+ if WINDOWS:
88
+ # The file's ACL is its privacy (DEC-0032): set explicitly and protected — before the bytes go in —
89
+ # so it does not depend on what the folder hands down. A rename keeps it.
90
+ _win_protect(Path(tmp), folder=False)
91
91
  handle.write(data)
92
92
  handle.flush()
93
93
  os.fsync(handle.fileno())
@@ -97,6 +97,6 @@ def atomic_write(path: Path, data: bytes, mode: int = 0o600) -> None:
97
97
  except BaseException:
98
98
  try:
99
99
  os.unlink(tmp)
100
- except FileNotFoundError:
101
- pass
100
+ except OSError:
101
+ pass # the error that got us here is the one to report, not a failed cleanup (FAA-85)
102
102
  raise
@@ -1,6 +1,6 @@
1
1
  """Windows, where the kit needs it (DEC-0032): named pipes that hold one copy, protecting a file to its owner, and
2
2
  reading a file's ACL to refuse a token file others can read. On other systems the same names exist and do nothing
3
- or answer "absent". Part of the service kit (FAA-65, layer L3)."""
3
+ or answer "absent". Part of the service kit (FAA-65, layer L1)."""
4
4
  from __future__ import annotations
5
5
 
6
6
  import os
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fabric-service-kit",
3
- "version": "0.44.1",
3
+ "version": "0.44.2",
4
4
  "about": "The service kit's modules in dependency order: a module imports only modules listed before it. Written by fabric_kit.py build; edit the order and layers by hand, never the digests.",
5
5
  "python": [
6
6
  {
@@ -40,6 +40,32 @@
40
40
  "imports": [],
41
41
  "sha256": "9c34aee20dbe4d6742e4fdbaab68ceb934bbe7dbd3a904c0010824ace16cdeaa"
42
42
  },
43
+ {
44
+ "module": "fabric_base",
45
+ "file": "fabric_base.py",
46
+ "layer": "L1",
47
+ "imports": [],
48
+ "sha256": "f62bcc2ed9912660fa875d27a09f60867260cc4925f79873501fd9620be59611"
49
+ },
50
+ {
51
+ "module": "fabric_platform",
52
+ "file": "fabric_platform.py",
53
+ "layer": "L1",
54
+ "imports": [
55
+ "fabric_base"
56
+ ],
57
+ "sha256": "a9350dff55ef0fb3a23cdb4d0320a15868b15a8deb10d2eb74d72c58740c284b"
58
+ },
59
+ {
60
+ "module": "fabric_paths",
61
+ "file": "fabric_paths.py",
62
+ "layer": "L1",
63
+ "imports": [
64
+ "fabric_base",
65
+ "fabric_platform"
66
+ ],
67
+ "sha256": "6c92af34292baddf7e10d3134d0a5b0bb23387741812a9f79c409cf1628bad23"
68
+ },
43
69
  {
44
70
  "module": "fabric_estate",
45
71
  "file": "fabric_estate.py",
@@ -60,9 +86,10 @@
60
86
  "imports": [
61
87
  "fabric_crypto",
62
88
  "fabric_estate",
63
- "fabric_jsvalue"
89
+ "fabric_jsvalue",
90
+ "fabric_paths"
64
91
  ],
65
- "sha256": "350e30cc0fb527bce1739c5f96bb9bec9028144def9d1b2630d1478529f8f996"
92
+ "sha256": "4eb5004188fdc6f5c0fd21fb0f9f1f538899a0383bcde0365dea080ef8347182"
66
93
  },
67
94
  {
68
95
  "module": "fabric_share",
@@ -116,32 +143,6 @@
116
143
  ],
117
144
  "sha256": "ff533f1b3f92b4ea0f532fcec50b68c610d47549930eef8ad5247692a64dfb3c"
118
145
  },
119
- {
120
- "module": "fabric_base",
121
- "file": "fabric_base.py",
122
- "layer": "L3",
123
- "imports": [],
124
- "sha256": "684533b3a2aa3acd9b9e645a7a443427d279408f9f12f13456a0a991d57954ce"
125
- },
126
- {
127
- "module": "fabric_platform",
128
- "file": "fabric_platform.py",
129
- "layer": "L3",
130
- "imports": [
131
- "fabric_base"
132
- ],
133
- "sha256": "8b0cd89193bc55da204a4a1850665c96929c6778523a8715b8156c5643745288"
134
- },
135
- {
136
- "module": "fabric_paths",
137
- "file": "fabric_paths.py",
138
- "layer": "L3",
139
- "imports": [
140
- "fabric_base",
141
- "fabric_platform"
142
- ],
143
- "sha256": "0d87e572bde2b930391b27aa370d808e093ce45cfba6148706f5318219906d30"
144
- },
145
146
  {
146
147
  "module": "fabric_protocols",
147
148
  "file": "fabric_protocols.py",
@@ -435,6 +436,32 @@
435
436
  "imports": [],
436
437
  "sha256": "038e03689701e3c9721a1e7f8e0a4d02a52d6a5d1661b0dc84035edc3ebbfcf6"
437
438
  },
439
+ {
440
+ "module": "fabric-base",
441
+ "file": "fabric-base.mjs",
442
+ "layer": "L1",
443
+ "imports": [],
444
+ "sha256": "7804b2df7715dbbf9702a9b61b6b8cef2110f9a52b04cabd8fb0a66458d87512"
445
+ },
446
+ {
447
+ "module": "fabric-platform",
448
+ "file": "fabric-platform.mjs",
449
+ "layer": "L1",
450
+ "imports": [
451
+ "fabric-base"
452
+ ],
453
+ "sha256": "a8119d95ebba4d589a9e401f5d6fc8dda62d59d44e4c1ff811d97fac3771ac0c"
454
+ },
455
+ {
456
+ "module": "fabric-paths",
457
+ "file": "fabric-paths.mjs",
458
+ "layer": "L1",
459
+ "imports": [
460
+ "fabric-base",
461
+ "fabric-platform"
462
+ ],
463
+ "sha256": "2201b4ed7126f260931b63e8386377b4317d8dcad419d109bf22c683e44b7f29"
464
+ },
438
465
  {
439
466
  "module": "fabric-estate",
440
467
  "file": "fabric-estate.mjs",
@@ -455,9 +482,10 @@
455
482
  "imports": [
456
483
  "fabric-crypto",
457
484
  "fabric-estate",
458
- "fabric-jsvalue"
485
+ "fabric-jsvalue",
486
+ "fabric-paths"
459
487
  ],
460
- "sha256": "2bc4310c6c7f0f6a11ba29d8bad2341feb0e0285758c33080e879e0a3a5cf128"
488
+ "sha256": "85a7e00e606244e7e02f9cbecc3e421bfcb9c1e12cd2a91daadf8a9c2403104d"
461
489
  },
462
490
  {
463
491
  "module": "fabric-share",
@@ -509,32 +537,6 @@
509
537
  ],
510
538
  "sha256": "49b757eefcc50e4c91585d5a5694bf3c83d0b03d112c1837f1c9f01466797ab5"
511
539
  },
512
- {
513
- "module": "fabric-base",
514
- "file": "fabric-base.mjs",
515
- "layer": "L3",
516
- "imports": [],
517
- "sha256": "17a92f5e9b71a855648e39e06388bad7f1b969605bd7b1f534ddf67b41a2fb5d"
518
- },
519
- {
520
- "module": "fabric-platform",
521
- "file": "fabric-platform.mjs",
522
- "layer": "L3",
523
- "imports": [
524
- "fabric-base"
525
- ],
526
- "sha256": "1349e3638c21caf7da7937ef6a5dfeefe05a8ee733520f0d581624095efeb388"
527
- },
528
- {
529
- "module": "fabric-paths",
530
- "file": "fabric-paths.mjs",
531
- "layer": "L3",
532
- "imports": [
533
- "fabric-base",
534
- "fabric-platform"
535
- ],
536
- "sha256": "e6f5e2ce7c8e7a1452d6ee69977489f4c09ca6f1d3100df9c303274f0b7b16b1"
537
- },
538
540
  {
539
541
  "module": "fabric-protocols",
540
542
  "file": "fabric-protocols.mjs",
@@ -2037,6 +2039,82 @@
2037
2039
  "fabric-openrouter.mjs": "f8f0168691f968b7cd85f36aa98e2167e88cc44f1104ff514fd0c7699b339253",
2038
2040
  "fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
2039
2041
  "share-registration.schema.json": "0df979d5973809d194723b23a0d18e520d9f1badc0f4a9e557aa33cbe7bc2922"
2042
+ },
2043
+ "0.44.2": {
2044
+ "fabric_jsvalue.py": "0cd4eab0a5d6ae35d097f7c59a08dc29173cb61c561c49e5291a8dad15d36779",
2045
+ "fabric_time.py": "588f383da4ac6a243ea95b6ffc3a0aa99ca94245732dc4937734f190b7af4ae9",
2046
+ "fabric_identifiers.py": "0fd814d521ac3aa39907458265870753046a73f48af3d8581ab864b93b211607",
2047
+ "fabric_secrets.py": "68a0b5e9e90c468ec9ac67b2f0fd1848e08813d6ec1ec14a2a47337eb1a98911",
2048
+ "fabric_crypto.py": "9c34aee20dbe4d6742e4fdbaab68ceb934bbe7dbd3a904c0010824ace16cdeaa",
2049
+ "fabric_base.py": "f62bcc2ed9912660fa875d27a09f60867260cc4925f79873501fd9620be59611",
2050
+ "fabric_platform.py": "a9350dff55ef0fb3a23cdb4d0320a15868b15a8deb10d2eb74d72c58740c284b",
2051
+ "fabric_paths.py": "6c92af34292baddf7e10d3134d0a5b0bb23387741812a9f79c409cf1628bad23",
2052
+ "fabric_estate.py": "50cc12166a00b680ba5b2e458200912d7bcfbef70bd73ec4edf57c7fcfa9b687",
2053
+ "fabric_delegation.py": "4eb5004188fdc6f5c0fd21fb0f9f1f538899a0383bcde0365dea080ef8347182",
2054
+ "fabric_share.py": "78506fe1a60829c525dbf6266a0aa0749a2164290ed94da8249a20b4e9be5605",
2055
+ "fabric_ceremonies.py": "a59e83cf4adb2669a9b98008e3d3a0cba991a35cbff97bc604fc82fe81cfd49f",
2056
+ "fabric_package_schema.py": "e623f0408d38e3343ed66222fb812907c6c52e1a286eb1c1176ab2e64640c9ad",
2057
+ "fabric_package.py": "ff533f1b3f92b4ea0f532fcec50b68c610d47549930eef8ad5247692a64dfb3c",
2058
+ "fabric_protocols.py": "71482284e57334b2d364a44596fc4183baddfe61a80083d3099b7ef423dc6f38",
2059
+ "fabric_connections.py": "77d3ccf863c70e9209d21ef45c46a6db9c06237019bc20d54f8d3946873f3f11",
2060
+ "fabric_lock.py": "ba2399d2137c7a7791b7133b9db9cca36693f4eb7e30955b25a75ade814e95ba",
2061
+ "fabric_usage.py": "ce685cb9fdfd62ea75fff8b1b2be12a2ba758da783e4bfb4dcebe47bcbeb832b",
2062
+ "fabric_backups.py": "02dc5eb66ec956723d3ddba07b6dd15f6a9726d901f4d60edfd02eee57880ceb",
2063
+ "fabric_descriptor.py": "5f6c8f3593fe0cef92d866109cd9def807f67dd5beae2c4bca05452f50521080",
2064
+ "fabric_auth.py": "55794587750f6c9f40935b74295d83d7096cb4b26a0b36ac292334cd87d8f853",
2065
+ "fabric_events.py": "0086886c2c29dbd5c9d152be9d375c5bdf4a29f89b8095baff8490c2bcd64e47",
2066
+ "fabric_logs.py": "86dc55bfafa2a57264722e2403510a249b95de0e4a722b2e4bc3948e3bd93da9",
2067
+ "fabric_supervisors.py": "a2dbf15aa1c4eb9de42996b413103fa4814afd2e4e66d1ab7315f30e06ab6841",
2068
+ "fabric_service.py": "d411433ce6ff3e81189b10b2c1a8462335a97cd99574ab0ee7d1c28cf48e1694",
2069
+ "fabric_profiles.py": "26e21ec29c016000f8ca8053b7b489184854a73be1b7fdc0a18d12990203db9b",
2070
+ "fabric_interop_rules.py": "845d87f7ec601bc2a8ce1ab0dcdc48a95f474ec38ba0ebd7aace85046c3c43f5",
2071
+ "fabric_interop.py": "0b4ca623caad90814426f00e328a7cf2bb52b936d824972136372dd9a0f87d7b",
2072
+ "fabric_hub.py": "b9ac852e601b1d54cf61351677a628afc69faeed7d1fc74ebe541c1cf38e0c2a",
2073
+ "fabric_board_shapes.py": "a8daefdc9283219206875b5d964b49552b6b3ba7e69c925abe08a44afc91c234",
2074
+ "fabric_board_link.py": "b5bff994cb615c6a4bb0d88d020e3a59504166180e1fa1aea3be93224f2aeccb",
2075
+ "fabric_board_session.py": "878ceed970a84087a320fd8eb971c210613a0fa2c524b68793fb32042910581e",
2076
+ "fabric_board_fixture.py": "69761ce205ec640762ec9b591c6903e5a87f844e8d423b041681924027e39d1e",
2077
+ "fabric_board.py": "0f075894b3e352194fcaf3fc7d08dee4e9f1c215e859769ed85fa5010e4a1599",
2078
+ "fabric_http.py": "5d7f72af3a73fdbe8c1f487ecf60cef23a7c46289eba542b03aff4706b8218d4",
2079
+ "fabric_openrouter.py": "2017d898c17001d7275f58267de653be7ecf6acd17ad8d9b24ecb7a43e5617d4",
2080
+ "fabric-jsvalue.mjs": "dfbdb8c41584972c9389750a41719374a1cfc5652ed438dd1623025190b0106e",
2081
+ "fabric-time.mjs": "3ff932069038a720df1c68c6492976906737b2e67e5c12d9c81c418597f661de",
2082
+ "fabric-identifiers.mjs": "a18c2a501a4aa170bfd3d99e571ad6b7662649b4d3b9d2a540c002ea42811bbf",
2083
+ "fabric-secrets.mjs": "6ad8ab18ac899ecc2384e8ec6a3fb689b92be3b9a5ce3a59b92a37d52da5d766",
2084
+ "fabric-crypto.mjs": "038e03689701e3c9721a1e7f8e0a4d02a52d6a5d1661b0dc84035edc3ebbfcf6",
2085
+ "fabric-base.mjs": "7804b2df7715dbbf9702a9b61b6b8cef2110f9a52b04cabd8fb0a66458d87512",
2086
+ "fabric-platform.mjs": "a8119d95ebba4d589a9e401f5d6fc8dda62d59d44e4c1ff811d97fac3771ac0c",
2087
+ "fabric-paths.mjs": "2201b4ed7126f260931b63e8386377b4317d8dcad419d109bf22c683e44b7f29",
2088
+ "fabric-estate.mjs": "912b1ceab57ed20f946986bf14ae2faf41fb8ea539e818164496874f3749ef65",
2089
+ "fabric-delegation.mjs": "85a7e00e606244e7e02f9cbecc3e421bfcb9c1e12cd2a91daadf8a9c2403104d",
2090
+ "fabric-share.mjs": "d40a7405d7bd4c3213ed691330b7549afe8e023db0753b582e249714e672010d",
2091
+ "fabric-ceremonies.mjs": "117d4374c9e95c930a38de7adbd4323774798f4fe6ec6f24afcd6f2c7298ca44",
2092
+ "fabric-package-schema.mjs": "cd28092375db0fc21ffab1f0bb7794f7f8979ee08c64d3b9faf4b3845357caa6",
2093
+ "fabric-package.mjs": "49b757eefcc50e4c91585d5a5694bf3c83d0b03d112c1837f1c9f01466797ab5",
2094
+ "fabric-protocols.mjs": "0ecc3c19bb0bd0393ff3a9ec503034e0ab251eaaf0254edf353e15d1b561f761",
2095
+ "fabric-connections.mjs": "303432e547ce563e90ca9ffcd827f5612f51d3582929834e1add0fdaf6485dcc",
2096
+ "fabric-lock.mjs": "ac219ab0a326d5c43c7c4c255e0c3843d4794de795a60e3af661e7d5350ea052",
2097
+ "fabric-usage.mjs": "e413569620bbc8221bc59e24b27e22d1483825ed18457801ed58d54a57de8114",
2098
+ "fabric-backups.mjs": "849acdc6eba0fff648c8158e61f6b68cccd7bedf0880f7d5ec03a6a20f1e7005",
2099
+ "fabric-descriptor.mjs": "e75b16bbf15ee72a3c581df8164533ea84270f6167e7a0d2527e15bf4b78457d",
2100
+ "fabric-auth.mjs": "3ea6796470fcd829bc72a772fb7e4c37532a09d1e37ff41592dcf1a1a3074ca2",
2101
+ "fabric-events.mjs": "c463d6ffcae24229a5c608d8fcea4268d2ccc5024b19fa10e5a452284068fa71",
2102
+ "fabric-logs.mjs": "58467e5719c16e099d05bbedec47a95712506ab03c33f3cd4be1252e8498a946",
2103
+ "fabric-supervisors.mjs": "9d61c1a17538a5e2453e33e5ae347337336748041bc054478a96dd51f3d4fc51",
2104
+ "fabric-service.mjs": "bc67550e52aa6aa9c6d2ed6cbae52418a3e836623e17164166699f953d8aafa8",
2105
+ "fabric-profiles.mjs": "314376cf2deb87f235fb18b11d3b532e211f585b9af0a9302b5f4cc39971b532",
2106
+ "fabric-interop-rules.mjs": "317f29e407d30ab2afa9bc5e87b3c57c547f216a4c51844d6427d05d6f8f6c9e",
2107
+ "fabric-interop.mjs": "11051f914f2457fd1b3424d7b4174d64500a08f7ce66ac10ed8eda71565511b1",
2108
+ "fabric-hub.mjs": "c005115a864cfd67daa4862097bb14acfe5a60bf653897e5bf8a570dd80f1070",
2109
+ "fabric-board-shapes.mjs": "ad1094397540862b104d9317d6902031d35e64b16c12bf849fb883e12cb78d45",
2110
+ "fabric-board-link.mjs": "4cd6d4e21713a38c8e56f7d59db3148638b8c27c08e774d96a0f6283c6049e0a",
2111
+ "fabric-board-session.mjs": "744a8c9a518c27f2ddfd20b1b22afebc3ccc4f59aeeb7a38d7c12c2ddcae158d",
2112
+ "fabric-board-fixture.mjs": "83c4b7e33ee47b68385faf2569d38d5c8a0c5cb0f8656090f41e1b0eed2f436e",
2113
+ "fabric-board.mjs": "9e7bfe4d412521982224ef12bebfc2ff255eeeaf8d96cf40234ac18de68e7a59",
2114
+ "fabric-http.mjs": "f886bcb49c4353d039387ac9568738dda26697a94dd07fc6a6204500f0bc27bf",
2115
+ "fabric-openrouter.mjs": "f8f0168691f968b7cd85f36aa98e2167e88cc44f1104ff514fd0c7699b339253",
2116
+ "fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
2117
+ "share-registration.schema.json": "0df979d5973809d194723b23a0d18e520d9f1badc0f4a9e557aa33cbe7bc2922"
2040
2118
  }
2041
2119
  },
2042
2120
  "data": {
@@ -5,7 +5,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
5
5
  compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode. Ships in one plugin with adapting-projects-to-fabric, whose scripts it reuses.
6
6
  metadata:
7
7
  author: PassionCode.ai
8
- version: "0.44.1"
8
+ version: "0.44.2"
9
9
  contract-version: "0.1.0"
10
10
  contract-commit: "bfa9a67aa3c6cb808c093e7d83cd59799f1ee7d0"
11
11
  ---
@@ -19,7 +19,7 @@ compatibility: >-
19
19
  this plugin; Codex/Kimi use command hooks; Hermes/OpenCode/OpenClaw/Pi use native context plugins after opt-in.
20
20
  metadata:
21
21
  author: PassionCode.ai
22
- version: "0.44.1"
22
+ version: "0.44.2"
23
23
  ---
24
24
 
25
25
  # Working with Fabric
@@ -57,7 +57,7 @@ SESSION_ID = re.compile(r"[A-Za-z0-9._:-]{1,128}")
57
57
  LOOPBACK_ORIGIN = re.compile(r"http://127\.0\.0\.1:(\d{1,5})")
58
58
 
59
59
 
60
- VERSION = "0.44.1"
60
+ VERSION = "0.44.2"
61
61
 
62
62
 
63
63
  HOSTS = {"claude": "Claude Code", "codex": "Codex", "kimi": "Kimi Code",