@passioncode-ai/fabric-agent-adapter 0.43.0 → 0.44.1

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 (31) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/package.json +1 -1
  3. package/plugins/fabric-agent-adapter/.claude-plugin/plugin.json +1 -1
  4. package/plugins/fabric-agent-adapter/skills/adapting-projects-to-fabric/SKILL.md +1 -1
  5. package/plugins/fabric-agent-adapter/skills/building-fabric-services/SKILL.md +7 -2
  6. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/dashboard-kit.md +2 -1
  7. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/kit-modules.md +7 -3
  8. package/plugins/fabric-agent-adapter/skills/building-fabric-services/references/protocol.md +20 -0
  9. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_dashboard_layout.mjs +8 -5
  10. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/check_service.py +9 -0
  11. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-connections.mjs +186 -0
  12. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-descriptor.mjs +6 -0
  13. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop-rules.mjs +264 -0
  14. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-interop.mjs +31 -254
  15. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package-schema.mjs +100 -0
  16. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-package.mjs +2 -89
  17. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-secrets.mjs +2 -2
  18. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric-service.mjs +1 -0
  19. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_connections.py +448 -0
  20. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_descriptor.py +6 -0
  21. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop.py +54 -369
  22. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_interop_rules.py +390 -0
  23. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package.py +20 -187
  24. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_package_schema.py +207 -0
  25. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/fabric_service.py +6 -0
  26. package/plugins/fabric-agent-adapter/skills/building-fabric-services/scripts/kit.json +234 -19
  27. package/plugins/fabric-agent-adapter/skills/creating-fabric-agents/SKILL.md +1 -1
  28. package/plugins/fabric-agent-adapter/skills/working-with-fabric/SKILL.md +1 -1
  29. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_env.py +1 -1
  30. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/fabric_session_mcp.py +4 -3
  31. package/plugins/fabric-agent-adapter/skills/working-with-fabric/scripts/host_hooks.py +3 -1
