@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.
Files changed (26) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +14 -3
  3. package/package.json +1 -1
  4. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  5. package/plugins/fabric-agent-adapter/hooks/hooks.json +17 -0
  6. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +3 -3
  7. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
  8. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +21 -8
  9. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/demo.html +110 -0
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +198 -0
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +253 -0
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +28 -0
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/themes.json +350 -0
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +133 -0
  15. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +4 -3
  16. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +25 -3
  17. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +7 -4
  18. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +19 -2
  19. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_layout.mjs +295 -0
  20. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +88 -5
  21. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +437 -0
  22. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +143 -17
  23. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +195 -36
  24. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample-remote-service.mjs +9 -1
  25. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +29 -4
  26. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
@@ -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
- <style>body{{font:15px system-ui;margin:2rem;color:#e9e4ec;background:#0a070d}}li{{margin:.3rem 0}}</style>
35
- </head><body><h1>{name}</h1><p>Status: {status}</p><ul>{rows}</ul></body></html>"""
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
- self.codes = fs.LoginCodes(self.data / "auth")
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 'unsafe-inline'; frame-ancestors 'self'")
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.3"
8
+ version: "0.10.0"
9
9
  contract-version: "0.1.0"
10
- contract-commit: "52da526d7cc1e063d74c5b520dbc03d0ace15246"
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 `52da526d7cc1e063d74c5b520dbc03d0ace15246` and
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