@passioncode-ai/fabric-agent-adapter 0.83.1 → 0.85.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 (129) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +2 -1
  3. package/package.json +1 -1
  4. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  5. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +1 -1
  6. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/check_dashboard_link.py +3 -0
  7. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_identifiers.py +1 -0
  8. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/scripts/fabric_secrets.py +1 -0
  9. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +2 -2
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-button.js +3 -2
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.css +2 -1
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/fabric-dashboard.js +3 -2
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/assets/dashboard-kit/kit.json +9 -4
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +8 -3
  15. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +1 -1
  16. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +9 -1
  17. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/lifecycle.md +3 -2
  18. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_link.py +3 -0
  19. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-a2a-server.mjs +1 -0
  20. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-a2a.mjs +1 -0
  21. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-actions.mjs +1 -0
  22. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-auth.mjs +1 -0
  23. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-backups.mjs +1 -0
  24. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-base.mjs +1 -0
  25. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-fixture.mjs +1 -0
  26. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-link.mjs +1 -0
  27. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-session.mjs +2 -0
  28. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-shapes.mjs +1 -0
  29. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-slots.mjs +9 -1
  30. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board.mjs +1 -0
  31. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ceremonies.mjs +1 -0
  32. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-connections.mjs +1 -0
  33. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-context.mjs +1 -0
  34. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-crypto.mjs +1 -0
  35. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-delegation.mjs +1 -0
  36. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +2 -1
  37. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate-rules.mjs +1 -0
  38. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-estate.mjs +1 -0
  39. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-events.mjs +1 -0
  40. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-holds.mjs +1 -0
  41. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-http.mjs +1 -0
  42. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-hub.mjs +1 -0
  43. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-identifiers.mjs +1 -0
  44. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop-rules.mjs +1 -0
  45. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +6 -2
  46. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-jsvalue.mjs +1 -0
  47. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-load.mjs +1 -0
  48. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-lock.mjs +1 -0
  49. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-logs.mjs +1 -0
  50. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-mandate.mjs +4 -2
  51. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-openrouter.mjs +1 -0
  52. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-ops-digest.mjs +1 -0
  53. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package-schema.mjs +1 -0
  54. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +1 -0
  55. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-page-links.mjs +1 -0
  56. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-paths.mjs +1 -0
  57. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-peer-owner.mjs +2 -1
  58. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-platform.mjs +1 -0
  59. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-profiles.mjs +1 -0
  60. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-protocols.mjs +1 -0
  61. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-secrets.mjs +1 -0
  62. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +1 -0
  63. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-share.mjs +1 -0
  64. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-socket-proof.mjs +1 -0
  65. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-supervisors.mjs +15 -3
  66. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-tailnet-identity.mjs +1 -0
  67. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-tailnet.mjs +1 -0
  68. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-time.mjs +1 -0
  69. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-usage.mjs +1 -0
  70. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_a2a.py +1 -0
  71. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_a2a_server.py +1 -0
  72. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_actions.py +1 -0
  73. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_auth.py +1 -0
  74. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_backups.py +1 -0
  75. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_base.py +1 -0
  76. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board.py +1 -0
  77. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_fixture.py +1 -0
  78. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_link.py +1 -0
  79. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_session.py +2 -0
  80. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_shapes.py +1 -0
  81. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_slots.py +10 -1
  82. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ceremonies.py +1 -0
  83. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_connections.py +1 -0
  84. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_context.py +1 -0
  85. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_crypto.py +1 -0
  86. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_delegation.py +1 -0
  87. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +2 -1
  88. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate.py +1 -0
  89. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_estate_rules.py +1 -0
  90. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_events.py +1 -0
  91. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_holds.py +1 -0
  92. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_http.py +1 -0
  93. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_hub.py +1 -0
  94. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_identifiers.py +1 -0
  95. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +2 -0
  96. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop_rules.py +1 -0
  97. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_jsvalue.py +3 -0
  98. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_load.py +1 -0
  99. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_lock.py +1 -0
  100. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_logs.py +1 -0
  101. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_mandate.py +20 -3
  102. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_openrouter.py +1 -0
  103. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_ops_digest.py +1 -0
  104. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +1 -0
  105. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package_schema.py +1 -0
  106. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_page_links.py +1 -0
  107. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_paths.py +1 -0
  108. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_peer_owner.py +47 -47
  109. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_platform.py +1 -0
  110. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_profiles.py +1 -0
  111. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_protocols.py +1 -0
  112. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_secrets.py +1 -0
  113. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +1 -0
  114. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_share.py +1 -0
  115. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_socket_proof.py +1 -0
  116. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_supervisors.py +16 -8
  117. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet.py +1 -0
  118. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_tailnet_identity.py +1 -0
  119. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_time.py +1 -0
  120. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_usage.py +1 -0
  121. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +428 -105
  122. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +2 -1
  123. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +3 -3
  124. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/where-agents-run.md +2 -2
  125. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/admit.py +33 -13
  126. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/scripts/check_dashboard_link.py +3 -0
  127. package/plugins/fabric-agent-adapter/skills/observing-products/SKILL.md +1 -1
  128. package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +1 -1
  129. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
