@passioncode-ai/fabric-agent-adapter 0.8.3 → 0.10.0
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 +100 -0
- package/README.md +14 -3
- package/package.json +1 -1
- package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/plugins/fabric-agent-adapter/hooks/hooks.json +17 -0
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +3 -3
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +21 -8
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/demo.html +110 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +198 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +253 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +28 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/themes.json +350 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +133 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +4 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +25 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +7 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +19 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_layout.mjs +295 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +88 -5
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +437 -0
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +143 -17
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +195 -36
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample-remote-service.mjs +9 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +29 -4
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py
CHANGED
|
@@ -29,10 +29,21 @@ import fabric_service as fs # noqa: E402
|
|
|
29
29
|
import fabric_interop as fi # noqa: E402
|
|
30
30
|
|
|
31
31
|
VERSION = "0.1.0"
|
|
32
|
+
# The dashboard is built from the dashboard kit (fabric-dashboard/0.1, DEC-0036) and declares it
|
|
33
|
+
# in the well-known document only when the kit is there to serve.
|
|
34
|
+
KIT_DIR = Path(__file__).resolve().parent.parent / "assets" / "dashboard-kit"
|
|
35
|
+
KIT_FILES = {"/kit/fabric-dashboard.css": ("fabric-dashboard.css", "text/css; charset=utf-8"),
|
|
36
|
+
"/kit/fabric-dashboard.js": ("fabric-dashboard.js", "text/javascript; charset=utf-8")}
|
|
32
37
|
PAGE = """<!doctype html><html lang="en"><head><meta charset="utf-8">
|
|
33
38
|
<meta name="viewport" content="width=device-width,initial-scale=1"><title>{name}</title>
|
|
34
|
-
<
|
|
35
|
-
</head><body><
|
|
39
|
+
<link rel="stylesheet" href="/kit/fabric-dashboard.css"><script src="/kit/fabric-dashboard.js" defer></script>
|
|
40
|
+
</head><body><div class="fd-chrome"><header class="fd-header"><p class="fd-title">{name}</p>
|
|
41
|
+
<span class="fd-chip fd-s-ok"><span class="fd-dot"></span>Status: {status}</span></header>
|
|
42
|
+
<nav class="fd-nav" aria-label="Sections"><ul class="fd-nav-list"><li><a href="#events" aria-current="page">Events</a></li>
|
|
43
|
+
<li><a href="#about">About</a></li></ul></nav></div>
|
|
44
|
+
<main class="fd-page"><section id="events"><h2>Events</h2><ul>{rows}</ul></section>
|
|
45
|
+
<section id="about"><h2>About</h2><p class="fd-hint">A sample fabric-service/0.1 service built on the kit.</p></section></main>
|
|
46
|
+
</body></html>"""
|
|
36
47
|
|
|
37
48
|
|
|
38
49
|
def _schema(name: str, body: Dict[str, Any]) -> Dict[str, Any]:
|
|
@@ -73,7 +84,8 @@ class Service:
|
|
|
73
84
|
self.log = fs.JsonlEventLog(self.data / "events.jsonl")
|
|
74
85
|
self.usage = fs.JsonlUsageLedger(self.data / "usage.jsonl") # DEC-0021
|
|
75
86
|
self.usage.prune()
|
|
76
|
-
|
|
87
|
+
# DEC-0039: the token= revision ends sessions begun under a token that has since rotated.
|
|
88
|
+
self.codes = fs.LoginCodes(self.data / "auth", token=self.token)
|
|
77
89
|
self.jobs = fi.JobStore(self.data / "jobs")
|
|
78
90
|
self.mcp = fi.McpToolServer(self.id, VERSION, jobs=self.jobs, on_job_started=self.draft_started, on_input=self.draft_answered)
|
|
79
91
|
for cap in CAPABILITIES:
|
|
@@ -130,6 +142,7 @@ class Service:
|
|
|
130
142
|
surfaces={"dashboard": {"path": "/", "login": True}, "events": {"path": "/fabric/v1/events"},
|
|
131
143
|
"mcp": {"path": "/mcp", "transport": "streamable-http", "capabilities": [c["name"] for c in CAPABILITIES]},
|
|
132
144
|
"usage": {"path": fs.USAGE_PATH}},
|
|
145
|
+
extensions=fs.dashboard_extension() if (KIT_DIR / "fabric-dashboard.css").is_file() else None,
|
|
133
146
|
)
|
|
134
147
|
|
|
135
148
|
|
|
@@ -148,7 +161,7 @@ def make_handler(svc: Service):
|
|
|
148
161
|
self.send_response(status)
|
|
149
162
|
self.send_header("Cache-Control", "no-store")
|
|
150
163
|
self.send_header("X-Content-Type-Options", "nosniff")
|
|
151
|
-
self.send_header("Content-Security-Policy", "default-src 'none'; style-src '
|
|
164
|
+
self.send_header("Content-Security-Policy", "default-src 'none'; style-src 'self'; script-src 'self'; frame-ancestors 'self'")
|
|
152
165
|
if body is not None:
|
|
153
166
|
self.send_header("Content-Type", content_type)
|
|
154
167
|
self.send_header("Content-Length", str(len(payload)))
|
|
@@ -203,6 +216,12 @@ def make_handler(svc: Service):
|
|
|
203
216
|
if not cookie:
|
|
204
217
|
return self._send(403, "This sign-in link was already used or has expired.", content_type="text/plain")
|
|
205
218
|
return self._send(302, None, {"Location": "/", "Set-Cookie": fs.session_cookie_header(cookie)})
|
|
219
|
+
if url.path in KIT_FILES:
|
|
220
|
+
name, kind = KIT_FILES[url.path]
|
|
221
|
+
try:
|
|
222
|
+
return self._send(200, (KIT_DIR / name).read_text(encoding="utf-8"), content_type=kind)
|
|
223
|
+
except OSError:
|
|
224
|
+
return self._send(404, {"error": "Not found."})
|
|
206
225
|
if url.path == "/":
|
|
207
226
|
if not self._session_ok():
|
|
208
227
|
return self._send(401, "Open this dashboard from Fabric Dashboards.", content_type="text/plain")
|
|
@@ -237,6 +256,12 @@ def make_handler(svc: Service):
|
|
|
237
256
|
if not self._token_ok():
|
|
238
257
|
return
|
|
239
258
|
return self._send(200, svc.codes.issue())
|
|
259
|
+
if url.path == "/logout":
|
|
260
|
+
# A browser write: the custom header keeps another site's form from signing the operator out.
|
|
261
|
+
if self.headers.get("X-Fabric-Request") != "1":
|
|
262
|
+
return self._send(403, {"error": "Missing request header."})
|
|
263
|
+
svc.codes.logout(fs.cookie_value(self.headers.get("Cookie")))
|
|
264
|
+
return self._send(204, None, {"Set-Cookie": fs.expired_session_cookie_header()})
|
|
240
265
|
if url.path == "/api/emit":
|
|
241
266
|
if not (self._session_ok() or fs.token_matches(self.headers.get("Authorization"), svc.token)):
|
|
242
267
|
return self._send(401, {"error": "Sign in first."})
|
|
@@ -5,9 +5,9 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
5
5
|
compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode. Ships in one plugin with adapting-projects-to-fabric, whose scripts it reuses.
|
|
6
6
|
metadata:
|
|
7
7
|
author: PassionCode.ai
|
|
8
|
-
version: "0.
|
|
8
|
+
version: "0.10.0"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Creating Fabric-compatible agents
|
|
@@ -119,7 +119,7 @@ python3 <plugin-dir>/skills/adapting-projects-to-fabric/scripts/adapt_project.py
|
|
|
119
119
|
--schema-base <immutable-base-uri>
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
Pin exactly contract `0.1.0` at commit `
|
|
122
|
+
Pin exactly contract `0.1.0` at commit `8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5` and
|
|
123
123
|
read the pinned guide before implementing protocol details. If this skill is installed
|
|
124
124
|
without its sibling, the scaffolder is absent: create the bundle by hand from the pinned
|
|
125
125
|
contract's `docs/guides/connecting-compatible-agents.md` and mark the structural check
|