@passioncode-ai/fabric-agent-adapter 0.3.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/LICENSE +151 -17
  3. package/README.md +51 -6
  4. package/SECURITY.md +16 -3
  5. package/bin/fabric-agent-adapter.js +87 -43
  6. package/package.json +13 -8
  7. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +5 -6
  8. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +8 -5
  9. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +1 -1
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +240 -0
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +32 -0
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/events-and-notifications.md +44 -0
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +63 -0
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/migrating-a-service.md +32 -0
  15. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +83 -0
  16. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +58 -0
  17. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +373 -0
  18. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +380 -0
  19. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +663 -0
  20. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +226 -0
  21. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +23 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,87 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.3 - 2026-09-29
4
+
5
+ ### Changed
6
+
7
+ - **License.** The adapter is now source-available under
8
+ `PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0`, with a
9
+ commercial license on request (contact@passioncode.ai). Versions up to and including
10
+ v0.4.2, and npm releases up to and including 0.3.1, were released under MIT and remain
11
+ available under it. The manifests, the three skills' `license:` and the README say the
12
+ same; contributions come in under `CLA.md`, which the new PR template asks for.
13
+ `test/validate.py` fails a tree that slips back to MIT.
14
+ - Author and marketplace owner are PassionCode.ai (`https://passioncode.ai/`).
15
+ - **Contract pin** moves from `20a818e` to `a5a2709` (fabric-agent-contract `main`), the
16
+ commit `building-fabric-services` already pinned. Between the two the provider
17
+ profiles are unchanged — only the `fabric-service/0.1` extension was added — and
18
+ `adapt_project.py check --contract` gives the same verdicts for an MCP, an A2A and a
19
+ local-runner bundle at both commits (declaration shape PASS). One pin for all three
20
+ skills.
21
+ - `creating-fabric-agents` hands the agent's own loop to `agent-orchestrator`, its
22
+ eval suite to `agent-evals` (agent-stack) and plugin packaging to `make-skill`;
23
+ `adapting-projects-to-fabric` sends wire-level MCP/A2A questions to `agent-interop`.
24
+
25
+ ### Fixed
26
+
27
+ - The installer's help names the launcher by its npm org name,
28
+ `npx @passioncode-ai/passioncode@latest update`; the bare `passioncode` is not ours.
29
+ - A distributed eval named a personal agent as its example service; the
30
+ `building-fabric-services` evals use `example-agent`, and its description says "a
31
+ macOS machine" instead of naming whose.
32
+
33
+ ## 0.4.2 - 2026-09-29
34
+
35
+ - Kit: `LoopbackHTTPServer`, a `ThreadingHTTPServer` whose bind asks no resolver.
36
+ `http.server` calls `socket.getfqdn()` between `bind()` and `listen()`; on a macOS
37
+ CI runner that held a service's port bound but silent for over 20 seconds. The
38
+ sample service and the skill's startup order use it, and the skill names the trap.
39
+ - Kit: a garbled pid file (for example a superscript digit) now reads as "no pid"
40
+ instead of raising `ValueError` while naming the holder of a lock.
41
+
42
+ ## 0.4.1 - 2026-09-29
43
+
44
+ ### Fixed
45
+
46
+ - `building-fabric-services` could not be loaded by a strict YAML reader: its
47
+ front-matter `description` was an unquoted plain scalar holding `: `
48
+ ("fabric-service/0.1 extension: which surface", line 3, column 493), which YAML
49
+ rejects with "mapping values are not allowed here". Claude Code read it
50
+ leniently, so the plugin worked, but an agent reading the skill from
51
+ `~/.agents/skills` could drop it. The description is now a folded block
52
+ scalar (`>-`) with the exact same text (927 characters).
53
+ - The validator could not see that class of defect: `test/validate.py` now
54
+ parses every SKILL.md front matter strictly (standard library only) and
55
+ rejects what a YAML reader rejects in an unquoted value — `: ` or a trailing
56
+ `:`, ` #` (a comment that silently truncates the value), a leading indicator
57
+ character, a duplicate key, an unclosed quote, an undeclared multi-line
58
+ value — with the line and column. `test/test_validate.py` plants each case.
59
+ `validate.py --frontmatter <SKILL.md ...>` checks installed copies anywhere.
60
+ - The release smoke test looked for `~/.claude/skills`, where the installer has
61
+ not written since 0.4.0, so it would fail on the first release that ran it.
62
+ It now checks all three skills in `~/.agents/skills`, that `~/.claude/skills`
63
+ stays untouched, and that the installed front matter parses strictly.
64
+ - `SKILL-CARD.md` versions and the release smoke paths joined the validator's
65
+ sync checks.
66
+
67
+ ## 0.4.0 - 2026-09-28
68
+
69
+ - Add the `building-fabric-services` skill for the `fabric-service/0.1` local
70
+ service extension (Fabric Agent Contract DEC-0015): surface choice (MCP
71
+ streamable HTTP, CLI, A2A), token and one-time login, state and cache
72
+ directories, one copy per machine, launchd, descriptor, well-known document,
73
+ events feed and notifications.
74
+ - Ship reference kits in Python (`fabric_service.py`) and Node
75
+ (`fabric-service.mjs`) whose instance locks exclude each other, a complete
76
+ `sample_service.py`, and `check_service.py`, a live conformance probe that
77
+ reports PASS, FAIL or NOT_RUN per rule.
78
+ - `creating-fabric-agents` now routes an agent that runs as a service through
79
+ the new skill.
80
+ - Fix the installer shadowing its own plugin: `npx @passioncode-ai/fabric-agent-adapter`
81
+ and `install.sh` now install into the agents hub `~/.agents/skills`; a plain
82
+ copy into `~/.claude/skills` is refused while the plugin is installed, and
83
+ `--prune-shadow` moves existing shadowing copies aside.
84
+
3
85
  ## 0.3.1 - 2026-08-27
