@agimon-ai/doompi-team 0.0.1-alpha.44 → 0.0.1-alpha.45

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.
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src/adapters/teamCatalogApi.cjs");exports.TEAM_API_BASE_PATH=e.TEAM_API_BASE_PATH,exports.TEAM_CATALOG_ROUTE=e.TEAM_CATALOG_ROUTE,exports.api=e.api,exports.createTeamCatalogApi=e.createTeamCatalogApi;
@@ -0,0 +1,2 @@
1
+ import { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, TeamCatalogApiOptions, TeamCatalogSnapshot, api, createTeamCatalogApi } from "./src/adapters/teamCatalogApi.cjs";
2
+ export { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, type TeamCatalogApiOptions, type TeamCatalogSnapshot, api, createTeamCatalogApi };
@@ -0,0 +1,2 @@
1
+ import { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, TeamCatalogApiOptions, TeamCatalogSnapshot, api, createTeamCatalogApi } from "./src/adapters/teamCatalogApi.mjs";
2
+ export { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, type TeamCatalogApiOptions, type TeamCatalogSnapshot, api, createTeamCatalogApi };
@@ -0,0 +1 @@
1
+ import{TEAM_API_BASE_PATH as e,TEAM_CATALOG_ROUTE as t,api as n,createTeamCatalogApi as r}from"./src/adapters/teamCatalogApi.mjs";export{e as TEAM_API_BASE_PATH,t as TEAM_CATALOG_ROUTE,n as api,r as createTeamCatalogApi};
@@ -0,0 +1,2 @@
1
+ const e=require("./agents/discovery.cjs"),t=`team`;function n(t){let n=new e.AgentDiscoveryService,r=t.read??(t=>({agents:n.discover(t,`both`).agents,models:e.resolveActiveTeamModelSpecs()??[]}));return{fetch(e){let n=new URL(e.url);if(e.method!==`GET`||n.pathname!==`/catalog`)return Response.json({error:`Not found.`},{status:404});try{return Response.json(r(t.cwd))}catch(e){let t=e instanceof Error?e.message:String(e);return Response.json({error:t},{status:500})}},close:()=>void 0}}const r={basePath:t,start(e){return n({cwd:e.cwd??process.cwd()})}};exports.TEAM_API_BASE_PATH=t,exports.TEAM_CATALOG_ROUTE=`/catalog`,exports.api=r,exports.createTeamCatalogApi=n;
2
+ //# sourceMappingURL=teamCatalogApi.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teamCatalogApi.cjs","names":["AgentDiscoveryService","resolveActiveTeamModelSpecs"],"sources":["../../../src/adapters/teamCatalogApi.ts"],"sourcesContent":["import type { DoomApi, DoomApiHandler } from '@agimon-ai/doompi-extension-contracts/package-api';\nimport type { CatalogAgentInput } from '../services/webSubagentCatalog.ts';\nimport { AgentDiscoveryService, resolveActiveTeamModelSpecs } from './agents/discovery.ts';\n\nexport const TEAM_API_BASE_PATH = 'team';\nexport const TEAM_CATALOG_ROUTE = '/catalog';\n\nexport interface TeamCatalogSnapshot {\n agents: CatalogAgentInput[];\n models: string[];\n}\n\nexport interface TeamCatalogApiOptions {\n cwd: string;\n read?: (cwd: string) => TeamCatalogSnapshot;\n}\n\n/** Serves catalog discovery from the session process, which owns the active domain environment. */\nexport function createTeamCatalogApi(options: TeamCatalogApiOptions): DoomApiHandler {\n const discovery = new AgentDiscoveryService();\n const read =\n options.read ??\n ((cwd: string): TeamCatalogSnapshot => ({\n agents: discovery.discover(cwd, 'both').agents,\n models: resolveActiveTeamModelSpecs() ?? [],\n }));\n\n return {\n fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET' || url.pathname !== TEAM_CATALOG_ROUTE) {\n return Response.json({ error: 'Not found.' }, { status: 404 });\n }\n try {\n return Response.json(read(options.cwd));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return Response.json({ error: message }, { status: 500 });\n }\n },\n close: () => undefined,\n };\n}\n\n/** Session package API entry loaded by doompi-server. */\nexport const api: DoomApi = {\n basePath: TEAM_API_BASE_PATH,\n start(context) {\n return createTeamCatalogApi({ cwd: context.cwd ?? process.cwd() });\n },\n};\n"],"mappings":"0CAIa,EAAqB,OAclC,SAAgB,EAAqB,EAAgD,CACnF,IAAM,EAAY,IAAIA,EAAAA,sBAChB,EACJ,EAAQ,OACN,IAAsC,CACtC,OAAQ,EAAU,SAAS,EAAK,MAAM,CAAC,CAAC,OACxC,OAAQC,EAAAA,4BAA4B,GAAK,CAAC,CAC5C,IAEF,MAAO,CACL,MAAM,EAAS,CACb,IAAM,EAAM,IAAI,IAAI,EAAQ,GAAG,EAC/B,GAAI,EAAQ,SAAW,OAAS,EAAI,WAAA,WAClC,OAAO,SAAS,KAAK,CAAE,MAAO,YAAa,EAAG,CAAE,OAAQ,GAAI,CAAC,EAE/D,GAAI,CACF,OAAO,SAAS,KAAK,EAAK,EAAQ,GAAG,CAAC,CACxC,OAAS,EAAO,CACd,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,OAAO,SAAS,KAAK,CAAE,MAAO,CAAQ,EAAG,CAAE,OAAQ,GAAI,CAAC,CAC1D,CACF,EACA,UAAa,IAAA,EACf,CACF,CAGA,MAAa,EAAe,CAC1B,SAAU,EACV,MAAM,EAAS,CACb,OAAO,EAAqB,CAAE,IAAK,EAAQ,KAAO,QAAQ,IAAI,CAAE,CAAC,CACnE,CACF"}
@@ -0,0 +1,20 @@
1
+ import { CatalogAgentInput } from "../services/webSubagentCatalog.cjs";
2
+ import { DoomApi, DoomApiHandler } from "@agimon-ai/doompi-extension-contracts/package-api";
3
+ //#region src/adapters/teamCatalogApi.d.ts
4
+ declare const TEAM_API_BASE_PATH = "team";
5
+ declare const TEAM_CATALOG_ROUTE = "/catalog";
6
+ interface TeamCatalogSnapshot {
7
+ agents: CatalogAgentInput[];
8
+ models: string[];
9
+ }
10
+ interface TeamCatalogApiOptions {
11
+ cwd: string;
12
+ read?: (cwd: string) => TeamCatalogSnapshot;
13
+ }
14
+ /** Serves catalog discovery from the session process, which owns the active domain environment. */
15
+ declare function createTeamCatalogApi(options: TeamCatalogApiOptions): DoomApiHandler;
16
+ /** Session package API entry loaded by doompi-server. */
17
+ declare const api: DoomApi;
18
+ //#endregion
19
+ export { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, TeamCatalogApiOptions, TeamCatalogSnapshot, api, createTeamCatalogApi };
20
+ //# sourceMappingURL=teamCatalogApi.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teamCatalogApi.d.cts","names":[],"sources":["../../../src/adapters/teamCatalogApi.ts"],"mappings":";;;cAIa;cACA;UAEI;EACf,QAAQ;EACR;;UAGe;EACf;EACA,QAAQ,gBAAgB;;;iBAIV,qBAAqB,SAAS,wBAAwB;;cA2BzD,KAAK"}
@@ -0,0 +1,20 @@
1
+ import { CatalogAgentInput } from "../services/webSubagentCatalog.mjs";
2
+ import { DoomApi, DoomApiHandler } from "@agimon-ai/doompi-extension-contracts/package-api";
3
+ //#region src/adapters/teamCatalogApi.d.ts
4
+ declare const TEAM_API_BASE_PATH = "team";
5
+ declare const TEAM_CATALOG_ROUTE = "/catalog";
6
+ interface TeamCatalogSnapshot {
7
+ agents: CatalogAgentInput[];
8
+ models: string[];
9
+ }
10
+ interface TeamCatalogApiOptions {
11
+ cwd: string;
12
+ read?: (cwd: string) => TeamCatalogSnapshot;
13
+ }
14
+ /** Serves catalog discovery from the session process, which owns the active domain environment. */
15
+ declare function createTeamCatalogApi(options: TeamCatalogApiOptions): DoomApiHandler;
16
+ /** Session package API entry loaded by doompi-server. */
17
+ declare const api: DoomApi;
18
+ //#endregion
19
+ export { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, TeamCatalogApiOptions, TeamCatalogSnapshot, api, createTeamCatalogApi };
20
+ //# sourceMappingURL=teamCatalogApi.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teamCatalogApi.d.mts","names":[],"sources":["../../../src/adapters/teamCatalogApi.ts"],"mappings":";;;cAIa;cACA;UAEI;EACf,QAAQ;EACR;;UAGe;EACf;EACA,QAAQ,gBAAgB;;;iBAIV,qBAAqB,SAAS,wBAAwB;;cA2BzD,KAAK"}
@@ -0,0 +1,2 @@
1
+ import{AgentDiscoveryService as e,resolveActiveTeamModelSpecs as t}from"./agents/discovery.mjs";const n=`team`,r=`/catalog`;function i(n){let r=new e,i=n.read??(e=>({agents:r.discover(e,`both`).agents,models:t()??[]}));return{fetch(e){let t=new URL(e.url);if(e.method!==`GET`||t.pathname!==`/catalog`)return Response.json({error:`Not found.`},{status:404});try{return Response.json(i(n.cwd))}catch(e){let t=e instanceof Error?e.message:String(e);return Response.json({error:t},{status:500})}},close:()=>void 0}}const a={basePath:n,start(e){return i({cwd:e.cwd??process.cwd()})}};export{n as TEAM_API_BASE_PATH,r as TEAM_CATALOG_ROUTE,a as api,i as createTeamCatalogApi};
2
+ //# sourceMappingURL=teamCatalogApi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teamCatalogApi.mjs","names":[],"sources":["../../../src/adapters/teamCatalogApi.ts"],"sourcesContent":["import type { DoomApi, DoomApiHandler } from '@agimon-ai/doompi-extension-contracts/package-api';\nimport type { CatalogAgentInput } from '../services/webSubagentCatalog.ts';\nimport { AgentDiscoveryService, resolveActiveTeamModelSpecs } from './agents/discovery.ts';\n\nexport const TEAM_API_BASE_PATH = 'team';\nexport const TEAM_CATALOG_ROUTE = '/catalog';\n\nexport interface TeamCatalogSnapshot {\n agents: CatalogAgentInput[];\n models: string[];\n}\n\nexport interface TeamCatalogApiOptions {\n cwd: string;\n read?: (cwd: string) => TeamCatalogSnapshot;\n}\n\n/** Serves catalog discovery from the session process, which owns the active domain environment. */\nexport function createTeamCatalogApi(options: TeamCatalogApiOptions): DoomApiHandler {\n const discovery = new AgentDiscoveryService();\n const read =\n options.read ??\n ((cwd: string): TeamCatalogSnapshot => ({\n agents: discovery.discover(cwd, 'both').agents,\n models: resolveActiveTeamModelSpecs() ?? [],\n }));\n\n return {\n fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET' || url.pathname !== TEAM_CATALOG_ROUTE) {\n return Response.json({ error: 'Not found.' }, { status: 404 });\n }\n try {\n return Response.json(read(options.cwd));\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return Response.json({ error: message }, { status: 500 });\n }\n },\n close: () => undefined,\n };\n}\n\n/** Session package API entry loaded by doompi-server. */\nexport const api: DoomApi = {\n basePath: TEAM_API_BASE_PATH,\n start(context) {\n return createTeamCatalogApi({ cwd: context.cwd ?? process.cwd() });\n },\n};\n"],"mappings":"gGAIA,MAAa,EAAqB,OACrB,EAAqB,WAalC,SAAgB,EAAqB,EAAgD,CACnF,IAAM,EAAY,IAAI,EAChB,EACJ,EAAQ,OACN,IAAsC,CACtC,OAAQ,EAAU,SAAS,EAAK,MAAM,CAAC,CAAC,OACxC,OAAQ,EAA4B,GAAK,CAAC,CAC5C,IAEF,MAAO,CACL,MAAM,EAAS,CACb,IAAM,EAAM,IAAI,IAAI,EAAQ,GAAG,EAC/B,GAAI,EAAQ,SAAW,OAAS,EAAI,WAAA,WAClC,OAAO,SAAS,KAAK,CAAE,MAAO,YAAa,EAAG,CAAE,OAAQ,GAAI,CAAC,EAE/D,GAAI,CACF,OAAO,SAAS,KAAK,EAAK,EAAQ,GAAG,CAAC,CACxC,OAAS,EAAO,CACd,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,OAAO,SAAS,KAAK,CAAE,MAAO,CAAQ,EAAG,CAAE,OAAQ,GAAI,CAAC,CAC1D,CACF,EACA,UAAa,IAAA,EACf,CACF,CAGA,MAAa,EAAe,CAC1B,SAAU,EACV,MAAM,EAAS,CACb,OAAO,EAAqB,CAAE,IAAK,EAAQ,KAAO,QAAQ,IAAI,CAAE,CAAC,CACnE,CACF"}
@@ -1,2 +1,2 @@
1
- const e=require("./agents/discovery.cjs"),t=require("../services/webSubagentCatalog.cjs"),n=require("../types/webSubagents.cjs");function r(){let t=new e.AgentDiscoveryService;return n=>({agents:t.discover(n,`both`).agents,models:e.resolveActiveTeamModelSpecs()??[]})}function i(e=r(),i=15e3){return{frameType:n.SUBAGENT_CATALOG_TYPE,start(n){let r=new Map,a=new Map,o=n=>{try{let{agents:r,models:i}=e(n.cwd);return{cwd:n.cwd,agents:t.presentCatalog(r),models:t.catalogModels(r,i)}}catch(e){let t=e instanceof Error?e.message:String(e);return{cwd:n.cwd,agents:[],models:[],warning:t}}},s=(e,t)=>{let r=o(e),i=JSON.stringify(r);return a.get(e.sessionId)===i?r:(a.set(e.sessionId,i),r.warning!==void 0&&n.onNotice(`subagent catalog for ${e.cwd} is unavailable (${r.warning})`),t&&n.publish(e.sessionId,r),r)},c=setInterval(()=>{for(let e of r.values())s(e,!0)},i);return{payloadFor(e){return r.has(e.sessionId)?s(e,!1):void 0},sessionAdded(e){r.set(e.sessionId,e),s(e,!0)},sessionRemoved(e){r.delete(e),a.delete(e)},close(){clearInterval(c),r.clear(),a.clear()}}}}}exports.createSubagentCatalogChannel=i,exports.defaultCatalogReader=r;
1
+ const e=require("./agents/discovery.cjs"),t=require("./teamCatalogApi.cjs"),n=require("../services/webSubagentCatalog.cjs"),r=require("../types/webSubagents.cjs");function i(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function a(e){if(!i(e)||!Array.isArray(e.agents)||!e.agents.every(i)||!Array.isArray(e.models))throw Error(`Session catalog API returned an invalid payload.`);return{agents:e.agents,models:e.models.filter(e=>typeof e==`string`)}}async function o(e,n,r,o){let s=await e.requestSessionApi(n,{basePath:t.TEAM_API_BASE_PATH,path:t.TEAM_CATALOG_ROUTE,method:`GET`,signal:r});if(s.status===404)return await o(n.cwd);let c=await s.json();if(!s.ok){let e=i(c)&&typeof c.error==`string`?c.error:`HTTP ${String(s.status)}`;throw Error(`Session catalog API failed: ${e}`)}return a(c)}function s(t,i=15e3){return{frameType:r.SUBAGENT_CATALOG_TYPE,start(r){let a=new Map,s=new Map,c=new Map,l=new Map,u=new AbortController,d=new e.AgentDiscoveryService,f=t=>({agents:d.discover(t,`both`).agents,models:e.resolveActiveTeamModelSpecs()??[]}),p=!1,m=(e,t,n)=>{let i=a.get(e.sessionId);if(p||i?.cwd!==e.cwd||l.get(e.sessionId)!==t)return;let o=JSON.stringify(n);s.get(e.sessionId)!==o&&(s.set(e.sessionId,o),c.set(e.sessionId,n),n.warning!==void 0&&r.onNotice(`subagent catalog for ${e.cwd} is unavailable (${n.warning})`),r.publish(e.sessionId,n))},h=async e=>{let i=(l.get(e.sessionId)??0)+1;l.set(e.sessionId,i);try{let a=await(t===void 0?o(r,e,u.signal,f):t(e.cwd));m(e,i,{cwd:e.cwd,agents:n.presentCatalog(a.agents),models:n.catalogModels(a.agents,a.models)})}catch(t){if(p||u.signal.aborted)return;let n=t instanceof Error?t.message:String(t);m(e,i,{cwd:e.cwd,agents:[],models:[],warning:n})}},g=setInterval(()=>{for(let e of a.values())h(e)},i);return{payloadFor(e){if(a.has(e.sessionId))return h(e),c.get(e.sessionId)},sessionAdded(e){a.set(e.sessionId,e),h(e)},sessionRemoved(e){a.delete(e),s.delete(e),c.delete(e),l.delete(e)},close(){p=!0,u.abort(),clearInterval(g),a.clear(),s.clear(),c.clear(),l.clear()}}}}}exports.createSubagentCatalogChannel=s;
2
2
  //# sourceMappingURL=webSubagentCatalogChannel.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"webSubagentCatalogChannel.cjs","names":["AgentDiscoveryService","resolveActiveTeamModelSpecs","SUBAGENT_CATALOG_TYPE","presentCatalog","catalogModels"],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"sourcesContent":["import type { HubChannelSource, HubSessionScope, WebHubChannel } from '@agimon-ai/doompi-web-contracts';\nimport { type CatalogAgentInput, catalogModels, presentCatalog } from '../services/webSubagentCatalog.ts';\nimport { SUBAGENT_CATALOG_TYPE, type SubagentCatalogPayload } from '../types/webSubagents.ts';\nimport { AgentDiscoveryService, resolveActiveTeamModelSpecs } from './agents/discovery.ts';\n\n/** Agent files change rarely; discovery's own cache makes each look cheap. */\nconst CATALOG_REFRESH_MS = 15_000;\n\n/** Reads the launchable agents for one directory; injectable so a test needs no agent files on disk. */\nexport type CatalogReader = (cwd: string) => { agents: CatalogAgentInput[]; models: string[] };\n\nexport function defaultCatalogReader(): CatalogReader {\n const discovery = new AgentDiscoveryService();\n return (cwd) => ({\n agents: discovery.discover(cwd, 'both').agents,\n models: resolveActiveTeamModelSpecs() ?? [],\n });\n}\n\n/**\n * The subagent catalog data channel: what each managed session's directory\n * can launch, published as 'subagent_catalog' payloads. Discovery runs once\n * per session on arrival, again at every subscribe, and on a slow tick so an\n * agent file written while the page is open shows up without a reload. A\n * failed read publishes an empty list with the reason rather than nothing.\n */\nexport function createSubagentCatalogChannel(\n read: CatalogReader = defaultCatalogReader(),\n refreshMs = CATALOG_REFRESH_MS,\n): WebHubChannel {\n return {\n frameType: SUBAGENT_CATALOG_TYPE,\n start(host) {\n const scopes = new Map<string, HubSessionScope>();\n const latest = new Map<string, string>();\n\n const compute = (scope: HubSessionScope): SubagentCatalogPayload => {\n try {\n const { agents, models } = read(scope.cwd);\n return { cwd: scope.cwd, agents: presentCatalog(agents), models: catalogModels(agents, models) };\n } catch (error) {\n const warning = error instanceof Error ? error.message : String(error);\n return { cwd: scope.cwd, agents: [], models: [], warning };\n }\n };\n\n /** Recomputes and remembers; publishes only what changed, so the tick stays quiet. */\n const refresh = (scope: HubSessionScope, publish: boolean): SubagentCatalogPayload => {\n const payload = compute(scope);\n const json = JSON.stringify(payload);\n if (latest.get(scope.sessionId) === json) return payload;\n latest.set(scope.sessionId, json);\n if (payload.warning !== undefined) {\n host.onNotice(`subagent catalog for ${scope.cwd} is unavailable (${payload.warning})`);\n }\n if (publish) host.publish(scope.sessionId, payload);\n return payload;\n };\n\n const timer = setInterval(() => {\n for (const scope of scopes.values()) refresh(scope, true);\n }, refreshMs);\n\n const source: HubChannelSource = {\n payloadFor(scope) {\n // The snapshot travels on its own, so a fresh read is remembered but not also published.\n return scopes.has(scope.sessionId) ? refresh(scope, false) : undefined;\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n refresh(scope, true);\n },\n sessionRemoved(sessionId) {\n scopes.delete(sessionId);\n latest.delete(sessionId);\n },\n close() {\n clearInterval(timer);\n scopes.clear();\n latest.clear();\n },\n };\n return source;\n },\n };\n}\n"],"mappings":"iIAWA,SAAgB,GAAsC,CACpD,IAAM,EAAY,IAAIA,EAAAA,sBACtB,MAAQ,KAAS,CACf,OAAQ,EAAU,SAAS,EAAK,MAAM,CAAC,CAAC,OACxC,OAAQC,EAAAA,4BAA4B,GAAK,CAAC,CAC5C,EACF,CASA,SAAgB,EACd,EAAsB,EAAqB,EAC3C,EAAY,KACG,CACf,MAAO,CACL,UAAWC,EAAAA,sBACX,MAAM,EAAM,CACV,IAAM,EAAS,IAAI,IACb,EAAS,IAAI,IAEb,EAAW,GAAmD,CAClE,GAAI,CACF,GAAM,CAAE,SAAQ,UAAW,EAAK,EAAM,GAAG,EACzC,MAAO,CAAE,IAAK,EAAM,IAAK,OAAQC,EAAAA,eAAe,CAAM,EAAG,OAAQC,EAAAA,cAAc,EAAQ,CAAM,CAAE,CACjG,OAAS,EAAO,CACd,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,MAAO,CAAE,IAAK,EAAM,IAAK,OAAQ,CAAC,EAAG,OAAQ,CAAC,EAAG,SAAQ,CAC3D,CACF,EAGM,GAAW,EAAwB,IAA6C,CACpF,IAAM,EAAU,EAAQ,CAAK,EACvB,EAAO,KAAK,UAAU,CAAO,EAOnC,OANI,EAAO,IAAI,EAAM,SAAS,IAAM,EAAa,GACjD,EAAO,IAAI,EAAM,UAAW,CAAI,EAC5B,EAAQ,UAAY,IAAA,IACtB,EAAK,SAAS,wBAAwB,EAAM,IAAI,mBAAmB,EAAQ,QAAQ,EAAE,EAEnF,GAAS,EAAK,QAAQ,EAAM,UAAW,CAAO,EAC3C,EACT,EAEM,EAAQ,gBAAkB,CAC9B,IAAK,IAAM,KAAS,EAAO,OAAO,EAAG,EAAQ,EAAO,EAAI,CAC1D,EAAG,CAAS,EAqBZ,MAAO,CAlBL,WAAW,EAAO,CAEhB,OAAO,EAAO,IAAI,EAAM,SAAS,EAAI,EAAQ,EAAO,EAAK,EAAI,IAAA,EAC/D,EACA,aAAa,EAAO,CAClB,EAAO,IAAI,EAAM,UAAW,CAAK,EACjC,EAAQ,EAAO,EAAI,CACrB,EACA,eAAe,EAAW,CACxB,EAAO,OAAO,CAAS,EACvB,EAAO,OAAO,CAAS,CACzB,EACA,OAAQ,CACN,cAAc,CAAK,EACnB,EAAO,MAAM,EACb,EAAO,MAAM,CACf,CAEU,CACd,CACF,CACF"}
1
+ {"version":3,"file":"webSubagentCatalogChannel.cjs","names":["TEAM_API_BASE_PATH","TEAM_CATALOG_ROUTE","SUBAGENT_CATALOG_TYPE","AgentDiscoveryService","resolveActiveTeamModelSpecs","presentCatalog","catalogModels"],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"sourcesContent":["import type { HubChannelHost, HubChannelSource, HubSessionScope, WebHubChannel } from '@agimon-ai/doompi-web-contracts';\nimport { type CatalogAgentInput, catalogModels, presentCatalog } from '../services/webSubagentCatalog.ts';\nimport { SUBAGENT_CATALOG_TYPE, type SubagentCatalogPayload } from '../types/webSubagents.ts';\nimport { AgentDiscoveryService, resolveActiveTeamModelSpecs } from './agents/discovery.ts';\nimport { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, type TeamCatalogSnapshot } from './teamCatalogApi.ts';\n\n/** Agent files change rarely; discovery's own cache makes each look cheap. */\nconst CATALOG_REFRESH_MS = 15_000;\n\n/** Injectable catalog read for tests and alternate hosts. Production reads through the session API. */\nexport type CatalogReader = (cwd: string) => TeamCatalogSnapshot | Promise<TeamCatalogSnapshot>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseCatalogSnapshot(value: unknown): TeamCatalogSnapshot {\n if (\n !isRecord(value) ||\n !Array.isArray(value.agents) ||\n !value.agents.every(isRecord) ||\n !Array.isArray(value.models)\n ) {\n throw new Error('Session catalog API returned an invalid payload.');\n }\n return {\n agents: value.agents as unknown as CatalogAgentInput[],\n models: value.models.filter((model): model is string => typeof model === 'string'),\n };\n}\n\nasync function readSessionCatalog(\n host: HubChannelHost,\n scope: HubSessionScope,\n signal: AbortSignal,\n fallback: CatalogReader,\n): Promise<TeamCatalogSnapshot> {\n const response = await host.requestSessionApi(scope, {\n basePath: TEAM_API_BASE_PATH,\n path: TEAM_CATALOG_ROUTE,\n method: 'GET',\n signal,\n });\n if (response.status === 404) return await fallback(scope.cwd);\n const payload: unknown = await response.json();\n if (!response.ok) {\n const reason =\n isRecord(payload) && typeof payload.error === 'string' ? payload.error : `HTTP ${String(response.status)}`;\n throw new Error(`Session catalog API failed: ${reason}`);\n }\n return parseCatalogSnapshot(payload);\n}\n\n/**\n * The subagent catalog data channel: what each managed session can launch.\n *\n * Discovery runs inside the session API because that process owns the active\n * domain projection and its plugin agent directories. The hub refreshes and\n * publishes that result, with local discovery only for older sessions lacking\n * the API route.\n */\nexport function createSubagentCatalogChannel(read?: CatalogReader, refreshMs = CATALOG_REFRESH_MS): WebHubChannel {\n return {\n frameType: SUBAGENT_CATALOG_TYPE,\n start(host) {\n const scopes = new Map<string, HubSessionScope>();\n const latestJson = new Map<string, string>();\n const latestPayload = new Map<string, SubagentCatalogPayload>();\n const generations = new Map<string, number>();\n const abort = new AbortController();\n const fallbackDiscovery = new AgentDiscoveryService();\n const fallback: CatalogReader = (cwd) => ({\n agents: fallbackDiscovery.discover(cwd, 'both').agents,\n models: resolveActiveTeamModelSpecs() ?? [],\n });\n let closed = false;\n\n const commit = (scope: HubSessionScope, generation: number, payload: SubagentCatalogPayload): void => {\n const active = scopes.get(scope.sessionId);\n if (closed || active?.cwd !== scope.cwd || generations.get(scope.sessionId) !== generation) return;\n const json = JSON.stringify(payload);\n if (latestJson.get(scope.sessionId) === json) return;\n latestJson.set(scope.sessionId, json);\n latestPayload.set(scope.sessionId, payload);\n if (payload.warning !== undefined) {\n host.onNotice(`subagent catalog for ${scope.cwd} is unavailable (${payload.warning})`);\n }\n host.publish(scope.sessionId, payload);\n };\n\n const refresh = async (scope: HubSessionScope): Promise<void> => {\n const generation = (generations.get(scope.sessionId) ?? 0) + 1;\n generations.set(scope.sessionId, generation);\n try {\n const snapshot = await (read === undefined\n ? readSessionCatalog(host, scope, abort.signal, fallback)\n : read(scope.cwd));\n commit(scope, generation, {\n cwd: scope.cwd,\n agents: presentCatalog(snapshot.agents),\n models: catalogModels(snapshot.agents, snapshot.models),\n });\n } catch (error) {\n if (closed || abort.signal.aborted) return;\n const warning = error instanceof Error ? error.message : String(error);\n commit(scope, generation, { cwd: scope.cwd, agents: [], models: [], warning });\n }\n };\n\n const timer = setInterval(() => {\n for (const scope of scopes.values()) void refresh(scope);\n }, refreshMs);\n\n const source: HubChannelSource = {\n payloadFor(scope) {\n if (!scopes.has(scope.sessionId)) return undefined;\n void refresh(scope);\n return latestPayload.get(scope.sessionId);\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n void refresh(scope);\n },\n sessionRemoved(sessionId) {\n scopes.delete(sessionId);\n latestJson.delete(sessionId);\n latestPayload.delete(sessionId);\n generations.delete(sessionId);\n },\n close() {\n closed = true;\n abort.abort();\n clearInterval(timer);\n scopes.clear();\n latestJson.clear();\n latestPayload.clear();\n generations.clear();\n },\n };\n return source;\n },\n };\n}\n"],"mappings":"mKAYA,SAAS,EAAS,EAAkD,CAClE,OAAO,OAAO,GAAU,YAAY,GAAkB,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAEA,SAAS,EAAqB,EAAqC,CACjE,GACE,CAAC,EAAS,CAAK,GACf,CAAC,MAAM,QAAQ,EAAM,MAAM,GAC3B,CAAC,EAAM,OAAO,MAAM,CAAQ,GAC5B,CAAC,MAAM,QAAQ,EAAM,MAAM,EAE3B,MAAU,MAAM,kDAAkD,EAEpE,MAAO,CACL,OAAQ,EAAM,OACd,OAAQ,EAAM,OAAO,OAAQ,GAA2B,OAAO,GAAU,QAAQ,CACnF,CACF,CAEA,eAAe,EACb,EACA,EACA,EACA,EAC8B,CAC9B,IAAM,EAAW,MAAM,EAAK,kBAAkB,EAAO,CACnD,SAAUA,EAAAA,mBACV,KAAMC,EAAAA,mBACN,OAAQ,MACR,QACF,CAAC,EACD,GAAI,EAAS,SAAW,IAAK,OAAO,MAAM,EAAS,EAAM,GAAG,EAC5D,IAAM,EAAmB,MAAM,EAAS,KAAK,EAC7C,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EACJ,EAAS,CAAO,GAAK,OAAO,EAAQ,OAAU,SAAW,EAAQ,MAAQ,QAAQ,OAAO,EAAS,MAAM,IACzG,MAAU,MAAM,+BAA+B,GAAQ,CACzD,CACA,OAAO,EAAqB,CAAO,CACrC,CAUA,SAAgB,EAA6B,EAAsB,EAAY,KAAmC,CAChH,MAAO,CACL,UAAWC,EAAAA,sBACX,MAAM,EAAM,CACV,IAAM,EAAS,IAAI,IACb,EAAa,IAAI,IACjB,EAAgB,IAAI,IACpB,EAAc,IAAI,IAClB,EAAQ,IAAI,gBACZ,EAAoB,IAAIC,EAAAA,sBACxB,EAA2B,IAAS,CACxC,OAAQ,EAAkB,SAAS,EAAK,MAAM,CAAC,CAAC,OAChD,OAAQC,EAAAA,4BAA4B,GAAK,CAAC,CAC5C,GACI,EAAS,GAEP,GAAU,EAAwB,EAAoB,IAA0C,CACpG,IAAM,EAAS,EAAO,IAAI,EAAM,SAAS,EACzC,GAAI,GAAU,GAAQ,MAAQ,EAAM,KAAO,EAAY,IAAI,EAAM,SAAS,IAAM,EAAY,OAC5F,IAAM,EAAO,KAAK,UAAU,CAAO,EAC/B,EAAW,IAAI,EAAM,SAAS,IAAM,IACxC,EAAW,IAAI,EAAM,UAAW,CAAI,EACpC,EAAc,IAAI,EAAM,UAAW,CAAO,EACtC,EAAQ,UAAY,IAAA,IACtB,EAAK,SAAS,wBAAwB,EAAM,IAAI,mBAAmB,EAAQ,QAAQ,EAAE,EAEvF,EAAK,QAAQ,EAAM,UAAW,CAAO,EACvC,EAEM,EAAU,KAAO,IAA0C,CAC/D,IAAM,GAAc,EAAY,IAAI,EAAM,SAAS,GAAK,GAAK,EAC7D,EAAY,IAAI,EAAM,UAAW,CAAU,EAC3C,GAAI,CACF,IAAM,EAAW,MAAO,IAAS,IAAA,GAC7B,EAAmB,EAAM,EAAO,EAAM,OAAQ,CAAQ,EACtD,EAAK,EAAM,GAAG,GAClB,EAAO,EAAO,EAAY,CACxB,IAAK,EAAM,IACX,OAAQC,EAAAA,eAAe,EAAS,MAAM,EACtC,OAAQC,EAAAA,cAAc,EAAS,OAAQ,EAAS,MAAM,CACxD,CAAC,CACH,OAAS,EAAO,CACd,GAAI,GAAU,EAAM,OAAO,QAAS,OACpC,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,EAAO,EAAO,EAAY,CAAE,IAAK,EAAM,IAAK,OAAQ,CAAC,EAAG,OAAQ,CAAC,EAAG,SAAQ,CAAC,CAC/E,CACF,EAEM,EAAQ,gBAAkB,CAC9B,IAAK,IAAM,KAAS,EAAO,OAAO,EAAG,EAAa,CAAK,CACzD,EAAG,CAAS,EA4BZ,MAAO,CAzBL,WAAW,EAAO,CACX,KAAO,IAAI,EAAM,SAAS,EAE/B,OADA,EAAa,CAAK,EACX,EAAc,IAAI,EAAM,SAAS,CAC1C,EACA,aAAa,EAAO,CAClB,EAAO,IAAI,EAAM,UAAW,CAAK,EACjC,EAAa,CAAK,CACpB,EACA,eAAe,EAAW,CACxB,EAAO,OAAO,CAAS,EACvB,EAAW,OAAO,CAAS,EAC3B,EAAc,OAAO,CAAS,EAC9B,EAAY,OAAO,CAAS,CAC9B,EACA,OAAQ,CACN,EAAS,GACT,EAAM,MAAM,EACZ,cAAc,CAAK,EACnB,EAAO,MAAM,EACb,EAAW,MAAM,EACjB,EAAc,MAAM,EACpB,EAAY,MAAM,CACpB,CAEU,CACd,CACF,CACF"}
@@ -1,17 +1,15 @@
1
- import { CatalogAgentInput } from "../services/webSubagentCatalog.cjs";
1
+ import { TeamCatalogSnapshot } from "./teamCatalogApi.cjs";
2
2
  import { WebHubChannel } from "@agimon-ai/doompi-web-contracts";
3
3
  //#region src/adapters/webSubagentCatalogChannel.d.ts
4
- /** Reads the launchable agents for one directory; injectable so a test needs no agent files on disk. */
5
- type CatalogReader = (cwd: string) => {
6
- agents: CatalogAgentInput[];
7
- models: string[];
8
- };
4
+ /** Injectable catalog read for tests and alternate hosts. Production reads through the session API. */
5
+ type CatalogReader = (cwd: string) => TeamCatalogSnapshot | Promise<TeamCatalogSnapshot>;
9
6
  /**
10
- * The subagent catalog data channel: what each managed session's directory
11
- * can launch, published as 'subagent_catalog' payloads. Discovery runs once
12
- * per session on arrival, again at every subscribe, and on a slow tick so an
13
- * agent file written while the page is open shows up without a reload. A
14
- * failed read publishes an empty list with the reason rather than nothing.
7
+ * The subagent catalog data channel: what each managed session can launch.
8
+ *
9
+ * Discovery runs inside the session API because that process owns the active
10
+ * domain projection and its plugin agent directories. The hub refreshes and
11
+ * publishes that result, with local discovery only for older sessions lacking
12
+ * the API route.
15
13
  */
16
14
  declare function createSubagentCatalogChannel(read?: CatalogReader, refreshMs?: number): WebHubChannel;
17
15
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"webSubagentCatalogChannel.d.cts","names":[],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"mappings":";;;;KASY,iBAAiB;EAAkB,QAAQ;EAAqB;;;;;;;;;iBAiB5D,6BACd,OAAM,eACN,qBACC"}
1
+ {"version":3,"file":"webSubagentCatalogChannel.d.cts","names":[],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"mappings":";;;;KAUY,iBAAiB,gBAAgB,sBAAsB,QAAQ;;;;;;;;;iBAmD3D,6BAA6B,OAAO,eAAe,qBAAiC"}
@@ -1,17 +1,15 @@
1
- import { CatalogAgentInput } from "../services/webSubagentCatalog.mjs";
1
+ import { TeamCatalogSnapshot } from "./teamCatalogApi.mjs";
2
2
  import { WebHubChannel } from "@agimon-ai/doompi-web-contracts";