@@ -218,7 +218,8 @@ class Service:
218
218
  if not fs.feed_data_problems(data): # data the feed refuses never undoes the answer
219
219
  extra = {"data": data}
220
220
  break
221
- self.log.append("board.slot.returned", "info", "%s took the %s slot back%s; the service enrolls once the "
221
+ # Its own kind (FAA-325): the slot is still away; the kit says board.slot.returned once it is held again.
222
+ self.log.append("board.slot.taken_back", "info", "%s took the %s slot back%s; the service enrolls once the "
222
223
  "other session lets it go." % (who, capability, how),
223
224
  subject={"type": "capability", "id": capability}, **extra)
224
225
  return {"capability": capability, "moved": False}
@@ -9,7 +9,7 @@ license: AGPL-3.0-only OR LicenseRef-PassionCode-Commercial
9
9
  compatibility: Requires filesystem access and Python 3.9+. Exact schema checks additionally need git, Node.js, pnpm, and the pinned fabric-agent-contract checkout (a public repository). Works without those tools in an explicitly degraded structural-check mode. Ships in one plugin with adapting-projects-to-fabric, whose scripts it reuses.
10
10
  metadata:
11
11
  author: PassionCode.ai
12
- version: "0.83.1"
12
+ version: "0.85.0"
13
13
  contract-version: "0.1.0"
14
14
  contract-commit: "93e7db164c7829e2783b4b7705c4113bb5201131"
15
15
  ---
@@ -70,7 +70,7 @@ board (or, with a grant, its scan tool over the source projects), and build from
70
70
  | **Which profile?** | `mcp` when Fabric owns planning and retries and the capability has a schema; `a2a` when the provider owns its task lifecycle end to end; `local-runner` when it is a terminal agent Fabric drives. When unsure, the sibling skill's profile-selection reference is the decision record |
71
71
  | **What effects?** | declare anything money-, deletion-, or publication-adjacent now; the host's floor and grants are designed against these declarations, and one discovered late invalidates the admission |
72
72
  | **Where does it run, for whom?** | this machine, the person's cloud or an organization's, and in which contexts (`personal`, `org:<id>`): one instance per context, its secrets, spend and journal never crossing into another. Record which capabilities need the person's machine and what they answer when it is off (references/where-agents-run.md) |
73
- | **Does it run around the clock?** | the uptime category, decided now: **A** when a capability must answer while the owner's machine is off or asleep (a schedule, a chat, callers outside the machine): the agent gets a cloud host from its first release, Heroku unless a reason names another (the person's or an organization's cloud, or PassionCode's for a paid agent), built as an online service (building-fabric-services, the remote placement) and started from the cloud Fabric-server template once that template's repository exists; **B** when nothing needs it then: local only, no cloud (a local service, or a CLI or local runner when nothing calls it while the owner is away), reading an A agent's data through that agent's MCP or API. The README names the category (references/where-agents-run.md) |
73
+ | **Does it run around the clock?** | the uptime category, decided now: **A** when a capability must answer while the owner's machine is off or asleep (a schedule, a chat, callers outside the machine): the agent gets a cloud host from its first release, Heroku unless a reason names another (the person's or an organization's cloud, or PassionCode's for a paid agent), built as an online service (building-fabric-services, the remote placement) and started from the cloud Fabric-server template, whose repository an agent reads from the instance's settings or the estate's agent map, never from this skill; **B** when nothing needs it then: local only, no cloud (a local service, or a CLI or local runner when nothing calls it while the owner is away), reading an A agent's data through that agent's MCP or API. The README names the category (references/where-agents-run.md) |
74
74
  | **Whose data does it keep?** | the kind of its data, named in the README: **U** when it keeps data of people outside the owner's team (messages, support requests, reviews, customers' answers), which never enters the source, a copy of it or its tests: the source holds the schema and synthetic fixtures, and a copy starts with an empty store of its own; **O** when it keeps none (a tool or service for other agents, the owner's reports, runs and media). In doubt, U. Either way the data lives in `<agent>-data` (a kit service: the kit's folders; on a cloud host: a durable store), apart from the source, from the first commit (references/source-and-instance.md) |
