@passioncode-ai/passioncode 0.1.30 → 0.1.31
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 +9 -0
- package/family.json +1 -1
- package/package.json +1 -1
- package/payload/.claude-plugin/marketplace.json +2 -2
- package/payload/manifest.json +8 -8
- package/payload/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +3 -3
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +37 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +35 -3
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
- package/payload/plugins/passioncode/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.31 - 2026-10-08
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Fabric Agent Adapter is pinned at `v0.8.1`** (it was `v0.8.0`). Its default contract pin moves to Fabric
|
|
8
|
+
Agent Contract `main` `623bf61` (DEC-0025 through DEC-0031: settings backups, runner routes, spending limits,
|
|
9
|
+
activity telemetry, devices — optional surfaces the kits do not emit yet), and `Mcp-Name` values outside plain
|
|
10
|
+
ASCII use the MCP 2026-07-28 Base64 sentinel. Bundles issued under the earlier contract revisions stay valid.
|
|
11
|
+
|
|
3
12
|
## 0.1.30 - 2026-10-07
|
|
4
13
|
|
|
5
14
|
### Changed
|
package/family.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/passioncode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"description": "The PassionCode.ai agent skill set \u2014 Fabric Agent Adapter, Observatory Log and the organisation's working rules \u2014 for Claude Code and every other agent on the machine, updated as one set.",
|
|
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.8.
|
|
14
|
+
"version": "0.8.1",
|
|
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.",
|
|
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.1.
|
|
38
|
+
"version": "0.1.31",
|
|
39
39
|
"description": "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",
|
package/payload/manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"family": "passioncode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
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.8.
|
|
11
|
-
"commit": "
|
|
12
|
-
"version": "0.8.
|
|
10
|
+
"ref": "v0.8.1",
|
|
11
|
+
"commit": "0f5df40c0e8603806b5488e94646ed7ddc3e9cef",
|
|
12
|
+
"version": "0.8.1",
|
|
13
13
|
"via": "clone of https://***@github.com/passioncode-ai/fabric-agent-adapter.git",
|
|
14
14
|
"skills": [
|
|
15
15
|
"adapting-projects-to-fabric",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"legacyMarketplaces": [
|
|
23
23
|
"fabric-agent-adapter"
|
|
24
24
|
],
|
|
25
|
-
"contentHash": "sha256:
|
|
25
|
+
"contentHash": "sha256:b677c34c789b3a1c12ac1736ded76c03b5f027e9827617ec95b7d888c1e66e96",
|
|
26
26
|
"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.",
|
|
27
27
|
"author": {
|
|
28
28
|
"name": "PassionCode.ai",
|
|
@@ -61,16 +61,16 @@
|
|
|
61
61
|
"name": "passioncode",
|
|
62
62
|
"displayName": "PassionCode.ai",
|
|
63
63
|
"repo": "passioncode-ai/passioncode",
|
|
64
|
-
"ref": "v0.1.
|
|
64
|
+
"ref": "v0.1.31",
|
|
65
65
|
"commit": null,
|
|
66
|
-
"version": "0.1.
|
|
66
|
+
"version": "0.1.31",
|
|
67
67
|
"via": "this repository",
|
|
68
68
|
"skills": [
|
|
69
69
|
"working-in-passioncode"
|
|
70
70
|
],
|
|
71
71
|
"legacyPluginIds": [],
|
|
72
72
|
"legacyMarketplaces": [],
|
|
73
|
-
"contentHash": "sha256:
|
|
73
|
+
"contentHash": "sha256:ef970f490e58573c303b7244ccc678351fb1efe2652a3128f8dcb9c86d0fffa4",
|
|
74
74
|
"description": "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.",
|
|
75
75
|
"author": {
|
|
76
76
|
"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.",
|
|
6
|
-
"version": "0.8.
|
|
6
|
+
"version": "0.8.1",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -5,9 +5,9 @@ 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.8.
|
|
8
|
+
version: "0.8.1"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "623bf61358c339cb10297807b3f024b5d9f1f327"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Adapting projects to Fabric
|
|
@@ -70,7 +70,7 @@ Use exactly:
|
|
|
70
70
|
|
|
71
71
|
- contract version `0.1.0`;
|
|
72
72
|
- repository `https://github.com/passioncode-ai/fabric-agent-contract`;
|
|
73
|
-
- commit `
|
|
73
|
+
- commit `623bf61358c339cb10297807b3f024b5d9f1f327`.
|
|
74
74
|
|
|
75
75
|
This is the default for new bundles. When checking an issued legacy bundle, preserve its
|
|
76
76
|
explicit supported lock and use that exact clean checkout. Never silently upgrade or
|
|
@@ -16,10 +16,10 @@ from urllib.parse import urlparse
|
|
|
16
16
|
|
|
17
17
|
CONTRACT_VERSION = "0.1.0"
|
|
18
18
|
CONTRACT_REPOSITORY = "https://github.com/passioncode-ai/fabric-agent-contract"
|
|
19
|
-
CONTRACT_COMMIT = "
|
|
19
|
+
CONTRACT_COMMIT = "623bf61358c339cb10297807b3f024b5d9f1f327"
|
|
20
20
|
# #region supported-contract-revisions — docs: README.md#contract-pin
|
|
21
21
|
# Only this declaration may name a legacy revision in live files.
|
|
22
|
-
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
22
|
+
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
23
23
|
# #endregion supported-contract-revisions
|
|
24
24
|
INTEROP_KEY = "https://fabric.passioncode.ai/agent-contract/extensions/interop/0.1"
|
|
25
25
|
MCP_REVISION = "2026-07-28"
|
|
@@ -16,10 +16,10 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
16
16
|
compatibility: Python 3.9+ or Node.js 20+ for the kits; the probe needs Python 3.9+. launchd steps are macOS-only (Linux services use lifecycle manager none until a systemd adapter exists). Dashboard handoff optionally uses Fabric Dashboards MCP link/host_status/open; without it, report unresolved host capability. The contract checkout is optional.
|
|
17
17
|
metadata:
|
|
18
18
|
author: PassionCode.ai
|
|
19
|
-
version: "0.8.
|
|
19
|
+
version: "0.8.1"
|
|
20
20
|
contract-version: "0.1.0"
|
|
21
21
|
extension: "fabric-service/0.1"
|
|
22
|
-
extension-commit: "
|
|
22
|
+
extension-commit: "623bf61358c339cb10297807b3f024b5d9f1f327"
|
|
23
23
|
---
|
|
24
24
|
|
|
25
25
|
# Building Fabric services
|
package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# fabric-service/0.1 — wire reference
|
|
2
2
|
|
|
3
|
-
Pinned to `fabric-agent-contract` commit `
|
|
3
|
+
Pinned to `fabric-agent-contract` commit `623bf61358c339cb10297807b3f024b5d9f1f327`
|
|
4
4
|
(`docs/specification/service.md`, DEC-0015; the usage report DEC-0021). The contract's schemas are normative;
|
|
5
5
|
this page is the working summary. Extension key:
|
|
6
6
|
`https://fabric.passioncode.ai/agent-contract/extensions/service/0.1`.
|
|
@@ -226,6 +226,37 @@ export class JobStore {
|
|
|
226
226
|
export const NAMED_METHODS = { 'tools/call': 'name', 'prompts/get': 'name', 'resources/read': 'uri' };
|
|
227
227
|
export const HEADER_MISMATCH = -32020; // the code the official 2026-07-28 server SDK answers a header/body mismatch with
|
|
228
228
|
|
|
229
|
+
const SENTINEL = ['=?base64?', '?='];
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* A body value as an HTTP header value, by MCP 2026-07-28 Streamable HTTP "Value Encoding": as it
|
|
233
|
+
* is when it is printable ASCII without leading or trailing whitespace, otherwise — and for a plain
|
|
234
|
+
* value that itself looks like the sentinel — `=?base64?<base64 of its UTF-8>?=`.
|
|
235
|
+
*/
|
|
236
|
+
export function encodeHeaderValue(value) {
|
|
237
|
+
const s = String(value);
|
|
238
|
+
const plain = /^[\x20-\x7e]*$/.test(s) && s === s.replace(/^ +| +$/g, '') && !(s.startsWith(SENTINEL[0]) && s.endsWith(SENTINEL[1]));
|
|
239
|
+
if (plain) return s;
|
|
240
|
+
let binary = '';
|
|
241
|
+
for (const byte of new TextEncoder().encode(s)) binary += String.fromCharCode(byte);
|
|
242
|
+
return SENTINEL[0] + btoa(binary) + SENTINEL[1];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** The body value a header carries, decoding the Base64 sentinel; null for invalid characters or a
|
|
246
|
+
* sentinel that is not valid Base64 of UTF-8 (a server rejects both). */
|
|
247
|
+
export function decodeHeaderValue(value) {
|
|
248
|
+
const s = String(value);
|
|
249
|
+
if (s.startsWith(SENTINEL[0]) && s.endsWith(SENTINEL[1]) && s.length >= SENTINEL[0].length + SENTINEL[1].length) {
|
|
250
|
+
const body = s.slice(SENTINEL[0].length, -SENTINEL[1].length);
|
|
251
|
+
if (body.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(body)) return null;
|
|
252
|
+
try {
|
|
253
|
+
const bytes = Uint8Array.from(atob(body), (c) => c.charCodeAt(0));
|
|
254
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
|
|
255
|
+
} catch { return null; }
|
|
256
|
+
}
|
|
257
|
+
return /^[\x20-\x7e\t]*$/.test(s) ? s : null;
|
|
258
|
+
}
|
|
259
|
+
|
|
229
260
|
/**
|
|
230
261
|
* MCP 2026-07-28 Streamable HTTP mirrors the body in `Mcp-Method` (every request and
|
|
231
262
|
* notification) and `Mcp-Name` (`params.name` or `params.uri` of tools/call, prompts/get,
|
|
@@ -250,7 +281,11 @@ export function mcpHeaderProblem(message, headers) {
|
|
|
250
281
|
if (field) {
|
|
251
282
|
const named = header('Mcp-Name');
|
|
252
283
|
if (named === null && declared) return `the body carries params.${field} but the required Mcp-Name header is absent`;
|
|
253
|
-
if (named !== null
|
|
284
|
+
if (named !== null) {
|
|
285
|
+
const decoded = decodeHeaderValue(named);
|
|
286
|
+
if (decoded === null) return 'Mcp-Name is malformed: invalid characters or a broken =?base64?…?= value';
|
|
287
|
+
if (decoded !== String(message.params?.[field])) return `Mcp-Name disagrees with the body's params.${field}`;
|
|
288
|
+
}
|
|
254
289
|
}
|
|
255
290
|
return null;
|
|
256
291
|
}
|
|
@@ -259,6 +294,6 @@ export function mcpHeaderProblem(message, headers) {
|
|
|
259
294
|
export function mcpRequestHeaders(method, params = {}) {
|
|
260
295
|
const out = { 'MCP-Protocol-Version': MCP_REVISION, 'Mcp-Method': method };
|
|
261
296
|
const field = NAMED_METHODS[method];
|
|
262
|
-
if (field && params[field] !== undefined && params[field] !== null) out['Mcp-Name'] =
|
|
297
|
+
if (field && params[field] !== undefined && params[field] !== null) out['Mcp-Name'] = encodeHeaderValue(params[field]);
|
|
263
298
|
return out;
|
|
264
299
|
}
|
|
@@ -17,6 +17,7 @@ Normative source: fabric-agent-contract docs/specification/interop.md (DEC-0016,
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
+
import base64
|
|
20
21
|
import json
|
|
21
22
|
from pathlib import Path
|
|
22
23
|
import re
|
|
@@ -386,6 +387,33 @@ NAMED_METHODS = {"tools/call": "name", "prompts/get": "name", "resources/read":
|
|
|
386
387
|
HEADER_MISMATCH = -32020 # the code the official 2026-07-28 server SDK answers a header/body mismatch with
|
|
387
388
|
|
|
388
389
|
|
|
390
|
+
_SENTINEL = ("=?base64?", "?=")
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
def encode_header_value(value: str) -> str:
|
|
394
|
+
"""A body value as an HTTP header value, by MCP 2026-07-28 Streamable HTTP "Value Encoding": as
|
|
395
|
+
it is when it is printable ASCII without leading or trailing whitespace, otherwise — and for a
|
|
396
|
+
plain value that itself looks like the sentinel — `=?base64?<base64 of its UTF-8>?=`."""
|
|
397
|
+
plain = (all(0x20 <= ord(c) <= 0x7E for c in value) and value == value.strip(" ")
|
|
398
|
+
and not (value.startswith(_SENTINEL[0]) and value.endswith(_SENTINEL[1])))
|
|
399
|
+
if plain:
|
|
400
|
+
return value
|
|
401
|
+
return _SENTINEL[0] + base64.b64encode(value.encode("utf-8")).decode("ascii") + _SENTINEL[1]
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def decode_header_value(value: str) -> Optional[str]:
|
|
405
|
+
"""The body value a header carries, decoding the Base64 sentinel; None for a header value with
|
|
406
|
+
invalid characters or a sentinel that is not valid Base64 of UTF-8 (a server rejects both)."""
|
|
407
|
+
if value.startswith(_SENTINEL[0]) and value.endswith(_SENTINEL[1]) and len(value) >= len(_SENTINEL[0]) + len(_SENTINEL[1]):
|
|
408
|
+
try:
|
|
409
|
+
return base64.b64decode(value[len(_SENTINEL[0]):-len(_SENTINEL[1])], validate=True).decode("utf-8")
|
|
410
|
+
except ValueError: # binascii.Error and UnicodeDecodeError are both ValueErrors
|
|
411
|
+
return None
|
|
412
|
+
if any(not (0x20 <= ord(c) <= 0x7E or c == "\t") for c in value):
|
|
413
|
+
return None
|
|
414
|
+
return value
|
|
415
|
+
|
|
416
|
+
|
|
389
417
|
def mcp_header_problem(message: Any, headers: Any) -> Optional[str]:
|
|
390
418
|
"""MCP 2026-07-28 Streamable HTTP mirrors the body in `Mcp-Method` (every request and
|
|
391
419
|
notification) and `Mcp-Name` (`params.name` or `params.uri` of tools/call, prompts/get,
|
|
@@ -414,8 +442,12 @@ def mcp_header_problem(message: Any, headers: Any) -> Optional[str]:
|
|
|
414
442
|
named = header("Mcp-Name")
|
|
415
443
|
if named is None and declared:
|
|
416
444
|
return "the body carries params.%s but the required Mcp-Name header is absent" % field
|
|
417
|
-
if named is not None
|
|
418
|
-
|
|
445
|
+
if named is not None:
|
|
446
|
+
decoded = decode_header_value(named)
|
|
447
|
+
if decoded is None:
|
|
448
|
+
return "Mcp-Name is malformed: invalid characters or a broken =?base64?…?= value"
|
|
449
|
+
if decoded != str(value):
|
|
450
|
+
return "Mcp-Name disagrees with the body's params.%s" % field
|
|
419
451
|
return None
|
|
420
452
|
|
|
421
453
|
|
|
@@ -424,7 +456,7 @@ def mcp_request_headers(method: str, params: Dict[str, Any]) -> Dict[str, str]:
|
|
|
424
456
|
out = {"MCP-Protocol-Version": MCP_REVISION, "Mcp-Method": method}
|
|
425
457
|
field = NAMED_METHODS.get(method)
|
|
426
458
|
if field and params.get(field) is not None:
|
|
427
|
-
out["Mcp-Name"] = str(params[field])
|
|
459
|
+
out["Mcp-Name"] = encode_header_value(str(params[field]))
|
|
428
460
|
return out
|
|
429
461
|
|
|
430
462
|
|
|
@@ -5,9 +5,9 @@ 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.8.
|
|
8
|
+
version: "0.8.1"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "623bf61358c339cb10297807b3f024b5d9f1f327"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Creating Fabric-compatible agents
|
|
@@ -119,7 +119,7 @@ python3 <plugin-dir>/skills/adapting-projects-to-fabric/scripts/adapt_project.py
|
|
|
119
119
|
--schema-base <immutable-base-uri>
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
Pin exactly contract `0.1.0` at commit `
|
|
122
|
+
Pin exactly contract `0.1.0` at commit `623bf61358c339cb10297807b3f024b5d9f1f327` and
|
|
123
123
|
read the pinned guide before implementing protocol details. If this skill is installed
|
|
124
124
|
without its sibling, the scaffolder is absent: create the bundle by hand from the pinned
|
|
125
125
|
contract's `docs/guides/connecting-compatible-agents.md` and mark the structural check
|
|
@@ -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.1.
|
|
5
|
+
"version": "0.1.31",
|
|
6
6
|
"description": "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",
|