@agentproto/app-kit 0.3.2 → 0.5.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/README.md CHANGED
@@ -87,6 +87,10 @@ by at least one agent. A dangling ref or an orphan workflow throws
87
87
  `{ id }`), so a company, persona, or role rides along without app-kit depending
88
88
  on each doctype package.
89
89
 
90
+ An app may also declare `requires: ["@acme/shared", ...]` — app ids that must be
91
+ applied to the same scope before this one can run. The runtime validates the
92
+ graph when mounting apps via `app_apply`.
93
+
90
94
  ## Consuming a bundle
91
95
 
92
96
  ### `handle.toMastraAgents(resolvers)` — run them
@@ -119,6 +123,7 @@ shared root `.agents/` convention:
119
123
 
120
124
  ```
121
125
  <dir>/WORKSPACE.md (AIP-34 root manifest — only when the app has a workspace)
126
+ <dir>/.agentproto/APP.md (root index — always written)
122
127
  <dir>/.agentproto/agents/reviewer/AGENT.md
123
128
  <dir>/.agentproto/agents/fixer/AGENT.md
124
129
  <dir>/.agentproto/workflows/review-and-fix/WORKFLOW.md (shared — a workflow may be run by several agents)
@@ -128,10 +133,33 @@ The daemon's state root is migrating toward a `tenants/<t>/…` segment
128
133
  (AIP-46 / DESIGN.md §9); app-kit will add that segment once the daemon's tenant
129
134
  layer lands, rather than inventing the shape ahead of it.
130
135
 
131
- Both are plain markdown: frontmatter = the validated handle, body = the agent's
132
- `body` (AGENT.md) / the workflow description (WORKFLOW.md). Because a
133
- `defineWorkflow` handle is pure data, the `WORKFLOW.md` needs no `entry:` module —
134
- the manifest *is* the workflow, so `loadWorkflowHandle` returns it directly.
136
+ All manifests are plain markdown: frontmatter = the validated handle, body = the
137
+ agent's `body` (AGENT.md) / the workflow description (WORKFLOW.md) / the app
138
+ description (APP.md). Because a `defineWorkflow` handle is pure data, the
139
+ `WORKFLOW.md` needs no `entry:` module — the manifest *is* the workflow, so
140
+ `loadWorkflowHandle` returns it directly.
141
+
142
+ ### `APP.md` — the root index, and `loadAppHandle(dir)`
143
+
144
+ `emit` always writes `<dir>/.agentproto/APP.md`: a `schema: "app/v1"` manifest
145
+ whose frontmatter lists every agent + workflow the app bundles as `{ id, path }`
146
+ refs (relative to `dir`), plus the app's own optional `id` / `name` / `version`
147
+ (defaults to `"0.1.0"` when `id` is set) / `description`, an optional `requires`
148
+ array of app ids it depends on, and, when the app has a home workspace, that
149
+ workspace's `id`. Nothing reads `AGENT.md`/`WORKFLOW.md` files on their own today
150
+ — `APP.md` is the thing a future daemon `app_install` discovers and consumes.
151
+
152
+ `loadAppHandle(dir)` is the inverse: it reads `APP.md`, loads each referenced
153
+ `AGENT.md` / `WORKFLOW.md` (and `WORKSPACE.md`, if declared) with their own
154
+ package's loader, and re-runs `defineApp` on the result — so the attachment
155
+ invariant re-validates exactly as it did at authoring time.
156
+
157
+ ```ts
158
+ import { loadAppHandle } from "@agentproto/app-kit"
159
+
160
+ const app = await loadAppHandle("/path/to/emitted/app")
161
+ app.agents.map((e) => e.agent.id) // ["@agentik/reviewer", "fixer"]
162
+ ```
135
163
 
136
164
  ## Runtime note
137
165
 
@@ -1 +1 @@
1
- {"version":3,"file":"define-app.d.ts","sourceRoot":"","sources":["../src/define-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAEV,aAAa,EACb,SAAS,EACT,aAAa,EAGd,MAAM,YAAY,CAAA;AAInB,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,CAqDvD;AA8GD,YAAY,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"define-app.d.ts","sourceRoot":"","sources":["../src/define-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAEV,aAAa,EACb,SAAS,EACT,aAAa,EAGd,MAAM,YAAY,CAAA;AAInB,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,CA4FvD;AA8GD,YAAY,EAAE,aAAa,EAAE,CAAA"}
package/dist/emit.d.ts CHANGED
@@ -9,24 +9,42 @@
9
9
  * <dir>/.agentproto/agents/<id>/AGENT.md (one per agent)
10
10
  * <dir>/.agentproto/workflows/<wf.id>/WORKFLOW.md (shared — a workflow may
11
11
  * be run by several agents)
12
+ * <dir>/.agentproto/APP.md (root index — always
13
+ * written, so a future
14
+ * `app_install` can
15
+ * discover the bundle)
12
16
  *
13
17
  * The "tenant" isn't a `tenants/<t>/…` path segment — it's the `owner` of
14
18
  * the AIP-34 WORKSPACE.md (guild / user / org), and local storage is its
15
19
  * AIP-35 `storage` block. So there is no bespoke tenant folder to invent.
16
20
  *
17
- * Both are plain markdown manifests: frontmatter = the validated handle,
18
- * body = the agent's `body` (its system prompt) or the workflow description.
19
- * Because a `defineWorkflow` handle is pure data, the WORKFLOW.md needs no
20
- * `entry:` module the manifest *is* the workflow, so `loadWorkflowHandle`
21
- * returns it directly with nothing to reconcile against.
21
+ * All manifests are plain markdown: frontmatter = the validated handle (or,
22
+ * for APP.md, the identity + a manifest of `{ id, path }` refs to every
23
+ * agent/workflow it bundles), body = the agent's `body` (its system prompt),
24
+ * the workflow description, or the app description. Because a
25
+ * `defineWorkflow` handle is pure data, the WORKFLOW.md needs no `entry:`
26
+ * module — the manifest *is* the workflow, so `loadWorkflowHandle` returns
27
+ * it directly with nothing to reconcile against.
28
+ *
29
+ * `emitApp` stays dependency-light on purpose (no Mastra import) — that
30
+ * split lets a host write/discover an app without paying for the Mastra
31
+ * build path.
22
32
  */
23
33
  import type { WorkflowHandle } from "@agentproto/workflow";
24
34
  import type { WorkspaceHandle } from "@agentproto/workspace";
25
- import type { AgentEntry, EmittedApp } from "./types.js";
35
+ import type { AgentEntry, AppArtifactDecl, AppDevDefinition, AppUiDefinition, EmittedApp } from "./types.js";
26
36
  interface EmitInput {
27
37
  readonly agents: readonly AgentEntry[];
28
38
  readonly workflows: readonly WorkflowHandle[];
29
39
  readonly workspace?: WorkspaceHandle;
40
+ readonly id?: string;
41
+ readonly name?: string;
42
+ readonly version?: string;
43
+ readonly description?: string;
44
+ readonly requires?: readonly string[];
45
+ readonly ui?: AppUiDefinition;
46
+ readonly artifacts?: readonly AppArtifactDecl[];
47
+ readonly dev?: AppDevDefinition;
30
48
  }
31
49
  export declare function emitApp(app: EmitInput, dir: string): Promise<EmittedApp>;
32
50
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAGxD,UAAU,SAAS;IACjB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAA;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;CACrC;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAkC9E"}
1
+ {"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAG5G,UAAU,SAAS;IACjB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAA;IAC7C,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;IACpC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC,QAAQ,CAAC,EAAE,CAAC,EAAE,eAAe,CAAA;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,eAAe,EAAE,CAAA;IAC/C,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,CAAA;CAChC;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAsF9E"}
package/dist/index.d.ts CHANGED
@@ -16,7 +16,11 @@
16
16
  * - `handle.emit(dir)` writes `.agentproto/agents/<id>/AGENT.md` + shared
17
17
  * `.agentproto/workflows/<id>/WORKFLOW.md` manifests under an
18
18
  * agentproto-owned base (not the shared root `.agents/`), plus a root
19
- * `WORKSPACE.md` when the app has a `workspace`.
19
+ * `.agentproto/APP.md` index (always) and a root `WORKSPACE.md` when the
20
+ * app has a `workspace`.
21
+ * - `loadAppHandle(dir)` reads that `APP.md` back — plus every AGENT.md /
22
+ * WORKFLOW.md / WORKSPACE.md it references — and re-runs `defineApp` so
23
+ * the attachment invariant re-validates. The inverse of `emit`.
20
24
  *
21
25
  * An app may declare a home `workspace` (AIP-34 `defineWorkspace`, or a
22
26
  * `{ id, name, owner, storage? }` shorthand). Its `owner` is the tenant
@@ -34,6 +38,7 @@
34
38
  */
35
39
  export { defineApp, AppDefinitionError } from "./define-app.js";
36
40
  export { emitApp } from "./emit.js";
41
+ export { loadAppHandle, AppLoadError } from "./load-app.js";
37
42
  export { refKey, stripOwner } from "./refs.js";
38
- export type { AppDefinition, AppHandle, AgentEntry, DoctypeHandle, WorkspaceShorthand, WorkspaceInput, ToMastraAgentOptions, EmittedApp, } from "./types.js";
43
+ export type { AppDefinition, AppHandle, AgentEntry, DoctypeHandle, WorkspaceShorthand, WorkspaceInput, AppUiDefinition, AppArtifactDecl, AppDevLaunchConfig, AppDevDefinition, ToMastraAgentOptions, EmittedApp, } from "./types.js";
39
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC9C,YAAY,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,UAAU,GACX,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC9C,YAAY,EACV,aAAa,EACb,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,UAAU,GACX,MAAM,YAAY,CAAA"}
package/dist/index.mjs CHANGED
@@ -1,8 +1,11 @@
1
1
  import { buildMastraAgent } from '@agentproto/mastra';
2
2
  import { defineWorkspace } from '@agentproto/workspace';
3
- import { mkdir, writeFile } from 'fs/promises';
4
- import { join } from 'path';
3
+ import { mkdir, writeFile, readFile } from 'fs/promises';
4
+ import { join, relative, isAbsolute } from 'path';
5
5
  import matter from 'gray-matter';
6
+ import { parseAgentManifest, agentFromManifest } from '@agentproto/agent/manifest';
7
+ import { loadWorkflowHandle } from '@agentproto/workflow-loader';
8
+ import { workspaceFromManifest, parseWorkspaceManifest } from '@agentproto/workspace/manifest';
6
9
 
7
10
  /**
8
11
  * @agentproto/app-kit v0.1.0
@@ -38,15 +41,59 @@ async function emitApp(app, dir) {
38
41
  await writeFile(agentPath, toManifest(agent, body ?? ""), "utf8");
39
42
  agentPaths[agent.id] = agentPath;
40
43
  }
44
+ let uiPath;
45
+ let uiFrontmatter;
46
+ if (app.ui) {
47
+ const uiDir = join(dir, ".agentproto", "ui");
48
+ await mkdir(uiDir, { recursive: true });
49
+ uiPath = join(uiDir, "index.html");
50
+ await writeFile(uiPath, app.ui.html, "utf8");
51
+ uiFrontmatter = {
52
+ path: relative(dir, uiPath),
53
+ ...app.ui.title !== void 0 ? { title: app.ui.title } : {},
54
+ ...app.ui.description !== void 0 ? { description: app.ui.description } : {},
55
+ ...app.ui.tools !== void 0 ? { tools: app.ui.tools } : {},
56
+ ...app.ui.csp !== void 0 ? { csp: app.ui.csp } : {}
57
+ };
58
+ }
41
59
  const workflowPaths = [];
60
+ const workflowRefs2 = [];
42
61
  for (const wf of app.workflows) {
43
62
  const wfDir = join(dir, ".agentproto", "workflows", wf.id);
44
63
  await mkdir(wfDir, { recursive: true });
45
64
  const wfPath = join(wfDir, "WORKFLOW.md");
46
65
  await writeFile(wfPath, toManifest(wf, wf.description ?? ""), "utf8");
47
66
  workflowPaths.push(wfPath);
67
+ workflowRefs2.push({ id: wf.id, path: relative(dir, wfPath) });
48
68
  }
49
- return { agentPaths, workflowPaths, ...workspacePath ? { workspacePath } : {} };
69
+ await mkdir(join(dir, ".agentproto"), { recursive: true });
70
+ const appPath = join(dir, ".agentproto", "APP.md");
71
+ const agentRefs = app.agents.map(({ agent }) => ({
72
+ id: agent.id,
73
+ path: relative(dir, agentPaths[agent.id])
74
+ }));
75
+ const appFrontmatter = {
76
+ schema: "app/v1",
77
+ ...app.id !== void 0 ? { id: app.id } : {},
78
+ ...app.name !== void 0 ? { name: app.name } : {},
79
+ version: app.version ?? "0.1.0",
80
+ ...app.description !== void 0 ? { description: app.description } : {},
81
+ agents: agentRefs,
82
+ workflows: workflowRefs2,
83
+ ...app.workspace ? { workspace: app.workspace.id } : {},
84
+ ...app.requires !== void 0 ? { requires: app.requires } : {},
85
+ ...uiFrontmatter !== void 0 ? { ui: uiFrontmatter } : {},
86
+ ...app.artifacts !== void 0 ? { artifacts: app.artifacts } : {},
87
+ ...app.dev !== void 0 ? { dev: app.dev } : {}
88
+ };
89
+ await writeFile(appPath, toManifest(appFrontmatter, app.description ?? ""), "utf8");
90
+ return {
91
+ agentPaths,
92
+ workflowPaths,
93
+ appPath,
94
+ ...workspacePath ? { workspacePath } : {},
95
+ ...uiPath ? { uiPath } : {}
96
+ };
50
97
  }
51
98
  function toManifest(handle, body) {
52
99
  const data = JSON.parse(JSON.stringify(handle));
@@ -66,10 +113,27 @@ function defineApp(def) {
66
113
  if (!Array.isArray(def.agents) || def.agents.length === 0) {
67
114
  throw new AppDefinitionError("`agents` must be a non-empty array.");
68
115
  }
116
+ if (def.id !== void 0 && def.id.trim() === "") {
117
+ throw new AppDefinitionError("`id` must be non-empty when present.");
118
+ }
119
+ if (def.ui !== void 0 && (typeof def.ui.html !== "string" || def.ui.html.trim() === "")) {
120
+ throw new AppDefinitionError("`ui.html` must be a non-empty string when `ui` is present.");
121
+ }
122
+ if (def.dev !== void 0 && (!Array.isArray(def.dev.launch) || def.dev.launch.length === 0)) {
123
+ throw new AppDefinitionError("`dev.launch` must be a non-empty array when `dev` is present.");
124
+ }
69
125
  const agents = def.agents.map(normalizeEntry);
70
126
  const workflows = def.workflows ?? [];
71
127
  const attachments = def.attach ?? [];
72
128
  const workspace = def.workspace ? toWorkspaceHandle(def.workspace) : void 0;
129
+ const id = def.id;
130
+ const name = def.name;
131
+ const version = def.version ?? (id ? "0.1.0" : void 0);
132
+ const description = def.description;
133
+ const requires = def.requires ? Object.freeze([...def.requires]) : void 0;
134
+ const ui = def.ui ? Object.freeze({ ...def.ui }) : void 0;
135
+ const artifacts = def.artifacts ? Object.freeze(def.artifacts.map((a) => Object.freeze({ ...a }))) : void 0;
136
+ const dev = def.dev ? Object.freeze({ launch: Object.freeze(def.dev.launch.map((l) => Object.freeze({ ...l }))) }) : void 0;
73
137
  validateAttachment(agents, workflows);
74
138
  const frozenAgents = Object.freeze(agents.map((e) => Object.freeze({ ...e })));
75
139
  const frozenWorkflows = Object.freeze([...workflows]);
@@ -79,6 +143,14 @@ function defineApp(def) {
79
143
  workflows: frozenWorkflows,
80
144
  attachments: frozenAttachments,
81
145
  ...workspace ? { workspace } : {},
146
+ ...id !== void 0 ? { id } : {},
147
+ ...name !== void 0 ? { name } : {},
148
+ ...version !== void 0 ? { version } : {},
149
+ ...description !== void 0 ? { description } : {},
150
+ ...requires !== void 0 ? { requires } : {},
151
+ ...ui !== void 0 ? { ui } : {},
152
+ ...artifacts !== void 0 ? { artifacts } : {},
153
+ ...dev !== void 0 ? { dev } : {},
82
154
  async toMastraAgents(opts, only) {
83
155
  const targets = only ? selectAgents(frozenAgents, only) : frozenAgents;
84
156
  const out = {};
@@ -100,7 +172,19 @@ function defineApp(def) {
100
172
  },
101
173
  emit(dir) {
102
174
  return emitApp(
103
- { agents: frozenAgents, workflows: frozenWorkflows, ...workspace ? { workspace } : {} },
175
+ {
176
+ agents: frozenAgents,
177
+ workflows: frozenWorkflows,
178
+ ...workspace ? { workspace } : {},
179
+ ...id !== void 0 ? { id } : {},
180
+ ...name !== void 0 ? { name } : {},
181
+ ...version !== void 0 ? { version } : {},
182
+ ...description !== void 0 ? { description } : {},
183
+ ...requires !== void 0 ? { requires } : {},
184
+ ...ui !== void 0 ? { ui } : {},
185
+ ...artifacts !== void 0 ? { artifacts } : {},
186
+ ...dev !== void 0 ? { dev } : {}
187
+ },
104
188
  dir
105
189
  );
106
190
  }
@@ -176,7 +260,146 @@ function validateAttachment(agents, workflows) {
176
260
  function workflowRefs(agent) {
177
261
  return agent.workflows ?? [];
178
262
  }
263
+ var AppLoadError = class extends Error {
264
+ constructor(message) {
265
+ super(`loadAppHandle: ${message}`);
266
+ this.name = "AppLoadError";
267
+ }
268
+ };
269
+ function resolveRef(dir, path) {
270
+ return isAbsolute(path) ? path : join(dir, path);
271
+ }
272
+ function isRefArray(v) {
273
+ return Array.isArray(v) && v.every(
274
+ (e) => typeof e === "object" && e !== null && typeof e.id === "string" && typeof e.path === "string"
275
+ );
276
+ }
277
+ function parseAppFrontmatter(data, appPath) {
278
+ if (data.schema !== "app/v1") {
279
+ throw new AppLoadError(
280
+ `'${appPath}': expected frontmatter 'schema: app/v1', got ${JSON.stringify(data.schema)}.`
281
+ );
282
+ }
283
+ if (!isRefArray(data.agents)) {
284
+ throw new AppLoadError(`'${appPath}': frontmatter 'agents' must be an array of { id, path }.`);
285
+ }
286
+ if (!isRefArray(data.workflows)) {
287
+ throw new AppLoadError(
288
+ `'${appPath}': frontmatter 'workflows' must be an array of { id, path }.`
289
+ );
290
+ }
291
+ if (data.requires !== void 0) {
292
+ if (!Array.isArray(data.requires) || !data.requires.every((e) => typeof e === "string")) {
293
+ throw new AppLoadError(`'${appPath}': frontmatter 'requires' must be an array of strings.`);
294
+ }
295
+ }
296
+ return data;
297
+ }
298
+ async function loadAgentEntry(dir, ref) {
299
+ const agentPath = resolveRef(dir, ref.path);
300
+ let source;
301
+ try {
302
+ source = await readFile(agentPath, "utf8");
303
+ } catch (err) {
304
+ throw new AppLoadError(
305
+ `agent '${ref.id}': cannot read '${agentPath}': ${err instanceof Error ? err.message : String(err)}`
306
+ );
307
+ }
308
+ let body;
309
+ let manifest;
310
+ try {
311
+ manifest = parseAgentManifest(source);
312
+ body = manifest.body.trim();
313
+ } catch (err) {
314
+ throw new AppLoadError(
315
+ `agent '${ref.id}' at '${agentPath}': ${err instanceof Error ? err.message : String(err)}`
316
+ );
317
+ }
318
+ return { agent: agentFromManifest(manifest), ...body ? { body } : {} };
319
+ }
320
+ async function loadWorkflowRef(dir, ref) {
321
+ const wfPath = resolveRef(dir, ref.path);
322
+ try {
323
+ return await loadWorkflowHandle(wfPath);
324
+ } catch (err) {
325
+ throw new AppLoadError(
326
+ `workflow '${ref.id}' at '${wfPath}': ${err instanceof Error ? err.message : String(err)}`
327
+ );
328
+ }
329
+ }
330
+ async function loadAppHandle(dir) {
331
+ const appPath = join(dir, ".agentproto", "APP.md");
332
+ let source;
333
+ try {
334
+ source = await readFile(appPath, "utf8");
335
+ } catch (err) {
336
+ throw new AppLoadError(
337
+ `cannot read '${appPath}': ${err instanceof Error ? err.message : String(err)}`
338
+ );
339
+ }
340
+ const parsed = matter(source);
341
+ const fm = parseAppFrontmatter(parsed.data, appPath);
342
+ const agents = [];
343
+ for (const ref of fm.agents) {
344
+ agents.push(await loadAgentEntry(dir, ref));
345
+ }
346
+ const workflows = [];
347
+ for (const ref of fm.workflows) {
348
+ workflows.push(await loadWorkflowRef(dir, ref));
349
+ }
350
+ let workspace;
351
+ if (fm.workspace) {
352
+ const workspacePath = join(dir, "WORKSPACE.md");
353
+ let workspaceSource;
354
+ try {
355
+ workspaceSource = await readFile(workspacePath, "utf8");
356
+ } catch (err) {
357
+ throw new AppLoadError(
358
+ `workspace '${fm.workspace}': cannot read '${workspacePath}': ${err instanceof Error ? err.message : String(err)}`
359
+ );
360
+ }
361
+ try {
362
+ workspace = workspaceFromManifest(parseWorkspaceManifest(workspaceSource));
363
+ } catch (err) {
364
+ throw new AppLoadError(
365
+ `workspace '${fm.workspace}' at '${workspacePath}': ${err instanceof Error ? err.message : String(err)}`
366
+ );
367
+ }
368
+ }
369
+ let ui;
370
+ if (fm.ui) {
371
+ const uiPath = resolveRef(dir, fm.ui.path);
372
+ let html;
373
+ try {
374
+ html = await readFile(uiPath, "utf8");
375
+ } catch (err) {
376
+ throw new AppLoadError(
377
+ `ui: cannot read '${uiPath}': ${err instanceof Error ? err.message : String(err)}`
378
+ );
379
+ }
380
+ ui = {
381
+ html,
382
+ ...fm.ui.title !== void 0 ? { title: fm.ui.title } : {},
383
+ ...fm.ui.description !== void 0 ? { description: fm.ui.description } : {},
384
+ ...fm.ui.tools !== void 0 ? { tools: fm.ui.tools } : {},
385
+ ...fm.ui.csp !== void 0 ? { csp: fm.ui.csp } : {}
386
+ };
387
+ }
388
+ return defineApp({
389
+ agents,
390
+ workflows,
391
+ ...workspace ? { workspace } : {},
392
+ ...fm.id !== void 0 ? { id: fm.id } : {},
393
+ ...fm.name !== void 0 ? { name: fm.name } : {},
394
+ ...fm.version !== void 0 ? { version: fm.version } : {},
395
+ ...fm.description !== void 0 ? { description: fm.description } : {},
396
+ ...fm.requires !== void 0 ? { requires: fm.requires } : {},
397
+ ...ui !== void 0 ? { ui } : {},
398
+ ...fm.artifacts !== void 0 ? { artifacts: fm.artifacts } : {},
399
+ ...fm.dev !== void 0 ? { dev: fm.dev } : {}
400
+ });
401
+ }
179
402
 
180
- export { AppDefinitionError, defineApp, emitApp, refKey, stripOwner };
403
+ export { AppDefinitionError, AppLoadError, defineApp, emitApp, loadAppHandle, refKey, stripOwner };
181
404
  //# sourceMappingURL=index.mjs.map
182
405
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/refs.ts","../src/emit.ts","../src/define-app.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Ref-key extraction, shared with the same convention `buildMastraAgent`\n * uses (`packages/mastra/src/build-agent.ts` `refKey`). An AIP-27 ref is\n * a string shorthand or `{ ref | file | inline }`; the key is the string,\n * else `.ref`, else `.file`, else a stable JSON of the inline payload.\n */\n\nimport type { AnyRef } from \"@agentproto/agent\"\n\nexport function refKey(ref: AnyRef): string {\n if (typeof ref === \"string\") return ref\n return ref.ref ?? ref.file ?? JSON.stringify(ref.inline ?? ref)\n}\n\n/** `@agentik/writer` → `writer`; bare ids untouched. */\nexport function stripOwner(id: string): string {\n const m = id.match(/^@[^/]+\\/(.+)$/)\n return m ? m[1]! : id\n}\n","/**\n * `emitApp(app, dir)` — write an app's agents + workflows to disk under an\n * agentproto-owned base, so the manifests don't squat the shared root\n * `.agents/` convention:\n *\n * <dir>/WORKSPACE.md (when the app has a\n * workspace — AIP-34 root\n * manifest; owner = tenant)\n * <dir>/.agentproto/agents/<id>/AGENT.md (one per agent)\n * <dir>/.agentproto/workflows/<wf.id>/WORKFLOW.md (shared — a workflow may\n * be run by several agents)\n *\n * The \"tenant\" isn't a `tenants/<t>/…` path segment — it's the `owner` of\n * the AIP-34 WORKSPACE.md (guild / user / org), and local storage is its\n * AIP-35 `storage` block. So there is no bespoke tenant folder to invent.\n *\n * Both are plain markdown manifests: frontmatter = the validated handle,\n * body = the agent's `body` (its system prompt) or the workflow description.\n * Because a `defineWorkflow` handle is pure data, the WORKFLOW.md needs no\n * `entry:` module — the manifest *is* the workflow, so `loadWorkflowHandle`\n * returns it directly with nothing to reconcile against.\n */\n\nimport { mkdir, writeFile } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport matter from \"gray-matter\"\nimport type { WorkflowHandle } from \"@agentproto/workflow\"\nimport type { WorkspaceHandle } from \"@agentproto/workspace\"\nimport type { AgentEntry, EmittedApp } from \"./types.js\"\nimport { stripOwner } from \"./refs.js\"\n\ninterface EmitInput {\n readonly agents: readonly AgentEntry[]\n readonly workflows: readonly WorkflowHandle[]\n readonly workspace?: WorkspaceHandle\n}\n\nexport async function emitApp(app: EmitInput, dir: string): Promise<EmittedApp> {\n // Root WORKSPACE.md (AIP-34): the workspace manifest whose `owner` names\n // the tenant and whose `storage` names the backing store. The agents +\n // workflows below live *inside* this workspace, under `.agentproto/`.\n let workspacePath: string | undefined\n if (app.workspace) {\n await mkdir(dir, { recursive: true })\n workspacePath = join(dir, \"WORKSPACE.md\")\n await writeFile(\n workspacePath,\n toManifest(app.workspace, app.workspace.description ?? app.workspace.name),\n \"utf8\",\n )\n }\n\n const agentPaths: Record<string, string> = {}\n for (const { agent, body } of app.agents) {\n const agentDir = join(dir, \".agentproto\", \"agents\", stripOwner(agent.id))\n await mkdir(agentDir, { recursive: true })\n const agentPath = join(agentDir, \"AGENT.md\")\n await writeFile(agentPath, toManifest(agent, body ?? \"\"), \"utf8\")\n agentPaths[agent.id] = agentPath\n }\n\n const workflowPaths: string[] = []\n for (const wf of app.workflows) {\n const wfDir = join(dir, \".agentproto\", \"workflows\", wf.id)\n await mkdir(wfDir, { recursive: true })\n const wfPath = join(wfDir, \"WORKFLOW.md\")\n await writeFile(wfPath, toManifest(wf, wf.description ?? \"\"), \"utf8\")\n workflowPaths.push(wfPath)\n }\n\n return { agentPaths, workflowPaths, ...(workspacePath ? { workspacePath } : {}) }\n}\n\n/**\n * Serialize a handle to a `.md` manifest. gray-matter's YAML engine\n * rejects `undefined` values; a JSON clone drops them and yields a plain\n * data object (AIP handles are pure data, no functions/Dates) that\n * round-trips through the matching `parse*Manifest`. gray-matter appends\n * a trailing newline, so manifests end in exactly one newline.\n */\nfunction toManifest(handle: object, body: string): string {\n const data: Record<string, unknown> = JSON.parse(JSON.stringify(handle))\n return matter.stringify(`\\n${body}\\n`, data)\n}\n","/**\n * `defineApp({ agents, workflows, attach })` — bundle one or more AIP-42\n * agents, the AIP-15 workflows they run, and any other AIP artifacts into\n * one cross-linked, frozen handle.\n *\n * The only new invariant app-kit adds is *attachment*: the agents and the\n * bundled workflows must reference each other. Everything else (field\n * validation) already ran when the caller built the handles with\n * `defineAgent` / `defineWorkflow`, so `defineApp` validates the coupling,\n * not the fields.\n *\n * - agent ids are unique within the app.\n * - every `agent.workflows[]` ref MUST resolve to a bundled workflow id.\n * - every bundled workflow MUST be referenced by at least one agent.\n *\n * A dangling ref (an agent points at a workflow the app didn't bundle) or\n * an orphan (a bundled workflow no agent lists) throws — that is what \"an\n * agent attached to its workflows\" means, made checkable.\n */\n\nimport { buildMastraAgent } from \"@agentproto/mastra\"\nimport { defineWorkspace } from \"@agentproto/workspace\"\nimport type { AgentHandle, AnyRef } from \"@agentproto/agent\"\nimport type { WorkflowHandle } from \"@agentproto/workflow\"\nimport type { WorkspaceHandle } from \"@agentproto/workspace\"\nimport type {\n AgentEntry,\n AppDefinition,\n AppHandle,\n DoctypeHandle,\n ToMastraAgentOptions,\n WorkspaceInput,\n} from \"./types.js\"\nimport { refKey } from \"./refs.js\"\nimport { emitApp } from \"./emit.js\"\n\nexport class AppDefinitionError extends Error {\n constructor(message: string) {\n super(`defineApp (app-kit): ${message}`)\n this.name = \"AppDefinitionError\"\n }\n}\n\nexport function defineApp(def: AppDefinition): AppHandle {\n if (!Array.isArray(def.agents) || def.agents.length === 0) {\n throw new AppDefinitionError(\"`agents` must be a non-empty array.\")\n }\n\n const agents = def.agents.map(normalizeEntry)\n const workflows = def.workflows ?? []\n const attachments = def.attach ?? []\n const workspace = def.workspace ? toWorkspaceHandle(def.workspace) : undefined\n\n validateAttachment(agents, workflows)\n\n const frozenAgents = Object.freeze(agents.map((e) => Object.freeze({ ...e })))\n const frozenWorkflows = Object.freeze([...workflows])\n const frozenAttachments = Object.freeze([...attachments])\n\n const handle: AppHandle = {\n agents: frozenAgents,\n workflows: frozenWorkflows,\n attachments: frozenAttachments,\n ...(workspace ? { workspace } : {}),\n\n async toMastraAgents(opts: ToMastraAgentOptions, only?: readonly string[]) {\n const targets = only ? selectAgents(frozenAgents, only) : frozenAgents\n const out: Record<string, Awaited<ReturnType<typeof buildMastraAgent>>> = {}\n for (const entry of targets) {\n out[entry.agent.id] = await buildOne(entry, opts)\n }\n return out\n },\n\n pick(ids: readonly string[]) {\n return selectAgents(frozenAgents, ids)\n },\n\n async toMastraAgent(opts: ToMastraAgentOptions) {\n if (frozenAgents.length !== 1) {\n throw new AppDefinitionError(\n `toMastraAgent requires exactly one agent (app has ${frozenAgents.length}); use toMastraAgents.`,\n )\n }\n return buildOne(frozenAgents[0]!, opts)\n },\n\n emit(dir: string) {\n return emitApp(\n { agents: frozenAgents, workflows: frozenWorkflows, ...(workspace ? { workspace } : {}) },\n dir,\n )\n },\n }\n\n return Object.freeze(handle)\n}\n\n/**\n * Normalize the `workspace` input to an AIP-34 `WorkspaceHandle`. A built\n * handle (already run through `defineWorkspace`) carries `schema:\n * \"workspace/v1\"` and passes straight through; a `WorkspaceShorthand` is\n * completed with a local-fs storage default and a `0.1.0` version, then\n * validated by `defineWorkspace` — so a malformed shorthand fails with the\n * same AIP-34 diagnostic as a malformed WORKSPACE.md.\n */\nfunction toWorkspaceHandle(input: WorkspaceInput): WorkspaceHandle {\n if (\"schema\" in input) return input\n return defineWorkspace({\n schema: \"workspace/v1\",\n version: input.version ?? \"0.1.0\",\n id: input.id,\n name: input.name,\n owner: input.owner,\n storage: input.storage ?? { inline: { provider: \"local-fs\", config: {} } },\n ...(input.description ? { description: input.description } : {}),\n })\n}\n\n/**\n * Resolve `ids` to their app entries, preserving the caller's order. Throws\n * `AppDefinitionError` on any id the app doesn't bundle — a hand-picked list\n * that names a missing agent is a bug, not a silent no-op.\n */\nfunction selectAgents(\n agents: readonly AgentEntry[],\n ids: readonly string[],\n): readonly AgentEntry[] {\n const byId = new Map(agents.map((e) => [e.agent.id, e]))\n return ids.map((id) => {\n const entry = byId.get(id)\n if (!entry) {\n throw new AppDefinitionError(\n `agent '${id}' is not in this app. Bundled: [${[...byId.keys()].join(\", \")}].`,\n )\n }\n return entry\n })\n}\n\nfunction buildOne(entry: AgentEntry, opts: ToMastraAgentOptions) {\n // `entry.body` (the AGENT.md body) wins as instructions; an explicit\n // `opts.body` still overrides, matching buildMastraAgent's contract.\n return buildMastraAgent(entry.agent, { body: entry.body, ...opts })\n}\n\nfunction normalizeEntry(input: AgentEntry | AgentHandle): AgentEntry {\n // An AgentEntry has an `.agent`; a bare AgentHandle has `.id`/`.schema`.\n if (\"agent\" in input) return input\n return { agent: input }\n}\n\n/**\n * The attachment invariant across all agents: bundled workflow ids and\n * the union of every agent's `workflows[]` refs must be the same set.\n * External/registry workflow refs are out of scope for an app bundle —\n * if an agent lists it, the app must ship it.\n */\nfunction validateAttachment(\n agents: readonly AgentEntry[],\n workflows: readonly WorkflowHandle[],\n): void {\n const seenAgentIds = new Set<string>()\n for (const { agent } of agents) {\n if (seenAgentIds.has(agent.id)) {\n throw new AppDefinitionError(`duplicate agent id '${agent.id}' in the bundle.`)\n }\n seenAgentIds.add(agent.id)\n }\n\n const bundledIds = new Set<string>()\n for (const wf of workflows) {\n if (bundledIds.has(wf.id)) {\n throw new AppDefinitionError(`duplicate workflow id '${wf.id}' in the bundle.`)\n }\n bundledIds.add(wf.id)\n }\n\n const referenced = new Set<string>()\n for (const { agent } of agents) {\n for (const ref of workflowRefs(agent)) {\n const key = refKey(ref)\n referenced.add(key)\n if (!bundledIds.has(key)) {\n throw new AppDefinitionError(\n `agent '${agent.id}' references workflow '${key}' but the app does not bundle it. ` +\n `Bundled: [${[...bundledIds].join(\", \") || \"none\"}].`,\n )\n }\n }\n }\n\n for (const id of bundledIds) {\n if (!referenced.has(id)) {\n throw new AppDefinitionError(\n `workflow '${id}' is bundled but no agent lists it in workflows[]. ` +\n `Add { ref: \"${id}\" } to an agent, or drop the workflow.`,\n )\n }\n }\n}\n\nfunction workflowRefs(agent: AgentHandle): readonly AnyRef[] {\n return agent.workflows ?? []\n}\n\nexport type { DoctypeHandle }\n"]}
1
+ {"version":3,"sources":["../src/refs.ts","../src/emit.ts","../src/define-app.ts","../src/load-app.ts"],"names":["workflowRefs","join","matter"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Ref-key extraction, shared with the same convention `buildMastraAgent`\n * uses (`packages/mastra/src/build-agent.ts` `refKey`). An AIP-27 ref is\n * a string shorthand or `{ ref | file | inline }`; the key is the string,\n * else `.ref`, else `.file`, else a stable JSON of the inline payload.\n */\n\nimport type { AnyRef } from \"@agentproto/agent\"\n\nexport function refKey(ref: AnyRef): string {\n if (typeof ref === \"string\") return ref\n return ref.ref ?? ref.file ?? JSON.stringify(ref.inline ?? ref)\n}\n\n/** `@agentik/writer` → `writer`; bare ids untouched. */\nexport function stripOwner(id: string): string {\n const m = id.match(/^@[^/]+\\/(.+)$/)\n return m ? m[1]! : id\n}\n","/**\n * `emitApp(app, dir)` — write an app's agents + workflows to disk under an\n * agentproto-owned base, so the manifests don't squat the shared root\n * `.agents/` convention:\n *\n * <dir>/WORKSPACE.md (when the app has a\n * workspace — AIP-34 root\n * manifest; owner = tenant)\n * <dir>/.agentproto/agents/<id>/AGENT.md (one per agent)\n * <dir>/.agentproto/workflows/<wf.id>/WORKFLOW.md (shared — a workflow may\n * be run by several agents)\n * <dir>/.agentproto/APP.md (root index — always\n * written, so a future\n * `app_install` can\n * discover the bundle)\n *\n * The \"tenant\" isn't a `tenants/<t>/…` path segment — it's the `owner` of\n * the AIP-34 WORKSPACE.md (guild / user / org), and local storage is its\n * AIP-35 `storage` block. So there is no bespoke tenant folder to invent.\n *\n * All manifests are plain markdown: frontmatter = the validated handle (or,\n * for APP.md, the identity + a manifest of `{ id, path }` refs to every\n * agent/workflow it bundles), body = the agent's `body` (its system prompt),\n * the workflow description, or the app description. Because a\n * `defineWorkflow` handle is pure data, the WORKFLOW.md needs no `entry:`\n * module — the manifest *is* the workflow, so `loadWorkflowHandle` returns\n * it directly with nothing to reconcile against.\n *\n * `emitApp` stays dependency-light on purpose (no Mastra import) — that\n * split lets a host write/discover an app without paying for the Mastra\n * build path.\n */\n\nimport { mkdir, writeFile } from \"node:fs/promises\"\nimport { join, relative } from \"node:path\"\nimport matter from \"gray-matter\"\nimport type { WorkflowHandle } from \"@agentproto/workflow\"\nimport type { WorkspaceHandle } from \"@agentproto/workspace\"\nimport type { AgentEntry, AppArtifactDecl, AppDevDefinition, AppUiDefinition, EmittedApp } from \"./types.js\"\nimport { stripOwner } from \"./refs.js\"\n\ninterface EmitInput {\n readonly agents: readonly AgentEntry[]\n readonly workflows: readonly WorkflowHandle[]\n readonly workspace?: WorkspaceHandle\n readonly id?: string\n readonly name?: string\n readonly version?: string\n readonly description?: string\n readonly requires?: readonly string[]\n readonly ui?: AppUiDefinition\n readonly artifacts?: readonly AppArtifactDecl[]\n readonly dev?: AppDevDefinition\n}\n\nexport async function emitApp(app: EmitInput, dir: string): Promise<EmittedApp> {\n // Root WORKSPACE.md (AIP-34): the workspace manifest whose `owner` names\n // the tenant and whose `storage` names the backing store. The agents +\n // workflows below live *inside* this workspace, under `.agentproto/`.\n let workspacePath: string | undefined\n if (app.workspace) {\n await mkdir(dir, { recursive: true })\n workspacePath = join(dir, \"WORKSPACE.md\")\n await writeFile(\n workspacePath,\n toManifest(app.workspace, app.workspace.description ?? app.workspace.name),\n \"utf8\",\n )\n }\n\n const agentPaths: Record<string, string> = {}\n for (const { agent, body } of app.agents) {\n const agentDir = join(dir, \".agentproto\", \"agents\", stripOwner(agent.id))\n await mkdir(agentDir, { recursive: true })\n const agentPath = join(agentDir, \"AGENT.md\")\n await writeFile(agentPath, toManifest(agent, body ?? \"\"), \"utf8\")\n agentPaths[agent.id] = agentPath\n }\n\n // UI surface (`.agentproto/ui/index.html`): the `html` body is written to\n // disk, never inlined into APP.md frontmatter — the frontmatter carries\n // only the relative `path` plus the display metadata.\n let uiPath: string | undefined\n let uiFrontmatter: Record<string, unknown> | undefined\n if (app.ui) {\n const uiDir = join(dir, \".agentproto\", \"ui\")\n await mkdir(uiDir, { recursive: true })\n uiPath = join(uiDir, \"index.html\")\n await writeFile(uiPath, app.ui.html, \"utf8\")\n uiFrontmatter = {\n path: relative(dir, uiPath),\n ...(app.ui.title !== undefined ? { title: app.ui.title } : {}),\n ...(app.ui.description !== undefined ? { description: app.ui.description } : {}),\n ...(app.ui.tools !== undefined ? { tools: app.ui.tools } : {}),\n ...(app.ui.csp !== undefined ? { csp: app.ui.csp } : {}),\n }\n }\n\n const workflowPaths: string[] = []\n const workflowRefs: { id: string; path: string }[] = []\n for (const wf of app.workflows) {\n const wfDir = join(dir, \".agentproto\", \"workflows\", wf.id)\n await mkdir(wfDir, { recursive: true })\n const wfPath = join(wfDir, \"WORKFLOW.md\")\n await writeFile(wfPath, toManifest(wf, wf.description ?? \"\"), \"utf8\")\n workflowPaths.push(wfPath)\n workflowRefs.push({ id: wf.id, path: relative(dir, wfPath) })\n }\n\n // Root APP.md (this WP): the index a future `app_install` reads to\n // discover the bundle — always written, unlike WORKSPACE.md which is\n // conditional on the app having a home workspace.\n await mkdir(join(dir, \".agentproto\"), { recursive: true })\n const appPath = join(dir, \".agentproto\", \"APP.md\")\n const agentRefs = app.agents.map(({ agent }) => ({\n id: agent.id,\n path: relative(dir, agentPaths[agent.id]!),\n }))\n const appFrontmatter: Record<string, unknown> = {\n schema: \"app/v1\",\n ...(app.id !== undefined ? { id: app.id } : {}),\n ...(app.name !== undefined ? { name: app.name } : {}),\n version: app.version ?? \"0.1.0\",\n ...(app.description !== undefined ? { description: app.description } : {}),\n agents: agentRefs,\n workflows: workflowRefs,\n ...(app.workspace ? { workspace: app.workspace.id } : {}),\n ...(app.requires !== undefined ? { requires: app.requires } : {}),\n ...(uiFrontmatter !== undefined ? { ui: uiFrontmatter } : {}),\n ...(app.artifacts !== undefined ? { artifacts: app.artifacts } : {}),\n ...(app.dev !== undefined ? { dev: app.dev } : {}),\n }\n await writeFile(appPath, toManifest(appFrontmatter, app.description ?? \"\"), \"utf8\")\n\n return {\n agentPaths,\n workflowPaths,\n appPath,\n ...(workspacePath ? { workspacePath } : {}),\n ...(uiPath ? { uiPath } : {}),\n }\n}\n\n/**\n * Serialize a handle to a `.md` manifest. gray-matter's YAML engine\n * rejects `undefined` values; a JSON clone drops them and yields a plain\n * data object (AIP handles are pure data, no functions/Dates) that\n * round-trips through the matching `parse*Manifest`. gray-matter appends\n * a trailing newline, so manifests end in exactly one newline.\n */\nfunction toManifest(handle: object, body: string): string {\n const data: Record<string, unknown> = JSON.parse(JSON.stringify(handle))\n return matter.stringify(`\\n${body}\\n`, data)\n}\n","/**\n * `defineApp({ agents, workflows, attach })` — bundle one or more AIP-42\n * agents, the AIP-15 workflows they run, and any other AIP artifacts into\n * one cross-linked, frozen handle.\n *\n * The only new invariant app-kit adds is *attachment*: the agents and the\n * bundled workflows must reference each other. Everything else (field\n * validation) already ran when the caller built the handles with\n * `defineAgent` / `defineWorkflow`, so `defineApp` validates the coupling,\n * not the fields.\n *\n * - agent ids are unique within the app.\n * - every `agent.workflows[]` ref MUST resolve to a bundled workflow id.\n * - every bundled workflow MUST be referenced by at least one agent.\n *\n * A dangling ref (an agent points at a workflow the app didn't bundle) or\n * an orphan (a bundled workflow no agent lists) throws — that is what \"an\n * agent attached to its workflows\" means, made checkable.\n */\n\nimport { buildMastraAgent } from \"@agentproto/mastra\"\nimport { defineWorkspace } from \"@agentproto/workspace\"\nimport type { AgentHandle, AnyRef } from \"@agentproto/agent\"\nimport type { WorkflowHandle } from \"@agentproto/workflow\"\nimport type { WorkspaceHandle } from \"@agentproto/workspace\"\nimport type {\n AgentEntry,\n AppDefinition,\n AppHandle,\n DoctypeHandle,\n ToMastraAgentOptions,\n WorkspaceInput,\n} from \"./types.js\"\nimport { refKey } from \"./refs.js\"\nimport { emitApp } from \"./emit.js\"\n\nexport class AppDefinitionError extends Error {\n constructor(message: string) {\n super(`defineApp (app-kit): ${message}`)\n this.name = \"AppDefinitionError\"\n }\n}\n\nexport function defineApp(def: AppDefinition): AppHandle {\n if (!Array.isArray(def.agents) || def.agents.length === 0) {\n throw new AppDefinitionError(\"`agents` must be a non-empty array.\")\n }\n if (def.id !== undefined && def.id.trim() === \"\") {\n throw new AppDefinitionError(\"`id` must be non-empty when present.\")\n }\n if (def.ui !== undefined && (typeof def.ui.html !== \"string\" || def.ui.html.trim() === \"\")) {\n throw new AppDefinitionError(\"`ui.html` must be a non-empty string when `ui` is present.\")\n }\n if (def.dev !== undefined && (!Array.isArray(def.dev.launch) || def.dev.launch.length === 0)) {\n throw new AppDefinitionError(\"`dev.launch` must be a non-empty array when `dev` is present.\")\n }\n\n const agents = def.agents.map(normalizeEntry)\n const workflows = def.workflows ?? []\n const attachments = def.attach ?? []\n const workspace = def.workspace ? toWorkspaceHandle(def.workspace) : undefined\n const id = def.id\n const name = def.name\n const version = def.version ?? (id ? \"0.1.0\" : undefined)\n const description = def.description\n const requires = def.requires ? Object.freeze([...def.requires]) : undefined\n const ui = def.ui ? Object.freeze({ ...def.ui }) : undefined\n const artifacts = def.artifacts ? Object.freeze(def.artifacts.map(a => Object.freeze({ ...a }))) : undefined\n const dev = def.dev\n ? Object.freeze({ launch: Object.freeze(def.dev.launch.map(l => Object.freeze({ ...l }))) })\n : undefined\n\n validateAttachment(agents, workflows)\n\n const frozenAgents = Object.freeze(agents.map((e) => Object.freeze({ ...e })))\n const frozenWorkflows = Object.freeze([...workflows])\n const frozenAttachments = Object.freeze([...attachments])\n\n const handle: AppHandle = {\n agents: frozenAgents,\n workflows: frozenWorkflows,\n attachments: frozenAttachments,\n ...(workspace ? { workspace } : {}),\n ...(id !== undefined ? { id } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(version !== undefined ? { version } : {}),\n ...(description !== undefined ? { description } : {}),\n ...(requires !== undefined ? { requires } : {}),\n ...(ui !== undefined ? { ui } : {}),\n ...(artifacts !== undefined ? { artifacts } : {}),\n ...(dev !== undefined ? { dev } : {}),\n\n async toMastraAgents(opts: ToMastraAgentOptions, only?: readonly string[]) {\n const targets = only ? selectAgents(frozenAgents, only) : frozenAgents\n const out: Record<string, Awaited<ReturnType<typeof buildMastraAgent>>> = {}\n for (const entry of targets) {\n out[entry.agent.id] = await buildOne(entry, opts)\n }\n return out\n },\n\n pick(ids: readonly string[]) {\n return selectAgents(frozenAgents, ids)\n },\n\n async toMastraAgent(opts: ToMastraAgentOptions) {\n if (frozenAgents.length !== 1) {\n throw new AppDefinitionError(\n `toMastraAgent requires exactly one agent (app has ${frozenAgents.length}); use toMastraAgents.`,\n )\n }\n return buildOne(frozenAgents[0]!, opts)\n },\n\n emit(dir: string) {\n return emitApp(\n {\n agents: frozenAgents,\n workflows: frozenWorkflows,\n ...(workspace ? { workspace } : {}),\n ...(id !== undefined ? { id } : {}),\n ...(name !== undefined ? { name } : {}),\n ...(version !== undefined ? { version } : {}),\n ...(description !== undefined ? { description } : {}),\n ...(requires !== undefined ? { requires } : {}),\n ...(ui !== undefined ? { ui } : {}),\n ...(artifacts !== undefined ? { artifacts } : {}),\n ...(dev !== undefined ? { dev } : {}),\n },\n dir,\n )\n },\n }\n\n return Object.freeze(handle)\n}\n\n/**\n * Normalize the `workspace` input to an AIP-34 `WorkspaceHandle`. A built\n * handle (already run through `defineWorkspace`) carries `schema:\n * \"workspace/v1\"` and passes straight through; a `WorkspaceShorthand` is\n * completed with a local-fs storage default and a `0.1.0` version, then\n * validated by `defineWorkspace` — so a malformed shorthand fails with the\n * same AIP-34 diagnostic as a malformed WORKSPACE.md.\n */\nfunction toWorkspaceHandle(input: WorkspaceInput): WorkspaceHandle {\n if (\"schema\" in input) return input\n return defineWorkspace({\n schema: \"workspace/v1\",\n version: input.version ?? \"0.1.0\",\n id: input.id,\n name: input.name,\n owner: input.owner,\n storage: input.storage ?? { inline: { provider: \"local-fs\", config: {} } },\n ...(input.description ? { description: input.description } : {}),\n })\n}\n\n/**\n * Resolve `ids` to their app entries, preserving the caller's order. Throws\n * `AppDefinitionError` on any id the app doesn't bundle — a hand-picked list\n * that names a missing agent is a bug, not a silent no-op.\n */\nfunction selectAgents(\n agents: readonly AgentEntry[],\n ids: readonly string[],\n): readonly AgentEntry[] {\n const byId = new Map(agents.map((e) => [e.agent.id, e]))\n return ids.map((id) => {\n const entry = byId.get(id)\n if (!entry) {\n throw new AppDefinitionError(\n `agent '${id}' is not in this app. Bundled: [${[...byId.keys()].join(\", \")}].`,\n )\n }\n return entry\n })\n}\n\nfunction buildOne(entry: AgentEntry, opts: ToMastraAgentOptions) {\n // `entry.body` (the AGENT.md body) wins as instructions; an explicit\n // `opts.body` still overrides, matching buildMastraAgent's contract.\n return buildMastraAgent(entry.agent, { body: entry.body, ...opts })\n}\n\nfunction normalizeEntry(input: AgentEntry | AgentHandle): AgentEntry {\n // An AgentEntry has an `.agent`; a bare AgentHandle has `.id`/`.schema`.\n if (\"agent\" in input) return input\n return { agent: input }\n}\n\n/**\n * The attachment invariant across all agents: bundled workflow ids and\n * the union of every agent's `workflows[]` refs must be the same set.\n * External/registry workflow refs are out of scope for an app bundle —\n * if an agent lists it, the app must ship it.\n */\nfunction validateAttachment(\n agents: readonly AgentEntry[],\n workflows: readonly WorkflowHandle[],\n): void {\n const seenAgentIds = new Set<string>()\n for (const { agent } of agents) {\n if (seenAgentIds.has(agent.id)) {\n throw new AppDefinitionError(`duplicate agent id '${agent.id}' in the bundle.`)\n }\n seenAgentIds.add(agent.id)\n }\n\n const bundledIds = new Set<string>()\n for (const wf of workflows) {\n if (bundledIds.has(wf.id)) {\n throw new AppDefinitionError(`duplicate workflow id '${wf.id}' in the bundle.`)\n }\n bundledIds.add(wf.id)\n }\n\n const referenced = new Set<string>()\n for (const { agent } of agents) {\n for (const ref of workflowRefs(agent)) {\n const key = refKey(ref)\n referenced.add(key)\n if (!bundledIds.has(key)) {\n throw new AppDefinitionError(\n `agent '${agent.id}' references workflow '${key}' but the app does not bundle it. ` +\n `Bundled: [${[...bundledIds].join(\", \") || \"none\"}].`,\n )\n }\n }\n }\n\n for (const id of bundledIds) {\n if (!referenced.has(id)) {\n throw new AppDefinitionError(\n `workflow '${id}' is bundled but no agent lists it in workflows[]. ` +\n `Add { ref: \"${id}\" } to an agent, or drop the workflow.`,\n )\n }\n }\n}\n\nfunction workflowRefs(agent: AgentHandle): readonly AnyRef[] {\n return agent.workflows ?? []\n}\n\nexport type { DoctypeHandle }\n","/**\n * `loadAppHandle(dir)` — read a root `APP.md` off disk into an `AppHandle`.\n *\n * Mirror of `@agentproto/workflow-loader`'s `loadWorkflowHandle`: this is\n * the host-side seam that touches the filesystem so the pure packages\n * (`@agentproto/agent`, `@agentproto/workflow`, `@agentproto/workspace`)\n * don't have to.\n *\n * `<dir>/.agentproto/APP.md` lists every agent + workflow the app bundles\n * as `{ id, path }` refs (relative to `dir`, the shape `emitApp` writes).\n * Each is loaded with its own package's manifest reader — `AGENT.md` via\n * `@agentproto/agent/manifest`, `WORKFLOW.md` via\n * `@agentproto/workflow-loader` (which itself resolves an `entry:` module\n * when present) — then the whole bundle is re-run through `defineApp` so\n * the attachment invariant (every agent/workflow ref resolves both ways)\n * re-validates exactly as it did at authoring time. A stale or hand-edited\n * APP.md that drifted from its AGENT.md/WORKFLOW.md refs fails the same\n * way a bad `defineApp({...})` call would.\n *\n * The frontmatter shape intentionally has no generated zod schema (unlike\n * AGENT.md/WORKFLOW.md, there's no AIP number for \"app\" yet) and validation\n * here stays loose on purpose — a future key (e.g. WP-B3's `requires.tools`)\n * should round-trip without this loader rejecting it.\n */\n\nimport { readFile } from \"node:fs/promises\"\nimport { isAbsolute, join } from \"node:path\"\nimport matter from \"gray-matter\"\nimport { agentFromManifest, parseAgentManifest } from \"@agentproto/agent/manifest\"\nimport { loadWorkflowHandle } from \"@agentproto/workflow-loader\"\nimport { parseWorkspaceManifest, workspaceFromManifest } from \"@agentproto/workspace/manifest\"\nimport type { AgentEntry, AppArtifactDecl, AppDevDefinition, AppHandle } from \"./types.js\"\nimport { defineApp } from \"./define-app.js\"\n\nexport class AppLoadError extends Error {\n constructor(message: string) {\n super(`loadAppHandle: ${message}`)\n this.name = \"AppLoadError\"\n }\n}\n\ninterface AppRef {\n readonly id: string\n readonly path: string\n}\n\ninterface AppFrontmatterUi {\n readonly path: string\n readonly title?: string\n readonly description?: string\n readonly tools?: readonly string[]\n readonly csp?: {\n readonly connectDomains?: readonly string[]\n readonly resourceDomains?: readonly string[]\n }\n}\n\ninterface AppFrontmatter {\n readonly schema: string\n readonly id?: string\n readonly name?: string\n readonly version?: string\n readonly description?: string\n readonly agents: readonly AppRef[]\n readonly workflows: readonly AppRef[]\n readonly workspace?: string\n readonly requires?: readonly string[]\n readonly ui?: AppFrontmatterUi\n readonly artifacts?: readonly AppArtifactDecl[]\n readonly dev?: AppDevDefinition\n}\n\nfunction resolveRef(dir: string, path: string): string {\n return isAbsolute(path) ? path : join(dir, path)\n}\n\nfunction isRefArray(v: unknown): v is AppRef[] {\n return (\n Array.isArray(v) &&\n v.every(\n (e) =>\n typeof e === \"object\" &&\n e !== null &&\n typeof (e as { id?: unknown }).id === \"string\" &&\n typeof (e as { path?: unknown }).path === \"string\",\n )\n )\n}\n\n/** Minimal shape check — see the module doc for why this stays loose. */\nfunction parseAppFrontmatter(data: Record<string, unknown>, appPath: string): AppFrontmatter {\n if (data.schema !== \"app/v1\") {\n throw new AppLoadError(\n `'${appPath}': expected frontmatter 'schema: app/v1', got ${JSON.stringify(data.schema)}.`,\n )\n }\n if (!isRefArray(data.agents)) {\n throw new AppLoadError(`'${appPath}': frontmatter 'agents' must be an array of { id, path }.`)\n }\n if (!isRefArray(data.workflows)) {\n throw new AppLoadError(\n `'${appPath}': frontmatter 'workflows' must be an array of { id, path }.`,\n )\n }\n if (data.requires !== undefined) {\n if (!Array.isArray(data.requires) || !data.requires.every((e) => typeof e === \"string\")) {\n throw new AppLoadError(`'${appPath}': frontmatter 'requires' must be an array of strings.`)\n }\n }\n return data as unknown as AppFrontmatter\n}\n\nasync function loadAgentEntry(dir: string, ref: AppRef): Promise<AgentEntry> {\n const agentPath = resolveRef(dir, ref.path)\n let source: string\n try {\n source = await readFile(agentPath, \"utf8\")\n } catch (err) {\n throw new AppLoadError(\n `agent '${ref.id}': cannot read '${agentPath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n let body: string\n let manifest: ReturnType<typeof parseAgentManifest>\n try {\n manifest = parseAgentManifest(source)\n body = manifest.body.trim()\n } catch (err) {\n throw new AppLoadError(\n `agent '${ref.id}' at '${agentPath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n return { agent: agentFromManifest(manifest), ...(body ? { body } : {}) }\n}\n\nasync function loadWorkflowRef(dir: string, ref: AppRef) {\n const wfPath = resolveRef(dir, ref.path)\n try {\n return await loadWorkflowHandle(wfPath)\n } catch (err) {\n throw new AppLoadError(\n `workflow '${ref.id}' at '${wfPath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\n/**\n * Load `<dir>/.agentproto/APP.md` and every AGENT.md/WORKFLOW.md (and, if\n * declared, `<dir>/WORKSPACE.md`) it references, then re-run `defineApp` on\n * the result. Throws {@link AppLoadError} naming the offending path on a\n * missing APP.md, a missing referenced file, or a frontmatter/schema\n * mismatch; throws `AppDefinitionError` (from `defineApp`) if the loaded\n * bundle fails the attachment invariant.\n */\nexport async function loadAppHandle(dir: string): Promise<AppHandle> {\n const appPath = join(dir, \".agentproto\", \"APP.md\")\n let source: string\n try {\n source = await readFile(appPath, \"utf8\")\n } catch (err) {\n throw new AppLoadError(\n `cannot read '${appPath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n\n const parsed = matter(source)\n const fm = parseAppFrontmatter(parsed.data, appPath)\n\n const agents: AgentEntry[] = []\n for (const ref of fm.agents) {\n agents.push(await loadAgentEntry(dir, ref))\n }\n\n const workflows = []\n for (const ref of fm.workflows) {\n workflows.push(await loadWorkflowRef(dir, ref))\n }\n\n let workspace\n if (fm.workspace) {\n const workspacePath = join(dir, \"WORKSPACE.md\")\n let workspaceSource: string\n try {\n workspaceSource = await readFile(workspacePath, \"utf8\")\n } catch (err) {\n throw new AppLoadError(\n `workspace '${fm.workspace}': cannot read '${workspacePath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n try {\n workspace = workspaceFromManifest(parseWorkspaceManifest(workspaceSource))\n } catch (err) {\n throw new AppLoadError(\n `workspace '${fm.workspace}' at '${workspacePath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n }\n\n let ui\n if (fm.ui) {\n const uiPath = resolveRef(dir, fm.ui.path)\n let html: string\n try {\n html = await readFile(uiPath, \"utf8\")\n } catch (err) {\n throw new AppLoadError(\n `ui: cannot read '${uiPath}': ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n ui = {\n html,\n ...(fm.ui.title !== undefined ? { title: fm.ui.title } : {}),\n ...(fm.ui.description !== undefined ? { description: fm.ui.description } : {}),\n ...(fm.ui.tools !== undefined ? { tools: fm.ui.tools } : {}),\n ...(fm.ui.csp !== undefined ? { csp: fm.ui.csp } : {}),\n }\n }\n\n return defineApp({\n agents,\n workflows,\n ...(workspace ? { workspace } : {}),\n ...(fm.id !== undefined ? { id: fm.id } : {}),\n ...(fm.name !== undefined ? { name: fm.name } : {}),\n ...(fm.version !== undefined ? { version: fm.version } : {}),\n ...(fm.description !== undefined ? { description: fm.description } : {}),\n ...(fm.requires !== undefined ? { requires: fm.requires } : {}),\n ...(ui !== undefined ? { ui } : {}),\n ...(fm.artifacts !== undefined ? { artifacts: fm.artifacts } : {}),\n ...(fm.dev !== undefined ? { dev: fm.dev } : {}),\n })\n}\n"]}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `loadAppHandle(dir)` — read a root `APP.md` off disk into an `AppHandle`.
3
+ *
4
+ * Mirror of `@agentproto/workflow-loader`'s `loadWorkflowHandle`: this is
5
+ * the host-side seam that touches the filesystem so the pure packages
6
+ * (`@agentproto/agent`, `@agentproto/workflow`, `@agentproto/workspace`)
7
+ * don't have to.
8
+ *
9
+ * `<dir>/.agentproto/APP.md` lists every agent + workflow the app bundles
10
+ * as `{ id, path }` refs (relative to `dir`, the shape `emitApp` writes).
11
+ * Each is loaded with its own package's manifest reader — `AGENT.md` via
12
+ * `@agentproto/agent/manifest`, `WORKFLOW.md` via
13
+ * `@agentproto/workflow-loader` (which itself resolves an `entry:` module
14
+ * when present) — then the whole bundle is re-run through `defineApp` so
15
+ * the attachment invariant (every agent/workflow ref resolves both ways)
16
+ * re-validates exactly as it did at authoring time. A stale or hand-edited
17
+ * APP.md that drifted from its AGENT.md/WORKFLOW.md refs fails the same
18
+ * way a bad `defineApp({...})` call would.
19
+ *
20
+ * The frontmatter shape intentionally has no generated zod schema (unlike
21
+ * AGENT.md/WORKFLOW.md, there's no AIP number for "app" yet) and validation
22
+ * here stays loose on purpose — a future key (e.g. WP-B3's `requires.tools`)
23
+ * should round-trip without this loader rejecting it.
24
+ */
25
+ import type { AppHandle } from "./types.js";
26
+ export declare class AppLoadError extends Error {
27
+ constructor(message: string);
28
+ }
29
+ /**
30
+ * Load `<dir>/.agentproto/APP.md` and every AGENT.md/WORKFLOW.md (and, if
31
+ * declared, `<dir>/WORKSPACE.md`) it references, then re-run `defineApp` on
32
+ * the result. Throws {@link AppLoadError} naming the offending path on a
33
+ * missing APP.md, a missing referenced file, or a frontmatter/schema
34
+ * mismatch; throws `AppDefinitionError` (from `defineApp`) if the loaded
35
+ * bundle fails the attachment invariant.
36
+ */
37
+ export declare function loadAppHandle(dir: string): Promise<AppHandle>;
38
+ //# sourceMappingURL=load-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-app.d.ts","sourceRoot":"","sources":["../src/load-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,OAAO,KAAK,EAAiD,SAAS,EAAE,MAAM,YAAY,CAAA;AAG1F,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAI5B;AA2GD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CA6EnE"}
package/dist/types.d.ts CHANGED
@@ -64,6 +64,39 @@ export interface WorkspaceShorthand {
64
64
  * structurally — a built handle carries `schema: "workspace/v1"`.
65
65
  */
66
66
  export type WorkspaceInput = WorkspaceHandle | WorkspaceShorthand;
67
+ /**
68
+ * A single HTML surface an app ships alongside its agents — the artifact a
69
+ * host renders (e.g. an embedded panel). `html` is the full document; `emit`
70
+ * writes it to `.agentproto/ui/index.html` rather than inlining it into the
71
+ * APP.md frontmatter.
72
+ */
73
+ export interface AppUiDefinition {
74
+ readonly html: string;
75
+ readonly title?: string;
76
+ readonly description?: string;
77
+ readonly tools?: readonly string[];
78
+ readonly csp?: {
79
+ readonly connectDomains?: readonly string[];
80
+ readonly resourceDomains?: readonly string[];
81
+ };
82
+ }
83
+ /** A kind of artifact the app's agents may produce, declared for discovery. */
84
+ export interface AppArtifactDecl {
85
+ readonly type: string;
86
+ readonly description?: string;
87
+ }
88
+ /** One way to launch the app for local development. */
89
+ export interface AppDevLaunchConfig {
90
+ readonly name: string;
91
+ readonly runtimeExecutable: string;
92
+ readonly runtimeArgs?: readonly string[];
93
+ readonly port?: number;
94
+ readonly url?: string;
95
+ }
96
+ /** Dev-launch configuration for the app, carried verbatim in APP.md frontmatter. */
97
+ export interface AppDevDefinition {
98
+ readonly launch: readonly AppDevLaunchConfig[];
99
+ }
67
100
  /**
68
101
  * Input to `defineApp`. Each `agents[]` entry is an already-validated
69
102
  * `AgentHandle` (bare, no body) or an `AgentEntry` (handle + body).
@@ -80,6 +113,26 @@ export interface AppDefinition {
80
113
  * alongside the agents. Omit for a workspace-less bundle.
81
114
  */
82
115
  readonly workspace?: WorkspaceInput;
116
+ /**
117
+ * Machine identifier for the app itself (distinct from its agents' ids).
118
+ * Must be non-empty when present. Setting it is what makes the app
119
+ * discoverable — `emit` writes it into the root `APP.md` identity block.
120
+ */
121
+ readonly id?: string;
122
+ /** Human-readable app name. */
123
+ readonly name?: string;
124
+ /** App version. Defaults to `"0.1.0"` when `id` is set. */
125
+ readonly version?: string;
126
+ /** App description. Becomes the `APP.md` body. */
127
+ readonly description?: string;
128
+ /** APP ids this app depends on. */
129
+ readonly requires?: readonly string[];
130
+ /** An HTML surface the app ships alongside its agents. */
131
+ readonly ui?: AppUiDefinition;
132
+ /** Artifact types this app's agents may produce, declared for discovery. */
133
+ readonly artifacts?: readonly AppArtifactDecl[];
134
+ /** Dev-launch configuration for running the app locally. */
135
+ readonly dev?: AppDevDefinition;
83
136
  }
84
137
  /** Options for `toMastraAgent(s)`. Same resolvers as `buildMastraAgent`. */
85
138
  export type ToMastraAgentOptions = BuildMastraAgentOptions;
@@ -91,6 +144,10 @@ export interface EmittedApp {
91
144
  readonly workflowPaths: readonly string[];
92
145
  /** Absolute path to the root `WORKSPACE.md`, when the app has a workspace. */
93
146
  readonly workspacePath?: string;
147
+ /** Absolute path to the root `APP.md` index, always written. */
148
+ readonly appPath: string;
149
+ /** Absolute path to the written `.agentproto/ui/index.html`, when the app has a `ui`. */
150
+ readonly uiPath?: string;
94
151
  }
95
152
  /**
96
153
  * The frozen result of `defineApp`. Carries the cross-linked agents +
@@ -102,6 +159,22 @@ export interface AppHandle {
102
159
  readonly attachments: readonly DoctypeHandle[];
103
160
  /** The app's home workspace (AIP-34), normalized to a handle. Absent if none. */
104
161
  readonly workspace?: WorkspaceHandle;
162
+ /** Machine identifier for the app itself. Absent for an anonymous bundle. */
163
+ readonly id?: string;
164
+ /** Human-readable app name. */
165
+ readonly name?: string;
166
+ /** App version. Defaulted to `"0.1.0"` when `id` is set. */
167
+ readonly version?: string;
168
+ /** App description. */
169
+ readonly description?: string;
170
+ /** APP ids this app depends on. */
171
+ readonly requires?: readonly string[];
172
+ /** An HTML surface the app ships alongside its agents. */
173
+ readonly ui?: AppUiDefinition;
174
+ /** Artifact types this app's agents may produce, declared for discovery. */
175
+ readonly artifacts?: readonly AppArtifactDecl[];
176
+ /** Dev-launch configuration for running the app locally. */
177
+ readonly dev?: AppDevDefinition;
105
178
  /**
106
179
  * Build agents into runnable Mastra agents whose `instructions` field is
107
180
  * the real system prompt (body → `composeInstructions`), keyed by agent id.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentproto/app-kit",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "description": "@agentproto/app-kit — declare an agent (with its system prompt) and its workflows in one TypeScript module and import them anywhere. A thin umbrella over AIP-42 defineAgent + AIP-15 defineWorkflow: defineApp cross-links the two (every workflow agent-step must target the app's agent, every agent workflow ref must resolve), toMastraAgent turns the AGENT.md body into a real Mastra `instructions` field, and emit writes the .agents/<id>/AGENT.md + WORKFLOW.md(+entry) pair that runs through the agentproto-run lane unchanged.",
5
5
  "keywords": [
6
6
  "agentproto",
@@ -44,8 +44,9 @@
44
44
  "dependencies": {
45
45
  "gray-matter": "^4.0.3",
46
46
  "@agentproto/agent": "0.2.1",
47
- "@agentproto/mastra": "0.2.4",
48
- "@agentproto/workflow": "0.1.1",
47
+ "@agentproto/mastra": "0.2.5",
48
+ "@agentproto/workflow-loader": "0.1.3",
49
+ "@agentproto/workflow": "0.2.0",
49
50
  "@agentproto/workspace": "0.1.0"
50
51
  },
51
52
  "peerDependencies": {
@@ -57,8 +58,7 @@
57
58
  "tsup": "^8.5.1",
58
59
  "typescript": "^5.9.3",
59
60
  "vitest": "^3.2.4",
60
- "@agentproto/tooling": "0.1.0-alpha.0",
61
- "@agentproto/workflow-loader": "0.1.2"
61
+ "@agentproto/tooling": "0.1.0-alpha.0"
62
62
  },
63
63
  "scripts": {
64
64
  "dev": "tsup --watch",