@passioncode-ai/passioncode 0.2.10 → 0.2.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.11 - 2026-10-19
4
+
5
+ ### Changed
6
+
7
+ - **Fabric Agent Adapter is pinned at `v0.35.4`** (it was `v0.35.3`). Its session hooks rejoin a Fabric session at most
8
+ once a minute, so many agent sessions on one machine no longer spend Fabric's shared request budget on every turn;
9
+ the resilience reference follows the contract's job limit codes (DEC-0087).
10
+
3
11
  ## 0.2.10 - 2026-10-19
4
12
 
5
13
  ### Changed
package/family.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "name": "fabric-agent-adapter",
9
9
  "displayName": "Fabric Agent Adapter",
10
10
  "repo": "passioncode-ai/fabric-agent-adapter",
11
- "ref": "v0.35.3",
11
+ "ref": "v0.35.4",
12
12
  "kind": "plugin",
13
13
  "path": "plugins/fabric-agent-adapter",
14
14
  "legacyPluginIds": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@passioncode-ai/passioncode",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "Set up PassionCode.ai on a computer with one command — the apps from their verified releases, their MCP servers for every coding agent and the PassionCode.ai skills — and check and repair it with the same command or `doctor`.",
5
5
  "bin": {
6
6
  "passioncode": "bin/passioncode.js"
@@ -11,7 +11,7 @@
11
11
  "name": "fabric-agent-adapter",
12
12
  "displayName": "Fabric Agent Adapter",
13
13
  "source": "./plugins/fabric-agent-adapter",
14
- "version": "0.35.3",
14
+ "version": "0.35.4",
15
15
  "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.",
16
16
  "author": {
17
17
  "name": "PassionCode.ai",
@@ -35,7 +35,7 @@
35
35
  "name": "passioncode",
36
36
  "displayName": "PassionCode.ai",
37
37
  "source": "./plugins/passioncode",
38
- "version": "0.2.10",
38
+ "version": "0.2.11",
39
39
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
40
40
  "author": {
41
41
  "name": "PassionCode.ai",
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "family": "passioncode",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "release": true,
5
5
  "members": [
6
6
  {
7
7
  "name": "fabric-agent-adapter",
8
8
  "displayName": "Fabric Agent Adapter",
9
9
  "repo": "passioncode-ai/fabric-agent-adapter",
10
- "ref": "v0.35.3",
11
- "commit": "5657241426db468e4f51f9ef72788efb98eab9f9",
12
- "version": "0.35.3",
10
+ "ref": "v0.35.4",
11
+ "commit": "71c94d652ab4a9a87ae305d404cb671f74a2c5bb",
12
+ "version": "0.35.4",
13
13
  "via": "clone of https://***@github.com/passioncode-ai/fabric-agent-adapter.git",
14
14
  "skills": [
15
15
  "adapting-projects-to-fabric",
@@ -23,7 +23,7 @@
23
23
  "legacyMarketplaces": [
24
24
  "fabric-agent-adapter"
25
25
  ],
26
- "contentHash": "sha256:392cd0dd9bf29f450346b9d02af7d6b4cb19922da13aed46dba7fb9b65715e8e",
26
+ "contentHash": "sha256:4aa085081429d6588539f01e59d1e518d326a428f6f64e8454b6d08b8856c593",
27
27
  "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.",
28
28
  "author": {
29
29
  "name": "PassionCode.ai",
@@ -62,9 +62,9 @@
62
62
  "name": "passioncode",
63
63
  "displayName": "PassionCode.ai",
64
64
  "repo": "passioncode-ai/passioncode",
65
- "ref": "v0.2.10",
65
+ "ref": "v0.2.11",
66
66
  "commit": null,
67
- "version": "0.2.10",
67
+ "version": "0.2.11",
68
68
  "via": "this repository",
69
69
  "skills": [
70
70
  "setting-up-passioncode",
@@ -72,7 +72,7 @@
72
72
  ],
73
73
  "legacyPluginIds": [],
74
74
  "legacyMarketplaces": [],
75
- "contentHash": "sha256:a34b46fa6572410a232b9c1442eb6df00dc92037b342fb7539b5a378e9c06dac",
75
+ "contentHash": "sha256:93516986dc641e423cbe5c746d9d46b1557b4edde23a7e0b208450ef02aca65c",
76
76
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
77
77
  "author": {
78
78
  "name": "PassionCode.ai",
@@ -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.35.3",
6
+ "version": "0.35.4",
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.35.3"
8
+ version: "0.35.4"
9
9
  contract-version: "0.1.0"
10
10
  contract-commit: "d8146cfb0a1c74fc6432284c4356bb0c864b37b5"
11
11
  ---
@@ -18,7 +18,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
18
18
  compatibility: Python 3.9+ or Node.js 20+ for the kits; 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.
19
19
  metadata:
20
20
  author: PassionCode.ai
21
- version: "0.35.3"
21
+ version: "0.35.4"
22
22
  contract-version: "0.1.0"
23
23
  extension: "fabric-service/0.1"
24
24
  extension-commit: "d8146cfb0a1c74fc6432284c4356bb0c864b37b5"
@@ -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.35.3"
8
+ version: "0.35.4"
9
9
  contract-version: "0.1.0"
10
10
  contract-commit: "d8146cfb0a1c74fc6432284c4356bb0c864b37b5"
11
11
  ---
@@ -19,9 +19,14 @@ mechanism that held after the fix. Every rule is cheaper to build in than to ret
19
19
 
20
20
  ## Limits are pauses
21
21
 
22
- 1. **A provider or subscription limit pauses the job; it never fails it.** Store a typed pause
23
- (`quota_exhausted`, `retryable: true`, the reset time when known) and resume from the same
24
- stage. Failing it cost callers whole jobs and resubmits.
22
+ 1. **A provider or subscription limit pauses the job; it never fails it.** Keep the job `working` and
23
+ write its `statusMessage` in the contract's pause grammar, `quota-exhausted` or
24
+ `quota-exhausted until <UTC instant>` (optionally `: <text>`, at most 500 characters), with
25
+ `pollIntervalMs` reaching the reset; resume from the same stage. Only a job its provider will not
26
+ resume ends `failed` with `error: {code: "quota-exhausted", message, data: {retryable, resetsAt?}}`:
27
+ `retryable: false` when a person must act, and `resetsAt` (UTC, `T` and `Z`, at most three
28
+ fraction digits) only when `retryable: true` (contract DEC-0087, `FAC-SEM-119`). Failing a job a
29
+ limit only paused cost callers whole jobs and resubmits.
25
30
  2. **Resume first.** Every worker reads its own state — checkpoint, worktree, branches, open
26
31
  pull requests, notes — before it acts, and continues from there. Relaunching from scratch
27
32
  after a limit recreated work over committed work and re-issued credentials already held.
@@ -88,7 +93,11 @@ mechanism that held after the fix. Every rule is cheaper to build in than to ret
88
93
  4. **A resend of an unknown outcome reuses its idempotency key — or does not happen.** Derive
89
94
  keys from the intent (action and entity, or run and step), never from a clock or a random
90
95
  value, and make them unique in storage: time-and-random keys let redelivered requests charge
91
- again. A write whose effect is uncertain stops as `outcome_unknown`; a new key there pays twice.
96
+ again. A write whose effect is uncertain ends `failed` with the code `outcome-unknown`; only an
97
+ observed result settles it, and a new key there pays twice. A caller acts on each answer as the
98
+ contract's `jobCallerAction` does: wait out a pause, resend a retryable `quota-exhausted` under the
99
+ same key after `resetsAt`, hand a non-retryable one or `limit-reached` to a person, reconcile an
100
+ `outcome-unknown`, and never resend it.
92
101
  5. **A client error at submit is a rejection, not a lost task.** Settle it with known usage (zero
93
102
  if none), release the reserved money in the same transaction, and never resend the identical
94
103
  request; a 4xx while polling is still a lost task.
@@ -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.35.3"
22
+ version: "0.35.4"
23
23
  ---
24
24
 
25
25
  # Working with Fabric
@@ -87,6 +87,9 @@ only variable names are looked at, never a value (two of them carry the session'
87
87
  - **Start a second Fabric session.** A `fabric-mcp` started on its own would enroll a new session, and Fabric ends a
88
88
  binding's oldest live session past eight (ADR-0134 amendment 2) — the agent's own. The worker and `watch-mail` run
89
89
  `fabric-mcp --rejoin-only --runtime-session-id <id>`, and only when Fabric advertises `session-hooks/1`.
90
+ - **Rejoin more than once a minute.** Every rejoin spends the agent's Fabric request budget, which every session of
91
+ the machine shares. A turn within 60 s of the session's last successful rejoin (the worker marks it as `rejoined`
92
+ in the session's folder) is spooled and waits for the next worker; the end of a session always starts one (FAA-53).
90
93
  - **Retry in a loop.** A refused call is logged by its error code and dropped; an answer that never came is logged
91
94
  as `outcome=unknown`. The calls carry an `idempotencyKey`, so a repeat is the same event.
92
95
 
@@ -56,6 +56,9 @@ LOCK_STALE_S = 30.0
56
56
  #: A session folder untouched this long belongs to a session that will not spool again: its worker failed, or the
57
57
  #: session ended without SessionEnd. Nothing retries it, so the next spooling hook removes it (FAA-50).
58
58
  SESSION_STALE_S = 7 * 86400
59
+ #: A session rejoins at most once in this span (FAA-53): every rejoin spends Fabric's per-agent request budget, which
60
+ #: every session of the machine shares; a turn inside it waits in the spool for the next worker, an end never waits.
61
+ REJOIN_MIN_INTERVAL_S = 60.0
59
62
  READ_CAP = 64 * 1024
60
63
  CONFIG_CAP = 32 * 1024 * 1024
61
64
  WATCH_MIN_INTERVAL_S = 10
@@ -63,7 +66,7 @@ WATCH_MAX_BACKOFF_S = 900
63
66
  SESSION_ID = re.compile(r"[A-Za-z0-9._:-]{1,128}")
64
67
  LOOPBACK_ORIGIN = re.compile(r"http://127\.0\.0\.1:(\d{1,5})")
65
68
  LOCAL_ORIGIN = re.compile(r'"origin": "http://(?:127\.0\.0\.1|localhost)')
66
- VERSION = "0.35.3"
69
+ VERSION = "0.35.4"
67
70
  HOSTS = {"claude": "Claude Code", "codex": "Codex", "kimi": "Kimi Code",
68
71
  "hermes": "Hermes", "opencode": "OpenCode", "openclaw": "OpenClaw", "pi": "Pi"}
69
72
  NATIVE_PLUGIN_HOSTS = frozenset(("hermes", "opencode", "openclaw", "pi"))
@@ -559,10 +562,21 @@ def hook_spool(payload: Dict[str, Any], event: str, env: Optional[Dict[str, str]
559
562
  if event == "end" and isinstance(payload.get("reason"), str):
560
563
  entry["reason"] = payload["reason"][:64]
561
564
  spool(directory, entry)
562
- if event == "end" or not lock_held(directory):
563
- spawn(directory)
564
- return "spooled: worker started"
565
- return "spooled: a worker is running"
565
+ if event != "end" and lock_held(directory):
566
+ return "spooled: a worker is running"
567
+ if event != "end" and rejoined_recently(directory):
568
+ return "spooled: rejoined recently"
569
+ spawn(directory)
570
+ return "spooled: worker started"
571
+
572
+
573
+ def rejoined_recently(directory: Path, now: Optional[float] = None) -> bool:
574
+ """Whether this session's last rejoin succeeded within REJOIN_MIN_INTERVAL_S (the worker marks it)."""
575
+ try:
576
+ mark = (directory / "rejoined").stat().st_mtime
577
+ except OSError:
578
+ return False
579
+ return 0 <= (time.time() if now is None else now) - mark < REJOIN_MIN_INTERVAL_S
566
580
 
567
581
 
568
582
  def _remove_tree(directory: Path) -> None:
@@ -801,6 +815,7 @@ def deliver(directory: Path, env: Optional[Dict[str, str]] = None, deadline_s: f
801
815
  "clientInfo": {"name": "fabric-agent-adapter-hooks", "version": VERSION}})
802
816
  client.notify("notifications/initialized")
803
817
  names = _wait_for_session_tools(client, deadline)
818
+ _write_private(directory / "rejoined", "")
804
819
  while entries:
805
820
  for path in entries:
806
821
  entry = json.loads(read_small(path) or "{}")
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "passioncode",
4
4
  "displayName": "PassionCode.ai",
5
- "version": "0.2.10",
5
+ "version": "0.2.11",
6
6
  "description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check at session start that keeps the PassionCode.ai skill set current.",
7
7
  "author": {
8
8
  "name": "PassionCode.ai",