@passioncode-ai/fabric-agent-adapter 0.82.0 → 0.84.1
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 +169 -3
- package/README.md +7 -3
- package/SECURITY.md +4 -3
- package/package.json +1 -1
- package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +7 -2
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/agents-database.md +10 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md +4 -2
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/source-and-instance.md +18 -4
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +16 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_identifiers.py +1 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_provider.py +31 -15
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_secrets.py +38 -12
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_check.py +21 -148
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_source_check_cli.py +164 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +15 -8
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +4 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +3 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +14 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/data-agent/README.md +76 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/data-agent/config.example.json +28 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/data-agent/data_agent.py +366 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md +32 -17
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/config.example.json +4 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/support-agent.mjs +115 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/support_agent.py +63 -11
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/a2a.md +98 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/agents-database.md +10 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +28 -12
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/connectors.md +2 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +14 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +13 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +11 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/ops-digest.md +75 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +7 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +25 -12
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +10 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +70 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_a2a.py +158 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-a2a-server.mjs +275 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-a2a.mjs +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-actions.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-auth.mjs +5 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-backups.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-base.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-fixture.mjs +15 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-link.mjs +55 -11
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-session.mjs +47 -31
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-shapes.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-slots.mjs +25 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ceremonies.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-connections.mjs +27 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-context.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-crypto.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +4 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +19 -12
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate-rules.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-events.mjs +7 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-holds.mjs +22 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-http.mjs +4 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-hub.mjs +7 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-identifiers.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop-rules.mjs +21 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +6 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-jsvalue.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-load.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-lock.mjs +16 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-logs.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-mandate.mjs +6 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-openrouter.mjs +25 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ops-digest.mjs +456 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package-schema.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +18 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-page-links.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-paths.mjs +19 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-peer-owner.mjs +56 -19
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-platform.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-profiles.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-secrets.mjs +16 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-share.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-socket-proof.mjs +181 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-supervisors.mjs +20 -15
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-tailnet-identity.mjs +469 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-tailnet.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-time.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-usage.mjs +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_a2a.py +3 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_a2a_server.py +405 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_actions.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_auth.py +7 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_backups.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_base.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_fixture.py +17 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_link.py +98 -9
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_session.py +37 -48
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_shapes.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_slots.py +25 -8
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ceremonies.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_connections.py +28 -6
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_context.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_crypto.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +19 -13
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +24 -14
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate_rules.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_events.py +4 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_holds.py +32 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_http.py +19 -16
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_hub.py +10 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_identifiers.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +56 -96
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop_rules.py +99 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_jsvalue.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_load.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_lock.py +16 -6
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_logs.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_mandate.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_openrouter.py +44 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ops_digest.py +648 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +17 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package_schema.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_page_links.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_paths.py +21 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_peer_owner.py +108 -108
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_platform.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_profiles.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_secrets.py +38 -12
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_share.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_socket_proof.py +391 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py +19 -16
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet_identity.py +493 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_time.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_usage.py +1 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +632 -104
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample-remote-service.mjs +2 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +17 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/tailnet-groups.schema.json +69 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +6 -5
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/agent-templates.md +16 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/agents-database.md +10 -0
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/agents-that-answer-people.md +14 -9
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/models-and-providers.md +4 -2
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/source-and-instance.md +18 -4
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/where-agents-run.md +4 -3
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/admit.py +182 -0
- package/plugins/fabric-agent-adapter/skills/observing-products/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +1 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/agents-database.md +10 -0
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/on-demand-session.md +14 -9
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +7 -4
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/session-hooks.md +10 -5
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session.py +2 -0
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_cli.py +16 -5
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +79 -8
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_paths.py +147 -45
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,171 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.84.1 (2026-11-13)
|
|
4
|
+
|
|
5
|
+
0.84.0 was tagged and not published: its release run failed one Node 18 test on the hosted floor runner.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **The board mandate's linear-time test reads bodies large enough to time** (FAA-135): at 64 KiB a read lasted under a
|
|
10
|
+
millisecond of CPU time, and one garbage collection made the 4x ratio read as 10x on Node 18; it now compares 256 KiB
|
|
11
|
+
with 1 MiB, where linear is still about 4 and quadratic about 16, and repeats each read until 50 ms of CPU time
|
|
12
|
+
(Windows counts it in 15.6 ms ticks, and one short read measured 0), in both twins' tests. No shipped code changes.
|
|
13
|
+
|
|
14
|
+
## 0.84.0 (2026-11-13)
|
|
15
|
+
|
|
16
|
+
Wave 6 of the backlog sweep of 2026-11-12. The contract pin stays at `93e7db16` (`v0.1.0+2026-11-08.1`).
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **Every service kit module carries the package's licence as an SPDX line** (FAA-192 item 15, the operator's decision
|
|
21
|
+
of 2026-11-13): `AGPL-3.0-only OR LicenseRef-PassionCode-Commercial`, right after a shebang or as the first line, so
|
|
22
|
+
every copy `fabric_kit.py install` makes keeps it, an agent whose own files are all rights reserved included; the
|
|
23
|
+
kit's JSON schemas cannot carry a comment. `kit.json`'s digests change for every module. The dashboard kit moves to
|
|
24
|
+
1.1.9 for the same line in its three copied files.
|
|
25
|
+
- **creating-fabric-agents names where an agent reads the private cloud Fabric-server template's repository, never the
|
|
26
|
+
repository** (FAA-192 item 1, the operator's decision of 2026-11-13): the instance's settings or the estate's agent
|
|
27
|
+
map.
|
|
28
|
+
- **`board.slot.returned` means one thing** (FAA-325): the reference service's take-back says `board.slot.taken_back`
|
|
29
|
+
(the slot still away), and the kit says `board.slot.returned` once the slot is held again, after a move back and now
|
|
30
|
+
also once an enroll or replace lands after the operator's take-back (once per take-back in the same process, both
|
|
31
|
+
twins); a take-back of a slot still held marks nothing.
|
|
32
|
+
- The supervisors' well-known reader uses the kit's one loopback rule (`fabric_socket_proof.loopback_host` /
|
|
33
|
+
`loopbackHost`): `127.1`, `2130706433`, `0x7f.1` and names under `.localhost` go on the checked connection (FAA-326).
|
|
34
|
+
- `fabric_peer_owner` no longer adds the kit folder to the host's `sys.path` (FAA-327): it asks the `fabric_socket_proof`
|
|
35
|
+
beside it, the host's imported module when that is the same file (one calibration in a process), else that file by
|
|
36
|
+
its path; a copy vendored alone keeps the table's answer, and every kit install that brings `fabric_peer_owner` still
|
|
37
|
+
brings `fabric_socket_proof`. `PEER_OWNER_VERSION` is `1.3.1+kit.8`.
|
|
38
|
+
- The supervisors' well-known reader refuses unread a loopback address the kit's rule does not take, with a zone
|
|
39
|
+
(`[::1%lo0]`) or IPv4-mapped (`[::ffff:127.0.0.1]`), where `urlopen` or `fetch` would reach the listener without the
|
|
40
|
+
owner check (0.84.0 seam reading).
|
|
41
|
+
- `test/validate.py` reads the private-terms list with the functions `admit.py` ships (`terms_file`, `terms_pattern`,
|
|
42
|
+
`term_lines`, `listed_files`), pinned to one case table; `admit.py`'s file listing no longer fails when `git` cannot
|
|
43
|
+
run (FAA-328).
|
|
44
|
+
|
|
45
|
+
### Upgrading
|
|
46
|
+
|
|
47
|
+
- A dashboard or feed that reads `board.slot.returned` as the operator's take-back request reads
|
|
48
|
+
`board.slot.taken_back` now (FAA-325).
|
|
49
|
+
|
|
50
|
+
## 0.83.1 (2026-11-13)
|
|
51
|
+
|
|
52
|
+
0.83.0 was tagged and not published: its release run failed one Windows test of the tailnet identity module.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- **A same-size rewrite of the groups file within one timestamp tick is seen** (FAA-324): `TailnetIdentity` read the
|
|
57
|
+
file again only when its inode, size, mtime or ctime changed, and Windows' runner left all of them as they were for
|
|
58
|
+
an in-place rewrite of the same size. While the file's mtime is under two seconds old, an unchanged stat now reads
|
|
59
|
+
its bytes and compares their SHA-256 (git's racy-clean rule), in both twins; an older unchanged stat is not read.
|
|
60
|
+
|
|
61
|
+
## 0.83.0 (2026-11-13)
|
|
62
|
+
|
|
63
|
+
Wave 5 of the backlog sweep of 2026-11-12. The contract pin stays at `93e7db16` (`v0.1.0+2026-11-08.1`).
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- **The accepted-socket proof** (FAA-292, FAA-272): a new L0 kit module, `fabric_socket_proof` /
|
|
68
|
+
`fabric-socket-proof.mjs`, finds the server end of a connection, or a listener on exactly 127.0.0.1, among this OS
|
|
69
|
+
account's own processes (DEC-0155 RT-2; Python reads libproc, calibrated on a pair of its own, with an lsof fallback;
|
|
70
|
+
Node reads `lsof -F pun`). `fabric_peer_owner` asks it on a restricted macOS table before the RT-3 vouch, and stands
|
|
71
|
+
alone without it. `PEER_OWNER_VERSION` is `1.3.1+kit.7`.
|
|
72
|
+
- **Operations digests** (FAA-206 part 2): `fabric_ops_digest` and `fabric-ops-digest.mjs` fold a service's own counts
|
|
73
|
+
into `ops.digest.hourly@1` and `ops.digest.daily@1` (DEC-0153), held to the contract's reference folds and its
|
|
74
|
+
fixtures (FAC-SEM-166, FAC-SEM-167); they keep the hour the service stops in for the next run, never fill hours
|
|
75
|
+
across a sleep, and catch up missed days. `ops_digest_extension` writes the descriptor's OD-9 declaration. New
|
|
76
|
+
`references/ops-digest.md`.
|
|
77
|
+
- **A2A serving and calling** (FAA-10): `fabric_a2a_server` and `fabric-a2a-server.mjs` build the Agent Card from the
|
|
78
|
+
service's capabilities, check it before serving it, and map the A2A 1.0 JSON-RPC binding (`SendMessage`,
|
|
79
|
+
`SendStreamingMessage` as server-sent events, `GetTask`, `CancelTask`) onto the interop job store. `A2AClient` reaches
|
|
80
|
+
only origins on the operator's list, with its key from the environment. `check_service_a2a.py` holds the probe rows.
|
|
81
|
+
New `references/a2a.md`. The interop test against Hermes waits on a reachable endpoint.
|
|
82
|
+
- **A data-agent recipe** (FAA-66): `recipes/data-agent/`, numbers computed by code from a read-only source and answered
|
|
83
|
+
with a truth envelope where missing is never zero (built from the agents database's `data-room` template).
|
|
84
|
+
- **The support recipe** (FAA-116, FAA-182, FAA-264): a person's categories are routed first, a same-vendor fallback is
|
|
85
|
+
refused at load, the outbox is redacted, knowledge ids must be citable, and `support-agent.mjs` is `check_reply`'s
|
|
86
|
+
Node twin (31 shared cases).
|
|
87
|
+
- **`FABRIC_DATA_HOME`** puts a service's data folder on a durable volume, both `fabric_paths` twins (FAA-192).
|
|
88
|
+
- Guidance: the data-home base and a second context's home, the uptime A and B rows, model classes on the spend policy
|
|
89
|
+
or grant, a template takes precedence over the communication prompt (FAA-277), adapting step 4c scoped to an
|
|
90
|
+
existing agent; building `SKILL.md` names the board responder's mandate opt-in, the LaunchDaemon refusing `purge`, and
|
|
91
|
+
Apple's Python on macOS 27.2.
|
|
92
|
+
- **`admit.py`** (FAA-271): `creating-fabric-agents/scripts/admit.py` chains the source check, the probe, the strict
|
|
93
|
+
template check and the private-terms list into one admission check.
|
|
94
|
+
- **`test/validate.py --private-terms`** (FAA-243): tracked files are checked against the operator's local list of
|
|
95
|
+
private terms (`$PASSIONCODE_PRIVATE_TERMS`, else `~/.config/passioncode/private-terms.txt`), printing paths and lines
|
|
96
|
+
only; it exits 2 when the list is absent, and the release checklist runs it before a push.
|
|
97
|
+
- **A person's identity at every door behind `tailscale serve`** (FAA-324, board request `087f41ef`): new L0 kit module
|
|
98
|
+
`fabric_tailnet_identity` / `fabric-tailnet-identity.mjs`. Each door (dashboard, MCP, the service's own door) reads
|
|
99
|
+
`Tailscale-User-Login`, believed only when the service listens on loopback and the peer is loopback (the local
|
|
100
|
+
`tailscale serve`, which strips and sets the identity headers); a request without a login, a tagged node's, a Funnel
|
|
101
|
+
request's or one from another peer is refused with a stable code, HTTP 403 and a sentence, never a silent pass.
|
|
102
|
+
Groups come from a `tailnet-groups/1` file (its JSON Schema beside the module) or from the agents base's
|
|
103
|
+
`door-groups/1`, read for one service; the file is read again on change without a restart, and every door is closed
|
|
104
|
+
while it is unreadable or invalid. `references/surfaces-and-auth.md` shows the wiring.
|
|
105
|
+
- **`identify_agent` / `identifyAgent`** (FAA-135): a per-agent credential's agent id is bound into the mandate chain
|
|
106
|
+
(`McpToolServer`, `identifiedAgent`) and through the board responder.
|
|
107
|
+
|
|
108
|
+
### Changed
|
|
109
|
+
|
|
110
|
+
- `pid_listens` takes an `owner` (this account by default, a uid, or None), and the LaunchDaemon check reads that one
|
|
111
|
+
lsof reader (FAA-286); a vouch is taken only for a connection that reached 127.0.0.1 (FAA-273).
|
|
112
|
+
- One loopback host rule (`loopback_host` / `loopbackHost`) for `fabric_http` and `fabric_delegation`; Python's
|
|
113
|
+
`check_url` and `JwksCache` refuse a host `new URL` refuses and one Python's IDNA codec cannot write, up front. One
|
|
114
|
+
base URL rule for both OpenRouter clients: a tab or line break, a non-ASCII path, a backslash or a dot segment is a
|
|
115
|
+
`config` error in both (Node used to rewrite and send it), and attribution reads the host as dialed (FAA-187).
|
|
116
|
+
- Hold records written before 0.83.0 are matched under both whitespace squashes; new records carry
|
|
117
|
+
`squash: "ecmascript"` (FAA-320). The connections reader finds URL schemes in linear time (FAA-322). A delegation key
|
|
118
|
+
set holding NaN or Infinity is refused (FAA-194). The adapter scaffold names `__pycache__/` and `*.pyc` in
|
|
119
|
+
`.gitignore` (FAA-190).
|
|
120
|
+
- `AGENTS.md` carries item 1a, the course check before every change (fabric-workspace `knowledge/rules.md` §0).
|
|
121
|
+
- Private terms in `CHANGELOG.md` and `docs/backlog.md` are replaced by neutral words; ids and findings stay (FAA-243).
|
|
122
|
+
- `fabric_secrets.repository_name` reads a JWT at a word's start in one pass, both twins (FAA-321). Neutral words replace
|
|
123
|
+
private terms in the docs and the dashboard kit, which moves to 1.1.8 (FAA-243; only comments changed, so moving a
|
|
124
|
+
copy from 1.1.7 is optional).
|
|
125
|
+
- The source check reads `fabric_secrets` by public names, refuses a detector of another version with exit 2, and has
|
|
126
|
+
its command line in `fabric_source_check_cli.py` (FAA-190). `register_remote` warns before it writes its token;
|
|
127
|
+
validators refuse a non-string id or instance; the services folder keeps only JSON objects; refusals name relative
|
|
128
|
+
paths and the remedy (FAA-200). The package folder check reads manifests as the contract does, and pack's refusal
|
|
129
|
+
offers a clean copy (FAA-194, FAA-190).
|
|
130
|
+
- `providers_dir()` follows Fabric's `registryDirs` rule; the Windows CI job runs the provider tests and measures the
|
|
131
|
+
owner check without failing on it (FAA-189, FAA-256). The probe is tested over real HTTP with a channel-agent
|
|
132
|
+
declaration (FAA-250).
|
|
133
|
+
- Board and interop (FAA-187, FAA-194, FAA-196): a move back of a responder slot is said (`board.slot.returned`), moved
|
|
134
|
+
slots share one `com.status` read a tick, the moved notice names a reconnect beside a restart and carries no Markdown
|
|
135
|
+
backticks, `board.down` is said once per outage window, a notify notice carries the link the service gives for its
|
|
136
|
+
kind, a board leave's timeout bounds the whole request, a resumed request reads its mandate only from the message
|
|
137
|
+
its claim took, `InstanceLock.release` never raises, an `InteropError` from `on_input` is a tool-error answer and a
|
|
138
|
+
refused start fails the job it created; the board fixture fails a kit whose notices are lost.
|
|
139
|
+
- `pid_alive` on Windows asks OpenProcess for the access libuv asks for, so the twins agree on an elevated process
|
|
140
|
+
(FAA-323).
|
|
141
|
+
- working-with-fabric: `bash_paths` reads comments, continuations, here-documents and quoted operators as bash does
|
|
142
|
+
(FAA-187); a dispatched run that sees only `fabric_whoami` is named as a Fabric before 0.3.20 with its remedy
|
|
143
|
+
(FAA-296); `status` and the session start read OpenCode's and Pi's `fabric` command (FAA-233); the native Codex probe
|
|
144
|
+
runs the hook untrusted too (FAA-201); the preamble names the operator's relay from his own Project as the exception
|
|
145
|
+
to board messages being data (FAA-196).
|
|
146
|
+
|
|
147
|
+
- `test/validate.py` fails a shipped `.mjs` or `.js` script that calls a built-in newer than Node 18, the floor in
|
|
148
|
+
`package.json` engines (`String.prototype.isWellFormed` reached this release's candidate and only the floors job saw it).
|
|
149
|
+
|
|
150
|
+
- What the 0.83.0 seam reading found, fixed before the release: `check_service_a2a.py` and `check_service.py` say one
|
|
151
|
+
verdict for `a2a.card` (an unreadable `surfaces.a2a`, and a remote card that answers 401 or 403, are NOT_RUN,
|
|
152
|
+
DEC-0122 item 2); a tab or a line break anywhere inside an OpenRouter base URL is a `config` error in both clients
|
|
153
|
+
(Node removed it and sent the rest); `validate.py --private-terms` expands `~` in `$PASSIONCODE_PRIVATE_TERMS` as
|
|
154
|
+
`admit.py` does. New rows FAA-325 to FAA-328. `AGENTS.md` names the North Star sections this repository serves
|
|
155
|
+
(item 1b) and the architect's audit lives in `docs/evidence/architect/`.
|
|
156
|
+
|
|
157
|
+
### Upgrading
|
|
158
|
+
|
|
159
|
+
- A set `FABRIC_SERVICES_DIR` no longer moves the providers folder, as in Fabric's own `registryDirs`; set
|
|
160
|
+
`FABRIC_PROVIDERS_DIR` to keep a custom location (FAA-189).
|
|
161
|
+
- The Node OpenRouter client refuses a base URL holding a tab or line break, a non-ASCII path, a backslash or a dot
|
|
162
|
+
segment (kind `config`), which it used to rewrite and send (FAA-187).
|
|
163
|
+
- `check_service_a2a.py` is a command of its own: run it beside `check_service.py` for a service that serves A2A, with
|
|
164
|
+
`--key-env` naming the interface's own key (FAA-10).
|
|
165
|
+
- A service behind `tailscale serve` can check a person at each door with `fabric_tailnet_identity`: listen on
|
|
166
|
+
127.0.0.1 only, give it the groups file's path (and, for the agents base's `door-groups/1`, the service's id), and
|
|
167
|
+
send its refusal at every door (FAA-324).
|
|
168
|
+
|
|
3
169
|
## 0.82.0 (2026-11-12)
|
|
4
170
|
|
|
5
171
|
Wave 4 of the backlog sweep of 2026-11-12. The contract pin stays at `93e7db16` (`v0.1.0+2026-11-08.1`). Kit modules
|
|
@@ -1013,7 +1179,7 @@ on the Linux jobs (`python`, `floors`), so 0.69.1 is the first npm release carry
|
|
|
1013
1179
|
### Fixed
|
|
1014
1180
|
|
|
1015
1181
|
- working-with-fabric: a run Fabric started on a board request closes its workflow only once the request is settled
|
|
1016
|
-
(FAA-213,
|
|
1182
|
+
(FAA-213, a board project's finding; Fabric agrees). On an error the run cannot get past (a refused
|
|
1017
1183
|
claim, a missing key, a tool that fails twice) `references/on-demand-session.md` closed the workflow while the
|
|
1018
1184
|
request could still be `queued` or `claimed`, and Fabric's next dispatch then failed at the take-back on every cycle
|
|
1019
1185
|
(Fabric's main at `a6f0ffda`, before 0.3.16).
|
|
@@ -2094,7 +2260,7 @@ command's POSIX paths through Windows path rules. 0.53.1 is 0.53.0 with this fix
|
|
|
2094
2260
|
### Fixed
|
|
2095
2261
|
|
|
2096
2262
|
- The hooks now name this release to Fabric: 0.51.1 still said 0.51.0, and `test/validate.py` now checks it.
|
|
2097
|
-
|
|
2263
|
+
Text check `4028969a-aa35-48f9-9300-331da036fb1d`: no findings.
|
|
2098
2264
|
|
|
2099
2265
|
## 0.51.1 (2026-10-26)
|
|
2100
2266
|
|
|
@@ -2213,7 +2379,7 @@ release carrying everything listed under 0.51.0 below.
|
|
|
2213
2379
|
its four strings were English only, so a Russian dashboard could not mount it without editing a vendored file that
|
|
2214
2380
|
`dashboard_kit.py install` then refuses as changed. The message now uses a colon. The button reads the page's `lang`
|
|
2215
2381
|
and shows Russian on a Russian page, English otherwise; `data-label-chat`, `data-label-session` (with `{name}`),
|
|
2216
|
-
`data-label-open` and `data-label-absent` set a page's own words. The strings were checked with
|
|
2382
|
+
`data-label-open` and `data-label-absent` set a page's own words. The strings were checked with the text checker in the
|
|
2217
2383
|
PassionCode.ai site voice (en-US report `239ff62c-e0af-4b8b-96e1-0c45c5eca02a`, ru-RU report
|
|
2218
2384
|
`be37143c-aff1-4502-b9d0-f8b1be56bbf3`, no findings). A test fails on U+2014 in any kit asset, and the WebKit test
|
|
2219
2385
|
opens a Russian page and a page with its own words. The button's accessible name follows the page too (*Открыть Fabric*, or
|
package/README.md
CHANGED
|
@@ -89,8 +89,9 @@ retries, the agent's own key, a spend ceiling before every attempt, usage receip
|
|
|
89
89
|
[connectors](plugins/fabric-agent-adapter/skills/building-fabric-services/references/connectors.md)); the draft-and-check step of a support agent as a
|
|
90
90
|
[recipe](plugins/fabric-agent-adapter/skills/building-fabric-services/recipes/support-agent/README.md)
|
|
91
91
|
(the whole agent starts from the [agents database](plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/agents-database.md)'s
|
|
92
|
-
template when one is named (a closed database reached through Fabric's board, or by a grant holder from its own checkout;
|
|
93
|
-
|
|
92
|
+
template when one is named (a closed database reached through Fabric's board, or by a grant holder from its own checkout; an ask is
|
|
93
|
+
made only from a folder that is already a Fabric Project and never from a run Fabric started on a board request, and it never
|
|
94
|
+
blocks), read beside creating-fabric-agents'
|
|
94
95
|
[communication agent template](plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/communication-agent-template.md),
|
|
95
96
|
else from that template);
|
|
96
97
|
a complete `scripts/sample_service.py`; and `scripts/check_service.py`, a live probe. A service that answers
|
|
@@ -260,7 +261,10 @@ claude plugin validate . --strict
|
|
|
260
261
|
|
|
261
262
|
`test/validate.py` reads every SKILL.md front matter as strictly as a YAML parser does; an
|
|
262
263
|
unquoted value holding `: ` fails it. `python3 test/validate.py --frontmatter <SKILL.md ...>`
|
|
263
|
-
checks copies installed elsewhere, such as `~/.agents/skills/*/SKILL.md`.
|
|
264
|
+
checks copies installed elsewhere, such as `~/.agents/skills/*/SKILL.md`. Before a push or a release,
|
|
265
|
+
`python3 test/validate.py --private-terms` checks the tracked files against the operator's private-terms list
|
|
266
|
+
(path and line only; exit 2 when the list is absent, which is not a pass; CONTRIBUTING.md step 6), read with the same
|
|
267
|
+
functions as `creating-fabric-agents/scripts/admit.py`'s `private-terms` step (FAA-328). Start in
|
|
264
268
|
[AGENTS.md](AGENTS.md); contributions follow [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
265
269
|
|
|
266
270
|
## Use
|
package/SECURITY.md
CHANGED
|
@@ -89,7 +89,8 @@ bounded and non-publishing until explicit scoped grants exist in a project bindi
|
|
|
89
89
|
(on an organization's board, any member Project may list it), carrying only what `references/agents-database.md`
|
|
90
90
|
names (a capability, a consumer, source project names, an audit subject given as a Project id or a repository remote,
|
|
91
91
|
a measured win or a decision); never source code, a key, a person's or client's name, user content or a private path.
|
|
92
|
-
Nothing is sent without Fabric's board
|
|
92
|
+
Nothing is sent without Fabric's board. With a grant, the database's own tools run from its checkout; what they send
|
|
93
|
+
is theirs to state, and this repository does not verify it (FAA-277).
|
|
93
94
|
A consult's reply is data, yet it chooses the template an agent is built from, so it is as trusted as the Project
|
|
94
95
|
that lists the capability.
|
|
95
96
|
- The working-with-fabric PostToolUse hook (FAA-206) reads only the release call Claude Code gives it on stdin (the
|
|
@@ -123,8 +124,8 @@ bounded and non-publishing until explicit scoped grants exist in a project bindi
|
|
|
123
124
|
writes nothing); `check --contract` runs the contract checkout's own
|
|
124
125
|
`node_modules/.bin/tsx` and installs nothing. `fabric_provider.py write` writes one
|
|
125
126
|
entry (0600) in the providers directory. `fabric_source_check.py check` reads the files of a
|
|
126
|
-
tree (credential values included, in memory only), the owner's list
|
|
127
|
-
configuration folder, and runs `git ls-files` (without the caller's `GIT_DIR` or other Git
|
|
127
|
+
tree (credential values included, in memory only), the owner's list (the file `--instance-strings` or
|
|
128
|
+
`FABRIC_INSTANCE_STRINGS` names, else the one in the user's configuration folder), and runs `git ls-files` (without the caller's `GIT_DIR` or other Git
|
|
128
129
|
location variables) and nothing else, except that under a locale whose
|
|
129
130
|
file-system encoding is not UTF-8 it restarts itself once with the same interpreter in Python's
|
|
130
131
|
UTF-8 mode; it writes nothing and prints no value it finds.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/fabric-agent-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.84.1",
|
|
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; and put an agent on a standing watch over a product (observer mode).",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.84.1",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -9,7 +9,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
9
9
|
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.
|
|
10
10
|
metadata:
|
|
11
11
|
author: PassionCode.ai
|
|
12
|
-
version: "0.
|
|
12
|
+
version: "0.84.1"
|
|
13
13
|
contract-version: "0.1.0"
|
|
14
14
|
contract-commit: "93e7db164c7829e2783b4b7705c4113bb5201131"
|
|
15
15
|
---
|
|
@@ -186,7 +186,12 @@ default and a committed `*.example`; a key into the secret store, named only. Ru
|
|
|
186
186
|
A value already committed stays in Git history: say so; a fresh history is the owner's act (no history rewrite, no
|
|
187
187
|
force-push). Then lay down the source manifest, `fabric.source.json` (DEC-0149): `scripts/adapt_project.py source
|
|
188
188
|
<project-root> --dry-run` proposes it, the author narrows `include` and names each key and store as a slot, and the
|
|
189
|
-
check reads the source under it (the reference, *The source manifest*).
|
|
189
|
+
check reads the source under it (the reference, *The source manifest*). An existing agent keeps its data where it is
|
|
190
|
+
until its owner moves it: of the reference's data home, apply what 4c asks (no instance value in the source); the
|
|
191
|
+
data home and the per-release transfer audit are for an agent built new, and an existing one adopts them only when
|
|
192
|
+
its owner asks. An existing agent that answers people (support, sales, reviews) is compared, part by part, with
|
|
193
|
+
creating-fabric-agents' communication agent template and `references/agents-that-answer-people.md`: each part it
|
|
194
|
+
lacks is a finding in the report.
|
|
190
195
|
|
|
191
196
|
### 5. Make probes safe and meaningful
|
|
192
197
|
|
|
@@ -48,6 +48,16 @@ repository-relative path at a commit, an eval report). A decision without a numb
|
|
|
48
48
|
| building-fabric-services | at each release | contribute the release's measured wins as success cases and its new technical decisions |
|
|
49
49
|
| working-with-fabric | the retro after work | a lesson with a measured effect is also a success case: contribute it beside the lesson it records |
|
|
50
50
|
|
|
51
|
+
## A template and the communication prompt
|
|
52
|
+
|
|
53
|
+
For an agent that talks with people on a channel, the database's template and creating-fabric-agents' communication
|
|
54
|
+
agent prompt (`references/communication-agent-template.md`) are read together, never as two templates (the database's
|
|
55
|
+
own rule). Where they disagree, the template wins, in every part and not only the first-release ones: it is the merged
|
|
56
|
+
practice of the agents of its kind. A part the prompt carries and the template lacks (a first-release part, a check, a
|
|
57
|
+
pipeline step) is built too, unless the template rules it out, and goes back to the database as feedback on that
|
|
58
|
+
template (`agents-db.contribute`); the completion report names each such part. Without a template for the kind, the
|
|
59
|
+
prompt is the recipe.
|
|
60
|
+
|
|
51
61
|
## Recording the template
|
|
52
62
|
|
|
53
63
|
An agent built from a template declares it: `provenance.template` with its id and version, so a later template
|
package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md
CHANGED
|
@@ -12,7 +12,7 @@ directory:
|
|
|
12
12
|
| macOS | `~/Library/Application Support/ai.passioncode.fabric/providers/` |
|
|
13
13
|
| Linux | `${XDG_DATA_HOME:-~/.local/share}/passioncode-fabric/providers/` |
|
|
14
14
|
| Windows | `%LOCALAPPDATA%\passioncode-fabric\providers\` (the same root as the services folder, DEC-0032; `~\AppData\Local` when `LOCALAPPDATA` is unset) |
|
|
15
|
-
| any | `FABRIC_PROVIDERS_DIR` when set |
|
|
15
|
+
| any | `FABRIC_PROVIDERS_DIR` when set; `FABRIC_SERVICES_DIR` moves the services folder only, as Fabric's `registryDirs` reads them (FAA-189) |
|
|
16
16
|
|
|
17
17
|
A service uses a descriptor instead (the `building-fabric-services` skill). One id is a
|
|
18
18
|
service or a provider, never both.
|
|
@@ -25,7 +25,7 @@ and refuses what the contract refuses.
|
|
|
25
25
|
```bash
|
|
26
26
|
python3 scripts/fabric_provider.py write --id example-agent --provider-id https://agents.example/providers/example-agent \
|
|
27
27
|
--name "Example Agent" \
|
|
28
|
-
--manifest ~/.local/share/example-agent/fabric-agent.json --installed-by "example-agent 1.0.0" \
|
|
28
|
+
--manifest '~/.local/share/example-agent/fabric-agent.json' --installed-by "example-agent 1.0.0" \
|
|
29
29
|
--env EXAMPLE_API_KEY=secret-ref:example-agent/EXAMPLE_API_KEY \
|
|
30
30
|
--stdio ~/.local/bin/example-agent mcp
|
|
31
31
|
python3 scripts/fabric_provider.py write ... --url http://127.0.0.1:47201/mcp
|
|
@@ -33,6 +33,8 @@ python3 scripts/fabric_provider.py validate ~/Library/Application\ Support/ai.pa
|
|
|
33
33
|
python3 scripts/fabric_provider.py remove example-agent # the uninstaller
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
The manifest is quoted so the entry keeps `~/`, which every Fabric release reads: unquoted, a shell expands it, and
|
|
37
|
+
Git Bash on Windows hands Python `C:/Users/...`, which Fabric v0.3.15 and earlier refuse (FAA-189).
|
|
36
38
|
`--stdio` comes last and takes the rest of the line as the argument array; there is no shell string. A writer
|
|
37
39
|
option after it (`--env`, `--name`, ...) is refused rather than swallowed into argv; write `--stdio -- EXECUTABLE ...`
|
|
38
40
|
when the server itself takes an option of that name. `--env` belongs to a stdio server and is refused with `--url`. An entry may carry
|
|
@@ -54,7 +54,11 @@ source under it.
|
|
|
54
54
|
|
|
55
55
|
- **The data has a home of its own from the first commit: `<agent>-data`.** For an agent that is not a kit service it
|
|
56
56
|
is a folder beside the checkout, never inside it, and `<AGENT>_DATA_DIR` names it (its default is
|
|
57
|
-
`../<agent>-data
|
|
57
|
+
`../<agent>-data`, resolved against the checkout's root, the folder that holds the agent's source, never the working
|
|
58
|
+
directory). Two sibling checkouts, and a second context's instance from the same checkout (an organization's beside
|
|
59
|
+
the personal one), would share that default: each sets its own `<AGENT>_DATA_DIR` (`../<agent>-data.<instance>`), so
|
|
60
|
+
no copy reads another's data. A kit service keeps the kit's folders above, and on a host whose disk does not persist
|
|
61
|
+
`FABRIC_DATA_HOME` moves its data folder onto a durable volume (building-fabric-services, the remote placement). When the owner keeps the data in Git, it goes to a
|
|
58
62
|
separate private repository named `<agent>-data`, never to the source's repository. On a cloud host that does not
|
|
59
63
|
keep its disk across a restart (Heroku and the like, an uptime A agent's default), the data home is a durable store
|
|
60
64
|
the same variable names (a database, an object store, that private repository); the folder and the kit's folders
|
|
@@ -114,13 +118,22 @@ untracked ones that are not ignored, as they are in the work tree; a staged copy
|
|
|
114
118
|
| Kind | Finds |
|
|
115
119
|
|---|---|
|
|
116
120
|
| `home-path` | an absolute path inside a person's home folder (a web route under `/home/` is reported too; a route under `/users/` is not): `/Users/<name>/`, `/home/<name>/`, `C:\Users\<name>\`, Git Bash's `/c/Users/<name>/`, WSL's `/mnt/c/Users/<name>/`, and the dashed (`-Users-<name>-`, `C--Users-<name>-`) and URL-encoded forms a tool makes of one. The name is ASCII, and in the dashed form it ends at the next dash: an owner whose home name holds a space, a dash, a dot, an underscore or an apostrophe (each a dash in the dashed form; a slashed name also ends at a space) declares it with `home: <name>` in the owner's list, which reads it whole in every form, and one whose home name is not ASCII, or holds another character, lists it as a plain string (a typographic apostrophe a keyboard typed, which the folder's name does not hold, is written as `'` in `home:`; a folder whose name holds `’` is listed as a plain string with `’` kept and declared too with `home: <name>` written with `'`, which reads the dashed forms; its URL-encoded `’` is not read; a name outside ASCII of one or two characters cannot be checked) |
|
|
117
|
-
| `secret` | a value shaped like a credential by the contract's detector (DEC-0044), read line by line: a provider key starting a word, a JWT, a bearer token, a long random value assigned to a credential's name (but a whole Ed25519 signature under a JSON `"sig"`, `"signature"` or `"signatures"` member, as `sign` writes it, which is public); or a private key: a PEM, OpenSSH or PGP block, or a JWK's `d` as a JSON member, escaped JSON or a Python dict; a URL with a password of 8 or more characters mixing letters and digits (a password without a digit or without a letter is not read) or a credential in its query, percent-encoded or not, JSON-escaped (`\u0026`, `\/`) or nested in another URL's parameter (two levels deep); a file that is a credential by its name, as `pack` refuses it (`.env`, `*.pem`, `*.key`, `.npmrc` and the rest), or a kit credential file (`*.token`, `board.credential`) |
|
|
121
|
+
| `secret` | a value shaped like a credential by the contract's detector (DEC-0044), read line by line: a provider key starting a word, a JWT, a bearer token, a long random value assigned to a credential's name (a run of 40 or more characters mixing upper case, lower case and digits, so a shorter key under `X_API_KEY=` is not read; but a whole Ed25519 signature under a JSON `"sig"`, `"signature"` or `"signatures"` member, as `sign` writes it, which is public); or a private key: a PEM, OpenSSH or PGP block, or a JWK's `d` as a JSON member, escaped JSON or a Python dict; a URL with a password of 8 or more characters mixing letters and digits (a password without a digit or without a letter is not read) or a credential in its query, percent-encoded or not, JSON-escaped (`\u0026`, `\/`) or nested in another URL's parameter (two levels deep); a file that is a credential by its name, as `pack` refuses it (`.env`, `*.pem`, `*.key`, `.npmrc` and the rest), or a kit credential file (`*.token`, `board.credential`) |
|
|
118
122
|
| `instance-string` | a string from the owner's list, in a file, in a file's path or in a link's target |
|
|
119
123
|
|
|
120
124
|
```bash
|
|
121
125
|
python3 <plugin-dir>/skills/adapting-projects-to-fabric/scripts/fabric_source_check.py check <project-root>
|
|
122
126
|
```
|
|
123
127
|
|
|
128
|
+
Run it by path, with its scripts folder whole: it loads its siblings (`fabric_source_ignore.py`,
|
|
129
|
+
`fabric_source_homes.py`, `fabric_source_restart.py`, `fabric_source_check_cli.py`, `fabric_source_tree.py` and the
|
|
130
|
+
contract's detector `fabric_secrets.py`) and refuses with exit `2` when one is missing or from another version, a
|
|
131
|
+
detector without one of the public names it reads included (FAA-190). `python3 -m fabric_source_check` writes its own
|
|
132
|
+
`.pyc` before the check turns bytecode off; run by path, it writes nothing. `ROOT` defaults to the current folder.
|
|
133
|
+
`--json` prints one object: `mode` (`git` or a walk), `files`, `findings` (`path`, `line`, `kind`, `rule`),
|
|
134
|
+
`notRead`, `skipped`, `dependencies`, `instanceStrings`, `ownerHomes`, `instanceList`, `blocking` (a finding) and
|
|
135
|
+
`complete` (every file read); `--help` names each option.
|
|
136
|
+
|
|
124
137
|
- It **never repeats** a value it found: no value, no line holding one, no entry of the owner's list and not the
|
|
125
138
|
folder it checks reaches its output. A file's path is checked like its text (line `0` of a finding), and printed
|
|
126
139
|
with an entry of the list as `<line N>`, a home folder's name as `<home>` and each segment holding a
|
|
@@ -167,7 +180,7 @@ python3 <plugin-dir>/skills/adapting-projects-to-fabric/scripts/fabric_source_ch
|
|
|
167
180
|
percent-encodings or an escaped apostrophe (`\'`, `\x27`, `\u0027`, `'`, `'`, `'`), the same separators it is found with in every form; a home that is also your name goes in the list
|
|
168
181
|
as a plain string too, to be found in text. It is `--instance-strings FILE`, else the file
|
|
169
182
|
`FABRIC_INSTANCE_STRINGS` names, else `passioncode-fabric/instance-strings.txt` in the user's configuration folder
|
|
170
|
-
(`$XDG_CONFIG_HOME` when it is absolute, else `~/.config`; `%APPDATA%`
|
|
183
|
+
(`$XDG_CONFIG_HOME` when it is absolute, else `~/.config`; on Windows `%APPDATA%` when it is absolute, else `~\AppData\Roaming`). A list inside the tree is refused, because it would
|
|
171
184
|
travel with the source. A person who already keeps private terms for org-index's `check_private.py`
|
|
172
185
|
(`~/.config/passioncode/private-terms.txt`) passes that file with `--instance-strings`; this check matches a term
|
|
173
186
|
anywhere in a word, and it does not look for e-mail addresses or account ids by their shape.
|
|
@@ -183,7 +196,8 @@ python3 <plugin-dir>/skills/adapting-projects-to-fabric/scripts/fabric_source_ch
|
|
|
183
196
|
repository is not read; `--every-file` and a folder outside Git read its files, its `.git` left out. An exception line (`!`) is refused, since what it would
|
|
184
197
|
bring back would go unread. Name the files, or a folder that holds
|
|
185
198
|
only synthetic vectors, never a whole source folder (a nested repository checked in its own tree is the one
|
|
186
|
-
exception), and say why on the line above. The
|
|
199
|
+
exception), and say why on the line above. The one owner's file named this way is the `LICENSE` (a file, never a
|
|
200
|
+
folder exception): its copyright line names the holder, which is
|
|
187
201
|
authorship and travels with the source, so when the holder is on the owner's list the licence file is named in the ignore
|
|
188
202
|
file by its own path (`LICENSE`, `LICENSE.md`) with that reason (`# the copyright holder is authorship and travels with the source`); no other file of the
|
|
189
203
|
owner's is. A file `pack` refuses by its name cannot ship in a package: a public
|
package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py
CHANGED
|
@@ -451,6 +451,20 @@ def _declared_effect(args: argparse.Namespace) -> Tuple[str, str]:
|
|
|
451
451
|
return effect, idempotency
|
|
452
452
|
|
|
453
453
|
|
|
454
|
+
#: What running the kit leaves in a scaffold, which the source check reads as binary in Git mode (FAA-190 item 36).
|
|
455
|
+
GITIGNORE_LINES = ("__pycache__/", "*.pyc")
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def _gitignore(root: Path, write: bool) -> str:
|
|
459
|
+
"""`.gitignore` holds GITIGNORE_LINES, created or with the missing lines appended (nothing else changes)."""
|
|
460
|
+
path = root / ".gitignore"
|
|
461
|
+
text = path.read_text(encoding="utf-8", errors="replace") if path.exists() else None
|
|
462
|
+
missing = "".join(line + "\n" for line in GITIGNORE_LINES if line not in (text or "").splitlines())
|
|
463
|
+
if missing and write:
|
|
464
|
+
path.write_text((text or "") + ("\n" if text and not text.endswith("\n") else "") + missing, encoding="utf-8")
|
|
465
|
+
return "unchanged" if not missing else "created" if text is None else "appended"
|
|
466
|
+
|
|
467
|
+
|
|
454
468
|
def scaffold_project(root: Path, args: argparse.Namespace) -> Dict[str, Any]:
|
|
455
469
|
if not root.is_dir():
|
|
456
470
|
raise AdaptationError("project path is not a directory: %s" % root)
|
|
@@ -472,6 +486,7 @@ def scaffold_project(root: Path, args: argparse.Namespace) -> Dict[str, Any]:
|
|
|
472
486
|
"wouldReplace": sorted(collisions),
|
|
473
487
|
"needsForce": bool(collisions) and not args.force,
|
|
474
488
|
"diffs": diffs,
|
|
489
|
+
"gitignore": _gitignore(root, write=False),
|
|
475
490
|
}
|
|
476
491
|
if collisions and not args.force:
|
|
477
492
|
raise AdaptationError("refusing to overwrite existing paths: %s" % ", ".join(collisions))
|
|
@@ -484,6 +499,7 @@ def scaffold_project(root: Path, args: argparse.Namespace) -> Dict[str, Any]:
|
|
|
484
499
|
"profile": args.profile,
|
|
485
500
|
"created": sorted(generated),
|
|
486
501
|
"replaced": sorted(collisions),
|
|
502
|
+
"gitignore": _gitignore(root, write=True),
|
|
487
503
|
"next": "Replace all placeholders, implement the adapter, then run check with the pinned contract checkout.",
|
|
488
504
|
}
|
|
489
505
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
1
2
|
"""Identifier equality (contract DEC-0076): two identifiers are the same when their normal forms are equal.
|
|
2
3
|
|
|
3
4
|
A port of the contract's `src/identifiers.ts`, held to its `fixtures/vectors/identifiers.json`. The normal form of a URI
|
package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_provider.py
CHANGED
|
@@ -93,26 +93,29 @@ class ProviderError(Exception):
|
|
|
93
93
|
"""An entry was refused; the message is one readable sentence and never quotes a value."""
|
|
94
94
|
|
|
95
95
|
|
|
96
|
-
def
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return Path(override).expanduser()
|
|
96
|
+
def fabric_root() -> Path:
|
|
97
|
+
"""The platform's Fabric root, as Fabric's registryDirs computes it: the folder `services/` and `providers/` sit in
|
|
98
|
+
when neither override is set."""
|
|
100
99
|
home = Path.home()
|
|
101
100
|
if sys.platform == "darwin":
|
|
102
|
-
return home / "Library/Application Support/ai.passioncode.fabric
|
|
101
|
+
return home / "Library/Application Support/ai.passioncode.fabric"
|
|
103
102
|
if sys.platform == "win32":
|
|
104
103
|
# provider.md "Where the directory is" (DEC-0032): LOCALAPPDATA, never the roaming APPDATA.
|
|
105
104
|
local = os.environ.get("LOCALAPPDATA")
|
|
106
|
-
return (Path(local) if local else home / "AppData" / "Local") / "passioncode-fabric"
|
|
107
|
-
return Path(os.environ.get("XDG_DATA_HOME") or str(home / ".local/share")) / "passioncode-fabric
|
|
105
|
+
return (Path(local) if local else home / "AppData" / "Local") / "passioncode-fabric"
|
|
106
|
+
return Path(os.environ.get("XDG_DATA_HOME") or str(home / ".local/share")) / "passioncode-fabric"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def services_dir() -> Path:
|
|
110
|
+
override = os.environ.get("FABRIC_SERVICES_DIR")
|
|
111
|
+
return Path(override).expanduser() if override else fabric_root() / "services"
|
|
108
112
|
|
|
109
113
|
|
|
110
114
|
def providers_dir() -> Path:
|
|
111
|
-
"""FABRIC_PROVIDERS_DIR, else `providers/` in the
|
|
115
|
+
"""FABRIC_PROVIDERS_DIR, else `providers/` in the platform's Fabric root, as Fabric's registryDirs reads it: a set
|
|
116
|
+
FABRIC_SERVICES_DIR moves the services folder only (FAA-189 (2))."""
|
|
112
117
|
override = os.environ.get("FABRIC_PROVIDERS_DIR")
|
|
113
|
-
if override
|
|
114
|
-
return Path(override).expanduser()
|
|
115
|
-
return services_dir().parent / "providers"
|
|
118
|
+
return Path(override).expanduser() if override else fabric_root() / "providers"
|
|
116
119
|
|
|
117
120
|
|
|
118
121
|
def looks_like_credential(value: str) -> bool:
|
|
@@ -155,7 +158,7 @@ def validate_provider_entry(entry: Any) -> List[str]:
|
|
|
155
158
|
# FAA-120, as the service kit: a repository is named, never reached with a credential in its URI. Said
|
|
156
159
|
# before the character check, so a password beside a character the URI class refuses (a backslash, as
|
|
157
160
|
# git reads one) is still named a credential (FAA-127).
|
|
158
|
-
problems.append("source.repository carries no password or credential: it names the repository")
|
|
161
|
+
problems.append("source.repository carries no password or credential: it names the repository (write the repository's name in lower case if it is one)")
|
|
159
162
|
elif "repository" in source and not _is_uri(source["repository"]):
|
|
160
163
|
problems.append("source.repository is an absolute URI")
|
|
161
164
|
if not isinstance(entry["installedAt"], str) or not _TIMESTAMP.fullmatch(entry["installedAt"]):
|
|
@@ -207,12 +210,17 @@ def _run_problems(run: Any) -> List[str]:
|
|
|
207
210
|
return problems
|
|
208
211
|
|
|
209
212
|
|
|
213
|
+
def _no_constant(name: str) -> Any:
|
|
214
|
+
raise ValueError("%s is no JSON" % name)
|
|
215
|
+
|
|
216
|
+
|
|
210
217
|
def manifest_problems(entry: Dict[str, Any]) -> List[str]:
|
|
211
218
|
"""FAC-SEM-014 (DEC-0017), URI half: the manifest resolves and its provider.id equals providerId, compared by normal
|
|
212
219
|
form (DEC-0076)."""
|
|
213
220
|
try:
|
|
214
|
-
manifest = json.loads(Path(os.path.expanduser(str(entry["manifest"]))).read_text(encoding="utf-8")
|
|
215
|
-
|
|
221
|
+
manifest = json.loads(Path(os.path.expanduser(str(entry["manifest"]))).read_text(encoding="utf-8"),
|
|
222
|
+
parse_constant=_no_constant)
|
|
223
|
+
except (OSError, ValueError, RecursionError): # NaN or Infinity is no JSON, as pack reads it (FAA-194 (38))
|
|
216
224
|
return ["the manifest %s does not resolve (FAC-SEM-014)" % entry["manifest"]]
|
|
217
225
|
provider = manifest.get("provider") if isinstance(manifest, dict) else None
|
|
218
226
|
if not isinstance(provider, dict) or not isinstance(manifest.get("capabilities"), list):
|
|
@@ -300,6 +308,14 @@ def entry_stem(path: str) -> str:
|
|
|
300
308
|
return re.sub(r"\.json\Z", "", re.sub(r"\A[^\n\r\u2028\u2029]*[\\/]", "", path, count=1))
|
|
301
309
|
|
|
302
310
|
|
|
311
|
+
def argument_stem(path: str, platform: Optional[str] = None) -> str:
|
|
312
|
+
"""The stem of the file a `validate` argument names: CT-193's, after a Windows drive-relative prefix (`C:name.json`
|
|
313
|
+
is name.json in that drive's folder) is set aside, which the registry never meets (FAA-189 (8))."""
|
|
314
|
+
if (platform or sys.platform) == "win32":
|
|
315
|
+
path = re.sub(r"\A[A-Za-z]:(?![\\/])", "", path)
|
|
316
|
+
return entry_stem(path)
|
|
317
|
+
|
|
318
|
+
|
|
303
319
|
def main(argv: Optional[List[str]] = None) -> int:
|
|
304
320
|
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
305
321
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
@@ -335,7 +351,7 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
335
351
|
entry = json.loads(args.path.read_text(encoding="utf-8"))
|
|
336
352
|
problems = validate_provider_entry(entry)
|
|
337
353
|
# CT-193 (FAC-SEM-014): the stem is what follows the last / or \ and loses .json, on every platform.
|
|
338
|
-
stem =
|
|
354
|
+
stem = argument_stem(str(args.path))
|
|
339
355
|
if isinstance(entry, dict) and entry.get("id") != stem:
|
|
340
356
|
problems.append("the file name %s is not <id>.json for %s (FAC-SEM-014)" % (args.path.name, entry.get("id")))
|
|
341
357
|
if not problems:
|