75
75
  | **Who holds the copyright?** | the holder the agent's `LICENSE` names: a new private agent (built for its owner or for a client) gets a `LICENSE` naming that holder in its first commit, all rights reserved unless the owner gives other terms; a public product keeps its own licence (a PassionCode.ai repository: the organization's, step 2) |
76
76
  | **Which models?** | per lane (planning, replies, volume work, media): a primary, a fallback of another vendor, an open-vendor model where it reads what users send, the input kinds each reads, named as catalogue models in the profile, narrowed by classes on the spend policy or grant (references/models-and-providers.md) |
@@ -139,7 +139,7 @@ lists them. An agent someone builds for themselves, or a private agent built for
139
139
  is its owner's choice and none of those files is required of it, but its first commit carries a `LICENSE` naming
140
140
  the copyright holder the grill recorded (all rights reserved unless the owner gives other terms); it covers the
141
141
  holder's own files, and the kit files the adapter copies in keep their own licence (AGPL-3.0-only OR
142
- LicenseRef-PassionCode-Commercial).
142
+ LicenseRef-PassionCode-Commercial), each service kit module in its own SPDX line.
143
143
 
144
144
  **Every credential the agent uses is read by name, never held as a value**, from its first commit:
145
145
  the README's Configure section lists key NAMES. With Project Observatory installed, the agent finds
@@ -106,8 +106,8 @@ Every new agent is given an uptime category on its first day, and the README nam
106
106
  (the places above), and a paid agent stays in PassionCode's cloud (selling an agent, below). On a host with no
107
107
  Fabric hub it answers what reaches its own origin (its schedule, its chat, its API); a call Fabric admits needs a
108
108
  cloud hub, as running while the laptop is closed says. The agent is an online service (building-fabric-services, the remote placement), often
109
- alongside its local instance, and starts from the cloud Fabric-server template once that template's repository
110
- exists. Its data lives where the cloud reaches it, in a durable store (a database, an object store, the private
109
+ alongside its local instance, and starts from the cloud Fabric-server template, whose repository an agent reads from
110
+ the instance's settings or the estate's agent map; this public skill names no repository or address for it. Its data lives where the cloud reaches it, in a durable store (a database, an object store, the private
111
111
  `<agent>-data` repository), never the host's own folder, which a platform such as Heroku does not keep across a
112
112
  restart.
113
113
  - **B, local only.** Nothing needs it while the machine sleeps: no cloud, and a local service only when other
@@ -87,34 +87,54 @@ def template_step(folders: List[str]) -> Dict[str, object]:
87
87
  "%d folder(s), %d error(s)" % (len(folders), len(errors)), errors)
88
88
 
89
89
 
90
- def _terms_file(named: Optional[str]) -> Path:
90
+ # The one private-terms reader (FAA-328): test/validate.py, the repository's own check, reads the list with these
91
+ # functions too, so the two never drift. They match as org-index's check_private.py does: case-insensitive, not inside a
92
+ # run of ASCII letters and digits, longest term first. Callers report paths and lines only, never a term.
93
+ def terms_file(named: Optional[str] = None) -> Path:
94
+ """The list: `named`, else `$PASSIONCODE_PRIVATE_TERMS`, else ~/.config/passioncode/private-terms.txt; `~` expanded."""
91
95
  named = named or os.environ.get(PRIVATE_TERMS_ENV)
92
96
  return Path(named).expanduser() if named else Path.home() / ".config/passioncode/private-terms.txt"
93
97
 
94
98
 
95
- def _files(root: Path) -> List[str]:
99
+ def terms_pattern(lines: List[str]) -> "Optional[re.Pattern[str]]":
100
+ """One alternation of the list's terms (a line that is blank or starts with # is none), longest first; None when
101
+ the list holds no term."""
102
+ terms = sorted({t.strip() for t in lines if t.strip() and not t.strip().startswith("#")}, key=len, reverse=True)
103
+ if not terms:
104
+ return None
105
+ return re.compile(r"(?<![A-Za-z0-9])(?:" + "|".join(re.escape(t) for t in terms) + r")(?![A-Za-z0-9])", re.IGNORECASE)
106
+
107
+
108
+ def term_lines(text: str, pattern: "re.Pattern[str]") -> List[int]:
109
+ """The 1-based numbers of the lines of `text` that hold a term."""
110
+ return [n for n, line in enumerate(text.splitlines(), 1) if pattern.search(line)]
111
+
112
+
113
+ def listed_files(root: Path) -> List[str]:
114
+ """Every tracked file and every untracked one Git does not ignore, as check_private.py reads a work tree; outside a
115
+ work tree, or where git cannot run, every file but the usual generated folders, never nothing."""
96
116
  if (root / ".git").exists():