@@ -0,0 +1,100 @@
1
+ // fabric-package/1, the schema reading: the package schema bundled from the contract at the pin, read by a JSON
2
+ // Schema 2020-12 subset with JavaScript's patterns, lengths in code points and the formats the contract uses.
3
+ // fabric-package.mjs checks, packs, signs and verifies on it and re-exports schemaProblems. Part of the Node service
4
+ // kit (FAA-92, split from fabric-package.mjs; layer L2); the twin of fabric_package_schema.py. Node 20+, no dependency.
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { isString, jsonEqual } from './fabric-jsvalue.mjs'; // the core's (FAA-65)
9
+
10
+ export const SCHEMA_FILE = path.join(path.dirname(fileURLToPath(import.meta.url)), 'fabric-package.schema.json');
11
+
12
+ // --- the schema (bundled from the contract at the pin) ---------------------------------------------------------------
13
+
14
+ export let schemaCache;
15
+ export const schema = () => (schemaCache ??= JSON.parse(fs.readFileSync(SCHEMA_FILE, 'utf8')));
16
+
17
+
18
+ export const typeOf = (v) => (v === null ? 'null' : Array.isArray(v) ? 'array' : typeof v === 'number' ? (Number.isInteger(v) ? 'integer' : 'number') : typeof v);
19
+ export const DATE_TIME = /^([0-9]{4})-([0-9]{2})-([0-9]{2})[Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?([Zz]|[+-]([0-9]{2}):([0-9]{2}))$/;
20
+ export const MONTH_DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
21
+ export const leap = (year) => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
22
+
23
+ export function formatOk(format, value) {
24
+ if (!isString(value)) return true;
25
+ if (format === 'date-time') {
26
+ const m = DATE_TIME.exec(value);
27
+ if (!m) return false;
28
+ const [y, mo, d, h, mi, s] = m.slice(1, 7).map(Number);
29
+ // The proleptic calendar the contract's ajv-formats checks: year 0000 exists and is a leap year (0000-02-29 holds).
30
+ // Counted here, not with Date.UTC, which reads years 0 to 99 as 1900 to 1999.
31
+ if (mo < 1 || mo > 12 || d < 1 || d > (mo === 2 && leap(y) ? 29 : MONTH_DAYS[mo]) || h > 23 || mi > 59 || s > 59) return false;
32
+ return m[8] === 'Z' || m[8] === 'z' || (Number(m[9]) < 24 && Number(m[10]) < 60);
33
+ }
34
+ if (format === 'uri') return /^[A-Za-z][A-Za-z0-9+.-]*:\S*$/.test(value);
35
+ return true;
36
+ }
37
+
38
+ export const pointer = (token) => String(token).replace(/~/g, '~0').replace(/\//g, '~1');
39
+ export const codePoints = (s) => [...s].length; // JSON Schema counts code points, not UTF-16 units
40
+
41
+ export function validate(node, value, at, out) {
42
+ if (node === true) return;
43
+ if (node === false) { out.push({ instancePath: at, message: 'is not allowed here' }); return; }
44
+ if (node.$ref) {
45
+ const target = node.$ref.replace(/^#\//, '').split('/').reduce((n, t) => n[t.replace(/~1/g, '/').replace(/~0/g, '~')], schema());
46
+ validate(target, value, at, out);
47
+ }
48
+ const kind = typeOf(value);
49
+ if (node.type !== undefined) {
50
+ const allowed = Array.isArray(node.type) ? node.type : [node.type];
51
+ if (!(allowed.includes(kind) || (kind === 'integer' && allowed.includes('number')))) { out.push({ instancePath: at, message: `must be ${allowed.join(' or ')}` }); return; }
52
+ }
53
+ if ('const' in node && !jsonEqual(node.const, value)) out.push({ instancePath: at, message: `must be ${JSON.stringify(node.const)}` });
54
+ if (node.enum && !node.enum.some((item) => jsonEqual(item, value))) out.push({ instancePath: at, message: `must be one of ${node.enum.map((i) => JSON.stringify(i)).join(', ')}` });
55
+ if (kind === 'string') {
56
+ const length = codePoints(value);
57
+ if (length < (node.minLength ?? 0)) out.push({ instancePath: at, message: `is shorter than ${node.minLength}` });
58
+ if (node.maxLength !== undefined && length > node.maxLength) out.push({ instancePath: at, message: `is longer than ${node.maxLength}` });
59
+ if (node.pattern !== undefined && !new RegExp(node.pattern, 'u').test(value)) out.push({ instancePath: at, message: `does not match ${node.pattern}` });
60
+ if (node.format !== undefined && !formatOk(node.format, value)) out.push({ instancePath: at, message: `is not a ${node.format}` });
61
+ }
62
+ if ((kind === 'integer' || kind === 'number') && node.minimum !== undefined && value < node.minimum) out.push({ instancePath: at, message: `is below ${node.minimum}` });
63
+ if (kind === 'array') {
64
+ if (value.length < (node.minItems ?? 0)) out.push({ instancePath: at, message: `has fewer than ${node.minItems} items` });
65
+ if (node.maxItems !== undefined && value.length > node.maxItems) out.push({ instancePath: at, message: `has more than ${node.maxItems} items` });
66
+ if (node.uniqueItems && value.some((item, i) => value.slice(0, i).some((other) => jsonEqual(item, other)))) out.push({ instancePath: at, message: 'has duplicate items' });
67
+ if (node.items !== undefined) value.forEach((item, i) => validate(node.items, item, `${at}/${i}`, out));
68
+ if (node.contains !== undefined) {
69
+ const matches = value.filter((item) => problemsOf(node.contains, item).length === 0).length;
70
+ if (matches < (node.minContains ?? 1)) out.push({ instancePath: at, message: `has fewer than ${node.minContains ?? 1} matching items` });
71
+ if (node.maxContains !== undefined && matches > node.maxContains) out.push({ instancePath: at, message: `has more than ${node.maxContains} matching items` });
72
+ }
73
+ }
74
+ if (kind === 'object') {
75
+ for (const name of node.required ?? []) if (!Object.hasOwn(value, name)) out.push({ instancePath: at, message: `must have ${name}` });
76
+ const properties = node.properties ?? {};
77
+ for (const [name, member] of Object.entries(value)) {
78
+ const where = `${at}/${pointer(name)}`;
79
+ if (Object.hasOwn(properties, name)) validate(properties[name], member, where, out);
80
+ else if (node.additionalProperties === false) out.push({ instancePath: where, message: 'is not a member of this object' });
81
+ else if (node.additionalProperties !== undefined) validate(node.additionalProperties, member, where, out);
82
+ if (node.propertyNames !== undefined) validate(node.propertyNames, name, where, out);
83
+ }
84
+ }
85
+ for (const sub of node.allOf ?? []) validate(sub, value, at, out);
86
+ if (node.not !== undefined && problemsOf(node.not, value).length === 0) out.push({ instancePath: at, message: 'must not match' });
87
+ if (node.if !== undefined) {
88
+ const branch = problemsOf(node.if, value).length === 0 ? node.then : node.else;
89
+ if (branch !== undefined) validate(branch, value, at, out);
90
+ }
91
+ }
92
+
93
+ export function problemsOf(node, value) {
94
+ const out = [];
95
+ validate(node, value, '', out);
96
+ return out;
97
+ }
98
+
99
+ /** Where the package breaks fabric-package.schema.json (the contract's, bundled at the pin). */
100
+ export const schemaProblems = (pkg) => problemsOf(schema(), pkg);
@@ -24,7 +24,6 @@ export const PLUGIN_MANIFEST = '.claude-plugin/plugin.json';
24
24
  export const SIGNATURE_STATEMENT = 'fabric-package-signature/1';
25
25
  /** DEC-0051: ES256 joins when Fabric records its decision D2; until then a verifier refuses it as unknown-algorithm. */
26
26
  export const PACKAGE_ALGORITHMS = Object.freeze(['EdDSA']);
27
- const SCHEMA_FILE = path.join(path.dirname(fileURLToPath(import.meta.url)), 'fabric-package.schema.json');
28
27
  // What pack refuses to list: version-control and cache litter, and files that are credentials by their name.
29
28
  const JUNK = /^(\.git|__pycache__|\.DS_Store|.*\.pyc)$/;
30
29
  const SECRET_FILE = /^(\.env(\..+)?|.*\.(pem|key|p12|pfx|jks|keystore)|id_(rsa|dsa|ecdsa|ed25519)|\.(npmrc|netrc|pypirc))$/;
@@ -125,95 +124,9 @@ export function readSigningKey(file, kid) {
125
124
  return { seed, kid };
126
125
  }
127
126
 
128
- // --- the schema (bundled from the contract at the pin) ---------------------------------------------------------------
127
+ export { schemaProblems } from './fabric-package-schema.mjs'; // the schema reading (FAA-92)
128
+ import { pointer, schema, schemaProblems } from './fabric-package-schema.mjs';
129
129
 
130
- let schemaCache;
131
- const schema = () => (schemaCache ??= JSON.parse(fs.readFileSync(SCHEMA_FILE, 'utf8')));
132
-
133
-
134
- const typeOf = (v) => (v === null ? 'null' : Array.isArray(v) ? 'array' : typeof v === 'number' ? (Number.isInteger(v) ? 'integer' : 'number') : typeof v);
135
- const DATE_TIME = /^([0-9]{4})-([0-9]{2})-([0-9]{2})[Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?([Zz]|[+-]([0-9]{2}):([0-9]{2}))$/;
136
- const MONTH_DAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
137
- const leap = (year) => year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
138
-
139
- function formatOk(format, value) {
140
- if (!isString(value)) return true;
141
- if (format === 'date-time') {
142
- const m = DATE_TIME.exec(value);
143
- if (!m) return false;
144
- const [y, mo, d, h, mi, s] = m.slice(1, 7).map(Number);
145
- // The proleptic calendar the contract's ajv-formats checks: year 0000 exists and is a leap year (0000-02-29 holds).
146
- // Counted here, not with Date.UTC, which reads years 0 to 99 as 1900 to 1999.
147
- if (mo < 1 || mo > 12 || d < 1 || d > (mo === 2 && leap(y) ? 29 : MONTH_DAYS[mo]) || h > 23 || mi > 59 || s > 59) return false;
148
- return m[8] === 'Z' || m[8] === 'z' || (Number(m[9]) < 24 && Number(m[10]) < 60);
149
- }
150
- if (format === 'uri') return /^[A-Za-z][A-Za-z0-9+.-]*:\S*$/.test(value);
151
- return true;
152
- }
153
-
154
- const pointer = (token) => String(token).replace(/~/g, '~0').replace(/\//g, '~1');
155
- const codePoints = (s) => [...s].length; // JSON Schema counts code points, not UTF-16 units
156
-
157
- function validate(node, value, at, out) {
158
- if (node === true) return;
159
- if (node === false) { out.push({ instancePath: at, message: 'is not allowed here' }); return; }
160
- if (node.$ref) {
161
- const target = node.$ref.replace(/^#\//, '').split('/').reduce((n, t) => n[t.replace(/~1/g, '/').replace(/~0/g, '~')], schema());
162
- validate(target, value, at, out);
163
- }
164
- const kind = typeOf(value);
165
- if (node.type !== undefined) {
166
- const allowed = Array.isArray(node.type) ? node.type : [node.type];
167
- if (!(allowed.includes(kind) || (kind === 'integer' && allowed.includes('number')))) { out.push({ instancePath: at, message: `must be ${allowed.join(' or ')}` }); return; }
168
- }
169
- if ('const' in node && !jsonEqual(node.const, value)) out.push({ instancePath: at, message: `must be ${JSON.stringify(node.const)}` });
170
- if (node.enum && !node.enum.some((item) => jsonEqual(item, value))) out.push({ instancePath: at, message: `must be one of ${node.enum.map((i) => JSON.stringify(i)).join(', ')}` });
171
- if (kind === 'string') {
172
- const length = codePoints(value);
173
- if (length < (node.minLength ?? 0)) out.push({ instancePath: at, message: `is shorter than ${node.minLength}` });
174
- if (node.maxLength !== undefined && length > node.maxLength) out.push({ instancePath: at, message: `is longer than ${node.maxLength}` });
175
- if (node.pattern !== undefined && !new RegExp(node.pattern, 'u').test(value)) out.push({ instancePath: at, message: `does not match ${node.pattern}` });
176
- if (node.format !== undefined && !formatOk(node.format, value)) out.push({ instancePath: at, message: `is not a ${node.format}` });
177
- }
178
- if ((kind === 'integer' || kind === 'number') && node.minimum !== undefined && value < node.minimum) out.push({ instancePath: at, message: `is below ${node.minimum}` });
179
- if (kind === 'array') {
180
- if (value.length < (node.minItems ?? 0)) out.push({ instancePath: at, message: `has fewer than ${node.minItems} items` });
181
- if (node.maxItems !== undefined && value.length > node.maxItems) out.push({ instancePath: at, message: `has more than ${node.maxItems} items` });
182
- if (node.uniqueItems && value.some((item, i) => value.slice(0, i).some((other) => jsonEqual(item, other)))) out.push({ instancePath: at, message: 'has duplicate items' });
183
- if (node.items !== undefined) value.forEach((item, i) => validate(node.items, item, `${at}/${i}`, out));
184
- if (node.contains !== undefined) {
185
- const matches = value.filter((item) => problemsOf(node.contains, item).length === 0).length;
186
- if (matches < (node.minContains ?? 1)) out.push({ instancePath: at, message: `has fewer than ${node.minContains ?? 1} matching items` });
187
- if (node.maxContains !== undefined && matches > node.maxContains) out.push({ instancePath: at, message: `has more than ${node.maxContains} matching items` });
188
- }
189
- }
190
- if (kind === 'object') {
191
- for (const name of node.required ?? []) if (!Object.hasOwn(value, name)) out.push({ instancePath: at, message: `must have ${name}` });
192
- const properties = node.properties ?? {};
193
- for (const [name, member] of Object.entries(value)) {
194
- const where = `${at}/${pointer(name)}`;
195
- if (Object.hasOwn(properties, name)) validate(properties[name], member, where, out);
196
- else if (node.additionalProperties === false) out.push({ instancePath: where, message: 'is not a member of this object' });
197
- else if (node.additionalProperties !== undefined) validate(node.additionalProperties, member, where, out);
198
- if (node.propertyNames !== undefined) validate(node.propertyNames, name, where, out);
199
- }
200
- }
201
- for (const sub of node.allOf ?? []) validate(sub, value, at, out);
202
- if (node.not !== undefined && problemsOf(node.not, value).length === 0) out.push({ instancePath: at, message: 'must not match' });
203
- if (node.if !== undefined) {
204
- const branch = problemsOf(node.if, value).length === 0 ? node.then : node.else;
205
- if (branch !== undefined) validate(branch, value, at, out);
206
- }
207
- }
208
-
209
- function problemsOf(node, value) {
210
- const out = [];
211
- validate(node, value, '', out);
212
- return out;
213
- }
214
-
215
- /** Where the package breaks fabric-package.schema.json (the contract's, bundled at the pin). */
216
- export const schemaProblems = (pkg) => problemsOf(schema(), pkg);
217
130
 
218
131
  // --- the contract's rules (FAC-SEM-064…066, FAC-SEM-102), ported line for line from src/package-rules.ts --------------
219
132
 
@@ -41,12 +41,12 @@ export const JWT_SHAPE = /eyJ[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]{2,}\.[A-Za-z0-9_-]
41
41
  /** A value that says it is a credential, or a provider key's shape. */
42
42
  export const SECRET_VALUE = /(^bearer\s.+|sk-[A-Za-z0-9_-]{16,}|gh[pousr]_[A-Za-z0-9]{20,}|xox[abposr]-[A-Za-z0-9-]{10,}|AKIA[0-9A-Z]{16}|glpat-[A-Za-z0-9_-]{20,})/i;
43
43
  const LONG_RUN = /[A-Za-z0-9+/=_-]{40,}/g;
44
- const longSecret = (value) => (value.match(LONG_RUN) ?? []).some((run) => /[a-z]/.test(run) && /[A-Z]/.test(run) && /[0-9]/.test(run));
44
+ export const longSecret = (value) => (value.match(LONG_RUN) ?? []).some((run) => /[a-z]/.test(run) && /[A-Z]/.test(run) && /[0-9]/.test(run));
45
45
 
46
46
  /** Whether a value could be a credential: a JWT anywhere, a provider key or `Bearer …`, or a long secret-shaped run. */
47
47
  export const secretValue = (value) => JWT_SHAPE.test(value) || SECRET_VALUE.test(value) || longSecret(value);
48
48
 
49
- const BEARER_INSIDE = /\bbearer\s+(?=[A-Za-z0-9._~+/-]*\d)[A-Za-z0-9._~+/-]{12,}=*/i;
49
+ export const BEARER_INSIDE = /\bbearer\s+(?=[A-Za-z0-9._~+/-]*\d)[A-Za-z0-9._~+/-]{12,}=*/i;
50
50
  const PATH_LIKE = /^(?:[/~.]|[A-Za-z]:[\\/]|[a-z][a-z0-9+.-]*:\/\/)/i;
51
51
  const pathLike = (piece) =>
52
52
  PATH_LIKE.test(piece) ||
@@ -40,6 +40,7 @@ export {
40
40
  feedDataFindings,
41
41
  feedDataProblems,
42
42
  } from './fabric-protocols.mjs';
43
+ export { CONNECTIONS_EXTENSION_KEY, connectionsExtension, connectionsRules, connectionsView } from './fabric-connections.mjs';
43
44
  export {
44
45
  EXIT_ALREADY_RUNNING,
45
46
  LOCK_WAIT_SUPERVISED_SECONDS,