@passioncode-ai/passioncode 0.2.37 → 0.2.39
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 +16 -0
- package/family.json +1 -1
- package/package.json +1 -1
- package/payload/.claude-plugin/marketplace.json +2 -2
- package/payload/manifest.json +8 -8
- package/payload/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +29 -11
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/dashboard-links.md +53 -3
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/operator-channel-and-repository.md +11 -3
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/provider-entry.md +3 -1
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/adapt_project.py +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_provider.py +4 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +50 -14
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +38 -12
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +2 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +14 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +9 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-links.md +53 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard.md +13 -4
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/delegation.md +10 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/interop.md +99 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +1 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +5 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/remote-placement.md +6 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/settings-backups.md +2 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/references/surfaces-and-auth.md +5 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +47 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service_rules.py +325 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/dashboard_kit.py +2 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-actions.mjs +246 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-auth.mjs +4 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-backups.mjs +3 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +22 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +45 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop-rules.mjs +45 -3
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +2 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +1 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_actions.py +302 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_auth.py +7 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_backups.py +2 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +22 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +58 -5
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +154 -8
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop_rules.py +45 -2
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +1 -1
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +9 -0
- package/payload/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +202 -18
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +29 -11
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/dashboard-links.md +53 -3
- package/payload/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/operator-channel-and-repository.md +11 -3
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +41 -9
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +2 -0
- package/payload/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
- package/payload/plugins/passioncode/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.39 - 2026-10-26
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Fabric Agent Adapter is pinned at `v0.50.0`** (it was `v0.49.3`): the contract release `v0.1.0+2026-10-25` with
|
|
8
|
+
dashboard action parity (every dashboard button has an agent tool, and the operator's agent relays their decision),
|
|
9
|
+
agent pages that open only in Fabric Dashboards, and new probe rules. Notes are in the adapter's CHANGELOG.
|
|
10
|
+
|
|
11
|
+
## 0.2.38 - 2026-10-26
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **Fabric Agent Adapter is pinned at `v0.49.3`** (it was `v0.49.2`): Fabric's button in the dashboard kit shows
|
|
16
|
+
Russian on a Russian page and takes a page's own words, with no em dash, and a remote service registers the
|
|
17
|
+
repository of its code. Notes are in the adapter's CHANGELOG.
|
|
18
|
+
|
|
3
19
|
## 0.2.37 - 2026-10-24
|
|
4
20
|
|
|
5
21
|
### Changed
|
package/family.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@passioncode-ai/passioncode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.39",
|
|
4
4
|
"description": "Set up PassionCode.ai on a computer with one command — the apps from their verified releases, their MCP servers for every coding agent and the PassionCode.ai skills — and check and repair it with the same command or `doctor`.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"passioncode": "bin/passioncode.js"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"name": "fabric-agent-adapter",
|
|
12
12
|
"displayName": "Fabric Agent Adapter",
|
|
13
13
|
"source": "./plugins/fabric-agent-adapter",
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.50.0",
|
|
15
15
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks.",
|
|
16
16
|
"author": {
|
|
17
17
|
"name": "PassionCode.ai",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"name": "passioncode",
|
|
36
36
|
"displayName": "PassionCode.ai",
|
|
37
37
|
"source": "./plugins/passioncode",
|
|
38
|
-
"version": "0.2.
|
|
38
|
+
"version": "0.2.39",
|
|
39
39
|
"description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
|
|
40
40
|
"author": {
|
|
41
41
|
"name": "PassionCode.ai",
|
package/payload/manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"family": "passioncode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.39",
|
|
4
4
|
"release": true,
|
|
5
5
|
"members": [
|
|
6
6
|
{
|
|
7
7
|
"name": "fabric-agent-adapter",
|
|
8
8
|
"displayName": "Fabric Agent Adapter",
|
|
9
9
|
"repo": "passioncode-ai/fabric-agent-adapter",
|
|
10
|
-
"ref": "v0.
|
|
11
|
-
"commit": "
|
|
12
|
-
"version": "0.
|
|
10
|
+
"ref": "v0.50.0",
|
|
11
|
+
"commit": "d813a4e07a7b721619bd98b80f7dd9920d896ba0",
|
|
12
|
+
"version": "0.50.0",
|
|
13
13
|
"via": "clone of https://***@github.com/passioncode-ai/fabric-agent-adapter.git",
|
|
14
14
|
"skills": [
|
|
15
15
|
"adapting-projects-to-fabric",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"legacyMarketplaces": [
|
|
24
24
|
"fabric-agent-adapter"
|
|
25
25
|
],
|
|
26
|
-
"contentHash": "sha256:
|
|
26
|
+
"contentHash": "sha256:d2577bec959c6231e91deb459bd70fbd613914bd1a08dd4c479c21bef516d2e9",
|
|
27
27
|
"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.",
|
|
28
28
|
"author": {
|
|
29
29
|
"name": "PassionCode.ai",
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"name": "passioncode",
|
|
63
63
|
"displayName": "PassionCode.ai",
|
|
64
64
|
"repo": "passioncode-ai/passioncode",
|
|
65
|
-
"ref": "v0.2.
|
|
65
|
+
"ref": "v0.2.39",
|
|
66
66
|
"commit": null,
|
|
67
|
-
"version": "0.2.
|
|
67
|
+
"version": "0.2.39",
|
|
68
68
|
"via": "this repository",
|
|
69
69
|
"skills": [
|
|
70
70
|
"setting-up-passioncode",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
],
|
|
73
73
|
"legacyPluginIds": [],
|
|
74
74
|
"legacyMarketplaces": [],
|
|
75
|
-
"contentHash": "sha256:
|
|
75
|
+
"contentHash": "sha256:9d3b6b75814363291607bf77221b1b5f0326cf65139f5ce68fef96d67df010cd",
|
|
76
76
|
"description": "Set up and check PassionCode.ai on a computer with one command (setting-up-passioncode), the organisation's working rules for every contributor's agent (working-in-passioncode), and a once-a-day check that keeps the PassionCode.ai set current.",
|
|
77
77
|
"author": {
|
|
78
78
|
"name": "PassionCode.ai",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "fabric-agent-adapter",
|
|
4
4
|
"displayName": "Fabric Agent Adapter",
|
|
5
5
|
"description": "Create new Fabric-compatible agents, build them as always-alive local services with dashboards (fabric-service/0.1), and adapt existing projects to the Fabric Agent Contract through evidence-backed MCP, A2A, or local-runner provider bundles; and teach a coding agent to work in a project through Fabric (fabric-mcp, fabric_whoami, claim and release), with Claude Code session hooks.",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.50.0",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "PassionCode.ai",
|
|
9
9
|
"url": "https://passioncode.ai/"
|
|
@@ -5,9 +5,9 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
5
5
|
compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode.
|
|
6
6
|
metadata:
|
|
7
7
|
author: PassionCode.ai
|
|
8
|
-
version: "0.
|
|
8
|
+
version: "0.50.0"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
|
-
contract-commit: "
|
|
10
|
+
contract-commit: "52c7d798b9f4eb784eb4e29e717038a8912c759d"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Adapting projects to Fabric
|
|
@@ -76,7 +76,7 @@ Use exactly:
|
|
|
76
76
|
|
|
77
77
|
- contract version `0.1.0`;
|
|
78
78
|
- repository `https://github.com/passioncode-ai/fabric-agent-contract`;
|
|
79
|
-
- commit `
|
|
79
|
+
- commit `52c7d798b9f4eb784eb4e29e717038a8912c759d`.
|
|
80
80
|
|
|
81
81
|
This is the default for new bundles. When checking an issued legacy bundle, preserve its
|
|
82
82
|
explicit supported lock and use that exact clean checkout. Never silently upgrade or
|
|
@@ -218,9 +218,9 @@ not a connected provider.
|
|
|
218
218
|
If the agent has a human stop (a choice, an approval, a confirmation) or emits `notify: true`
|
|
219
219
|
events, propose its operator channel (`fabric-operator-channel/0.1`, OC-11) to the operator once,
|
|
220
220
|
now, as [the operator channel and the repository standard](references/operator-channel-and-repository.md)
|
|
221
|
-
describes: the operator's four steps, the answer recorded and never asked again,
|
|
222
|
-
token and enabling the channel
|
|
223
|
-
skips this step.
|
|
221
|
+
describes: the operator's four steps, the answer recorded and never asked again, the bot and the
|
|
222
|
+
token left to the person, and enabling the channel to the operator's decision (on the page or
|
|
223
|
+
relayed, DEC-0121). An agent with neither stops nor notify events skips this step.
|
|
224
224
|
|
|
225
225
|
## The repository around the provider
|
|
226
226
|
|
|
@@ -245,8 +245,26 @@ Report:
|
|
|
245
245
|
Never summarize the outcome as “Fabric-compatible” unless all required admission gates
|
|
246
246
|
passed against a real provider and the project binding is valid.
|
|
247
247
|
|
|
248
|
-
##
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
## Agent pages open only in Fabric Dashboards
|
|
249
|
+
|
|
250
|
+
The operator's rule (2026-10-24) for every page of an agent or a local Fabric service, in any host: a
|
|
251
|
+
link in an answer or a notification, `<tool> dashboard`, a completion message, a page the agent opens
|
|
252
|
+
itself. Hand over the `open_link` the `fabric-dashboards` MCP's `link` tool returns for the exact
|
|
253
|
+
registered service key (`list_services`, never guessed) and the page's path; open it only with the
|
|
254
|
+
host's `open` and `fallback=never`. Never `open <url>`, `open -a Safari`, `xdg-open`,
|
|
255
|
+
`webbrowser.open` or `shell.openExternal` aimed at the agent's pages. A browser only on a confirmed
|
|
256
|
+
`not_installed` host; an installed host that failed to open is reported, never replaced by HTTP.
|
|
257
|
+
Links carry no token or login code.
|
|
258
|
+
|
|
259
|
+
The agent's `AGENTS.md` carries this as its dashboard rule block, and its checks run the adapter's link gate
|
|
260
|
+
(`scripts/check_dashboard_link.py` from this skill's own directory; it is not copied into the project) on every
|
|
261
|
+
completion and notification action before delivery:
|
|
262
|
+
[dashboard links](references/dashboard-links.md) has the block, the gate's input and the remote case.
|
|
263
|
+
Headless agents need no dashboard.
|
|
264
|
+
|
|
265
|
+
## An agent with a page and no service descriptor
|
|
266
|
+
|
|
267
|
+
A local page no service descriptor names cannot open in Fabric Dashboards. Never open it in a browser
|
|
268
|
+
instead: make the agent a `fabric-service/0.1` service with `building-fabric-services` (the descriptor,
|
|
269
|
+
the well-known document, the login-code routes and a declared dashboard), and until that lands file a
|
|
270
|
+
board row for it and say the page waits on it.
|
|
@@ -5,6 +5,19 @@ an existing Fabric service dashboard to a person. This also applies to generated
|
|
|
5
5
|
agent instructions and completion messages. Headless agents need no dashboard;
|
|
6
6
|
API origins, external docs and OAuth links are not dashboard actions.
|
|
7
7
|
|
|
8
|
+
The rule (the operator's, 2026-10-24): every page of an agent or a local Fabric
|
|
9
|
+
service opens only in Fabric Dashboards, never in Safari, Dia, Chrome or any
|
|
10
|
+
other browser, unless Fabric Dashboards is confirmed not installed.
|
|
11
|
+
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- Resolve, then hand over
|
|
15
|
+
- The block a generated AGENTS.md carries
|
|
16
|
+
- An agent with a page and no service descriptor
|
|
17
|
+
- Device and channel
|
|
18
|
+
- Portable output gate
|
|
19
|
+
- Degradation
|
|
20
|
+
|
|
8
21
|
## Resolve, then hand over
|
|
9
22
|
|
|
10
23
|
1. Discover the target computer and exact registered `service.id.instance`.
|
|
@@ -20,9 +33,12 @@ API origins, external docs and OAuth links are not dashboard actions.
|
|
|
20
33
|
compatible host resolver or report the limitation, not presumed absence.
|
|
21
34
|
4. A request for a link opens nothing. A request to open uses the host `open`
|
|
22
35
|
tool/approved opener, which starts or focuses the existing Fabric Dashboards
|
|
23
|
-
and reuses the service view
|
|
24
|
-
permits one only for confirmed absence. Discover schema support
|
|
25
|
-
`open` implementations may silently fall back on failure and are
|
|
36
|
+
and reuses the service view, with `fallback=never`: it forbids a browser.
|
|
37
|
+
`if_absent` permits one only for confirmed absence. Discover schema support
|
|
38
|
+
first: older `open` implementations may silently fall back on failure and are
|
|
39
|
+
not strict. Never
|
|
40
|
+
`open <url>`, `open -a Safari`, `xdg-open`, `start <url>`, `webbrowser.open`
|
|
41
|
+
or `shell.openExternal` aimed at the service's pages.
|
|
26
42
|
5. An installed host that failed to open is **not absent**. Report the failure;
|
|
27
43
|
do not silently launch HTTP in a browser, a second server, `npm run dev`, or
|
|
28
44
|
another standalone dashboard. A stopped backend stays on its host status/Start
|
|
@@ -31,6 +47,40 @@ API origins, external docs and OAuth links are not dashboard actions.
|
|
|
31
47
|
not page readiness, a successful login, or a completed job. Links carry no
|
|
32
48
|
bearer tokens or login codes. The host handles dashboard authentication.
|
|
33
49
|
|
|
50
|
+
## The block a generated AGENTS.md carries
|
|
51
|
+
|
|
52
|
+
An agent with a page carries this block in its `AGENTS.md` (its `CLAUDE.md` reads
|
|
53
|
+
it through `@AGENTS.md`), beside its browser rule, and its completion and
|
|
54
|
+
notification renderers follow it:
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
## Pages open only in Fabric Dashboards
|
|
58
|
+
|
|
59
|
+
Every page of this agent (its dashboard, a job, an approval, a report) opens in
|
|
60
|
+
Fabric Dashboards, never in a browser. Resolve the registered service key with
|
|
61
|
+
the fabric-dashboards MCP (`list_services`, never guessed) and hand over the
|
|
62
|
+
`open_link` its `link` tool returns for the page's path; to open it, call the
|
|
63
|
+
host's `open` with `fallback=never`. Never `open <url>`, `open -a Safari`,
|
|
64
|
+
`xdg-open`, `start <url>`, `webbrowser.open` or `shell.openExternal` on this
|
|
65
|
+
agent's pages. A browser only when `host_status` confirms `not_installed`; an
|
|
66
|
+
installed host that failed to open is reported, not replaced by HTTP. Links
|
|
67
|
+
carry no token or login code. Every completion and notification action passes
|
|
68
|
+
the Fabric Agent Adapter's link gate before delivery: `check_dashboard_link.py`
|
|
69
|
+
in its `building-fabric-services/scripts`, run from that skill's directory;
|
|
70
|
+
where it cannot run, the action is compared by hand and the check is NOT_RUN.
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The project's checks run the gate below on each renderer's action, and a test
|
|
74
|
+
holds a raw-HTTP primary action beside an available host refused.
|
|
75
|
+
|
|
76
|
+
## An agent with a page and no service descriptor
|
|
77
|
+
|
|
78
|
+
Fabric Dashboards opens only a page a service descriptor names. An agent that
|
|
79
|
+
serves a local page without one cannot be opened there, and a browser is not the
|
|
80
|
+
workaround. Make it a `fabric-service/0.1` service (`building-fabric-services`:
|
|
81
|
+
the descriptor, the well-known document, the login-code routes and a declared
|
|
82
|
+
dashboard); until that lands, file a board row for it and say the page waits on it.
|
|
83
|
+
|
|
34
84
|
## Device and channel
|
|
35
85
|
|
|
36
86
|
A custom scheme opens on the device receiving it. A phone's localhost is not the
|
|
@@ -26,9 +26,12 @@ bare `/command` in a group is not addressed), and a channel nobody receives on i
|
|
|
26
26
|
|
|
27
27
|
Record the answer (`accepted`, `declined` or `later`) in the agent's state and in its conformance
|
|
28
28
|
report, and do not ask again; an agent that serves `surfaces.operatorChannel` also shows it as
|
|
29
|
-
`proposal` in its status document. Creating the bot
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
`proposal` in its status document. Creating the bot and putting its token into the secret store
|
|
30
|
+
stay the person's (a `secret` step, contract DEC-0121 AP-4): never create the bot, or ask for or
|
|
31
|
+
store the token's value. Enabling the channel, and removing a webhook found on its token, are the
|
|
32
|
+
operator's decision, taken by them on the agent's page or relayed to its agent in their own words
|
|
33
|
+
with `_meta.decision` (OC-1, OC-2, DEC-0121 AP-2); never enable it on your own account. The default
|
|
34
|
+
pin carries DEC-0034 and DEC-0035: a served status document is
|
|
32
35
|
checked against the pinned `schemas/operator-channel-status.schema.json`; the channel's runtime
|
|
33
36
|
rules have no probe rule here yet, so report them `NOT_RUN`. An agent with neither stops nor notify
|
|
34
37
|
events skips this.
|
|
@@ -49,6 +52,11 @@ For a PassionCode.ai repository, the agent's repository follows the organization
|
|
|
49
52
|
- an `AGENTS.md` that opens with the template's *Read first* block and closes with *After work*,
|
|
50
53
|
and a `CLAUDE.md` whose first line is `@AGENTS.md`.
|
|
51
54
|
|
|
55
|
+
Whoever owns the repository, an agent with a page gets the dashboard rule block in its `AGENTS.md`
|
|
56
|
+
(pages open only in Fabric Dashboards; the block is in `references/dashboard-links.md`), and its
|
|
57
|
+
checks run the adapter's link gate (`scripts/check_dashboard_link.py` from the skill's own directory, not a copy in
|
|
58
|
+
the project).
|
|
59
|
+
|
|
52
60
|
org-index `scripts/check_format.py` reports 0 findings for it before it is called done. An agent
|
|
53
61
|
someone builds for themselves is not a PassionCode.ai repository: its licence is its owner's
|
|
54
62
|
choice, nothing about it is published or listed by the organization, and none of these files is
|
|
@@ -53,7 +53,9 @@ It refuses, with one sentence that never quotes a value:
|
|
|
53
53
|
1024 characters), a shell-string command, more than 32 arguments or one over 1024 characters, more than 64 env
|
|
54
54
|
names, a `source.repository` that is not an absolute URI, an `installedAt` that is not an RFC 3339 date-time,
|
|
55
55
|
unknown fields. The patterns are the schema's, copied (`test_provider.SchemaParityTests` compares them with a
|
|
56
|
-
contract checkout at the pin when `FABRIC_CONTRACT_NEW` names one)
|
|
56
|
+
contract checkout at the pin when `FABRIC_CONTRACT_NEW` names one);
|
|
57
|
+
- a `source.repository` with a `user:password@` or a value shaped like a credential: it names the repository, never
|
|
58
|
+
reaches it (since 0.49.3, as the service kit's descriptor check).
|
|
57
59
|
|
|
58
60
|
`validate` also checks that the file is named `<id>.json` (FAC-SEM-014, slug half).
|
|
59
61
|
From Python: `write_provider_entry(entry)`, `remove_provider_entry(id)`,
|
|
@@ -22,10 +22,10 @@ import fabric_secrets as _secrets # noqa: E402 - the contract's credential dete
|
|
|
22
22
|
|
|
23
23
|
CONTRACT_VERSION = "0.1.0"
|
|
24
24
|
CONTRACT_REPOSITORY = "https://github.com/passioncode-ai/fabric-agent-contract"
|
|
25
|
-
CONTRACT_COMMIT = "
|
|
25
|
+
CONTRACT_COMMIT = "52c7d798b9f4eb784eb4e29e717038a8912c759d"
|
|
26
26
|
# #region supported-contract-revisions — docs: README.md#contract-pin
|
|
27
27
|
# Only this declaration may name a legacy revision in live files.
|
|
28
|
-
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "87d384ffce2757081b7ab227e5dad3dddd08328f", "0a4ce773c4b9e6bec40c6387eb3f988af7152c0e", "e742016dc396aa31e5a13a893489e43f15786c69", "bfa9a67aa3c6cb808c093e7d83cd59799f1ee7d0", "c55f2d5a11c9a0197e958e87212fca7ae1154769", "07042181bfae2a481aa0da1a5651f24c76669c48", "d8146cfb0a1c74fc6432284c4356bb0c864b37b5", "82e163665e156a08aa3b92e4711015582c06162c", "1636fa97262f4a26e2086572d540c2ee701e0010", "f00a7685e3861c27f7899c033fb850a145a1708f", "a046f57cf46ea9e3da57ff8ce6a3ed4d26d8774b", "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0", "b291bf09e0a9f9fd3c16cf540832cd021203b7d1", "0cacd08b0e95b6abf131eae1206b60792138bc3c", "2eb91c00e852d9c31d804310d38fad91589fcbac", "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
28
|
+
SUPPORTED_CONTRACT_COMMITS = (CONTRACT_COMMIT, "2f020a696453ae299b123517f14957f6a1354379", "87d384ffce2757081b7ab227e5dad3dddd08328f", "0a4ce773c4b9e6bec40c6387eb3f988af7152c0e", "e742016dc396aa31e5a13a893489e43f15786c69", "bfa9a67aa3c6cb808c093e7d83cd59799f1ee7d0", "c55f2d5a11c9a0197e958e87212fca7ae1154769", "07042181bfae2a481aa0da1a5651f24c76669c48", "d8146cfb0a1c74fc6432284c4356bb0c864b37b5", "82e163665e156a08aa3b92e4711015582c06162c", "1636fa97262f4a26e2086572d540c2ee701e0010", "f00a7685e3861c27f7899c033fb850a145a1708f", "a046f57cf46ea9e3da57ff8ce6a3ed4d26d8774b", "fe55fc67cba1a9e34a736da7d148d4fe2a8fbfa0", "b291bf09e0a9f9fd3c16cf540832cd021203b7d1", "0cacd08b0e95b6abf131eae1206b60792138bc3c", "2eb91c00e852d9c31d804310d38fad91589fcbac", "8e49fbd5fbbf230e32c1969cd24ac3c22422f0a5", "a83bec6b47776af688402c18efec507143061f68", "52da526d7cc1e063d74c5b520dbc03d0ace15246", "78b2da018d2c4bd9ac1bde1dc3b7f1a110a175f5", "623bf61358c339cb10297807b3f024b5d9f1f327", "23f9fda4c05f8a3852246ee98d4f2adf74ed0875", "9091d3d6606b0c4b5591a38c3674356a01fd7f55", "df55c8c54a23251342a7ee57ba95642b7eb39e61", "2ce392291c6668598d12cd38327e24696b5ca15c")
|
|
29
29
|
# #endregion supported-contract-revisions
|
|
30
30
|
INTEROP_KEY = "https://fabric.passioncode.ai/agent-contract/extensions/interop/0.1"
|
|
31
31
|
MCP_REVISION = "2026-07-28"
|
|
@@ -47,6 +47,7 @@ ENV_MAX = 64
|
|
|
47
47
|
# Whole-value patterns end in \Z, never `$` (R1: `$` also matches before a trailing newline).
|
|
48
48
|
_ID = re.compile(r"^[a-z][a-z0-9-]{1,62}\Z")
|
|
49
49
|
_ENV_NAME = re.compile(r"^[A-Z_][A-Z0-9_]*\Z")
|
|
50
|
+
_URI_PASSWORD = re.compile(r"^[A-Za-z][A-Za-z0-9+.-]*://[^/?#@]*:[^/?#@]*@")
|
|
50
51
|
_SECRET_REF = re.compile(r"^secret-ref:([A-Za-z0-9][A-Za-z0-9._/:@-]{0,255})\Z")
|
|
51
52
|
_LOCAL_PATH = re.compile(LOCAL_PATH_PATTERN)
|
|
52
53
|
_URL = re.compile(URL_PATTERN)
|
|
@@ -131,6 +132,9 @@ def validate_provider_entry(entry: Any) -> List[str]:
|
|
|
131
132
|
problems.append("source is {repository?}")
|
|
132
133
|
elif "repository" in source and not _is_uri(source["repository"]):
|
|
133
134
|
problems.append("source.repository is an absolute URI")
|
|
135
|
+
elif "repository" in source and (_URI_PASSWORD.match(source["repository"]) or _secrets.secret_argument(source["repository"])):
|
|
136
|
+
# FAA-120, as the service kit: a repository is named, never reached with a credential in its URI.
|
|
137
|
+
problems.append("source.repository carries no password or credential: it names the repository")
|
|
134
138
|
if not isinstance(entry["installedAt"], str) or not _TIMESTAMP.fullmatch(entry["installedAt"]):
|
|
135
139
|
problems.append("installedAt is an RFC 3339 date-time")
|
|
136
140
|
if not isinstance(entry["installedBy"], str) or not 1 <= len(entry["installedBy"]) <= 200:
|
|
@@ -14,10 +14,10 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
|
|
|
14
14
|
compatibility: Python 3.9+ or Node.js 20+ for the kits (Node.js 22+ for a Linux service's instance lock); the probe needs Python 3.9+. launchd steps are macOS-only; Linux services install a systemd user unit and Windows ones a per-user Scheduled Task with the kits' writers. Dashboard handoff optionally uses Fabric Dashboards MCP link/host_status/open; without it, report unresolved host capability. The contract checkout is optional.
|
|
15
15
|
metadata:
|
|
16
16
|
author: PassionCode.ai
|
|
17
|
-
version: "0.
|
|
17
|
+
version: "0.50.0"
|
|
18
18
|
contract-version: "0.1.0"
|
|
19
19
|
extension: "fabric-service/0.1"
|
|
20
|
-
extension-commit: "
|
|
20
|
+
extension-commit: "52c7d798b9f4eb784eb4e29e717038a8912c759d"
|
|
21
21
|
---
|
|
22
22
|
|
|
23
23
|
# Building Fabric services
|
|
@@ -70,9 +70,9 @@ Answer before writing code, and record the answers in the project README:
|
|
|
70
70
|
| Caller | Surface | Why |
|
|
71
71
|
|---|---|---|
|
|
72
72
|
| Another agent on this machine | MCP `2026-07-28`, `streamable-http`, at `/mcp` on the service origin, token in a header | one process serves every session; stdio-per-session once left twenty stray servers on this machine |
|
|
73
|
-
| The operator or a script | a CLI: `<tool> service status\|start\|stop\|restart`, `<tool> dashboard
|
|
73
|
+
| The operator or a script | a CLI: `<tool> service status\|start\|stop\|restart`, `<tool> dashboard` (opens only in Fabric Dashboards, below), `<tool> doctor --json` | every verb delegates to launchd and the well-known document, never to its own process table |
|
|
74
74
|
| A remote agent | A2A `1.0` over HTTPS, or MCP behind an authenticated gateway | loopback reachability is not authorization |
|
|
75
|
-
| The dashboard page | same-origin REST under `/api`, session cookie plus a custom request header | the CSRF defence all four existing dashboards use |
|
|
75
|
+
| The dashboard page | same-origin REST under `/api`, session cookie plus a custom request header; every button on it also a tool on the MCP surface (Step 5) | the CSRF defence all four existing dashboards use |
|
|
76
76
|
|
|
77
77
|
Read [the surfaces and auth reference](references/surfaces-and-auth.md) when wiring
|
|
78
78
|
MCP registration into a client config, the login flow or the CSRF header.
|
|
@@ -248,6 +248,16 @@ and declare it with `extensions=fs.dashboard_extension()`. Read
|
|
|
248
248
|
declaration and how to upgrade a dashboard built before the kit: an upgrade you may make yourself,
|
|
249
249
|
which the plugin's session-start notice offers in a repository that owns the service.
|
|
250
250
|
|
|
251
|
+
**Every button has a tool** (`fabric-actions/0.1`, contract DEC-0121 AP-1). Each action the page lets a
|
|
252
|
+
person take is a tool on the MCP surface with the same effect, checks, audit record and an idempotency key,
|
|
253
|
+
registered with `server.add_tool(tool, handler, action={id, title, tool, gate})` (`gate` is `none`, `relayed`
|
|
254
|
+
or `human` with its `humanStep`) and declared with `build_well_known(actions=server.action_table())` under
|
|
255
|
+
`extensions/actions/0.1`. A `relayed` action called by the operator's own agent with their decision in
|
|
256
|
+
`_meta.decision` is the operator's act: never answer it "operator session required" or send them to the page.
|
|
257
|
+
A service adopts the relayed gate once Fabric's hub forwards decisions (CT-125), as the contract says; until then its tools
|
|
258
|
+
answer as today. Read the interop reference's *Actions* section for when to adopt, the gate, its hooks and its
|
|
259
|
+
refusals.
|
|
260
|
+
|
|
251
261
|
**Say what the agent uses** (`fabric-connections/0.1`, DEC-0096) so Fabric Dashboards draws its chain: the other
|
|
252
262
|
agents, models, connectors, stores and channels, each with its state, from
|
|
253
263
|
`connections_extension()` / `connectionsExtension()` in `fabric_connections`. Never a credential in it, never a call
|
|
@@ -283,10 +293,13 @@ python3 <skill-dir>/scripts/check_service.py <id>[.<instance>]
|
|
|
283
293
|
It reports `PASS`, `FAIL` or `NOT_RUN` per rule (descriptor, port claim, well-known
|
|
284
294
|
shape, identity, latency, Host/Origin/cross-site guards, loopback bind, token file,
|
|
285
295
|
events auth and shape, single-use login, state outside code, instance lock, plist,
|
|
286
|
-
launchd pid equals answering pid, `dashboard.declared` (ED-9),
|
|
296
|
+
launchd pid equals answering pid, `dashboard.declared` (ED-9), `well-known.actions` (DEC-0121),
|
|
297
|
+
`dashboard.actions-declared` (`NOT_RUN` when a dashboard declares no actions), `dashboard.opens-in-host` (no browser
|
|
298
|
+
opener aimed at the service's pages in its checkout; `--repo PATH` names the checkout, and a service installed
|
|
299
|
+
from a release folder needs it), and the `interop.*` rules:
|
|
287
300
|
manifest link, capability list, tools equal to the manifest, job tools, unknown job, trace
|
|
288
|
-
propagation, event trace pairs,
|
|
289
|
-
any `FAIL`. A `NOT_RUN` is not a pass;
|
|
301
|
+
propagation, event trace pairs, `interop.action-tools` (every declared action's tool is served), and
|
|
302
|
+
`board.responder` for a service that declares the project board) and exits 1 on any `FAIL`. A `NOT_RUN` is not a pass;
|
|
290
303
|
name it in the report. A service with a dashboard also runs the layout probe,
|
|
291
304
|
`node <skill-dir>/scripts/check_dashboard_layout.mjs --service <id>` (WebKit at 360, 480, 768
|
|
292
305
|
and 1280 px; needs Playwright, else `NOT_RUN` and exit 3: nothing was measured).
|
|
@@ -328,7 +341,8 @@ first commit:
|
|
|
328
341
|
- an `AGENTS.md` that opens with the template's *Read first* block and closes with *After work*,
|
|
329
342
|
and a `CLAUDE.md` whose first line is `@AGENTS.md`.
|
|
330
343
|
|
|
331
|
-
|
|
344
|
+
Whoever owns the repository, an agent with a page gets the dashboard rule block in its `AGENTS.md`
|
|
345
|
+
(below). org-index `scripts/check_format.py` reports 0 findings for it before it is called done. **An agent
|
|
332
346
|
someone builds for themselves is not a PassionCode.ai repository:** its licence is its owner's
|
|
333
347
|
choice, nothing about it is published or listed by the organization, and none of these files is
|
|
334
348
|
required of it, though the verified MCP quick start is still how anyone learns to drive it.
|
|
@@ -357,8 +371,9 @@ things change and the kits implement each:
|
|
|
357
371
|
so the platform's copy is known rather than invisible. Without Project Observatory, record
|
|
358
372
|
where the key lives in the person's own secret manager.
|
|
359
373
|
3. **Register it on the operator's computer**, the installer side, run there:
|
|
360
|
-
`registerRemote({ id, name, origin, token })` / `register_remote(...)` writes the token file
|
|
361
|
-
(0600) and the descriptor; pass the token from a file or
|
|
374
|
+
`registerRemote({ id, name, origin, token, source })` / `register_remote(...)` writes the token file
|
|
375
|
+
(0600) and the descriptor, with `source.repository` naming the code's repository; pass the token from a file or
|
|
376
|
+
stdin, never in argv. Public names
|
|
362
377
|
only in public artifacts: a private service is registered by a local descriptor and nowhere
|
|
363
378
|
else.
|
|
364
379
|
4. **Verify** with the probe: `check_service.py <id>` checks TLS, the token-gated well-known
|
|
@@ -417,8 +432,29 @@ the probe table verbatim with every `NOT_RUN` explained; the lock and kill-9 res
|
|
|
417
432
|
with pids; and the one next command. Never call a service conformant while the probe
|
|
418
433
|
reports a `FAIL`.
|
|
419
434
|
|
|
420
|
-
##
|
|
435
|
+
## Agent pages open only in Fabric Dashboards
|
|
436
|
+
|
|
437
|
+
The operator's rule (2026-10-24) for every page of an agent or a local Fabric service, in any host: a link in an
|
|
438
|
+
answer or a notification, `<tool> dashboard`, a completion message, a page the agent opens itself.
|
|
439
|
+
|
|
440
|
+
1. Resolve the exact registered service key (`id.instance`) with the `fabric-dashboards` MCP (`list_services`);
|
|
441
|
+
never guess it from a project name or a port.
|
|
442
|
+
2. Hand over the `open_link` its `link` tool returns for the service and the page's path, as the primary action.
|
|
443
|
+
3. To open it, use the host's `open` with `fallback=never`. Never `open <url>`, `open -a Safari`, `xdg-open`,
|
|
444
|
+
`start <url>`, `webbrowser.open` or `shell.openExternal` aimed at the service's pages.
|
|
445
|
+
4. A browser only on a confirmed `not_installed` host (`host_status`); an installed host that failed to open is
|
|
446
|
+
reported, never replaced by HTTP.
|
|
447
|
+
5. Links carry no token or login code: the host signs in.
|
|
448
|
+
|
|
449
|
+
Run `scripts/check_dashboard_link.py` (from this skill's own directory; it is not copied into the project) on an
|
|
450
|
+
action before it is printed or opened, and have the project's checks run it for every completion and notification
|
|
451
|
+
renderer. The generated `AGENTS.md` carries the rule as its dashboard
|
|
452
|
+
rule block; [dashboard links](references/dashboard-links.md) has the block, the gate's input and the remote case. The
|
|
453
|
+
probe's `dashboard.opens-in-host` fails a tracked file that opens the dashboard with a browser opener. Headless agents
|
|
454
|
+
need no dashboard.
|
|
455
|
+
|
|
456
|
+
## An agent with a page and no service descriptor
|
|
421
457
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
and
|
|
458
|
+
A local page no service descriptor names cannot open in Fabric Dashboards. Never open it in a browser instead:
|
|
459
|
+
make the agent a `fabric-service/0.1` service (this skill: the descriptor, the well-known document, the login-code
|
|
460
|
+
routes and a declared dashboard), and until that lands file a board row for it and say the page waits on it.
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
/* fabric-dashboard-kit@1.1.
|
|
1
|
+
/* fabric-dashboard-kit@1.1.5 · Fabric's button (Fabric Agent Contract DEC-0040, FB-1…FB-8, FL-1…FL-6)
|
|
2
2
|
Load it same-origin, after fabric-dashboard.css, with the service it opens Fabric on:
|
|
3
3
|
<script src="fabric-button.js" defer data-service="example-agent.default" data-service-name="Example Agent"
|
|
4
4
|
data-project="project-a" data-project-name="Project A"></script>
|
|
5
5
|
One floating menu button: "Chat with Fabric about <service>" and, when the page knows its project, "Open a coding
|
|
6
|
-
session in <project>"
|
|
6
|
+
session in <project>", in Russian on a page whose lang is ru; data-label-chat and data-label-session ({name} is the
|
|
7
|
+
service or the project), data-label-open and data-label-absent set the page's own words. Its links carry ids only and open a view in Fabric, nothing more (FB-8). It hides itself
|
|
7
8
|
when the host draws its own (the fabric_button cookie, FB-6) and says how to get Fabric when Fabric is absent
|
|
8
9
|
(FB-5). No inline script, no eval, nothing from a CDN; the only address it names is passioncode.ai/fabric.
|
|
9
10
|
Do not edit in place; `dashboard_kit.py install` replaces it on an upgrade. */
|
|
10
11
|
(function (root) {
|
|
11
12
|
'use strict';
|
|
12
13
|
|
|
13
|
-
var VERSION = '1.1.
|
|
14
|
+
var VERSION = '1.1.5';
|
|
14
15
|
var COOKIE = 'fabric_button';
|
|
15
16
|
var GET_FABRIC = 'https://passioncode.ai/fabric';
|
|
16
17
|
var ABSENT_AFTER_MS = 1500;
|
|
@@ -155,16 +156,39 @@
|
|
|
155
156
|
return null;
|
|
156
157
|
}
|
|
157
158
|
|
|
159
|
+
// The words a person reads (FAA-119): English, or Russian on a page whose lang is ru; the Russian is written as
|
|
160
|
+
// escapes so the file reads the same whatever charset it is served with. Checked with Copylot (en-US and ru-RU).
|
|
161
|
+
var LABELS = {
|
|
162
|
+
en: { chat: 'Chat with Fabric about {name}', session: 'Open a coding session in {name}', open: 'Open Fabric',
|
|
163
|
+
absent: 'Fabric is not installed. Get it at' },
|
|
164
|
+
ru: { chat: '\u0427\u0430\u0442 \u0441 Fabric \u043e \u0441\u0435\u0440\u0432\u0438\u0441\u0435 {name}', session: '\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u0435\u0441\u0441\u0438\u044e \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 {name}', open: '\u041e\u0442\u043a\u0440\u044b\u0442\u044c Fabric',
|
|
165
|
+
absent: 'Fabric \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d. \u0421\u043a\u0430\u0447\u0430\u0439\u0442\u0435 \u0435\u0433\u043e \u043d\u0430' }
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
/** The labels for a page language, each one replaced by a non-blank string the page gives (data-label-*) that keeps
|
|
169
|
+
the word Fabric: the visible label stays inside the name and each item (DEC-0124, WCAG 2.2 SC 2.5.3). */
|
|
170
|
+
function labelsFor(lang, overrides) {
|
|
171
|
+
var base = LABELS[/^ru(-|$)/i.test(String(lang || '')) ? 'ru' : 'en'];
|
|
172
|
+
var out = {};
|
|
173
|
+
Object.keys(base).forEach(function (k) {
|
|
174
|
+
var own = overrides ? overrides[k] : undefined;
|
|
175
|
+
out[k] = typeof own === 'string' && own.trim() && own.indexOf('Fabric') >= 0 ? own.trim() : base[k];
|
|
176
|
+
});
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
function named(label, name) { return label.split('{name}').join(name); }
|
|
180
|
+
|
|
158
181
|
/** The menu items for a page: the chat link always, the session link when the page knows its project. */
|
|
159
|
-
function menuItems(options) {
|
|
182
|
+
function menuItems(options, labels) {
|
|
183
|
+
var words = labels || labelsFor();
|
|
160
184
|
var items = [];
|
|
161
185
|
var chat = { action: 'chat', service: options.service };
|
|
162
186
|
if (options.project) chat.project = options.project;
|
|
163
|
-
items.push({ label:
|
|
187
|
+
items.push({ label: named(words.chat, options.serviceName || options.service), href: buildFabricLink(chat) });
|
|
164
188
|
if (options.project) {
|
|
165
189
|
var session = { action: 'session.new', project: options.project };
|
|
166
190
|
if (options.runner) session.runner = options.runner;
|
|
167
|
-
items.push({ label:
|
|
191
|
+
items.push({ label: named(words.session, options.projectName || options.project), href: buildFabricLink(session) });
|
|
168
192
|
}
|
|
169
193
|
return items;
|
|
170
194
|
}
|
|
@@ -197,11 +221,12 @@
|
|
|
197
221
|
function mount(doc, options) {
|
|
198
222
|
var cookie = parseButtonCookie(doc.cookie);
|
|
199
223
|
if (cookie && cookie.owner === 'host') return null;
|
|
200
|
-
var
|
|
224
|
+
var words = labelsFor(options.lang !== undefined ? options.lang : doc.documentElement.getAttribute('lang'), options.labels);
|
|
225
|
+
var items = menuItems(options, words);
|
|
201
226
|
var absent = options.fabric === 'absent' || (cookie && cookie.fabric === 'absent');
|
|
202
227
|
|
|
203
228
|
var wrap = el(doc, 'div', { 'class': 'fd-fabric-button-wrap' });
|
|
204
|
-
var button = el(doc, 'button', { type: 'button', 'class': 'fd-fabric-button', 'aria-haspopup': 'menu', 'aria-expanded': 'false', 'aria-label':
|
|
229
|
+
var button = el(doc, 'button', { type: 'button', 'class': 'fd-fabric-button', 'aria-haspopup': 'menu', 'aria-expanded': 'false', 'aria-label': words.open });
|
|
205
230
|
button.appendChild(mark(doc));
|
|
206
231
|
button.appendChild(el(doc, 'span', { 'class': 'fd-fabric-button-label', 'aria-hidden': 'true' }, 'Fabric'));
|
|
207
232
|
var menu = el(doc, 'div', { role: 'menu', 'class': 'fd-fabric-button-menu', 'aria-label': 'Fabric' });
|
|
@@ -212,7 +237,7 @@
|
|
|
212
237
|
return a;
|
|
213
238
|
});
|
|
214
239
|
var note = el(doc, 'p', { 'class': 'fd-fabric-button-note', role: 'note' });
|
|
215
|
-
note.appendChild(doc.createTextNode(
|
|
240
|
+
note.appendChild(doc.createTextNode(words.absent + ' '));
|
|
216
241
|
// The way to get Fabric is a menu item too, so the arrows reach it whenever the note shows.
|
|
217
242
|
var get = el(doc, 'a', { role: 'menuitem', href: GET_FABRIC, target: '_blank', rel: 'noopener', tabindex: '-1', 'class': 'fd-fabric-button-get' }, 'passioncode.ai/fabric');
|
|
218
243
|
note.appendChild(get);
|
|
@@ -274,18 +299,19 @@
|
|
|
274
299
|
|
|
275
300
|
function optionsFrom(script) {
|
|
276
301
|
var d = script.dataset;
|
|
277
|
-
return { service: d.service, serviceName: d.serviceName, project: d.project, projectName: d.projectName, runner: d.runner, fabric: d.fabric
|
|
302
|
+
return { service: d.service, serviceName: d.serviceName, project: d.project, projectName: d.projectName, runner: d.runner, fabric: d.fabric,
|
|
303
|
+
labels: { chat: d.labelChat, session: d.labelSession, open: d.labelOpen, absent: d.labelAbsent } };
|
|
278
304
|
}
|
|
279
305
|
|
|
280
306
|
var api = { version: VERSION, parseFabricLink: parseFabricLink, buildFabricLink: buildFabricLink, parseButtonCookie: parseButtonCookie,
|
|
281
|
-
menuItems: menuItems, credentialName: credentialName, secretValue: secretValue, nameWords: nameWords, mount: mount };
|
|
307
|
+
menuItems: menuItems, labelsFor: labelsFor, credentialName: credentialName, secretValue: secretValue, nameWords: nameWords, mount: mount };
|
|
282
308
|
root.FabricButton = api;
|
|
283
309
|
|
|
284
310
|
var doc = root.document;
|
|
285
311
|
var script = doc && doc.currentScript;
|
|
286
312
|
if (script && script.dataset && script.dataset.service) {
|
|
287
313
|
var start = function () {
|
|
288
|
-
try { mount(doc, optionsFrom(script)); } catch (err) { if (root.console) root.console.warn('fabric-button: not shown
|
|
314
|
+
try { mount(doc, optionsFrom(script)); } catch (err) { if (root.console) root.console.warn('fabric-button: not shown: ' + err.message); }
|
|
289
315
|
};
|
|
290
316
|
if (doc.readyState === 'loading') doc.addEventListener('DOMContentLoaded', start); else start();
|
|
291
317
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* fabric-dashboard-kit@1.1.
|
|
1
|
+
/* fabric-dashboard-kit@1.1.5 · fabric-dashboard/0.1 (Fabric Agent Contract DEC-0036)
|
|
2
2
|
A Fabric service dashboard shown inside a host pane: usable from 360 CSS px up, navigation always
|
|
3
3
|
reachable, wide content in its own scroll box, one vertical scroller, appearance from the host.
|
|
4
4
|
Copy this file next to fabric-dashboard.js; do not edit it in place. Put the page's own rules in
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* fabric-dashboard-kit@1.1.
|
|
1
|
+
/* fabric-dashboard-kit@1.1.5 · fabric-dashboard/0.1 (Fabric Agent Contract DEC-0036)
|
|
2
2
|
Load it same-origin with <script src="fabric-dashboard.js" defer></script>: no inline script, no
|
|
3
3
|
eval, nothing from a CDN. It applies the host's appearance (ED-6, ED-8), folds navigation that
|
|
4
4
|
does not fit into a More menu (ED-3), makes wide boxes keyboard-reachable (ED-4) and keeps
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
var KIT = 'fabric-dashboard-kit';
|
|
11
|
-
var VERSION = '1.1.
|
|
11
|
+
var VERSION = '1.1.5';
|
|
12
12
|
/* fabric-dashboard-kit:theme-ids:begin */
|
|
13
13
|
var THEMES = ['graphite', 'fabric', 'paper', 'forest', 'ocean', 'ember', 'contrast'];
|
|
14
14
|
/* fabric-dashboard-kit:theme-ids:end */
|