@synadia-ai/agent-fabric-claude-code 0.1.0 → 0.3.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/hooks/hooks.json CHANGED
@@ -1,6 +1,15 @@
1
1
  {
2
2
  "hooks": {
3
3
  "SessionStart": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/session-event.js\"",
9
+ "timeout": 10
10
+ }
11
+ ]
12
+ },
4
13
  {
5
14
  "hooks": [
6
15
  {
@@ -10,6 +19,50 @@
10
19
  }
11
20
  ]
12
21
  }
22
+ ],
23
+ "Stop": [
24
+ {
25
+ "hooks": [
26
+ {
27
+ "type": "command",
28
+ "command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/session-event.js\"",
29
+ "timeout": 10
30
+ }
31
+ ]
32
+ }
33
+ ],
34
+ "UserPromptSubmit": [
35
+ {
36
+ "hooks": [
37
+ {
38
+ "type": "command",
39
+ "command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/session-event.js\"",
40
+ "timeout": 10
41
+ }
42
+ ]
43
+ }
44
+ ],
45
+ "StopFailure": [
46
+ {
47
+ "hooks": [
48
+ {
49
+ "type": "command",
50
+ "command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/session-event.js\"",
51
+ "timeout": 10
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "PreToolUse": [
57
+ {
58
+ "hooks": [
59
+ {
60
+ "type": "command",
61
+ "command": "bun \"${CLAUDE_PLUGIN_ROOT}/hooks/session-event.js\"",
62
+ "timeout": 10
63
+ }
64
+ ]
65
+ }
13
66
  ]
14
67
  }
15
68
  }
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ import{writeSync as _n}from"fs";import{homedir as yn}from"os";import{join as bn}from"path";import{appendFileSync as Z,existsSync as hn,mkdirSync as y,readdirSync as kn,readFileSync as A,renameSync as z,rmSync as B,writeFileSync as G}from"fs";import{join as a}from"path";var X=/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/,W=/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/,Q=["discover_agents","prompt_agent","wait_agent","answer_agent","cancel_agent","list_agent_calls"];function l(n){return typeof n==="string"&&X.test(n)}function K(n){return typeof n==="string"&&W.test(n)}function f(n){return a(n,"sessions")}function V(n,t){return a(f(n),String(t))}function w(n,t){return a(f(n),`${t}.stop`)}function E(n,t){return a(f(n),`${t}.nudge`)}function M(n,t){return a(f(n),`${t}.turn`)}function Y(n,t){return a(f(n),`${t}.open`)}function nn(n,t){return a(f(n),`${t}.tools`)}function T(n,t){return a(f(n),`${t}.events`)}function I(n,t){let e=`${n}.${process.pid}.tmp`;G(e,t),z(e,n)}var en=new RegExp(`^mcp__.+__(${Q.join("|")})$`);function tn(n){return en.test(n)}function q(n){if(!("background_tasks"in n)&&!("session_crons"in n))return;return N(n.background_tasks)||N(n.session_crons)}function N(n){if(n===void 0||n===null||n===!1||n===0||n==="")return!1;if(Array.isArray(n))return n.length>0;if(typeof n==="object")return Object.keys(n).length>0;return!0}var P=/^plugin:[^"]+:nats$/,v=/^[A-Za-z0-9_-]{1,64}$/,rn=1024,sn=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/,J=64,U=200;function on(n){if(typeof n!=="string"||!n.startsWith("<channel "))return;let t=n.indexOf(">");if(t<0||t>rn)return;let e=n.slice(0,t),r=/\ssource="([^"]*)"/.exec(e)?.[1],o=/\srequest_id="([^"]*)"/.exec(e)?.[1];if(r===void 0||o===void 0)return;if(!P.test(r)||!v.test(o))return;let s=/\sts="([^"]*)"/.exec(e)?.[1];return{requestId:o,source:r,...s!==void 0&&j(s)!==void 0?{ts:s}:{}}}function j(n){if(typeof n!=="string"||!sn.test(n))return;let t=Date.parse(n);return Number.isFinite(t)?t:void 0}function k(n,t){if(typeof n!=="string")return;let e=Array.from(n.replace(/[\u0000-\u001f\u007f]+/g," ").trim()).slice(0,t).join("");return e.length>0?e:void 0}function R(n,t,e){y(f(n),{recursive:!0}),Z(T(n,t),`${JSON.stringify(e)}
4
+ `)}function F(n,t,e,r=Date.now()){let o=e.hook_event_name,s=l(e.session_id)?e.session_id:void 0,i=l(e.prompt_id)?e.prompt_id:void 0;if(o==="UserPromptSubmit"){let d=on(e.prompt);return R(n,t,{event:"submit",...s?{session_id:s}:{},...i?{prompt_id:i}:{},...d?{request_id:d.requestId,source:d.source}:{},...d?.ts!==void 0?{ts:d.ts}:{},at_ms:r}),"submit"}if(o==="StopFailure"){let d=k(e.error,J),u=k(e.error_details,U);return R(n,t,{event:"failure",...s?{session_id:s}:{},...i?{prompt_id:i}:{},...d!==void 0?{error:d}:{},...u!==void 0?{error_details:u}:{},at_ms:r}),"failure"}if(o==="SessionStart"){if(s===void 0)return;let d=typeof e.source==="string"?e.source:"unknown";return y(f(n),{recursive:!0}),I(V(n,t),`${JSON.stringify({session_id:s,source:d,at_ms:r})}
5
+ `),"session"}if(o==="Stop"){let d=q(e),u=D(n,t,e),c=u===void 0||u.length>0?un(n,t)??H(e):void 0,m={...s?{session_id:s}:{},...d!==void 0?{background:d}:{},...c!==void 0?{final_text:c}:{},at_ms:r};return y(f(n),{recursive:!0}),I(w(n,t),`${JSON.stringify(m)}
6
+ `),R(n,t,{event:"stop",...i?{prompt_id:i}:{},...m}),ln(E(n,t)),"stop"}if(o==="PreToolUse"){let{tool_use_id:d,tool_name:u}=e;if(typeof u!=="string"||u.length===0)return;if(y(f(n),{recursive:!0}),dn(n,t,e.prompt_id,r),!tn(u)||!K(d))return"turn";let c=nn(n,t);return y(c,{recursive:!0}),I(a(c,d),`${JSON.stringify({tool_use_id:d,tool_name:u,tool_input:e.tool_input??null,...i?{prompt_id:i}:{},at_ms:r})}
7
+ `),"tool"}return}function dn(n,t,e,r){let o=l(e)?e:void 0,s=x(M(n,t)),i=g(s?.at_ms),d=g(s?.first_ms),u=g(x(w(n,t))?.at_ms),c=s!==void 0&&s.prompt_id===o&&i!==void 0&&d!==void 0&&(u===void 0||i>u);I(M(n,t),`${JSON.stringify({...o!==void 0?{prompt_id:o}:{},first_ms:c?d:r,at_ms:r})}
8
+ `)}function L(n,t,e){if(e.hook_event_name!=="Stop"||e.stop_hook_active===!0)return;if(q(e)!==!1)return;let r=D(n,t,e);if(r===void 0||r.length===0)return;let o=r.map((s)=>`"${s}"`).join(", ");return`The NATS channel ${r.length===1?"request":"requests"} ${o} ${r.length===1?"is":"are"} still open: the sender has not received an answer, and cannot see this session's own output. Send your answer with the reply tool (load it with ToolSearch if it is deferred), with the request_id and done: true.`}function C(n,t,e,r=Date.now()){let o=H(e);y(f(n),{recursive:!0}),I(E(n,t),`${JSON.stringify({...o!==void 0?{final_text:o}:{},at_ms:r})}
9
+ `)}function un(n,t){let e=x(E(n,t)),r=g(e?.at_ms);if(e===void 0||r===void 0)return;let o=g(x(w(n,t))?.at_ms);if(o!==void 0&&r<=o)return;let s=e.final_text;return typeof s==="string"&&s.length>0?s:void 0}function cn(n,t){let e=x(Y(n,t));if(!e)return;let r=e.server_pid,o=O(e.request_ids),s=e.open_ids===void 0?o:O(e.open_ids);if(typeof r!=="number"||!Number.isSafeInteger(r)||r<=0)return;if(o===void 0||s===void 0)return;if(!mn(r))return;let i=g(e.since_ms);return{requestIds:o,openIds:s,...i!==void 0?{sinceMs:i}:{}}}function O(n){return Array.isArray(n)&&n.every((t)=>typeof t==="string"&&v.test(t))?n:void 0}function D(n,t,e){let r=cn(n,t);if(r===void 0)return;let o=l(e.prompt_id)?e.prompt_id:void 0;if(o===void 0)return r.requestIds;let s=gn(n,t);if(!s.some((u)=>u.kind==="submit"&&u.submit.promptId!==void 0))return r.requestIds;let i=new Map,d;for(let u of s){if(u.kind!=="submit"||u.submit.requestId===void 0){d=void 0;continue}let{requestId:c,promptId:m,atMs:b,sentAtMs:_}=u.submit,S=d!==void 0&&b-d.atMs<=fn?d.promptIds:new Set;S.add(m);let p=r.sinceMs;if(p===void 0||b>=p&&(_??p)>=p)i.set(c,S);d={atMs:b,promptIds:S}}return r.openIds.filter((u)=>i.get(u)?.has(o)===!0)}var fn=30000;function H(n){if("last_assistant_message"in n){let i=n.last_assistant_message;return typeof i==="string"&&i.trim().length>0?i.trim():void 0}let t=n.transcript_path;if(typeof t!=="string"||t.length===0)return;let e;try{e=A(t,"utf8")}catch{return}let r,o=[];for(let i of e.split(`
10
+ `)){if(i.trim().length===0)continue;let d;try{d=JSON.parse(i)}catch{continue}if(typeof d!=="object"||d===null)continue;let{type:u,message:c,uuid:m}=d;if(u!=="assistant"||typeof c!=="object"||c===null)continue;let{id:b,content:_}=c,h=b??m;if(h===void 0||h!==r)r=h,o=[];if(typeof _==="string")o.push(_);else if(Array.isArray(_))for(let S of _){let p=S;if(p?.type==="text"&&typeof p.text==="string")o.push(p.text)}}let s=o.join(`
11
+ `).trim();return s.length>0?s:void 0}function x(n){let t;try{t=A(n,"utf8")}catch{return}try{let e=JSON.parse(t);return typeof e==="object"&&e!==null&&!Array.isArray(e)?e:void 0}catch{return}}function g(n){return typeof n==="number"&&Number.isSafeInteger(n)&&n>=0?n:void 0}function an(n){if(!n)return;let t=g(n.at_ms);if(t===void 0)return;return{...l(n.session_id)?{sessionId:n.session_id}:{},...l(n.prompt_id)?{promptId:n.prompt_id}:{},...typeof n.background==="boolean"?{background:n.background}:{},...typeof n.final_text==="string"&&n.final_text.length>0?{finalText:n.final_text}:{},atMs:t}}function pn(n){let t;try{t=JSON.parse(n)}catch{return}if(typeof t!=="object"||t===null||Array.isArray(t))return;let e=t,r=g(e.at_ms);if(r===void 0)return;let o={...l(e.session_id)?{sessionId:e.session_id}:{},...l(e.prompt_id)?{promptId:e.prompt_id}:{}};switch(e.event){case"submit":{let s=typeof e.request_id==="string"&&v.test(e.request_id)&&typeof e.source==="string"&&P.test(e.source)?{requestId:e.request_id,source:e.source}:{},i=s.requestId!==void 0?j(e.ts):void 0;return{kind:"submit",submit:{...o,...s,...i!==void 0?{sentAtMs:i}:{},atMs:r}}}case"stop":{let s=an(e);return s?{kind:"stop",stop:s}:void 0}case"failure":{let s=k(e.error,J),i=k(e.error_details,U);return{kind:"failure",failure:{...o,...s!==void 0?{error:s}:{},...i!==void 0?{errorDetails:i}:{},atMs:r}}}default:return}}function gn(n,t){let e;try{e=A(T(n,t),"utf8")}catch{return[]}let r=[],o=e.lastIndexOf(`
12
+ `);for(let s of e.slice(0,o+1).split(`
13
+ `)){if(s.length===0)continue;let i=pn(s);if(i)r.push(i)}return r}function ln(n){try{B(n,{recursive:!0,force:!0})}catch{}}function mn(n){try{return process.kill(n,0),!0}catch(t){return t.code==="EPERM"}}var Sn=5000;setTimeout(()=>process.exit(0),Sn).unref();async function In(){let n=[];for await(let t of process.stdin)n.push(Buffer.from(t));return Buffer.concat(n).toString("utf8")}try{let n=process.env.CLAUDE_PID;if(n!==void 0&&/^\d+$/.test(n)){let t=JSON.parse(await In());if(typeof t==="object"&&t!==null&&!Array.isArray(t)){let e=process.env.NATS_STATE_DIR??bn(yn(),".claude","channels","nats"),r=t,o=L(e,n,r);if(o!==void 0){try{C(e,n,r)}catch{}_n(1,`${JSON.stringify({decision:"block",reason:o})}
14
+ `)}else F(e,n,r)}}}catch{}process.exit(0);
package/package.json CHANGED
@@ -1,58 +1,15 @@
1
1
  {
2
2
  "name": "@synadia-ai/agent-fabric-claude-code",
3
- "version": "0.1.0",
4
- "description": "The Synadia Agent Fabric add-on for the Claude Code channel plugin: the fabric's tracing on the plugin's service and client, each served prompt bound to its Claude Code session by the signed served pair (end at the turn's Stop), and the loop guard, as one extension module the plugin loads.",
5
- "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "types": "./dist/index.d.ts",
12
- "import": "./dist/index.js",
13
- "require": "./dist/index.cjs",
14
- "default": "./dist/index.js"
15
- },
16
- "./package.json": "./package.json"
17
- },
18
- "files": [
19
- "dist",
20
- ".claude-plugin",
21
- "hooks",
22
- "skills",
23
- "README.md",
24
- "CHANGELOG.md",
25
- "LICENSE"
26
- ],
27
- "sideEffects": false,
28
- "engines": {
29
- "node": ">=20.0.0"
30
- },
31
- "scripts": {
32
- "build": "tsup",
33
- "build:sp": "sh ../scratchpad-skill/install.sh --dest skills/scratchpad --allowed-tools 'Bash(${CLAUDE_SKILL_DIR}/scripts/sp *)'",
34
- "typecheck": "tsc --noEmit",
35
- "lint": "eslint .",
36
- "lint:fix": "eslint . --fix",
37
- "format": "prettier --write .",
38
- "format:check": "prettier --check .",
39
- "test": "vitest run",
40
- "test:unit": "vitest run test/unit",
41
- "test:integration": "vitest run test/integration",
42
- "test:watch": "vitest",
43
- "check": "npm run typecheck && npm run lint && npm run format:check && npm run test",
44
- "prepack": "npm run build:sp",
45
- "prepublishOnly": "npm run build"
46
- },
3
+ "version": "0.3.0",
4
+ "description": "Claude Code on the Synadia Agent Fabric: the NATS channel plugin for Claude Code with the fabric's tracing and ScratchPad, in one plugin",
47
5
  "keywords": [
48
- "nats",
49
- "ai",
50
- "agents",
51
- "agent-fabric",
52
- "tracing",
53
6
  "claude-code",
54
- "synadia",
55
- "sdk"
7
+ "claude-code-plugin",
8
+ "nats",
9
+ "agent",
10
+ "channel",
11
+ "synadia-agent-protocol",
12
+ "synadia-agent-fabric"
56
13
  ],
57
14
  "license": "Apache-2.0",
58
15
  "author": "Synadia Communications",
@@ -61,29 +18,23 @@
61
18
  "url": "git+https://github.com/synadia-ai/agent-fabric-sdk.git",
62
19
  "directory": "plugins/claude-code"
63
20
  },
64
- "homepage": "https://github.com/synadia-ai/agent-fabric-sdk/tree/main/plugins/claude-code",
65
- "bugs": {
66
- "url": "https://github.com/synadia-ai/agent-fabric-sdk/issues"
21
+ "type": "module",
22
+ "main": "./runtime/fabric.js",
23
+ "exports": {
24
+ ".": "./runtime/fabric.js",
25
+ "./package.json": "./package.json"
67
26
  },
27
+ "files": [
28
+ ".claude-plugin",
29
+ ".mcp.json",
30
+ "runtime",
31
+ "hooks",
32
+ "skills",
33
+ "BUILD",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
68
37
  "publishConfig": {
69
38
  "access": "public"
70
- },
71
- "dependencies": {
72
- "@synadia-ai/agent-fabric": "^0.1.0",
73
- "@synadia-ai/agent-service": "^0.6.0",
74
- "@synadia-ai/agents": "^0.6.0"
75
- },
76
- "devDependencies": {
77
- "@nats-io/nats-core": "^3.4.0",
78
- "@nats-io/transport-node": "^3.4.0",
79
- "@types/node": "^20.16.0",
80
- "ajv": "^8.17.0",
81
- "eslint": "^9.0.0",
82
- "eslint-config-prettier": "^9.1.0",
83
- "prettier": "3.9.5",
84
- "tsup": "^8.3.0",
85
- "typescript": "~5.6.0",
86
- "typescript-eslint": "^8.10.0",
87
- "vitest": "^3.2.0"
88
39
  }
89
40
  }