3
3
  //#region src/adapters/webSubagentCatalogChannel.d.ts
4
- /** Reads the launchable agents for one directory; injectable so a test needs no agent files on disk. */
5
- type CatalogReader = (cwd: string) => {
6
- agents: CatalogAgentInput[];
7
- models: string[];
8
- };
4
+ /** Injectable catalog read for tests and alternate hosts. Production reads through the session API. */
5
+ type CatalogReader = (cwd: string) => TeamCatalogSnapshot | Promise<TeamCatalogSnapshot>;
9
6
  /**
10
- * The subagent catalog data channel: what each managed session's directory
11
- * can launch, published as 'subagent_catalog' payloads. Discovery runs once
12
- * per session on arrival, again at every subscribe, and on a slow tick so an
13
- * agent file written while the page is open shows up without a reload. A
14
- * failed read publishes an empty list with the reason rather than nothing.
7
+ * The subagent catalog data channel: what each managed session can launch.
8
+ *
9
+ * Discovery runs inside the session API because that process owns the active
10
+ * domain projection and its plugin agent directories. The hub refreshes and
11
+ * publishes that result, with local discovery only for older sessions lacking
12
+ * the API route.
15
13
  */
16
14
  declare function createSubagentCatalogChannel(read?: CatalogReader, refreshMs?: number): WebHubChannel;