4
86
 
5
87
  - Fix the executable bit on `bin/fabric-agent-adapter.js` and `install.sh`: the
package/LICENSE CHANGED
@@ -1,22 +1,156 @@
1
- MIT License
1
+ Copyright (c) 2026 Siarhei Sheleh
2
2
 
3
- Copyright (c) 2026 passioncode-ai
3
+ This software is source-available, not open source. You may use it under
4
+ either of the two licenses below, at your option:
4
5
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
6
+ 1. PolyForm Noncommercial License 1.0.0
7
+ SPDX: PolyForm-Noncommercial-1.0.0
8
+ 2. PolyForm Internal Use License 1.0.0
9
+ SPDX: LicenseRef-PolyForm-Internal-Use-1.0.0
11
10
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
11
+ In short: individuals and noncommercial organisations may use, change and
12
+ share it for noncommercial purposes; any company may use it, and change it,
13
+ for its own internal operations. Distributing it commercially, or building
14
+ this software or its code into a product or service you provide to others,
15
+ needs a separate commercial license: contact@passioncode.ai.
16
+ This summary is not part of either license; the texts below govern.
14
17
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
18
+ Versions up to and including v0.4.2 of this repository (and npm releases up to and
19
+ including 0.3.1) were released under the MIT License; those releases remain available
20
+ under MIT.
22
21
 
