@passioncode-ai/fabric-agent-adapter 0.58.0 → 0.60.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 +97 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +3 -2
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/operator-channel-and-repository.md +4 -1
- package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/references/source-and-instance.md +27 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +16 -19
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/board.md +35 -13
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +1 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/package.md +7 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-session.mjs +9 -2
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-board-slots.mjs +80 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +6 -1
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_session.py +11 -3
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_slots.py +80 -4
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +14 -6
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +187 -7
- package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py +2 -2
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +19 -7
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/operator-channel-and-repository.md +4 -1
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/source-and-instance.md +27 -2
- package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/where-agents-run.md +23 -1
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +5 -5
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/references/project-board.md +21 -7
- package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_session.py
CHANGED
|
@@ -155,6 +155,7 @@ class Responder(SlotKeeper):
|
|
|
155
155
|
self.wait_until = 0.0
|
|
156
156
|
self.stopping = False
|
|
157
157
|
self.claim_keys: Dict[str, str] = {}
|
|
158
|
+
self._probing: set = set() # moved slots whose move-back claim lost its answer: asked again under the same key
|
|
158
159
|
self._said: Dict[str, str] = {}
|
|
159
160
|
self._rr = 0
|
|
160
161
|
#: The first pause under an operator's hold (DEC-0079); it doubles to HOLD_RETRY_MAX_SECONDS.
|
|
@@ -237,6 +238,7 @@ class Responder(SlotKeeper):
|
|
|
237
238
|
self.state = "connecting"
|
|
238
239
|
self.slots = {} # the previous session's slots are not this one's: a refusal now reconnects (FAA-163)
|
|
239
240
|
self._confirmed = {} # nor its confirmations: a slot may have moved between the two sessions
|
|
241
|
+
self._probing = set() # nor its lost move-back claims
|
|
240
242
|
grant = self.hub.join_board(self.project, self.credential_file)
|
|
241
243
|
missing = [c for c in self.capabilities if c not in grant.capabilities]
|
|
242
244
|
session = self.session_factory(grant)
|
|
@@ -516,7 +518,11 @@ class Responder(SlotKeeper):
|
|
|
516
518
|
"""Seconds this session's leases still run, by its own clock: the running attempt's, else the oldest held slot's."""
|
|
517
519
|
renewed = [self.current.renewed_at or 0.0] if self.current is not None else \
|
|
518
520
|
[s.get("renewed_at", 0.0) for s in self.slots.values() if s.get("state") == "held"
|
|
519
|
-
and s.get("renewed_at", 0.0) != float("-inf")]
|
|
521
|
+
and s.get("renewed_at", 0.0) != float("-inf")] + \
|
|
522
|
+
[s["probe_at"] for c, s in self.slots.items() if c in self._probing and "probe_at" in s
|
|
523
|
+
and self.now() - s["probe_at"] < LEASE_SECONDS - LEASE_MARGIN_SECONDS]
|
|
524
|
+
# a lapsed slot holds no lease (FAA-163); a move-back claim whose answer was lost holds one from its send, while
|
|
525
|
+
# more than the 10 s margin of that lease is left (FAA-165)
|
|
520
526
|
return min(renewed) + LEASE_SECONDS - self.now() if renewed and self.session is not None else 0.0
|
|
521
527
|
|
|
522
528
|
def _fault(self, exc: Exception) -> float:
|
|
@@ -588,8 +594,10 @@ class Responder(SlotKeeper):
|
|
|
588
594
|
self._gone(capability)
|
|
589
595
|
self._suspect.discard(capability)
|
|
590
596
|
for capability, slot in list(self.slots.items()):
|
|
591
|
-
if slot.get("state") == "moved":
|
|
592
|
-
|
|
597
|
+
if slot.get("state") == "moved": # never enrolled again on its own, even when the new holder lapses (FAA-155)
|
|
598
|
+
if self.now() - slot.get("renewed_at", 0) >= RENEW_SECONDS - 0.5:
|
|
599
|
+
self._moved_back(capability) # unless com.status shows a later generation it may hold (FAA-165)
|
|
600
|
+
continue
|
|
593
601
|
if slot.get("state") == "paused":
|
|
594
602
|
if capability != held_by_work and self.now() >= slot.get("retry_at", 0.0) and not self._gone(capability):
|
|
595
603
|
self._enroll(capability) # still held: a longer pause; lifted: the slot is ours again (moved: read first)
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_board_slots.py
CHANGED
|
@@ -120,22 +120,98 @@ class SlotKeeper:
|
|
|
120
120
|
self._to_resume = [r for r in self._to_resume if (self.checkpoint.entries.get(r) or {}).get("capability") != capability]
|
|
121
121
|
self.slots[capability] = {"state": "moved", "generation": now, "renewed_at": self.now()}
|
|
122
122
|
self._confirmed.pop(capability, None)
|
|
123
|
+
self.claim_keys.pop(capability, None) # the move returned that claim to the queue: its receipt is dead
|
|
123
124
|
if "moved" not in held:
|
|
124
125
|
self._note(capability, dict(held, moved=now)) # said again at the next start if it cannot be written
|
|
125
126
|
if "moved" not in held: # once, even across restarts
|
|
126
|
-
self._emit("board.slot.moved", "warning", "The %s slot on this Project moved to another session. This service stopped answering it
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
127
|
+
self._emit("board.slot.moved", "warning", "The %s slot on this Project moved to another session. This service stopped answering it; accepted "
|
|
128
|
+
"work stays `accepted` (work begun is the new holder's). The operator brings it back by take-back (once the "
|
|
129
|
+
"other session lets it go, or at a restart with accepted work waiting; a restart alone does not) or, where "
|
|
130
|
+
"Fabric offers it, a move back here. Else ask its maintainer." % capability,
|
|
130
131
|
notify=True, episode=capability, capability=capability, generation=now, held=held["generation"])
|
|
131
132
|
return True
|
|
132
133
|
|
|
134
|
+
def _moved_back(self, capability: str) -> None:
|
|
135
|
+
"""A moved slot asked about once per later generation (FAA-165): the operator may move it back to this session
|
|
136
|
+
(DEC-0140 PR-2), which this client cannot hear, so when com.status shows a generation past the recorded move, one
|
|
137
|
+
`com.claim` asks whether the slot is its own. A claim that lands makes it held again and starts what it handed
|
|
138
|
+
out; a `lease_expired` one (the move reached this session but its lease lapsed) enrolls again; a fenced one is
|
|
139
|
+
another session's, recorded so the same generation is not asked about twice. Never an enroll or a replace on a
|
|
140
|
+
slot another session holds: a slot moved off stays off unless it is handed back."""
|
|
141
|
+
if self.current is not None or self.stopping:
|
|
142
|
+
return # a claim now could hand out a second request, or start work while the responder stops
|
|
143
|
+
held = self.checkpoint.slots.get(capability) or {}
|
|
144
|
+
seen = held.get("moved")
|
|
145
|
+
if held.get("project") != self.project or not _is_int(seen, 1):
|
|
146
|
+
return
|
|
147
|
+
(self.slots.get(capability) or {})["renewed_at"] = self.now()
|
|
148
|
+
status = self._status()
|
|
149
|
+
now = _whole(next((r.get("generation") for r in status.get("responders") or [] if isinstance(r, dict) and r.get("capability") == capability), None))
|
|
150
|
+
if not _is_int(now, 1) or now <= seen:
|
|
151
|
+
return
|
|
152
|
+
key = self.claim_keys.get(capability) if capability in self._probing else None # read once: take_back may pop it
|
|
153
|
+
if key is None:
|
|
154
|
+
key = self.claim_keys[capability] = self._key("claim") # a fresh key: one from before the move may hold a dead receipt
|
|
155
|
+
(self.slots.get(capability) or {}).pop("probe_at", None) # and a send time of its own
|
|
156
|
+
sent = self.now()
|
|
157
|
+
try:
|
|
158
|
+
answer = self._receipt("com.claim", self._call("com.claim", {"idempotency": self._idem(key), "capability": capability}))
|
|
159
|
+
except BoardError as exc:
|
|
160
|
+
if exc.code == "unreachable": # the claim may have landed: asked again under this key, never left to the fault
|
|
161
|
+
self._probing.add(capability)
|
|
162
|
+
(self.slots.get(capability) or {}).setdefault("probe_at", sent) # its lease runs from the first send
|
|
163
|
+
return
|
|
164
|
+
self._probing.discard(capability)
|
|
165
|
+
if exc.code == "held":
|
|
166
|
+
return # the operator's hold: asked again at the next renewal
|
|
167
|
+
if exc.code in ("idempotency_window_expired", "capacity_exceeded"):
|
|
168
|
+
self.claim_keys.pop(capability, None)
|
|
169
|
+
return
|
|
170
|
+
if exc.code == "lease_expired":
|
|
171
|
+
self.claim_keys.pop(capability, None) # a dead attempt's receipt may sit under it
|
|
172
|
+
if self._back(capability, held, now):
|
|
173
|
+
self.slots[capability]["renewed_at"] = float("-inf") # lapsed: the enroll below is recorded first
|
|
174
|
+
self._enroll(capability)
|
|
175
|
+
return
|
|
176
|
+
if exc.code in SESSION_CODES and exc.code != "not_authorized":
|
|
177
|
+
raise # the board session's fault, not this slot's
|
|
178
|
+
with self._lock: # fenced, or another refusal of this claim: not this session's slot at this generation
|
|
179
|
+
if self.checkpoint.slots.get(capability) == held: # take_back meanwhile wins (FAA-158)
|
|
180
|
+
self._note(capability, dict(held, moved=now))
|
|
181
|
+
return
|
|
182
|
+
self._probing.discard(capability)
|
|
183
|
+
attempt = answer.get("attempt") if isinstance(answer.get("attempt"), dict) else {}
|
|
184
|
+
generation = _whole(attempt.get("generation"))
|
|
185
|
+
if _is_int(generation, 1) and generation < now: # a replay from before a later move: dead, asked again fresh
|
|
186
|
+
self.claim_keys.pop(capability, None)
|
|
187
|
+
return
|
|
188
|
+
if not self._back(capability, held, generation if _is_int(generation, 1) else now):
|
|
189
|
+
return
|
|
190
|
+
if "request" in answer:
|
|
191
|
+
self.claim_keys.pop(capability, None)
|
|
192
|
+
self.slots[capability]["renewed_at"] = self.now() # the claim just landed: its lease runs (finding 38)
|
|
193
|
+
self._start(capability, answer)
|
|
194
|
+
else:
|
|
195
|
+
self._enroll(capability) # renewed now: whether an empty com.claim renews the lease is not the contract's to say
|
|
196
|
+
|
|
197
|
+
def _back(self, capability: str, held: Dict[str, Any], generation: int) -> bool:
|
|
198
|
+
"""The slot is this session's again at `generation`: held, its record rewritten without the move (FAA-165)."""
|
|
199
|
+
with self._lock:
|
|
200
|
+
if self.checkpoint.slots.get(capability) != held:
|
|
201
|
+
return False # take_back (an action thread) forgot the record meanwhile; its own next tick enrolls
|
|
202
|
+
self.slots[capability] = {"state": "held", "generation": generation, "renewed_at": float("-inf")} # no lease yet
|
|
203
|
+
self._held_at(capability, generation)
|
|
204
|
+
self._said.pop("board.slot.moved", None) # a later move is said again
|
|
205
|
+
return True
|
|
206
|
+
|
|
133
207
|
def take_back(self, capability: str) -> None:
|
|
134
208
|
"""The operator's act, never the kit's: forget the move; the next tick enrolls once the slot is free (FAA-155)."""
|
|
135
209
|
if capability not in self.capabilities:
|
|
136
210
|
raise BoardError("invalid_arguments", "This responder does not answer %s." % capability)
|
|
137
211
|
with self._lock:
|
|
138
212
|
self.checkpoint.slot(capability, None)
|
|
213
|
+
self.claim_keys.pop(capability, None) # a receipt from before the take-back may be dead
|
|
214
|
+
self._probing.discard(capability)
|
|
139
215
|
if (self.slots.get(capability) or {}).get("state") == "moved":
|
|
140
216
|
self.slots[capability] = {"state": "contested", "renewed_at": 0.0}
|
|
141
217
|
self._said.pop("board.slot.moved", None)
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py
CHANGED
|
@@ -133,7 +133,7 @@ def read_signing_key(path: Any, kid: Optional[str] = None) -> Tuple[bytes, str]:
|
|
|
133
133
|
text = raw.decode("utf-8", "replace").strip(JS_WHITESPACE) # as JavaScript's trim: a leading BOM goes too
|
|
134
134
|
if text.startswith("{"):
|
|
135
135
|
try:
|
|
136
|
-
jwk = json.loads(text)
|
|
136
|
+
jwk = json.loads(text, parse_constant=fd._no_constant) # NaN and Infinity are no JSON, as JSON.parse says
|
|
137
137
|
except ValueError:
|
|
138
138
|
raise PackageError("The key file is neither a JWK nor a PEM private key.") from None
|
|
139
139
|
if not isinstance(jwk, dict) or jwk.get("kty") != "OKP" or jwk.get("crv") != "Ed25519" or not isinstance(jwk.get("d"), str):
|
|
@@ -394,8 +394,8 @@ def _parsed(data: Optional[bytes]) -> Optional[Dict[str, Any]]:
|
|
|
394
394
|
if data is None:
|
|
395
395
|
return None
|
|
396
396
|
try:
|
|
397
|
-
value = json.loads(data.decode("utf-8"))
|
|
398
|
-
except (ValueError, RecursionError): # invalid UTF-8 is no manifest, in both kits
|
|
397
|
+
value = json.loads(data.decode("utf-8"), parse_constant=fd._no_constant)
|
|
398
|
+
except (ValueError, RecursionError): # invalid UTF-8, NaN or Infinity is no manifest, in both kits
|
|
399
399
|
return None
|
|
400
400
|
return value if isinstance(value, dict) else None
|
|
401
401
|
|
|
@@ -424,7 +424,7 @@ def check_package_folder(pkg: Dict[str, Any], files: Dict[str, bytes]) -> List[D
|
|
|
424
424
|
provider = pkg.get("provider")
|
|
425
425
|
if isinstance(provider, str) and provider in files:
|
|
426
426
|
manifest = _parsed(files.get(provider))
|
|
427
|
-
if
|
|
427
|
+
if manifest is None or ("costPresets" in manifest and not ("costPresets" in pkg and _json_equal(manifest["costPresets"], pkg["costPresets"]))):
|
|
428
428
|
problems.append({"problem": "provider-manifest", "path": provider})
|
|
429
429
|
return problems
|
|
430
430
|
|
|
@@ -648,7 +648,7 @@ def _load_json(data: bytes, what: str) -> Dict[str, Any]:
|
|
|
648
648
|
if _nesting(text) > MAX_NESTING:
|
|
649
649
|
raise PackageError("%s nests deeper than %d levels." % (what, MAX_NESTING))
|
|
650
650
|
try:
|
|
651
|
-
value = json.loads(text, object_pairs_hook=fd._no_duplicates)
|
|
651
|
+
value = json.loads(text, object_pairs_hook=fd._no_duplicates, parse_constant=fd._no_constant)
|
|
652
652
|
except fd._Duplicate as exc:
|
|
653
653
|
raise PackageError("%s names %s twice in one object." % (what, json.dumps(exc.args[0], ensure_ascii=False))) from None
|
|
654
654
|
except (ValueError, RecursionError) as exc:
|
|
@@ -704,10 +704,18 @@ def _all_problems(pkg: Dict[str, Any], files: Dict[str, bytes]) -> List[Dict[str
|
|
|
704
704
|
problems = [dict(p, rule="schema") for p in schema_problems(pkg)]
|
|
705
705
|
problems += [dict(p, rule="path") for p in path_problems(pkg)]
|
|
706
706
|
problems += [dict(p, rule=p["code"]) for p in package_findings(pkg)]
|
|
707
|
-
problems += [{"rule": "folder", "problem": p["problem"], "instancePath": p["path"], "message": p["problem"]
|
|
707
|
+
problems += [{"rule": "folder", "problem": p["problem"], "instancePath": p["path"], "message": FOLDER_MESSAGES.get(p["problem"], p["problem"])}
|
|
708
|
+
for p in check_package_folder(pkg, files)]
|
|
708
709
|
return problems
|
|
709
710
|
|
|
710
711
|
|
|
712
|
+
#: What a folder problem means, where its code alone does not say what to change (FAA-193).
|
|
713
|
+
FOLDER_MESSAGES = {
|
|
714
|
+
"provider-manifest": "provider-manifest: the provider manifest must be a JSON object, and when it carries costPresets "
|
|
715
|
+
"fabric.package.json must carry the same costPresets (copy them; pack does not)",
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
|
|
711
719
|
def pack(folder: Any, apply: bool = False) -> Dict[str, Any]:
|
|
712
720
|
"""Pack ``folder`` (see the module's doc). The answer names the digest, ``agentRef`` and every problem; with
|
|
713
721
|
``apply`` and no problem, ``fabric.package.json`` is rewritten."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fabric-service-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.60.0",
|
|
4
4
|
"about": "The service kit's modules in dependency order: a module imports only modules listed before it. Written by fabric_kit.py build; edit the order and layers by hand, never the digests.",
|
|
5
5
|
"python": [
|
|
6
6
|
{
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
"fabric_package_schema",
|
|
166
166
|
"fabric_secrets"
|
|
167
167
|
],
|
|
168
|
-
"sha256": "
|
|
168
|
+
"sha256": "1f2b9e73b2b32a7e1e887d4b69f87c6e21b4d1227ad924a235334223e6dd51ca"
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"module": "fabric_protocols",
|
|
@@ -435,7 +435,7 @@
|
|
|
435
435
|
"imports": [
|
|
436
436
|
"fabric_board_shapes"
|
|
437
437
|
],
|
|
438
|
-
"sha256": "
|
|
438
|
+
"sha256": "92b065e3df935547cf46653245f1129e4a1f8b59b0a41e8fa9ffdc41596ee592"
|
|
439
439
|
},
|
|
440
440
|
{
|
|
441
441
|
"module": "fabric_board_session",
|
|
@@ -448,7 +448,7 @@
|
|
|
448
448
|
"fabric_hub",
|
|
449
449
|
"fabric_service"
|
|
450
450
|
],
|
|
451
|
-
"sha256": "
|
|
451
|
+
"sha256": "9b299b578ce8b1e834afdbbdb54183281df064302417fe364067e97e9ac23979"
|
|
452
452
|
},
|
|
453
453
|
{
|
|
454
454
|
"module": "fabric_board_fixture",
|
|
@@ -652,7 +652,7 @@
|
|
|
652
652
|
"fabric-package-schema",
|
|
653
653
|
"fabric-secrets"
|
|
654
654
|
],
|
|
655
|
-
"sha256": "
|
|
655
|
+
"sha256": "8cfb32eebbd4e1bcf28a6e4437344ae2dd54479b0e7c820f002e9f94ab9ecaad"
|
|
656
656
|
},
|
|
657
657
|
{
|
|
658
658
|
"module": "fabric-protocols",
|
|
@@ -917,7 +917,7 @@
|
|
|
917
917
|
"imports": [
|
|
918
918
|
"fabric-board-shapes"
|
|
919
919
|
],
|
|
920
|
-
"sha256": "
|
|
920
|
+
"sha256": "fc77a3c6e62aa18575568bef4f703cce2edaba8cef648813ebcdbb21bdc27a11"
|
|
921
921
|
},
|
|
922
922
|
{
|
|
923
923
|
"module": "fabric-board-session",
|
|
@@ -930,7 +930,7 @@
|
|
|
930
930
|
"fabric-hub",
|
|
931
931
|
"fabric-service"
|
|
932
932
|
],
|
|
933
|
-
"sha256": "
|
|
933
|
+
"sha256": "b81e74397fbae655183fc0dabb8d7406c9c5e9b6e02d893e046aa3521a3a8619"
|
|
934
934
|
},
|
|
935
935
|
{
|
|
936
936
|
"module": "fabric-board-fixture",
|
|
@@ -4408,6 +4408,186 @@
|
|
|
4408
4408
|
"fabric-openrouter.mjs": "6041f3ab30f516658e1dbab4897a651cc8509b2136cfa8e769802c6b40ec2f35",
|
|
4409
4409
|
"fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
|
|
4410
4410
|
"share-registration.schema.json": "34b3997eeaf936ebc861342a23045634a7c18c19f01d7ed4198310d81989f5b0"
|
|
4411
|
+
},
|
|
4412
|
+
"0.59.0": {
|
|
4413
|
+
"fabric_jsvalue.py": "12888a2c934a885d35999ac9782eaedc8d04946d9775213344a235a8814d3d28",
|
|
4414
|
+
"fabric_time.py": "588f383da4ac6a243ea95b6ffc3a0aa99ca94245732dc4937734f190b7af4ae9",
|
|
4415
|
+
"fabric_identifiers.py": "0fd814d521ac3aa39907458265870753046a73f48af3d8581ab864b93b211607",
|
|
4416
|
+
"fabric_secrets.py": "1d0191f0ec108fdc68345056b8c574b1f691509d1c353e41d98bfd58a59e8d3c",
|
|
4417
|
+
"fabric_crypto.py": "9c34aee20dbe4d6742e4fdbaab68ceb934bbe7dbd3a904c0010824ace16cdeaa",
|
|
4418
|
+
"fabric_base.py": "f62bcc2ed9912660fa875d27a09f60867260cc4925f79873501fd9620be59611",
|
|
4419
|
+
"fabric_platform.py": "a9350dff55ef0fb3a23cdb4d0320a15868b15a8deb10d2eb74d72c58740c284b",
|
|
4420
|
+
"fabric_paths.py": "8a1ee742f80f436e9f28c61b4f049a9545de2a9e0d66bfc61faa6ee5d1ba3734",
|
|
4421
|
+
"fabric_estate_rules.py": "8b36a7f4108d9c2b1fb38c8bff344778c807bed631a99b4a563ecb0a49c10b1c",
|
|
4422
|
+
"fabric_estate.py": "b3cd56dcb86e04d252980322ac8054da1aaef24ac64690f7aa80e7c765ee6f60",
|
|
4423
|
+
"fabric_mandate.py": "050c43d0166a7dfba82e29c4e978f05c364cf6da06d0a781bd023a566777c17b",
|
|
4424
|
+
"fabric_delegation.py": "716f0ff7ac01095f54b24970beac1962128e8ff33026b243fc0467876142ab03",
|
|
4425
|
+
"fabric_share.py": "da36a466426fc29dd7dd40013167f3959a18375f8fedd228bf64f298cec1040c",
|
|
4426
|
+
"fabric_ceremonies.py": "a59e83cf4adb2669a9b98008e3d3a0cba991a35cbff97bc604fc82fe81cfd49f",
|
|
4427
|
+
"fabric_package_schema.py": "e623f0408d38e3343ed66222fb812907c6c52e1a286eb1c1176ab2e64640c9ad",
|
|
4428
|
+
"fabric_package.py": "ff533f1b3f92b4ea0f532fcec50b68c610d47549930eef8ad5247692a64dfb3c",
|
|
4429
|
+
"fabric_protocols.py": "42529a7df4d753544d2e37a18ec81266d6e1e80477cb8558a3ab521416d45791",
|
|
4430
|
+
"fabric_actions.py": "ae21d1199614c4f74d1dcd1e0a87107a9d52434cd9e2d64aa24a7b1e196fb723",
|
|
4431
|
+
"fabric_connections.py": "7de55cb7d808f756d650effabfaa12027d40a5bd5d2f6d448c32969d47529ecb",
|
|
4432
|
+
"fabric_a2a.py": "8b01502131215bb4de1c01866187c56e99b791543923ed8577535573db33b919",
|
|
4433
|
+
"fabric_page_links.py": "1b57ea573c550e2f90d1ec3edcc655917ceaa0db9dd1635fccf422ec3024d25e",
|
|
4434
|
+
"fabric_lock.py": "ba2399d2137c7a7791b7133b9db9cca36693f4eb7e30955b25a75ade814e95ba",
|
|
4435
|
+
"fabric_usage.py": "5cc2e03ccc5b06e81987ed7bc3eead7a7e6cbf1a7cb8e05c6c64315eed9d91b6",
|
|
4436
|
+
"fabric_backups.py": "1f3f0d7ecf361b29e9101e07f1c53e5dc304d598bf26fd59ec89f16b9fed2420",
|
|
4437
|
+
"fabric_descriptor.py": "a6d7a4a38186f7ef527d16218bbf96e39e255f9547be668adcfbec063dabb7ed",
|
|
4438
|
+
"fabric_context.py": "6ae311ddc7217a4aff915e7ce2646486931acd128462b7bebe4a52bbb5fbb6c7",
|
|
4439
|
+
"fabric_auth.py": "71115d18c67b7b806cb57b64b77e01ad97fc0e63e6f49ee850f778123617d905",
|
|
4440
|
+
"fabric_events.py": "cd94b186e2a8f8cb4ad2b6bd44d83ec5021933075e28c5d655f387f16dff42b8",
|
|
4441
|
+
"fabric_logs.py": "86dc55bfafa2a57264722e2403510a249b95de0e4a722b2e4bc3948e3bd93da9",
|
|
4442
|
+
"fabric_supervisors.py": "3c5b2e8c310738720b1c1b779be4710e90251013d9be4c68f9952edc0bf55d5f",
|
|
4443
|
+
"fabric_service.py": "a2e813469a47d4d3eea996628635c8903007498bdb6a1ae032a7a5ce6f49fe2f",
|
|
4444
|
+
"fabric_profiles.py": "26e21ec29c016000f8ca8053b7b489184854a73be1b7fdc0a18d12990203db9b",
|
|
4445
|
+
"fabric_interop_rules.py": "82c079a4d9421ea2cd10c1dfa8e1c447b80d5e0dcc8d52d52415bf028e34c91e",
|
|
4446
|
+
"fabric_interop.py": "8f7e43bf01fa5e969d7d819f4b0188b9acfd846f6f85a37ea139e550d61e4e6c",
|
|
4447
|
+
"fabric_hub.py": "b9ac852e601b1d54cf61351677a628afc69faeed7d1fc74ebe541c1cf38e0c2a",
|
|
4448
|
+
"fabric_board_shapes.py": "0a0e8d3d40e33dfd8c457aedb85330b2ff25f8c49a33eb6cbd5a5cc8a5007f7e",
|
|
4449
|
+
"fabric_board_link.py": "e8d2310e5f53c75e4bf642c3d980b2faba692731eaf56ec245cea05446e38bef",
|
|
4450
|
+
"fabric_board_slots.py": "a3c705cded822103703a6c2d734bcd505fcd1d6c0293150c77dfa266fd416d53",
|
|
4451
|
+
"fabric_board_session.py": "9032c04fbafb63fd93809b494518aaa039215abef973ad181d960350beb56a9f",
|
|
4452
|
+
"fabric_board_fixture.py": "69761ce205ec640762ec9b591c6903e5a87f844e8d423b041681924027e39d1e",
|
|
4453
|
+
"fabric_board.py": "34c1200860040aa61cdd35f911f70d34d64b4a5cd91f892328d1169e4a89d8cd",
|
|
4454
|
+
"fabric_http.py": "80e22ae0bba91de13a94d64b595108b39c58f16f7b4137f3a48bdd9503f424fe",
|
|
4455
|
+
"fabric_openrouter.py": "d06a40f83f2fb8bd441ab3485ae882f1fbdd9cd7a9c1ec175eb47cb8ae2cce81",
|
|
4456
|
+
"fabric-jsvalue.mjs": "dfbdb8c41584972c9389750a41719374a1cfc5652ed438dd1623025190b0106e",
|
|
4457
|
+
"fabric-time.mjs": "3ff932069038a720df1c68c6492976906737b2e67e5c12d9c81c418597f661de",
|
|
4458
|
+
"fabric-identifiers.mjs": "a18c2a501a4aa170bfd3d99e571ad6b7662649b4d3b9d2a540c002ea42811bbf",
|
|
4459
|
+
"fabric-secrets.mjs": "6ad8ab18ac899ecc2384e8ec6a3fb689b92be3b9a5ce3a59b92a37d52da5d766",
|
|
4460
|
+
"fabric-crypto.mjs": "038e03689701e3c9721a1e7f8e0a4d02a52d6a5d1661b0dc84035edc3ebbfcf6",
|
|
4461
|
+
"fabric-base.mjs": "7804b2df7715dbbf9702a9b61b6b8cef2110f9a52b04cabd8fb0a66458d87512",
|
|
4462
|
+
"fabric-platform.mjs": "a8119d95ebba4d589a9e401f5d6fc8dda62d59d44e4c1ff811d97fac3771ac0c",
|
|
4463
|
+
"fabric-paths.mjs": "aa630d611e748a899e7043480f4a4e46b444f2e15ff945f30c2fbef21c1ceea5",
|
|
4464
|
+
"fabric-estate-rules.mjs": "7476be71174aa5b1026134f2b335abf647feaa55584e2f9de8618e3054aa8e1e",
|
|
4465
|
+
"fabric-estate.mjs": "e8a2e62d2313121e6cb502f6e6abad94d1d546a44b4d9b3ce2be29e7808e8cf3",
|
|
4466
|
+
"fabric-mandate.mjs": "deaab2bfb929d1bd35ae1bad71e7b9ad9902cc23b8eb51819ed592fd80eddf95",
|
|
4467
|
+
"fabric-delegation.mjs": "04eaf6cd1786d4309a253a27dbdb05e27b408cb511aa41b1633a96634b775e65",
|
|
4468
|
+
"fabric-share.mjs": "bfb26581c21ad984c2a337da02429f9f3a165cc582f8ba48de4d3dfb7d163a59",
|
|
4469
|
+
"fabric-ceremonies.mjs": "117d4374c9e95c930a38de7adbd4323774798f4fe6ec6f24afcd6f2c7298ca44",
|
|
4470
|
+
"fabric-package-schema.mjs": "cd28092375db0fc21ffab1f0bb7794f7f8979ee08c64d3b9faf4b3845357caa6",
|
|
4471
|
+
"fabric-package.mjs": "13913ea6d12056c3a31b8222b6c4aab8395941fe519913692e1a06d8672e1c88",
|
|
4472
|
+
"fabric-protocols.mjs": "5fd8765fdd3e507cc85c108492682bf5cbb4ae08873245c50374fb01d33c75e4",
|
|
4473
|
+
"fabric-actions.mjs": "06e42f5e24c96311d5417d0d1effa93479ef7128a7ab139903b2bcf59253f6be",
|
|
4474
|
+
"fabric-connections.mjs": "303432e547ce563e90ca9ffcd827f5612f51d3582929834e1add0fdaf6485dcc",
|
|
4475
|
+
"fabric-a2a.mjs": "51b72fe1d80649d659fcad3a8f96370db3476c4a7b30cbabd8522c138be69346",
|
|
4476
|
+
"fabric-page-links.mjs": "a8834926e9d4bbf7c4857f551451d2ebf6ac8873bbccaaf89c5e30cf45b17ee6",
|
|
4477
|
+
"fabric-lock.mjs": "ac219ab0a326d5c43c7c4c255e0c3843d4794de795a60e3af661e7d5350ea052",
|
|
4478
|
+
"fabric-usage.mjs": "1c4d18004639409624ac3516a02f2b60bbf55abdb612e9a96c37e83666eb87a7",
|
|
4479
|
+
"fabric-backups.mjs": "cfd8c9085e3d597a783099c2bd2ffe2f3faa0daaadab46dedd30523894cfeb06",
|
|
4480
|
+
"fabric-descriptor.mjs": "243bbce42989f67c4c5ec6b7659e201b3f9a1c08c71d429d88ec934d870f5104",
|
|
4481
|
+
"fabric-context.mjs": "1112d695e872f9825cbc94f08484974bff3880087bc29b8be59f885f03e8f7be",
|
|
4482
|
+
"fabric-auth.mjs": "782c2aa732f8320f604194660117640a7ea145e12b8155c04e88cef7c516a5b3",
|
|
4483
|
+
"fabric-events.mjs": "c463d6ffcae24229a5c608d8fcea4268d2ccc5024b19fa10e5a452284068fa71",
|
|
4484
|
+
"fabric-logs.mjs": "58467e5719c16e099d05bbedec47a95712506ab03c33f3cd4be1252e8498a946",
|
|
4485
|
+
"fabric-supervisors.mjs": "d45c38de0cb3ed85e083496c2d3c51dab004454accdd87f4762a512a6d442573",
|
|
4486
|
+
"fabric-service.mjs": "6aa673657427211b491a9b63f94b9847a7e6aa3ee1b7353e1af11f46469803a3",
|
|
4487
|
+
"fabric-profiles.mjs": "314376cf2deb87f235fb18b11d3b532e211f585b9af0a9302b5f4cc39971b532",
|
|
4488
|
+
"fabric-interop-rules.mjs": "e4f8b133138e27353a7976c0360bd1653c90daed43b3f843f85a19f14f5e9221",
|
|
4489
|
+
"fabric-interop.mjs": "ee7e6d32be1f42e6d21a943b8886652352408c49c6404d9749b8a02dc3901e92",
|
|
4490
|
+
"fabric-hub.mjs": "c005115a864cfd67daa4862097bb14acfe5a60bf653897e5bf8a570dd80f1070",
|
|
4491
|
+
"fabric-board-shapes.mjs": "c1db7b7bd0d58d82bb6d8dfbc3cd1547a256a333052d367e82ff1b3edf2804d7",
|
|
4492
|
+
"fabric-board-link.mjs": "b1ac329b65b679193b94b81fe735922e14427ed540ba910b1a815ce3447e3220",
|
|
4493
|
+
"fabric-board-slots.mjs": "43eb7ceb6c62989a4eb4b2089d1808e2c3cf8f873fcf9216fcb4c285e5b39eb4",
|
|
4494
|
+
"fabric-board-session.mjs": "04aa920b24a379157c55ebe3de516eb8b46bd0b0db50e4b883528d4ede7ed978",
|
|
4495
|
+
"fabric-board-fixture.mjs": "83c4b7e33ee47b68385faf2569d38d5c8a0c5cb0f8656090f41e1b0eed2f436e",
|
|
4496
|
+
"fabric-board.mjs": "0d75c3e27a0b791bdbc35b2e93b3299e5831d3ab3003ce441e6268397e32b448",
|
|
4497
|
+
"fabric-http.mjs": "9f899829073470b9c2b449605a9371b773848eec4e3a0122ed4ccde5eddcdb4b",
|
|
4498
|
+
"fabric-openrouter.mjs": "6041f3ab30f516658e1dbab4897a651cc8509b2136cfa8e769802c6b40ec2f35",
|
|
4499
|
+
"fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
|
|
4500
|
+
"share-registration.schema.json": "34b3997eeaf936ebc861342a23045634a7c18c19f01d7ed4198310d81989f5b0"
|
|
4501
|
+
},
|
|
4502
|
+
"0.60.0": {
|
|
4503
|
+
"fabric_jsvalue.py": "12888a2c934a885d35999ac9782eaedc8d04946d9775213344a235a8814d3d28",
|
|
4504
|
+
"fabric_time.py": "588f383da4ac6a243ea95b6ffc3a0aa99ca94245732dc4937734f190b7af4ae9",
|
|
4505
|
+
"fabric_identifiers.py": "0fd814d521ac3aa39907458265870753046a73f48af3d8581ab864b93b211607",
|
|
4506
|
+
"fabric_secrets.py": "1d0191f0ec108fdc68345056b8c574b1f691509d1c353e41d98bfd58a59e8d3c",
|
|
4507
|
+
"fabric_crypto.py": "9c34aee20dbe4d6742e4fdbaab68ceb934bbe7dbd3a904c0010824ace16cdeaa",
|
|
4508
|
+
"fabric_base.py": "f62bcc2ed9912660fa875d27a09f60867260cc4925f79873501fd9620be59611",
|
|
4509
|
+
"fabric_platform.py": "a9350dff55ef0fb3a23cdb4d0320a15868b15a8deb10d2eb74d72c58740c284b",
|
|
4510
|
+
"fabric_paths.py": "8a1ee742f80f436e9f28c61b4f049a9545de2a9e0d66bfc61faa6ee5d1ba3734",
|
|
4511
|
+
"fabric_estate_rules.py": "8b36a7f4108d9c2b1fb38c8bff344778c807bed631a99b4a563ecb0a49c10b1c",
|
|
4512
|
+
"fabric_estate.py": "b3cd56dcb86e04d252980322ac8054da1aaef24ac64690f7aa80e7c765ee6f60",
|
|
4513
|
+
"fabric_mandate.py": "050c43d0166a7dfba82e29c4e978f05c364cf6da06d0a781bd023a566777c17b",
|
|
4514
|
+
"fabric_delegation.py": "716f0ff7ac01095f54b24970beac1962128e8ff33026b243fc0467876142ab03",
|
|
4515
|
+
"fabric_share.py": "da36a466426fc29dd7dd40013167f3959a18375f8fedd228bf64f298cec1040c",
|
|
4516
|
+
"fabric_ceremonies.py": "a59e83cf4adb2669a9b98008e3d3a0cba991a35cbff97bc604fc82fe81cfd49f",
|
|
4517
|
+
"fabric_package_schema.py": "e623f0408d38e3343ed66222fb812907c6c52e1a286eb1c1176ab2e64640c9ad",
|
|
4518
|
+
"fabric_package.py": "1f2b9e73b2b32a7e1e887d4b69f87c6e21b4d1227ad924a235334223e6dd51ca",
|
|
4519
|
+
"fabric_protocols.py": "42529a7df4d753544d2e37a18ec81266d6e1e80477cb8558a3ab521416d45791",
|
|
4520
|
+
"fabric_actions.py": "ae21d1199614c4f74d1dcd1e0a87107a9d52434cd9e2d64aa24a7b1e196fb723",
|
|
4521
|
+
"fabric_connections.py": "7de55cb7d808f756d650effabfaa12027d40a5bd5d2f6d448c32969d47529ecb",
|
|
4522
|
+
"fabric_a2a.py": "8b01502131215bb4de1c01866187c56e99b791543923ed8577535573db33b919",
|
|
4523
|
+
"fabric_page_links.py": "1b57ea573c550e2f90d1ec3edcc655917ceaa0db9dd1635fccf422ec3024d25e",
|
|
4524
|
+
"fabric_lock.py": "ba2399d2137c7a7791b7133b9db9cca36693f4eb7e30955b25a75ade814e95ba",
|
|
4525
|
+
"fabric_usage.py": "5cc2e03ccc5b06e81987ed7bc3eead7a7e6cbf1a7cb8e05c6c64315eed9d91b6",
|
|
4526
|
+
"fabric_backups.py": "1f3f0d7ecf361b29e9101e07f1c53e5dc304d598bf26fd59ec89f16b9fed2420",
|
|
4527
|
+
"fabric_descriptor.py": "a6d7a4a38186f7ef527d16218bbf96e39e255f9547be668adcfbec063dabb7ed",
|
|
4528
|
+
"fabric_context.py": "6ae311ddc7217a4aff915e7ce2646486931acd128462b7bebe4a52bbb5fbb6c7",
|
|
4529
|
+
"fabric_auth.py": "71115d18c67b7b806cb57b64b77e01ad97fc0e63e6f49ee850f778123617d905",
|
|
4530
|
+
"fabric_events.py": "cd94b186e2a8f8cb4ad2b6bd44d83ec5021933075e28c5d655f387f16dff42b8",
|
|
4531
|
+
"fabric_logs.py": "86dc55bfafa2a57264722e2403510a249b95de0e4a722b2e4bc3948e3bd93da9",
|
|
4532
|
+
"fabric_supervisors.py": "3c5b2e8c310738720b1c1b779be4710e90251013d9be4c68f9952edc0bf55d5f",
|
|
4533
|
+
"fabric_service.py": "a2e813469a47d4d3eea996628635c8903007498bdb6a1ae032a7a5ce6f49fe2f",
|
|
4534
|
+
"fabric_profiles.py": "26e21ec29c016000f8ca8053b7b489184854a73be1b7fdc0a18d12990203db9b",
|
|
4535
|
+
"fabric_interop_rules.py": "82c079a4d9421ea2cd10c1dfa8e1c447b80d5e0dcc8d52d52415bf028e34c91e",
|
|
4536
|
+
"fabric_interop.py": "8f7e43bf01fa5e969d7d819f4b0188b9acfd846f6f85a37ea139e550d61e4e6c",
|
|
4537
|
+
"fabric_hub.py": "b9ac852e601b1d54cf61351677a628afc69faeed7d1fc74ebe541c1cf38e0c2a",
|
|
4538
|
+
"fabric_board_shapes.py": "0a0e8d3d40e33dfd8c457aedb85330b2ff25f8c49a33eb6cbd5a5cc8a5007f7e",
|
|
4539
|
+
"fabric_board_link.py": "e8d2310e5f53c75e4bf642c3d980b2faba692731eaf56ec245cea05446e38bef",
|
|
4540
|
+
"fabric_board_slots.py": "92b065e3df935547cf46653245f1129e4a1f8b59b0a41e8fa9ffdc41596ee592",
|
|
4541
|
+
"fabric_board_session.py": "9b299b578ce8b1e834afdbbdb54183281df064302417fe364067e97e9ac23979",
|
|
4542
|
+
"fabric_board_fixture.py": "69761ce205ec640762ec9b591c6903e5a87f844e8d423b041681924027e39d1e",
|
|
4543
|
+
"fabric_board.py": "34c1200860040aa61cdd35f911f70d34d64b4a5cd91f892328d1169e4a89d8cd",
|
|
4544
|
+
"fabric_http.py": "80e22ae0bba91de13a94d64b595108b39c58f16f7b4137f3a48bdd9503f424fe",
|
|
4545
|
+
"fabric_openrouter.py": "d06a40f83f2fb8bd441ab3485ae882f1fbdd9cd7a9c1ec175eb47cb8ae2cce81",
|
|
4546
|
+
"fabric-jsvalue.mjs": "dfbdb8c41584972c9389750a41719374a1cfc5652ed438dd1623025190b0106e",
|
|
4547
|
+
"fabric-time.mjs": "3ff932069038a720df1c68c6492976906737b2e67e5c12d9c81c418597f661de",
|
|
4548
|
+
"fabric-identifiers.mjs": "a18c2a501a4aa170bfd3d99e571ad6b7662649b4d3b9d2a540c002ea42811bbf",
|
|
4549
|
+
"fabric-secrets.mjs": "6ad8ab18ac899ecc2384e8ec6a3fb689b92be3b9a5ce3a59b92a37d52da5d766",
|
|
4550
|
+
"fabric-crypto.mjs": "038e03689701e3c9721a1e7f8e0a4d02a52d6a5d1661b0dc84035edc3ebbfcf6",
|
|
4551
|
+
"fabric-base.mjs": "7804b2df7715dbbf9702a9b61b6b8cef2110f9a52b04cabd8fb0a66458d87512",
|
|
4552
|
+
"fabric-platform.mjs": "a8119d95ebba4d589a9e401f5d6fc8dda62d59d44e4c1ff811d97fac3771ac0c",
|
|
4553
|
+
"fabric-paths.mjs": "aa630d611e748a899e7043480f4a4e46b444f2e15ff945f30c2fbef21c1ceea5",
|
|
4554
|
+
"fabric-estate-rules.mjs": "7476be71174aa5b1026134f2b335abf647feaa55584e2f9de8618e3054aa8e1e",
|
|
4555
|
+
"fabric-estate.mjs": "e8a2e62d2313121e6cb502f6e6abad94d1d546a44b4d9b3ce2be29e7808e8cf3",
|
|
4556
|
+
"fabric-mandate.mjs": "deaab2bfb929d1bd35ae1bad71e7b9ad9902cc23b8eb51819ed592fd80eddf95",
|
|
4557
|
+
"fabric-delegation.mjs": "04eaf6cd1786d4309a253a27dbdb05e27b408cb511aa41b1633a96634b775e65",
|
|
4558
|
+
"fabric-share.mjs": "bfb26581c21ad984c2a337da02429f9f3a165cc582f8ba48de4d3dfb7d163a59",
|
|
4559
|
+
"fabric-ceremonies.mjs": "117d4374c9e95c930a38de7adbd4323774798f4fe6ec6f24afcd6f2c7298ca44",
|
|
4560
|
+
"fabric-package-schema.mjs": "cd28092375db0fc21ffab1f0bb7794f7f8979ee08c64d3b9faf4b3845357caa6",
|
|
4561
|
+
"fabric-package.mjs": "8cfb32eebbd4e1bcf28a6e4437344ae2dd54479b0e7c820f002e9f94ab9ecaad",
|
|
4562
|
+
"fabric-protocols.mjs": "5fd8765fdd3e507cc85c108492682bf5cbb4ae08873245c50374fb01d33c75e4",
|
|
4563
|
+
"fabric-actions.mjs": "06e42f5e24c96311d5417d0d1effa93479ef7128a7ab139903b2bcf59253f6be",
|
|
4564
|
+
"fabric-connections.mjs": "303432e547ce563e90ca9ffcd827f5612f51d3582929834e1add0fdaf6485dcc",
|
|
4565
|
+
"fabric-a2a.mjs": "51b72fe1d80649d659fcad3a8f96370db3476c4a7b30cbabd8522c138be69346",
|
|
4566
|
+
"fabric-page-links.mjs": "a8834926e9d4bbf7c4857f551451d2ebf6ac8873bbccaaf89c5e30cf45b17ee6",
|
|
4567
|
+
"fabric-lock.mjs": "ac219ab0a326d5c43c7c4c255e0c3843d4794de795a60e3af661e7d5350ea052",
|
|
4568
|
+
"fabric-usage.mjs": "1c4d18004639409624ac3516a02f2b60bbf55abdb612e9a96c37e83666eb87a7",
|
|
4569
|
+
"fabric-backups.mjs": "cfd8c9085e3d597a783099c2bd2ffe2f3faa0daaadab46dedd30523894cfeb06",
|
|
4570
|
+
"fabric-descriptor.mjs": "243bbce42989f67c4c5ec6b7659e201b3f9a1c08c71d429d88ec934d870f5104",
|
|
4571
|
+
"fabric-context.mjs": "1112d695e872f9825cbc94f08484974bff3880087bc29b8be59f885f03e8f7be",
|
|
4572
|
+
"fabric-auth.mjs": "782c2aa732f8320f604194660117640a7ea145e12b8155c04e88cef7c516a5b3",
|
|
4573
|
+
"fabric-events.mjs": "c463d6ffcae24229a5c608d8fcea4268d2ccc5024b19fa10e5a452284068fa71",
|
|
4574
|
+
"fabric-logs.mjs": "58467e5719c16e099d05bbedec47a95712506ab03c33f3cd4be1252e8498a946",
|
|
4575
|
+
"fabric-supervisors.mjs": "d45c38de0cb3ed85e083496c2d3c51dab004454accdd87f4762a512a6d442573",
|
|
4576
|
+
"fabric-service.mjs": "6aa673657427211b491a9b63f94b9847a7e6aa3ee1b7353e1af11f46469803a3",
|
|
4577
|
+
"fabric-profiles.mjs": "314376cf2deb87f235fb18b11d3b532e211f585b9af0a9302b5f4cc39971b532",
|
|
4578
|
+
"fabric-interop-rules.mjs": "e4f8b133138e27353a7976c0360bd1653c90daed43b3f843f85a19f14f5e9221",
|
|
4579
|
+
"fabric-interop.mjs": "ee7e6d32be1f42e6d21a943b8886652352408c49c6404d9749b8a02dc3901e92",
|
|
4580
|
+
"fabric-hub.mjs": "c005115a864cfd67daa4862097bb14acfe5a60bf653897e5bf8a570dd80f1070",
|
|
4581
|
+
"fabric-board-shapes.mjs": "c1db7b7bd0d58d82bb6d8dfbc3cd1547a256a333052d367e82ff1b3edf2804d7",
|
|
4582
|
+
"fabric-board-link.mjs": "b1ac329b65b679193b94b81fe735922e14427ed540ba910b1a815ce3447e3220",
|
|
4583
|
+
"fabric-board-slots.mjs": "fc77a3c6e62aa18575568bef4f703cce2edaba8cef648813ebcdbb21bdc27a11",
|
|
4584
|
+
"fabric-board-session.mjs": "b81e74397fbae655183fc0dabb8d7406c9c5e9b6e02d893e046aa3521a3a8619",
|
|
4585
|
+
"fabric-board-fixture.mjs": "83c4b7e33ee47b68385faf2569d38d5c8a0c5cb0f8656090f41e1b0eed2f436e",
|
|
4586
|
+
"fabric-board.mjs": "0d75c3e27a0b791bdbc35b2e93b3299e5831d3ab3003ce441e6268397e32b448",
|
|
4587
|
+
"fabric-http.mjs": "9f899829073470b9c2b449605a9371b773848eec4e3a0122ed4ccde5eddcdb4b",
|
|
4588
|
+
"fabric-openrouter.mjs": "6041f3ab30f516658e1dbab4897a651cc8509b2136cfa8e769802c6b40ec2f35",
|
|
4589
|
+
"fabric-package.schema.json": "2ba799f576fad0f608029223c4ccccd122152f1c5dbfa8ce8b31cd63ac92ad44",
|
|
4590
|
+
"share-registration.schema.json": "34b3997eeaf936ebc861342a23045634a7c18c19f01d7ed4198310d81989f5b0"
|
|
4411
4591
|
}
|
|
4412
4592
|
},
|
|
4413
4593
|
"data": {
|
package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/sample_service.py
CHANGED
|
@@ -100,7 +100,7 @@ CAPABILITIES = [
|
|
|
100
100
|
#: manifest, so `register --board-project` writes it there.
|
|
101
101
|
TAKE_BACK_CAPABILITY: Dict[str, Any] = {
|
|
102
102
|
"name": TAKE_BACK["tool"], "effect": "change-policy", "idempotency": "required", "job": False,
|
|
103
|
-
"description": "Take back a board slot
|
|
103
|
+
"description": "Take back a board slot moved to another session.",
|
|
104
104
|
# A relayed action: a probe call carries no operator decision, so it is refused and changes nothing (unit r28).
|
|
105
105
|
"probeAssertion": "is refused as operator-decision-required without the operator's decision in _meta",
|
|
106
106
|
"input": _schema("board.take-back-input", TAKE_BACK_INPUT),
|
|
@@ -175,7 +175,7 @@ class Service:
|
|
|
175
175
|
|
|
176
176
|
# --- the project board (opt-in): the input gate and the answer -------------------
|
|
177
177
|
def board_moved(self) -> list:
|
|
178
|
-
"""The capabilities whose slot
|
|
178
|
+
"""The capabilities whose slot moved to another session (FAA-155): the page offers their take-back.
|
|
179
179
|
The live slot or the checkpoint's record says so: before a restart has reconnected (or while Fabric is down) the
|
|
180
180
|
record alone knows the move (0.56.0 seam r3)."""
|
|
181
181
|
if not self.board:
|
|
@@ -5,7 +5,7 @@ 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.60.0"
|
|
9
9
|
contract-version: "0.1.0"
|
|
10
10
|
contract-commit: "3830a3353923e20f826d466610e1c479f120bec0"
|
|
11
11
|
---
|
|
@@ -57,6 +57,9 @@ No file is created until every row has an answer. An answer of "later" fails the
|
|
|
57
57
|
| **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 |
|
|
58
58
|
| **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 |
|
|
59
59
|
| **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) |
|
|
60
|
+
| **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: a local service only, no cloud, reading an A agent's data through that agent's MCP or API. The README names the category (references/where-agents-run.md) |
|
|
61
|
+
| **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) |
|
|
62
|
+
| **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) |
|
|
60
63
|
| **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, declared as classes in the profile (references/models-and-providers.md) |
|
|
61
64
|
| **Who pays?** | one key per agent and context with its own ceiling, from the estate's key manager, read from the environment; checked before every call; a personal key never pays for an organization |
|
|
62
65
|
| **How does it learn?** | decisions recorded with reasons, one trace per turn, every failure a planted fixture first, history replayed, learnings proposed and never self-approved (references/orchestration-and-learning.md) |
|
|
@@ -111,8 +114,11 @@ are its seed because a source project's recorded failures count as production.
|
|
|
111
114
|
repository standard (`knowledge/repository-standard.md`) from its first commit: the licence files,
|
|
112
115
|
the README quick start verified with a real client, `AGENTS.md` and `CLAUDE.md`, as
|
|
113
116
|
[the operator channel and the repository standard](references/operator-channel-and-repository.md)
|
|
114
|
-
lists them. An agent someone builds for themselves is not a PassionCode.ai repository: its licence
|
|
115
|
-
is its owner's choice and none of those files is required of it
|
|
117
|
+
lists them. An agent someone builds for themselves, or a private agent built for a client, is not a PassionCode.ai repository: its licence
|
|
118
|
+
is its owner's choice and none of those files is required of it, but its first commit carries a `LICENSE` naming
|
|
119
|
+
the copyright holder the grill recorded (all rights reserved unless the owner gives other terms); it covers the
|
|
120
|
+
holder's own files, and the kit files the adapter copies in keep their own licence (AGPL-3.0-only OR
|
|
121
|
+
LicenseRef-PassionCode-Commercial).
|
|
116
122
|
|
|
117
123
|
**Every credential the agent uses is read by name, never held as a value**, from its first commit:
|
|
118
124
|
the README's Configure section lists key NAMES. With Project Observatory installed, the agent finds
|
|
@@ -127,7 +133,9 @@ never their values.
|
|
|
127
133
|
**The source stays apart from the instance**, from the first commit: instance values (the
|
|
128
134
|
repository address of the owner's account, folders, the owner, accounts, hosts) live in a configuration outside the repository, read through a
|
|
129
135
|
named variable with a neutral default and a committed `*.example`; records, logs and state documents live in the
|
|
130
|
-
instance folder; fixtures use neutral ids.
|
|
136
|
+
instance folder; fixtures use neutral ids. Its data has a home of its own from the same commit, the one the grill recorded: `<agent>-data` (a folder beside the
|
|
137
|
+
checkout, or a private repository of that name; a kit service: the kit's folders; on a cloud host: a durable store), and the README names the data kind (U or O) and the uptime
|
|
138
|
+
category (A or B) from the grill. Load [the source and the instance](references/source-and-instance.md). The
|
|
131
139
|
sibling's `scripts/fabric_source_check.py check <project-root>` finds instance data in the tree without repeating it;
|
|
132
140
|
run it with the owner's list of their own strings, or record that none was given (the owner's own home name, when it is neutral, has one or two letters, or holds a space, `.`, `_`, `-` or `'`, is declared there with `home: <name>` first; a container's, a cloud image's or a CI runner's user that only the image uses, such as `node` or `vscode`, is never declared); the skeleton is done when it exits 0 and the owner has reviewed it (a floor, not a secret scanner; without the sibling or Python 3.9+, record the check as NOT_RUN, as in step 3). Handing the source over stays the owner's act.
|
|
133
141
|
|
|
@@ -172,7 +180,8 @@ reference). An agent that is not a service is announced with a provider entry
|
|
|
172
180
|
If the agent keeps running on the operator's computer (it answers other agents, runs
|
|
173
181
|
long jobs or shows a dashboard), build it as a service with the sibling skill
|
|
174
182
|
`building-fabric-services`: its instance lock, launchd plist, descriptor, well-known
|
|
175
|
-
document and events feed are part of this step, not a later retrofit.
|
|
183
|
+
document and events feed are part of this step, not a later retrofit. An uptime A agent is built with the same
|
|
184
|
+
skill as an online service (its remote placement: the https origin, keys as the platform's secrets). If that skill is
|
|
176
185
|
absent, apply the `fabric-service/0.1` rules from the pinned contract's
|
|
177
186
|
`docs/specification/service.md` by hand and mark its probe `NOT_RUN`.
|
|
178
187
|
|
|
@@ -190,8 +199,11 @@ lets the output decide what counts as success.
|
|
|
190
199
|
|
|
191
200
|
Run the sibling skill's `check` (structural, then exact when the contract checkout is
|
|
192
201
|
available) and complete `fabric/FABRIC-CONFORMANCE.md` with dated receipts, exactly as
|
|
193
|
-
its workflow steps 5–7 prescribe, and run its `fabric_source_check.py check` again (exit 0)
|
|
194
|
-
|
|
202
|
+
its workflow steps 5–7 prescribe, and run its `fabric_source_check.py check` again (exit 0). Every release of the
|
|
203
|
+
agent runs it too, in Git mode on the checkout and with `--every-file` on the clean copy a transfer would carry (what
|
|
204
|
+
Git would commit, as building-fabric-services' `references/package.md` makes it), as the transfer audit (each exit 0, with the owner's list or
|
|
205
|
+
its absence recorded) until the contract's export (CT-194) replaces it; this skill adds no second verification path
|
|
206
|
+
on purpose. Then record one expectation the report must carry:
|
|
195
207
|
|
|
196
208
|
> When a Fabric host admits this provider, it enters under a **canary binding** (a
|
|
197
209
|
> checker on its output and a budget cap), regardless of who wrote it. Unsupervised
|
|
@@ -63,4 +63,7 @@ the project).
|
|
|
63
63
|
org-index `scripts/check_format.py` reports 0 findings for it before it is called done. An agent
|
|
64
64
|
someone builds for themselves is not a PassionCode.ai repository: its licence is its owner's
|
|
65
65
|
choice, nothing about it is published or listed by the organization, and none of these files is
|
|
66
|
-
required of it,
|
|
66
|
+
required of it, except that an agent built new carries a `LICENSE` naming the copyright holder (all rights reserved
|
|
67
|
+
unless the owner gives other terms), as does a new private agent built for a client; files the adapter copies in (the service kit, the dashboard kit) keep their own
|
|
68
|
+
licence, `AGPL-3.0-only OR LicenseRef-PassionCode-Commercial` ([COMMERCIAL-LICENSE.md](https://github.com/passioncode-ai/fabric-agent-adapter/blob/main/COMMERCIAL-LICENSE.md)).
|
|
69
|
+
The verified MCP quick start is still how anyone learns to drive it.
|
package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/references/source-and-instance.md
CHANGED
|
@@ -13,6 +13,7 @@ on it.
|
|
|
13
13
|
## Contents
|
|
14
14
|
|
|
15
15
|
- [The layout](#the-layout)
|
|
16
|
+
- [The data home and its kind](#the-data-home-and-its-kind)
|
|
16
17
|
- [The check](#the-check)
|
|
17
18
|
|
|
18
19
|
## The layout
|
|
@@ -31,7 +32,7 @@ on it.
|
|
|
31
32
|
(an organization's) is a sibling instance, `<id>.<instance>`, never a folder inside the personal one
|
|
32
33
|
(`references/estate-record.md` of that skill).
|
|
33
34
|
- **Ignore the instance in the source**: `.gitignore` names the real configuration (`config/*.json` with
|
|
34
|
-
`!config/*.example.json`), an instance folder
|
|
35
|
+
`!config/*.example.json`), an instance folder an existing project still keeps inside the checkout, and what running
|
|
35
36
|
the agent leaves (`__pycache__/`, `*.pyc`), which the check would otherwise report as binary in Git mode.
|
|
36
37
|
- **State documents are instance data.** A handoff, a decision log or a backlog about this codebase is source
|
|
37
38
|
documentation; a record of what this installation did (runs, conversations, the owner's notes, a journal) lives in
|
|
@@ -47,6 +48,27 @@ on it.
|
|
|
47
48
|
keeps the scaffold's sentinel, and a person's name or account is never written there. The adapter moves both when the
|
|
48
49
|
contract decides how an instance renames them (FAA-188 part 2).
|
|
49
50
|
|
|
51
|
+
## The data home and its kind
|
|
52
|
+
|
|
53
|
+
- **The data has a home of its own from the first commit: `<agent>-data`.** For an agent that is not a kit service it
|
|
54
|
+
is a folder beside the checkout, never inside it, and `<AGENT>_DATA_DIR` names it (its default is
|
|
55
|
+
`../<agent>-data`); a kit service keeps the kit's folders above. When the owner keeps the data in Git, it goes to a
|
|
56
|
+
separate private repository named `<agent>-data`, never to the source's repository. On a cloud host that does not
|
|
57
|
+
keep its disk across a restart (Heroku and the like, an uptime A agent's default), the data home is a durable store
|
|
58
|
+
the same variable names (a database, an object store, that private repository); the folder and the kit's folders
|
|
59
|
+
serve a machine whose disk persists. A copy of the agent starts with an empty home of its own and never connects
|
|
60
|
+
to the original's.
|
|
61
|
+
- **The README names the kind of the data.** **U**: the agent keeps data of people outside the owner's team
|
|
62
|
+
(messages, support requests, reviews, customers' answers); it never enters the source, a copy or its tests, and the
|
|
63
|
+
source holds only the schema and synthetic fixtures (its real-trace corpus and replay samples live in the data
|
|
64
|
+
home). **O**: it keeps none (a tool or service for other agents, the
|
|
65
|
+
owner's reports, runs and media); its working data still goes to the data home. When in doubt, the kind is U.
|
|
66
|
+
- **Every release runs the transfer audit.** `fabric_source_check.py check <project-root>` in Git mode, and
|
|
67
|
+
`check <clean-copy> --every-file` on a clean copy of what Git would commit (`git ls-files --cached --others
|
|
68
|
+
--exclude-standard`, as building-fabric-services' `references/package.md` makes it; never the checkout itself, whose ignored
|
|
69
|
+
configuration and dependency folders `--every-file` reads too), each exit 0, with the owner's list or its absence recorded, until the contract's export (CT-194)
|
|
70
|
+
replaces it.
|
|
71
|
+
|
|
50
72
|
## The check
|
|
51
73
|
|
|
52
74
|
`fabric_source_check.py check` reads the files the source would carry (what Git would commit: tracked files and
|
|
@@ -124,7 +146,10 @@ python3 <plugin-dir>/skills/adapting-projects-to-fabric/scripts/fabric_source_ch
|
|
|
124
146
|
repository is not read; `--every-file` and a folder outside Git read its files, its `.git` left out. An exception line (`!`) is refused, since what it would
|
|
125
147
|
bring back would go unread. Name the files, or a folder that holds
|
|
126
148
|
only synthetic vectors, never a whole source folder (a nested repository checked in its own tree is the one
|
|
127
|
-
exception), and say why on the line above.
|
|
149
|
+
exception), and say why on the line above. The `LICENSE` is the other: its copyright line names the holder, which is
|
|
150
|
+
authorship and travels with the source, so when the holder is on the owner's list the licence file is named in the ignore
|
|
151
|
+
file by its own path (`LICENSE`, `LICENSE.md`) with that reason (`# the copyright holder is authorship and travels with the source`); no other file of the
|
|
152
|
+
owner's is. A file `pack` refuses by its name cannot ship in a package: a public
|
|
128
153
|
certificate is renamed `*.crt`; a project `.npmrc` that holds no credential may be named in the ignore file, with
|
|
129
154
|
that reason, for the source check (the line then hides whatever is added to it later, so keep it credential-free),
|
|
130
155
|
and `pack` still refuses it, so a package is made from a copy without it (its
|