17
15
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"webSubagentCatalogChannel.d.mts","names":[],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"mappings":";;;;KASY,iBAAiB;EAAkB,QAAQ;EAAqB;;;;;;;;;iBAiB5D,6BACd,OAAM,eACN,qBACC"}
1
+ {"version":3,"file":"webSubagentCatalogChannel.d.mts","names":[],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"mappings":";;;;KAUY,iBAAiB,gBAAgB,sBAAsB,QAAQ;;;;;;;;;iBAmD3D,6BAA6B,OAAO,eAAe,qBAAiC"}
@@ -1,2 +1,2 @@
1
- import{AgentDiscoveryService as e,resolveActiveTeamModelSpecs as t}from"./agents/discovery.mjs";import{catalogModels as n,presentCatalog as r}from"../services/webSubagentCatalog.mjs";import{SUBAGENT_CATALOG_TYPE as i}from"../types/webSubagents.mjs";function a(){let n=new e;return e=>({agents:n.discover(e,`both`).agents,models:t()??[]})}function o(e=a(),t=15e3){return{frameType:i,start(i){let a=new Map,o=new Map,s=t=>{try{let{agents:i,models:a}=e(t.cwd);return{cwd:t.cwd,agents:r(i),models:n(i,a)}}catch(e){let n=e instanceof Error?e.message:String(e);return{cwd:t.cwd,agents:[],models:[],warning:n}}},c=(e,t)=>{let n=s(e),r=JSON.stringify(n);return o.get(e.sessionId)===r?n:(o.set(e.sessionId,r),n.warning!==void 0&&i.onNotice(`subagent catalog for ${e.cwd} is unavailable (${n.warning})`),t&&i.publish(e.sessionId,n),n)},l=setInterval(()=>{for(let e of a.values())c(e,!0)},t);return{payloadFor(e){return a.has(e.sessionId)?c(e,!1):void 0},sessionAdded(e){a.set(e.sessionId,e),c(e,!0)},sessionRemoved(e){a.delete(e),o.delete(e)},close(){clearInterval(l),a.clear(),o.clear()}}}}}export{o as createSubagentCatalogChannel,a as defaultCatalogReader};
1
+ import{AgentDiscoveryService as e,resolveActiveTeamModelSpecs as t}from"./agents/discovery.mjs";import{TEAM_API_BASE_PATH as n,TEAM_CATALOG_ROUTE as r}from"./teamCatalogApi.mjs";import{catalogModels as i,presentCatalog as a}from"../services/webSubagentCatalog.mjs";import{SUBAGENT_CATALOG_TYPE as o}from"../types/webSubagents.mjs";function s(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function c(e){if(!s(e)||!Array.isArray(e.agents)||!e.agents.every(s)||!Array.isArray(e.models))throw Error(`Session catalog API returned an invalid payload.`);return{agents:e.agents,models:e.models.filter(e=>typeof e==`string`)}}async function l(e,t,i,a){let o=await e.requestSessionApi(t,{basePath:n,path:r,method:`GET`,signal:i});if(o.status===404)return await a(t.cwd);let l=await o.json();if(!o.ok){let e=s(l)&&typeof l.error==`string`?l.error:`HTTP ${String(o.status)}`;throw Error(`Session catalog API failed: ${e}`)}return c(l)}function u(n,r=15e3){return{frameType:o,start(o){let s=new Map,c=new Map,u=new Map,d=new Map,f=new AbortController,p=new e,m=e=>({agents:p.discover(e,`both`).agents,models:t()??[]}),h=!1,g=(e,t,n)=>{let r=s.get(e.sessionId);if(h||r?.cwd!==e.cwd||d.get(e.sessionId)!==t)return;let i=JSON.stringify(n);c.get(e.sessionId)!==i&&(c.set(e.sessionId,i),u.set(e.sessionId,n),n.warning!==void 0&&o.onNotice(`subagent catalog for ${e.cwd} is unavailable (${n.warning})`),o.publish(e.sessionId,n))},_=async e=>{let t=(d.get(e.sessionId)??0)+1;d.set(e.sessionId,t);try{let r=await(n===void 0?l(o,e,f.signal,m):n(e.cwd));g(e,t,{cwd:e.cwd,agents:a(r.agents),models:i(r.agents,r.models)})}catch(n){if(h||f.signal.aborted)return;let r=n instanceof Error?n.message:String(n);g(e,t,{cwd:e.cwd,agents:[],models:[],warning:r})}},v=setInterval(()=>{for(let e of s.values())_(e)},r);return{payloadFor(e){if(s.has(e.sessionId))return _(e),u.get(e.sessionId)},sessionAdded(e){s.set(e.sessionId,e),_(e)},sessionRemoved(e){s.delete(e),c.delete(e),u.delete(e),d.delete(e)},close(){h=!0,f.abort(),clearInterval(v),s.clear(),c.clear(),u.clear(),d.clear()}}}}}export{u as createSubagentCatalogChannel};
2
2
  //# sourceMappingURL=webSubagentCatalogChannel.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"webSubagentCatalogChannel.mjs","names":[],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"sourcesContent":["import type { HubChannelSource, HubSessionScope, WebHubChannel } from '@agimon-ai/doompi-web-contracts';\nimport { type CatalogAgentInput, catalogModels, presentCatalog } from '../services/webSubagentCatalog.ts';\nimport { SUBAGENT_CATALOG_TYPE, type SubagentCatalogPayload } from '../types/webSubagents.ts';\nimport { AgentDiscoveryService, resolveActiveTeamModelSpecs } from './agents/discovery.ts';\n\n/** Agent files change rarely; discovery's own cache makes each look cheap. */\nconst CATALOG_REFRESH_MS = 15_000;\n\n/** Reads the launchable agents for one directory; injectable so a test needs no agent files on disk. */\nexport type CatalogReader = (cwd: string) => { agents: CatalogAgentInput[]; models: string[] };\n\nexport function defaultCatalogReader(): CatalogReader {\n const discovery = new AgentDiscoveryService();\n return (cwd) => ({\n agents: discovery.discover(cwd, 'both').agents,\n models: resolveActiveTeamModelSpecs() ?? [],\n });\n}\n\n/**\n * The subagent catalog data channel: what each managed session's directory\n * can launch, published as 'subagent_catalog' payloads. Discovery runs once\n * per session on arrival, again at every subscribe, and on a slow tick so an\n * agent file written while the page is open shows up without a reload. A\n * failed read publishes an empty list with the reason rather than nothing.\n */\nexport function createSubagentCatalogChannel(\n read: CatalogReader = defaultCatalogReader(),\n refreshMs = CATALOG_REFRESH_MS,\n): WebHubChannel {\n return {\n frameType: SUBAGENT_CATALOG_TYPE,\n start(host) {\n const scopes = new Map<string, HubSessionScope>();\n const latest = new Map<string, string>();\n\n const compute = (scope: HubSessionScope): SubagentCatalogPayload => {\n try {\n const { agents, models } = read(scope.cwd);\n return { cwd: scope.cwd, agents: presentCatalog(agents), models: catalogModels(agents, models) };\n } catch (error) {\n const warning = error instanceof Error ? error.message : String(error);\n return { cwd: scope.cwd, agents: [], models: [], warning };\n }\n };\n\n /** Recomputes and remembers; publishes only what changed, so the tick stays quiet. */\n const refresh = (scope: HubSessionScope, publish: boolean): SubagentCatalogPayload => {\n const payload = compute(scope);\n const json = JSON.stringify(payload);\n if (latest.get(scope.sessionId) === json) return payload;\n latest.set(scope.sessionId, json);\n if (payload.warning !== undefined) {\n host.onNotice(`subagent catalog for ${scope.cwd} is unavailable (${payload.warning})`);\n }\n if (publish) host.publish(scope.sessionId, payload);\n return payload;\n };\n\n const timer = setInterval(() => {\n for (const scope of scopes.values()) refresh(scope, true);\n }, refreshMs);\n\n const source: HubChannelSource = {\n payloadFor(scope) {\n // The snapshot travels on its own, so a fresh read is remembered but not also published.\n return scopes.has(scope.sessionId) ? refresh(scope, false) : undefined;\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n refresh(scope, true);\n },\n sessionRemoved(sessionId) {\n scopes.delete(sessionId);\n latest.delete(sessionId);\n },\n close() {\n clearInterval(timer);\n scopes.clear();\n latest.clear();\n },\n };\n return source;\n },\n };\n}\n"],"mappings":"yPAWA,SAAgB,GAAsC,CACpD,IAAM,EAAY,IAAI,EACtB,MAAQ,KAAS,CACf,OAAQ,EAAU,SAAS,EAAK,MAAM,CAAC,CAAC,OACxC,OAAQ,EAA4B,GAAK,CAAC,CAC5C,EACF,CASA,SAAgB,EACd,EAAsB,EAAqB,EAC3C,EAAY,KACG,CACf,MAAO,CACL,UAAW,EACX,MAAM,EAAM,CACV,IAAM,EAAS,IAAI,IACb,EAAS,IAAI,IAEb,EAAW,GAAmD,CAClE,GAAI,CACF,GAAM,CAAE,SAAQ,UAAW,EAAK,EAAM,GAAG,EACzC,MAAO,CAAE,IAAK,EAAM,IAAK,OAAQ,EAAe,CAAM,EAAG,OAAQ,EAAc,EAAQ,CAAM,CAAE,CACjG,OAAS,EAAO,CACd,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,MAAO,CAAE,IAAK,EAAM,IAAK,OAAQ,CAAC,EAAG,OAAQ,CAAC,EAAG,SAAQ,CAC3D,CACF,EAGM,GAAW,EAAwB,IAA6C,CACpF,IAAM,EAAU,EAAQ,CAAK,EACvB,EAAO,KAAK,UAAU,CAAO,EAOnC,OANI,EAAO,IAAI,EAAM,SAAS,IAAM,EAAa,GACjD,EAAO,IAAI,EAAM,UAAW,CAAI,EAC5B,EAAQ,UAAY,IAAA,IACtB,EAAK,SAAS,wBAAwB,EAAM,IAAI,mBAAmB,EAAQ,QAAQ,EAAE,EAEnF,GAAS,EAAK,QAAQ,EAAM,UAAW,CAAO,EAC3C,EACT,EAEM,EAAQ,gBAAkB,CAC9B,IAAK,IAAM,KAAS,EAAO,OAAO,EAAG,EAAQ,EAAO,EAAI,CAC1D,EAAG,CAAS,EAqBZ,MAAO,CAlBL,WAAW,EAAO,CAEhB,OAAO,EAAO,IAAI,EAAM,SAAS,EAAI,EAAQ,EAAO,EAAK,EAAI,IAAA,EAC/D,EACA,aAAa,EAAO,CAClB,EAAO,IAAI,EAAM,UAAW,CAAK,EACjC,EAAQ,EAAO,EAAI,CACrB,EACA,eAAe,EAAW,CACxB,EAAO,OAAO,CAAS,EACvB,EAAO,OAAO,CAAS,CACzB,EACA,OAAQ,CACN,cAAc,CAAK,EACnB,EAAO,MAAM,EACb,EAAO,MAAM,CACf,CAEU,CACd,CACF,CACF"}
1
+ {"version":3,"file":"webSubagentCatalogChannel.mjs","names":[],"sources":["../../../src/adapters/webSubagentCatalogChannel.ts"],"sourcesContent":["import type { HubChannelHost, HubChannelSource, HubSessionScope, WebHubChannel } from '@agimon-ai/doompi-web-contracts';\nimport { type CatalogAgentInput, catalogModels, presentCatalog } from '../services/webSubagentCatalog.ts';\nimport { SUBAGENT_CATALOG_TYPE, type SubagentCatalogPayload } from '../types/webSubagents.ts';\nimport { AgentDiscoveryService, resolveActiveTeamModelSpecs } from './agents/discovery.ts';\nimport { TEAM_API_BASE_PATH, TEAM_CATALOG_ROUTE, type TeamCatalogSnapshot } from './teamCatalogApi.ts';\n\n/** Agent files change rarely; discovery's own cache makes each look cheap. */\nconst CATALOG_REFRESH_MS = 15_000;\n\n/** Injectable catalog read for tests and alternate hosts. Production reads through the session API. */\nexport type CatalogReader = (cwd: string) => TeamCatalogSnapshot | Promise<TeamCatalogSnapshot>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction parseCatalogSnapshot(value: unknown): TeamCatalogSnapshot {\n if (\n !isRecord(value) ||\n !Array.isArray(value.agents) ||\n !value.agents.every(isRecord) ||\n !Array.isArray(value.models)\n ) {\n throw new Error('Session catalog API returned an invalid payload.');\n }\n return {\n agents: value.agents as unknown as CatalogAgentInput[],\n models: value.models.filter((model): model is string => typeof model === 'string'),\n };\n}\n\nasync function readSessionCatalog(\n host: HubChannelHost,\n scope: HubSessionScope,\n signal: AbortSignal,\n fallback: CatalogReader,\n): Promise<TeamCatalogSnapshot> {\n const response = await host.requestSessionApi(scope, {\n basePath: TEAM_API_BASE_PATH,\n path: TEAM_CATALOG_ROUTE,\n method: 'GET',\n signal,\n });\n if (response.status === 404) return await fallback(scope.cwd);\n const payload: unknown = await response.json();\n if (!response.ok) {\n const reason =\n isRecord(payload) && typeof payload.error === 'string' ? payload.error : `HTTP ${String(response.status)}`;\n throw new Error(`Session catalog API failed: ${reason}`);\n }\n return parseCatalogSnapshot(payload);\n}\n\n/**\n * The subagent catalog data channel: what each managed session can launch.\n *\n * Discovery runs inside the session API because that process owns the active\n * domain projection and its plugin agent directories. The hub refreshes and\n * publishes that result, with local discovery only for older sessions lacking\n * the API route.\n */\nexport function createSubagentCatalogChannel(read?: CatalogReader, refreshMs = CATALOG_REFRESH_MS): WebHubChannel {\n return {\n frameType: SUBAGENT_CATALOG_TYPE,\n start(host) {\n const scopes = new Map<string, HubSessionScope>();\n const latestJson = new Map<string, string>();\n const latestPayload = new Map<string, SubagentCatalogPayload>();\n const generations = new Map<string, number>();\n const abort = new AbortController();\n const fallbackDiscovery = new AgentDiscoveryService();\n const fallback: CatalogReader = (cwd) => ({\n agents: fallbackDiscovery.discover(cwd, 'both').agents,\n models: resolveActiveTeamModelSpecs() ?? [],\n });\n let closed = false;\n\n const commit = (scope: HubSessionScope, generation: number, payload: SubagentCatalogPayload): void => {\n const active = scopes.get(scope.sessionId);\n if (closed || active?.cwd !== scope.cwd || generations.get(scope.sessionId) !== generation) return;\n const json = JSON.stringify(payload);\n if (latestJson.get(scope.sessionId) === json) return;\n latestJson.set(scope.sessionId, json);\n latestPayload.set(scope.sessionId, payload);\n if (payload.warning !== undefined) {\n host.onNotice(`subagent catalog for ${scope.cwd} is unavailable (${payload.warning})`);\n }\n host.publish(scope.sessionId, payload);\n };\n\n const refresh = async (scope: HubSessionScope): Promise<void> => {\n const generation = (generations.get(scope.sessionId) ?? 0) + 1;\n generations.set(scope.sessionId, generation);\n try {\n const snapshot = await (read === undefined\n ? readSessionCatalog(host, scope, abort.signal, fallback)\n : read(scope.cwd));\n commit(scope, generation, {\n cwd: scope.cwd,\n agents: presentCatalog(snapshot.agents),\n models: catalogModels(snapshot.agents, snapshot.models),\n });\n } catch (error) {\n if (closed || abort.signal.aborted) return;\n const warning = error instanceof Error ? error.message : String(error);\n commit(scope, generation, { cwd: scope.cwd, agents: [], models: [], warning });\n }\n };\n\n const timer = setInterval(() => {\n for (const scope of scopes.values()) void refresh(scope);\n }, refreshMs);\n\n const source: HubChannelSource = {\n payloadFor(scope) {\n if (!scopes.has(scope.sessionId)) return undefined;\n void refresh(scope);\n return latestPayload.get(scope.sessionId);\n },\n sessionAdded(scope) {\n scopes.set(scope.sessionId, scope);\n void refresh(scope);\n },\n sessionRemoved(sessionId) {\n scopes.delete(sessionId);\n latestJson.delete(sessionId);\n latestPayload.delete(sessionId);\n generations.delete(sessionId);\n },\n close() {\n closed = true;\n abort.abort();\n clearInterval(timer);\n scopes.clear();\n latestJson.clear();\n latestPayload.clear();\n generations.clear();\n },\n };\n return source;\n },\n };\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-team",
3
- "version": "0.0.1-alpha.44",
3
+ "version": "0.0.1-alpha.45",
4
4
  "description": "Asynchronous named subagents, team runs, intercom, and model policy for Pi coding agents.",
5
5
  "keywords": [
6
6
  "agent-team",
@@ -57,11 +57,11 @@
57
57
  "yaml": "2.9.0",
58
58
  "@agimon-ai/doompi-cache": "0.0.1-alpha.11",
59
59
  "@agimon-ai/doompi-config": "0.0.1-alpha.44",
60
- "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.44",
60
+ "@agimon-ai/doompi-ui": "0.0.1-alpha.45",
61
61
  "@agimon-ai/doompi-telemetry": "0.0.1-alpha.44",
62
- "@agimon-ai/doompi-ui": "0.0.1-alpha.44",
63
- "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.7",
64
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.5"
62
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.5",
63
+ "@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.44",
64
+ "@agimon-ai/doompi-web-contracts": "0.0.1-alpha.8"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@earendil-works/pi-agent-core": "0.84.4",
@@ -100,6 +100,13 @@
100
100
  "engines": {
101
101
  "node": ">=22.19.0"
102
102
  },
103
+ "doompiApi": {
104
+ "basePath": "team",
105
+ "session": {
106
+ "entry": "./src/exports/sessionApi.ts",
107
+ "dist": "./dist/sessionApi.mjs"
108
+ }
109
+ },
103
110
  "doompiWeb": {
104
111
  "pluginId": "subagents",
105
112
  "channels": [