22
+ Required Notice: Copyright (c) 2026 Siarhei Sheleh (https://passioncode.ai)
23
+
24
+ ================================================================================
25
+
26
+ # PolyForm Noncommercial License 1.0.0
27
+
28
+ <https://polyformproject.org/licenses/noncommercial/1.0.0>
29
+
30
+ ## Acceptance
31
+
32
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
33
+
34
+ ## Copyright License
35
+
36
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
37
+
38
+ ## Distribution License
39
+
40
+ The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
41
+
42
+ ## Notices
43
+
44
+ You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
45
+
46
+ > Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
47
+
48
+ ## Changes and New Works License
49
+
50
+ The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
51
+
52
+ ## Patent License
53
+
54
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
55
+
56
+ ## Noncommercial Purposes
57
+
58
+ Any noncommercial purpose is a permitted purpose.
59
+
60
+ ## Personal Uses
61
+
62
+ Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
63
+
64
+ ## Noncommercial Organizations
65
+
66
+ Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
67
+
68
+ ## Fair Use
69
+
70
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
71
+
72
+ ## No Other Rights
73
+
74
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
75
+
76
+ ## Patent Defense
77
+
78
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
79
+
80
+ ## Violations
81
+
82
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
83
+
84
+ ## No Liability
85
+
86
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
87
+
88
+ ## Definitions
89
+
90
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
91
+
92
+ **You** refers to the individual or entity agreeing to these terms.
93
+
94
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
95
+
96
+ **Your licenses** are all the licenses granted to you for the software under these terms.
97
+
98
+ **Use** means anything you do with the software requiring one of your licenses.
99
+
100
+ ================================================================================
101
+
102
+ # PolyForm Internal Use License 1.0.0
103
+
104
+ <https://polyformproject.org/licenses/internal-use/1.0.0>
105
+
106
+ ## Acceptance
107
+
108
+ In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
109
+
110
+ ## Copyright License
111
+
112
+ The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license), and you may not distribute the software.
113
+
114
+ ## Changes and New Works License
115
+
116
+ The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
117
+
118
+ ## Patent License
119
+
120
+ The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
121
+
122
+ ## Fair Use
123
+
124
+ You may have "fair use" rights for the software under the law. These terms do not limit them.
125
+
126
+ ## Internal Business Use
127
+
128
+ Use of the software for the internal business operations of you and your company is use for a permitted purpose.
129
+
130
+ ## No Other Rights
131
+
132
+ These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
133
+
134
+ ## Patent Defense
135
+
136
+ If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
137
+
138
+ ## Violations
139
+
140
+ The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
141
+
142
+ ## No Liability
143
+
144
+ ***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
145
+
146
+ ## Definitions
147
+
148
+ The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
149
+
150
+ **You** refers to the individual or entity agreeing to these terms.
151
+
152
+ **Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
153
+
154
+ **Your licenses** are all the licenses granted to you for the software under these terms.
155
+
156
+ **Use** means anything you do with the software requiring one of your licenses.
package/README.md CHANGED
@@ -1,13 +1,38 @@
1
+ <p align="center">
2
+ <a href="https://passioncode.ai/">
3
+ <img src="assets/passioncode-icon-256.png" width="104" height="104" alt="PassionCode.ai passion fruit mark">
4
+ </a>
5
+ </p>
6
+
1
7
  # Fabric Agent Adapter
2
8
 