97
- listed = subprocess.run(["git", "-C", str(root), "ls-files", "-z", "--cached", "--others", "--exclude-standard"],
98
- capture_output=True, check=False)
99
- if listed.returncode == 0:
117
+ try:
118
+ listed = subprocess.run(["git", "-C", str(root), "ls-files", "-z", "--cached", "--others", "--exclude-standard"],
119
+ capture_output=True, check=False)
120
+ except OSError:
121
+ listed = None
122
+ if listed is not None and listed.returncode == 0:
100
123
  return sorted({rel for rel in listed.stdout.decode("utf-8", "replace").split("\0") if rel})
101
124
  return sorted(p.relative_to(root).as_posix() for p in root.rglob("*")
102
125
  if p.is_file() and not SKIP.intersection(p.relative_to(root).parts))
103
126
 
104
127
 
105
128
  def private_terms_step(root: Path, named: Optional[str]) -> Dict[str, object]:
106
- path = _terms_file(named)
129
+ path = terms_file(named)
107
130
  if not path.is_file():
108
131
  return _result("private-terms", "NOT_RUN", "no private-terms list on this machine (set %s): not a pass"
109
132
  % PRIVATE_TERMS_ENV)
110
- lines = path.read_text(encoding="utf-8").splitlines()
111
- terms = sorted({t.strip() for t in lines if t.strip() and not t.strip().startswith("#")}, key=len, reverse=True)
112
- if not terms:
133
+ pattern = terms_pattern(path.read_text(encoding="utf-8").splitlines())
134
+ if pattern is None:
113
135
  return _result("private-terms", "PASS", "the list holds no term")
114
- pattern = re.compile(r"(?<![A-Za-z0-9])(?:" + "|".join(re.escape(t) for t in terms) + r")(?![A-Za-z0-9])",
115
- re.IGNORECASE)
116
136
  hits: List[str] = []
117
- files = _files(root)
137
+ files = listed_files(root)
118
138
  for rel in files:
119
139
  try:
120
140
  data = (root / rel).read_bytes()
@@ -122,7 +142,7 @@ def private_terms_step(root: Path, named: Optional[str]) -> Dict[str, object]:
122
142
  continue
123
143
  if b"\0" in data[:8192]:
124
144
  continue
125
- found = [str(n) for n, line in enumerate(data.decode("utf-8", "replace").splitlines(), 1) if pattern.search(line)]
145
+ found = [str(n) for n in term_lines(data.decode("utf-8", "replace"), pattern)]
126
146
  if found:
127
147
  hits.append("%s: line%s %s" % (rel, "s" if len(found) > 1 else "", ", ".join(found)))
128
148
  return _result("private-terms", "FAIL" if hits else "PASS",
@@ -46,6 +46,9 @@ def has_jwt(text):
46
46
  return False
47
47
 
48
48
 
49
+ # Kept here, not imported: this gate runs alone in a dashboard's own checkout with no kit beside it, and its three copies
50
+ # stay byte-identical (test_dashboard_links.py). It is broader than `fabric_secrets` on purpose (FAA-136, FAA-187 (4)): a
51
+ # page link that only looks like a secret is refused, since a link is never a place for one.
49
52
  # The contract's SECRET_VALUE at the pin (DEC-0151): `Bearer ` at a value's start in any case, or a provider key with its
50
53
  # prefix in its canonical case after a boundary (the start, a character that is no ASCII letter or digit, or an escape);
51
54
  # an `sk-` key holds a digit and an upper-case letter with 16 or more characters, or a digit with 32 or more.
@@ -12,7 +12,7 @@ compatibility: >-
12
12
  from Project Observatory's vault by slot name when it is installed.
13
13
  metadata:
14
14
  author: PassionCode.ai
15
- version: "0.83.1"
15
+ version: "0.85.0"
16
16
  ---
17
17
 
18
18
  # Observing products
@@ -13,7 +13,7 @@ compatibility: >-
13
13
  this plugin; Codex/Kimi use command hooks; Hermes/OpenCode/OpenClaw/Pi use native context plugins after opt-in.
14
14
  metadata:
15
15
  author: PassionCode.ai
16
- version: "0.83.1"
16
+ version: "0.85.0"
17
17
  ---
18
18
 
19
19
  # Working with Fabric
@@ -58,7 +58,7 @@ SESSION_ID = re.compile(r"[A-Za-z0-9._:-]{1,128}")
58
58
  LOOPBACK_ORIGIN = re.compile(r"http://127\.0\.0\.1:(\d{1,5})")
59
59
 
60
60
 
61
- VERSION = "0.83.1"
61
+ VERSION = "0.85.0"
62
62
 
63
63
 
64
64
  HOSTS = {"claude": "Claude Code", "codex": "Codex", "kimi": "Kimi Code",