9
+ > **PassionCode.ai — The agent-agnostic operating system for AI-native teams.**
10
+
11
+ **From vibe coding to passion coding.** PassionCode.ai moves the control point from
12
+ managing agents one by one to operating Projects. Fabric Agent Adapter is the portable
13
+ on-ramp: it helps an existing repository become a compatible, replaceable Provider
14
+ without moving the Project onto one proprietary agent runtime.
15
+
3
16
  [![npm](https://img.shields.io/npm/v/%40passioncode-ai%2Ffabric-agent-adapter)](https://www.npmjs.com/package/@passioncode-ai/fabric-agent-adapter)
4
17
  [![validate](https://github.com/passioncode-ai/fabric-agent-adapter/actions/workflows/validate.yml/badge.svg)](https://github.com/passioncode-ai/fabric-agent-adapter/actions/workflows/validate.yml)
5
- [![license](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
18
+ [![license](https://img.shields.io/badge/license-source--available-blue.svg)](LICENSE)
19
+
20
+ Private, portable Agent Skills for the
21
+ [Fabric Agent Contract](https://github.com/passioncode-ai/fabric-agent-contract):
22
+ `adapting-projects-to-fabric`, `creating-fabric-agents` and
23
+ `building-fabric-services`.
6
24
 
7
- Private, portable Agent Skill for adapting an existing agent project to the
8
- [Fabric Agent Contract](https://github.com/passioncode-ai/fabric-agent-contract).
25
+ `building-fabric-services` makes an agent a long-lived local service with a dashboard
26
+ that is always alive, runs as one copy, keeps its state through a reinstall and appears
27
+ in Fabric Dashboards by itself — the `fabric-service/0.1` extension. It ships Python and
28
+ Node reference kits (`scripts/fabric_service.py`, `scripts/fabric-service.mjs`), a
29
+ complete `scripts/sample_service.py`, and `scripts/check_service.py`, a live probe:
30
+
31
+ ```bash
32
+ python3 plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py example-agent
33
+ ```
9
34
 
10
- It helps an agent author:
35
+ For provider bundles the adapting skill helps an agent author:
11
36
 
12
37
  - inspect the project's stable integration surfaces without executing it;
13
38
  - choose A2A `1.0`, MCP `2026-07-28`, or `fabric-local-runner/0.1` per capability;
@@ -26,7 +51,8 @@ The repository is private; the npm package is public. The npm path needs no GitH
26
51
  npm — no GitHub access required:
27
52
 
28
53
  ```bash
29
- npx @passioncode-ai/fabric-agent-adapter # installs both skills into ~/.claude/skills
54
+ npx @passioncode-ai/fabric-agent-adapter # installs every skill into the agents hub ~/.agents/skills
55
+ npx @passioncode-ai/fabric-agent-adapter --prune-shadow # remove ~/.claude/skills copies that shadow the plugin
30
56
  ```
31
57
 
32
58
  Generic Agent Skills clients:
@@ -34,6 +60,7 @@ Generic Agent Skills clients:
34
60
  ```bash
35
61
  npx skills add passioncode-ai/fabric-agent-adapter --skill adapting-projects-to-fabric
36
62
  npx skills add passioncode-ai/fabric-agent-adapter --skill creating-fabric-agents
63
+ npx skills add passioncode-ai/fabric-agent-adapter --skill building-fabric-services
37
64
  ```
38
65
 
39
66
  Claude Code plugin marketplace:
@@ -52,6 +79,12 @@ Adapt this project for Fabric compatibility. Inspect it, choose the profile per
52
79
  capability, scaffold the provider bundle, and report every conformance gate.
53
80
  ```
54
81
 
82
+ Or, for an agent that must keep running with a dashboard:
83
+
84
+ ```text
85
+ Make this agent a local service with an always-on dashboard, following fabric-service/0.1.
86
+ ```
87
+
55
88
  Or, for an agent that does not exist yet:
56
89
 
57
90
  ```text
@@ -86,11 +119,23 @@ claude plugin validate ./plugins/fabric-agent-adapter --strict
86
119
  claude plugin validate . --strict
87
120
  ```
88
121
 
122
+ `test/validate.py` reads every SKILL.md front matter as strictly as a YAML parser does; an
123
+ unquoted value holding `: ` fails it. `python3 test/validate.py --frontmatter <SKILL.md ...>`
124
+ checks copies installed elsewhere, such as `~/.agents/skills/*/SKILL.md`.
125
+
89
126
  ## Contract pin
90
127
 
91
128
  - version: `0.1.0`
92
- - commit: `20a818e648a4c09a60df0126d11626922e8b9094`
129
+ - commit: `a5a27092ba0dcc5facfbeae8b359146dfb403e9a`
93
130
 
94
131
  The contract repository is normative. Updating the pin requires a new adapter release,
95
132
  fixture review, and a complete validation run.
96
133
 
134
+ ## License
135
+
136
+ Source-available under PolyForm Noncommercial or Internal Use; commercial license on
137
+ request (contact@passioncode.ai). SPDX:
138
+ `PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0` — see
139
+ [LICENSE](LICENSE). Versions up to and including v0.4.2 (npm up to 0.3.1) were released
140
+ under the MIT License and remain available under it. Contributions are accepted under
141
+ [CLA.md](CLA.md) ([CONTRIBUTING.md](CONTRIBUTING.md)).
package/SECURITY.md CHANGED
@@ -1,10 +1,23 @@
1
1
  # Security
2
2
 
3
- Report vulnerabilities privately to the maintainers of the `passioncode-ai`
4
- organization. Do not open a public issue containing credentials, private provider URLs,
5
- or customer project data.
3
+ Report vulnerabilities privately to contact@passioncode.ai. Do not open a public issue
4
+ containing credentials, private provider URLs, or customer project data.
6
5
 
7
6
  The adapter must not write secret values to manifests, fixtures, probes, logs, or command
8
7
  arguments. Generated and external provider outputs are untrusted. Live probes must be
9
8
  bounded and non-publishing until explicit scoped grants exist in a project binding.
10
9
 
10
+
11
+ ## What the installers and scripts touch
12
+
13
+ - `npx @passioncode-ai/fabric-agent-adapter` and `install.sh` write only
14
+ `~/.agents/skills/<skill>`; `--target claude` writes `~/.claude/skills/<skill>` and is
15
+ refused while the plugin is installed; `--prune-shadow` moves shadowing copies into
16
+ `~/.claude/skills-shadow-backup/`.
17
+ - `building-fabric-services/scripts/check_service.py` reads a descriptor and the token
18
+ file it names, talks only to `127.0.0.1:<port>`, and redeems one login code it asked
19
+ for itself (creating one dashboard session). It never prints the token.
20
+ - The service kits create the service token (0600) and the instance lock in the
21
+ service's own data directory, and write a launchd plist and a descriptor only when an
22
+ installer calls them. The token is readable by any process of the same user; the
23
+ protocol defends against web pages and mistakes, not against hostile local code.
@@ -2,13 +2,12 @@
2
2
  /*
3
3
  * fabric-agent-adapter installer CLI.
4
4
  *
5
- * Installs every skill this plugin ships into ~/.claude/skills/<name>
6
- * (same layout as install.sh). Idempotent: an existing install is skipped unless
7
- * --force. Zero dependencies.
8
- *
9
- * For other agents (Cursor, Codex, 70+) use:
10
- * npx skills add passioncode-ai/fabric-agent-adapter (needs GitHub access —
11
- * the repository is private; the npm package needs none)
5
+ * Installs every skill this plugin ships into the shared agents hub
6
+ * ~/.agents/skills/<name> (read by Codex, Cursor, Gemini, OpenCode and others).
7
+ * Claude Code gets the skills through the plugin, never through a plain copy:
8
+ * a copy in ~/.claude/skills shadows the plugin and serves its frozen version
9
+ * forever. Idempotent; an existing install is skipped unless --force.
10
+ * Zero dependencies.
12
11
  */
13
12
  'use strict';
14
13
 
@@ -18,20 +17,25 @@ const os = require('os');
18
17
 
19
18
  const ROOT = path.resolve(__dirname, '..');
20
19
  const REPO = 'passioncode-ai/fabric-agent-adapter';
20
+ const PLUGIN_ID = 'fabric-agent-adapter@fabric-agent-adapter';
21
21
 
22
22
  function usage() {
23
23
  console.log(`fabric-agent-adapter installer
24
24
 
25
25
  Usage:
26
26
  npx @passioncode-ai/fabric-agent-adapter [--force]
27
- install every skill this plugin ships into ~/.claude
28
- (skip existing unless --force)
27
+ install every skill into the agents hub ~/.agents/skills
28
+ npx @passioncode-ai/fabric-agent-adapter --target claude [--force]
29
+ plain copy into ~/.claude/skills — refused while the plugin is installed
30
+ npx @passioncode-ai/fabric-agent-adapter --prune-shadow
31
+ remove plain ~/.claude/skills copies that shadow the installed plugin
29
32
  npx @passioncode-ai/fabric-agent-adapter --help
30
33
 
31
- Other install paths:
32
- Claude Code plugin: /plugin marketplace add ${REPO}
33
- /plugin install fabric-agent-adapter@fabric-agent-adapter
34
- Any agent (70+): npx skills add ${REPO} (private repo — GitHub auth required)`);
34
+ Claude Code (recommended):
35
+ claude plugin marketplace add ${REPO}
36
+ claude plugin install ${PLUGIN_ID}
37
+ Every PassionCode.ai skill for every agent at once:
38
+ npx @passioncode-ai/passioncode@latest update`);
35
39
  }
36
40
 
37
41
  function copyDir(src, dest) {
@@ -44,15 +48,38 @@ function copyDir(src, dest) {
44
48
  }
45
49
  }
46
50
 
47
- function installOne(label, src, dest, force) {
48
- if (fs.existsSync(dest) && !force) {
49
- console.log(`skip: ${label} already installed at ${dest} (rerun with --force to overwrite)`);
50
- return;
51
+ function pluginInstalled(home) {
52
+ try {
53
+ const data = JSON.parse(fs.readFileSync(path.join(home, '.claude/plugins/installed_plugins.json'), 'utf8'));
54
+ const records = (data.plugins || {})[PLUGIN_ID] || [];
55
+ return records.some((r) => r.installPath && fs.existsSync(path.join(r.installPath, 'skills')));
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ function skillNames() {
62
+ const skillRoot = path.join(ROOT, 'plugins/fabric-agent-adapter/skills');
63
+ if (!fs.existsSync(skillRoot)) return { skillRoot, names: [] };
64
+ // Iterate rather than name one skill: a skill added to the plugin must not
65
+ // require an installer change to reach anybody.
66
+ const names = fs.readdirSync(skillRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
67
+ return { skillRoot, names };
68
+ }
69
+
70
+ function pruneShadows(home, names) {
71
+ let removed = 0;
72
+ for (const name of names) {
73
+ const shadow = path.join(home, '.claude', 'skills', name);
74
+ let info;
75
+ try { info = fs.lstatSync(shadow); } catch { continue; }
76
+ const backup = path.join(home, '.claude', 'skills-shadow-backup', `${name}-${Date.now()}`);
77
+ fs.mkdirSync(path.dirname(backup), { recursive: true });
78
+ fs.renameSync(shadow, backup);
79
+ console.log(`Removed shadowing ${info.isSymbolicLink() ? 'link' : 'copy'} ${shadow} (kept at ${backup})`);
80
+ removed += 1;
51
81
  }
52
- fs.rmSync(dest, { recursive: true, force: true });
53
- fs.mkdirSync(path.dirname(dest), { recursive: true });
54
- copyDir(src, dest);
55
- console.log(`Installed ${label} -> ${dest}`);
82
+ if (!removed) console.log('No shadowing copies found.');
56
83
  }
57
84
 
58
85
  function main(argv) {
@@ -62,39 +89,56 @@ function main(argv) {
62
89
  return 0;
63
90
  }
64
91
  const force = args.includes('--force');
65
- const unknown = args.filter((a) => a !== '--force');
66
- if (unknown.length) {
67
- console.error(`unknown argument(s): ${unknown.join(' ')}`);
92
+ const prune = args.includes('--prune-shadow');
93
+ let target = 'agents';
94
+ const known = new Set(['--force', '--prune-shadow']);
95
+ const unknown = [];
96
+ for (let i = 0; i < args.length; i += 1) {
97
+ if (args[i] === '--target') {
98
+ target = args[i + 1];
99
+ i += 1;
100
+ } else if (!known.has(args[i])) unknown.push(args[i]);
101
+ }
102
+ if (unknown.length || !['agents', 'claude'].includes(target)) {
103
+ console.error(`unknown argument(s): ${unknown.concat(['agents', 'claude'].includes(target) ? [] : [`--target ${target}`]).join(' ')}`);
68
104
  usage();
69
105
  return 2;
70
106
  }
71
107
 
72
- const skillRoot = path.join(ROOT, 'plugins/fabric-agent-adapter/skills');
73
- if (!fs.existsSync(skillRoot)) {
74
- console.error(`error: skill sources missing at ${skillRoot} — corrupted package?`);
108
+ const { skillRoot, names } = skillNames();
109
+ if (!names.length) {
110
+ console.error(`error: no skills found under ${skillRoot} — corrupted package?`);
75
111
  return 1;
76
112
  }
113
+ const home = os.homedir();
114
+ const hasPlugin = pluginInstalled(home);
77
115
 
78
- // Iterate rather than name one skill: a skill added to the plugin must not
79
- // require an installer change to reach anybody.
80
- const names = fs
81
- .readdirSync(skillRoot, { withFileTypes: true })
82
- .filter((e) => e.isDirectory())
83
- .map((e) => e.name)
84
- .sort();
85
- if (!names.length) {
86
- console.error(`error: no skills found under ${skillRoot} — corrupted package?`);
116
+ if (prune) {
117
+ if (!hasPlugin) {
118
+ console.error(`error: the ${PLUGIN_ID} plugin is not installed, so a copy in ~/.claude/skills is not a shadow — nothing removed.`);
119
+ return 1;
120
+ }
121
+ pruneShadows(home, names);
122
+ return 0;
123
+ }
124
+ if (target === 'claude' && hasPlugin) {
125
+ console.error(`error: the ${PLUGIN_ID} plugin is installed; a plain copy in ~/.claude/skills would shadow it. Update the plugin instead:\n claude plugin marketplace update fabric-agent-adapter && claude plugin update ${PLUGIN_ID}`);
87
126
  return 1;
88
127
  }
89
128
 
90
- const home = os.homedir();
129
+ const destRoot = target === 'claude' ? path.join(home, '.claude', 'skills') : path.join(home, '.agents', 'skills');
91
130
  for (const name of names) {
92
- installOne(
93
- `${name} skill`,
94
- path.join(skillRoot, name),
95
- path.join(home, '.claude', 'skills', name),
96
- force
97
- );
131
+ const dest = path.join(destRoot, name);
132
+ if (fs.existsSync(dest) && !force) {
133
+ console.log(`skip: ${name} already installed at ${dest} (rerun with --force to overwrite)`);
134
+ continue;
135
+ }
136
+ fs.rmSync(dest, { recursive: true, force: true });
137
+ copyDir(path.join(skillRoot, name), dest);
138
+ console.log(`Installed ${name} -> ${dest}`);
139
+ }
140
+ if (target === 'agents' && !hasPlugin) {
141
+ console.log(`Claude Code reads plugins, not the hub:\n claude plugin marketplace add ${REPO} && claude plugin install ${PLUGIN_ID}`);
98
142
  }
99
143
  console.log('Restart your agent — skills load at session start.');
100
144
  return 0;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@passioncode-ai/fabric-agent-adapter",
3
- "version": "0.3.1",
4
- "description": "Create new Fabric-compatible agents and adapt existing projects to the Fabric Agent Contract — evidence-backed MCP, A2A, or local-runner provider bundles. This package is the installer CLI.",
3
+ "version": "0.4.3",
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
- "test": "python3 test/validate.py && python3 -m unittest discover -s test -q"
6
+ "test": "python3 test/validate.py && python3 -m unittest discover -s test -q && node --test test/"
7
7
  },
8
8
  "bin": {
9
9
  "fabric-agent-adapter": "bin/fabric-agent-adapter.js"
@@ -17,14 +17,16 @@
17
17
  "README.md",
18
18
  "LICENSE",
19
19
  "CHANGELOG.md",
20
- "SECURITY.md"
20
+ "SECURITY.md",
21
+ "!**/__pycache__/**",
22
+ "!**/*.pyc"
21
23
  ],
22
24
  "repository": "github:passioncode-ai/fabric-agent-adapter",
23
25
  "homepage": "https://github.com/passioncode-ai/fabric-agent-adapter",
24
- "license": "MIT",
26
+ "license": "PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0",
25
27
  "author": {
26
- "name": "passioncode-ai",
27
- "url": "https://github.com/passioncode-ai"
28
+ "name": "PassionCode.ai",
29
+ "url": "https://passioncode.ai/"
28
30
  },
29
31
  "engines": {
30
32
  "node": ">=16"
@@ -39,6 +41,9 @@
39
41
  "provider",
40
42
  "conformance",
41
43
  "claude-code",
42
- "skill"
44
+ "skill",
45
+ "local-service",
46
+ "dashboard",
47
+ "launchd"
43
48
  ]
44
49
  }
@@ -2,15 +2,15 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "fabric-agent-adapter",
4
4
  "displayName": "Fabric Agent Adapter",
5
- "description": "Create new Fabric-compatible agents and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles.",
6
- "version": "0.3.1",
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.4.3",
7
7
  "author": {
8
- "name": "passioncode-ai",
9
- "url": "https://github.com/passioncode-ai"
8
+ "name": "PassionCode.ai",
9
+ "url": "https://passioncode.ai/"
10
10
  },
11
11
  "homepage": "https://github.com/passioncode-ai/fabric-agent-adapter",
12
12
  "repository": "https://github.com/passioncode-ai/fabric-agent-adapter",
13
- "license": "MIT",
13
+ "license": "PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0",
14
14
  "keywords": [
15
15
  "fabric",
16
16
  "agent",
@@ -22,4 +22,3 @@
22
22
  "conformance"
23
23
  ]
24
24
  }
25
-