@agentage/extension 0.1.1 → 0.2.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.
Files changed (143) hide show
  1. package/README.md +6 -5
  2. package/dist/agcid/agcid.d.ts +1 -0
  3. package/dist/agcid/agcid.js +2 -2
  4. package/dist/agcid/current.d.ts +7 -0
  5. package/dist/agcid/current.js +4 -0
  6. package/dist/agcid/scope.d.ts +1 -1
  7. package/dist/agcid/scope.js +3 -4
  8. package/dist/command/args.d.ts +14 -0
  9. package/dist/command/args.js +60 -0
  10. package/dist/command/check-cli.d.ts +1 -0
  11. package/dist/command/check-cli.js +24 -0
  12. package/dist/command/command.types.d.ts +14 -0
  13. package/dist/command/command.types.js +2 -0
  14. package/dist/command/out.d.ts +19 -0
  15. package/dist/command/out.js +32 -0
  16. package/dist/command/run-command.d.ts +15 -0
  17. package/dist/command/run-command.js +53 -0
  18. package/dist/context/context.d.ts +8 -14
  19. package/dist/context/context.js +19 -21
  20. package/dist/context/settings.d.ts +5 -0
  21. package/dist/context/settings.js +32 -0
  22. package/dist/context/test-context.d.ts +44 -0
  23. package/dist/context/test-context.js +72 -0
  24. package/dist/discovery/discovery.d.ts +12 -1
  25. package/dist/discovery/discovery.js +21 -27
  26. package/dist/discovery/discovery.schema.d.ts +2 -26
  27. package/dist/discovery/discovery.schema.js +6 -4
  28. package/dist/discovery/openapi.d.ts +3 -0
  29. package/dist/discovery/openapi.js +19 -0
  30. package/dist/envelope/envelope.js +1 -0
  31. package/dist/envelope/envelope.schema.d.ts +0 -4
  32. package/dist/envelope/envelope.schema.js +3 -2
  33. package/dist/health/health.d.ts +5 -2
  34. package/dist/health/health.js +23 -8
  35. package/dist/health/health.schema.d.ts +2 -9
  36. package/dist/health/health.schema.js +3 -3
  37. package/dist/index.d.ts +19 -12
  38. package/dist/index.js +19 -12
  39. package/dist/log/log.d.ts +1 -0
  40. package/dist/log/log.js +7 -8
  41. package/dist/manifest/manifest.schema.d.ts +5 -75
  42. package/dist/manifest/manifest.schema.js +8 -4
  43. package/dist/manifest/primitives.schema.d.ts +1 -0
  44. package/dist/manifest/primitives.schema.js +3 -1
  45. package/dist/manifest/read-manifest.d.ts +1 -0
  46. package/dist/manifest/read-manifest.js +26 -3
  47. package/dist/mcp/mcp-app.d.ts +8 -0
  48. package/dist/mcp/mcp-app.js +74 -0
  49. package/dist/mcp/server.d.ts +8 -0
  50. package/dist/mcp/server.js +36 -0
  51. package/dist/mcp/snapshot.d.ts +11 -0
  52. package/dist/mcp/snapshot.js +69 -0
  53. package/dist/mcp/tools.d.ts +24 -0
  54. package/dist/mcp/tools.js +17 -0
  55. package/dist/pages/pages-app.d.ts +8 -0
  56. package/dist/pages/pages-app.js +29 -0
  57. package/dist/pages/pages.d.ts +4 -0
  58. package/dist/pages/pages.js +16 -0
  59. package/dist/runtime/build-info.d.ts +1 -0
  60. package/dist/runtime/build-info.js +4 -4
  61. package/dist/runtime/main.js +5 -2
  62. package/dist/runtime/part-runners.d.ts +20 -0
  63. package/dist/runtime/part-runners.js +68 -0
  64. package/dist/runtime/run-part.d.ts +4 -2
  65. package/dist/runtime/run-part.js +47 -34
  66. package/dist/server/app.d.ts +16 -2
  67. package/dist/server/app.js +28 -12
  68. package/dist/server/errors.d.ts +0 -2
  69. package/dist/server/errors.js +1 -1
  70. package/dist/server/serve.d.ts +0 -1
  71. package/dist/server/serve.js +2 -1
  72. package/dist/store/migrate.d.ts +2 -0
  73. package/dist/store/migrate.js +18 -0
  74. package/dist/store/migrations.d.ts +10 -0
  75. package/dist/store/migrations.js +55 -0
  76. package/dist/store/store.d.ts +10 -0
  77. package/dist/store/store.js +25 -0
  78. package/dist/store/store.types.d.ts +7 -0
  79. package/dist/store/store.types.js +1 -0
  80. package/dist/store/test-store.d.ts +5 -0
  81. package/dist/store/test-store.js +39 -0
  82. package/dist/testing/test-server.d.ts +6 -0
  83. package/dist/testing/test-server.js +31 -9
  84. package/dist/tool/build-info.js +2 -3
  85. package/dist/tool/build.d.ts +5 -2
  86. package/dist/tool/build.js +16 -24
  87. package/dist/tool/docker.d.ts +0 -1
  88. package/dist/tool/docker.js +2 -1
  89. package/dist/tool/exec.d.ts +4 -1
  90. package/dist/tool/exec.js +13 -5
  91. package/dist/tool/index.d.ts +9 -10
  92. package/dist/tool/index.js +9 -10
  93. package/dist/tool/kit-version.d.ts +1 -0
  94. package/dist/tool/kit-version.js +3 -0
  95. package/dist/tool/main.d.ts +6 -1
  96. package/dist/tool/main.js +58 -30
  97. package/dist/tool/recipe.d.ts +0 -1
  98. package/dist/tool/recipe.js +7 -3
  99. package/dist/tool/record-extras.d.ts +4 -0
  100. package/dist/tool/record-extras.js +60 -0
  101. package/dist/tool/stage.d.ts +3 -0
  102. package/dist/tool/stage.js +45 -12
  103. package/dist/tool/up/compose-run.d.ts +14 -0
  104. package/dist/tool/up/compose-run.js +24 -0
  105. package/dist/tool/up/compose.d.ts +18 -0
  106. package/dist/tool/up/compose.js +77 -0
  107. package/dist/tool/up/dev-issuer-app.d.ts +22 -0
  108. package/dist/tool/up/dev-issuer-app.js +80 -0
  109. package/dist/tool/up/dev-issuer.d.ts +2 -0
  110. package/dist/tool/up/dev-issuer.js +5 -0
  111. package/dist/tool/up/down.d.ts +12 -0
  112. package/dist/tool/up/down.js +38 -0
  113. package/dist/tool/up/gateway.d.ts +27 -0
  114. package/dist/tool/up/gateway.js +66 -0
  115. package/dist/tool/up/lines.d.ts +2 -0
  116. package/dist/tool/up/lines.js +3 -0
  117. package/dist/tool/up/local-record.d.ts +44 -0
  118. package/dist/tool/up/local-record.js +28 -0
  119. package/dist/tool/up/token.d.ts +6 -0
  120. package/dist/tool/up/token.js +18 -0
  121. package/dist/tool/up/up.d.ts +19 -0
  122. package/dist/tool/up/up.js +81 -0
  123. package/dist/tool/up/wait.d.ts +8 -0
  124. package/dist/tool/up/wait.js +24 -0
  125. package/dist/ui/ui-app.d.ts +6 -0
  126. package/dist/ui/ui-app.js +26 -0
  127. package/dist/worker/cron.d.ts +11 -0
  128. package/dist/worker/cron.js +73 -0
  129. package/dist/worker/job-options.d.ts +9 -0
  130. package/dist/worker/job-options.js +17 -0
  131. package/dist/worker/run-log.d.ts +9 -0
  132. package/dist/worker/run-log.js +38 -0
  133. package/dist/worker/runs.d.ts +20 -0
  134. package/dist/worker/runs.js +59 -0
  135. package/dist/worker/scheduler.d.ts +20 -0
  136. package/dist/worker/scheduler.js +97 -0
  137. package/dist/worker/worker.types.d.ts +5 -0
  138. package/dist/worker/worker.types.js +2 -0
  139. package/package.json +11 -2
  140. package/schemas/extension-discovery.schema.json +5 -0
  141. package/schemas/extension-package.schema.json +3 -0
  142. package/schemas/extension-record.schema.json +5 -0
  143. package/schemas/health.schema.json +1 -1
@@ -1,34 +1,33 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { formatIssues } from '../manifest/read-manifest.js';
1
+ import { formatIssues, readJsonIfExists } from '../manifest/read-manifest.js';
3
2
  import {} from '../manifest/manifest.schema.js';
4
3
  import { normalizeParts } from '../manifest/parts.js';
5
4
  import {} from '../manifest/primitives.schema.js';
6
5
  import { ExtensionRecordSchema } from './discovery.schema.js';
7
6
  export const DEFAULT_RECORD_FILE = '/run/agentage/agentage-extension.json';
8
- const commandNames = (pkg) => {
9
- const names = (pkg.agentage.commands ?? []).map((command) => command.name);
10
- return names.length > 0 ? names : undefined;
11
- };
12
- const partsOf = (pkg, images) => {
7
+ const partsOf = (pkg, images, migrations) => {
13
8
  const parts = {};
14
9
  for (const [kind, image] of Object.entries(images))
15
10
  parts[kind] = { image };
16
11
  const store = normalizeParts(pkg.agentage.parts).store;
17
12
  if (store)
18
- parts['store'] = { kind: store };
13
+ parts['store'] = migrations === undefined ? { kind: store } : { kind: store, migrations };
19
14
  return parts;
20
15
  };
21
- // From the manifest, the build and the pushed images by digest; OpenAPI, tools, widgets come later.
22
- export const recordOf = (pkg, build, images) => {
23
- const record = {
24
- id: pkg.agentage.id,
25
- version: pkg.version,
26
- commit: build.commit,
27
- buildTime: build.buildTime,
28
- parts: partsOf(pkg, images),
29
- commands: commandNames(pkg),
30
- };
31
- return JSON.parse(JSON.stringify(record));
16
+ // From the manifest, the build, the images by digest and what the code serves; OpenAPI comes later.
17
+ export const recordOf = (pkg, build, images, extras = {}) => {
18
+ const { id, commands } = pkg.agentage;
19
+ const { commit, buildTime } = build;
20
+ const parts = partsOf(pkg, images, extras.migrations);
21
+ const record = { id, version: pkg.version, commit, buildTime, parts };
22
+ if (extras.openapi)
23
+ record.openapi = extras.openapi;
24
+ if (extras.tools)
25
+ record.tools = extras.tools;
26
+ if (commands)
27
+ record.commands = commands.map((command) => command.name);
28
+ if (extras.widgets)
29
+ record.widgets = extras.widgets;
30
+ return record;
32
31
  };
33
32
  export const validateRecord = (value) => {
34
33
  const result = ExtensionRecordSchema.safeParse(value);
@@ -36,15 +35,10 @@ export const validateRecord = (value) => {
36
35
  return result.data;
37
36
  throw new Error(`invalid extension record: ${formatIssues(result.error.issues)}`);
38
37
  };
38
+ // No file means no record is mounted; any other read error stops the part from starting.
39
39
  export const loadRecord = async (file) => {
40
- let text;
41
- try {
42
- text = await readFile(file, 'utf8');
43
- }
44
- catch {
45
- return null; // no record mounted: discovery lists the part's own image by tag
46
- }
47
- return validateRecord(JSON.parse(text));
40
+ const record = await readJsonIfExists(file);
41
+ return record === undefined ? null : validateRecord(record);
48
42
  };
49
43
  export const discoveryDocument = (record, host) => {
50
44
  const { id, version, commit, buildTime, ...rest } = record;
@@ -1,30 +1,4 @@
1
1
  import { z } from 'zod';
2
- export declare const ImageDigestRefSchema: z.ZodString;
3
- export declare const PartsRecordSchema: z.ZodObject<{
4
- pages: z.ZodOptional<z.ZodObject<{
5
- image: z.ZodString;
6
- }, z.core.$strict>>;
7
- ui: z.ZodOptional<z.ZodObject<{
8
- image: z.ZodString;
9
- }, z.core.$strict>>;
10
- api: z.ZodOptional<z.ZodObject<{
11
- image: z.ZodString;
12
- }, z.core.$strict>>;
13
- mcp: z.ZodOptional<z.ZodObject<{
14
- image: z.ZodString;
15
- }, z.core.$strict>>;
16
- worker: z.ZodOptional<z.ZodObject<{
17
- image: z.ZodString;
18
- }, z.core.$strict>>;
19
- store: z.ZodOptional<z.ZodObject<{
20
- kind: z.ZodEnum<{
21
- postgres: "postgres";
22
- git: "git";
23
- signoz: "signoz";
24
- }>;
25
- }, z.core.$strict>>;
26
- }, z.core.$strict>;
27
- export declare const OriginSchema: z.ZodString;
28
2
  export declare const ExtensionRecordSchema: z.ZodObject<{
29
3
  id: z.ZodString;
30
4
  version: z.ZodString;
@@ -52,6 +26,7 @@ export declare const ExtensionRecordSchema: z.ZodObject<{
52
26
  git: "git";
53
27
  signoz: "signoz";
54
28
  }>;
29
+ migrations: z.ZodOptional<z.ZodInt>;
55
30
  }, z.core.$strict>>;
56
31
  }, z.core.$strict>;
57
32
  openapi: z.ZodOptional<z.ZodString>;
@@ -91,6 +66,7 @@ export declare const DiscoveryDocumentSchema: z.ZodObject<{
91
66
  git: "git";
92
67
  signoz: "signoz";
93
68
  }>;
69
+ migrations: z.ZodOptional<z.ZodInt>;
94
70
  }, z.core.$strict>>;
95
71
  }, z.core.$strict>;
96
72
  openapi: z.ZodOptional<z.ZodString>;
@@ -1,24 +1,26 @@
1
1
  import { z } from 'zod';
2
2
  import { CommandNameSchema, CommitSchema, ExtensionIdSchema, IMAGE_PART_KINDS, PrefixedToolNameSchema, StoreKindSchema, VersionSchema, } from '../manifest/primitives.schema.js';
3
3
  // registry host[:port]/owner/{id}-{part}@sha256: deployed by digest, a version's images never change.
4
- export const ImageDigestRefSchema = z
4
+ const ImageDigestRefSchema = z
5
5
  .string()
6
6
  .max(256)
7
7
  .regex(/^[a-z0-9][a-z0-9.-]*(:[0-9]{1,5})?\/[a-z0-9][a-z0-9-]*\/[a-z][a-z0-9-]*-(pages|ui|api|mcp|worker)@sha256:[0-9a-f]{64}$/);
8
8
  const PartImageSchema = z.strictObject({ image: ImageDigestRefSchema });
9
- export const PartsRecordSchema = z
9
+ const PartsRecordSchema = z
10
10
  .strictObject({
11
11
  pages: PartImageSchema.optional(),
12
12
  ui: PartImageSchema.optional(),
13
13
  api: PartImageSchema.optional(),
14
14
  mcp: PartImageSchema.optional(),
15
15
  worker: PartImageSchema.optional(),
16
- store: z.strictObject({ kind: StoreKindSchema }).optional(),
16
+ store: z
17
+ .strictObject({ kind: StoreKindSchema, migrations: z.int().min(0).optional() })
18
+ .optional(),
17
19
  })
18
20
  .refine((parts) => IMAGE_PART_KINDS.some((kind) => parts[kind] !== undefined), {
19
21
  message: 'at least one part with an image',
20
22
  });
21
- export const OriginSchema = z
23
+ const OriginSchema = z
22
24
  .string()
23
25
  .max(270)
24
26
  .regex(/^(https:\/\/[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+|http:\/\/(127\.0\.0\.1|localhost))(:[0-9]{1,5})?$/);
@@ -0,0 +1,3 @@
1
+ export declare const OPENAPI_FILE = "openapi.json";
2
+ export declare const OPENAPI_PATH = "/api/v1/openapi.json";
3
+ export declare const readOpenapi: (dir: string) => Promise<Record<string, unknown> | null>;
@@ -0,0 +1,19 @@
1
+ import { join } from 'node:path';
2
+ import { z } from 'zod';
3
+ import { readJsonIfExists } from '../manifest/read-manifest.js';
4
+ export const OPENAPI_FILE = 'openapi.json';
5
+ export const OPENAPI_PATH = '/api/v1/openapi.json';
6
+ const OpenapiSchema = z.looseObject({
7
+ openapi: z.string().regex(/^3\.1\.[0-9]+$/, { message: 'OpenAPI 3.1' }),
8
+ paths: z.record(z.string(), z.unknown()),
9
+ });
10
+ // The api's contract, committed beside package.json (the repo diffs it against its Zod schemas).
11
+ export const readOpenapi = async (dir) => {
12
+ const value = await readJsonIfExists(join(dir, OPENAPI_FILE));
13
+ if (value === undefined)
14
+ return null;
15
+ const result = OpenapiSchema.safeParse(value);
16
+ if (!result.success)
17
+ throw new Error(`${OPENAPI_FILE} is not an OpenAPI 3.1 document`);
18
+ return result.data;
19
+ };
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_RETRY_AFTER_SECONDS, ERROR_STATUS, RETRY_AFTER_CODES, } from './codes.js';
2
+ // A registry symbol, so a failure thrown through a second copy of the kit is still recognised.
2
3
  const FAILURE = Symbol.for('agentage.extension.failure');
3
4
  export const ok = (data, meta) => meta === undefined ? { success: true, data } : { success: true, data, meta };
4
5
  const retryAfterOf = (code, given) => {
@@ -1,8 +1,4 @@
1
1
  import { z } from 'zod';
2
- export declare const AgcidSchema: z.ZodString;
3
- export declare const ErrorCodeSchema: z.ZodEnum<{
4
- [x: string]: string;
5
- }>;
6
2
  export declare const ErrorEnvelopeSchema: z.ZodObject<{
7
3
  success: z.ZodLiteral<false>;
8
4
  error: z.ZodObject<{
@@ -1,7 +1,8 @@
1
1
  import { z } from 'zod';
2
+ import { AGCID_PATTERN } from '../agcid/agcid.js';
2
3
  import { ERROR_CODES } from './codes.js';
3
- export const AgcidSchema = z.string().regex(/^[A-Za-z0-9._:-]{8,128}$/);
4
- export const ErrorCodeSchema = z.enum(ERROR_CODES);
4
+ const AgcidSchema = z.string().regex(AGCID_PATTERN);
5
+ const ErrorCodeSchema = z.enum(ERROR_CODES);
5
6
  export const ErrorEnvelopeSchema = z.strictObject({
6
7
  success: z.literal(false),
7
8
  error: z.strictObject({
@@ -1,10 +1,11 @@
1
1
  import { type RequestHandler } from 'express';
2
2
  import { type BuildInfo } from '../discovery/discovery.js';
3
+ import { type ImagePartKind } from '../manifest/primitives.schema.js';
3
4
  import { type HealthBody, type HealthStatus } from './health.schema.js';
4
5
  export type HealthCheck = () => Promise<HealthStatus>;
5
6
  export interface HealthOptions {
6
7
  extension: string;
7
- part: 'api' | 'mcp' | 'worker' | 'pages' | 'ui';
8
+ part: ImagePartKind;
8
9
  version: string;
9
10
  build: BuildInfo;
10
11
  checks?: Record<string, HealthCheck>;
@@ -13,6 +14,8 @@ export interface HealthOptions {
13
14
  now?: () => Date;
14
15
  }
15
16
  export declare const worstOf: (statuses: HealthStatus[]) => HealthStatus;
17
+ export declare const CHECK_TIMEOUT_MS = 1000;
16
18
  export declare const isLoopback: (address: string | undefined) => boolean;
17
- export declare const healthBody: (options: HealthOptions) => Promise<HealthBody>;
19
+ export type ResolvedHealth = HealthOptions & Required<Pick<HealthOptions, 'instance' | 'startedAt'>>;
20
+ export declare const healthBody: (options: ResolvedHealth) => Promise<HealthBody>;
18
21
  export declare const createHealthHandler: (options: HealthOptions) => RequestHandler;
@@ -2,25 +2,40 @@ import { randomBytes } from 'node:crypto';
2
2
  import {} from 'express';
3
3
  import {} from '../discovery/discovery.js';
4
4
  import { fail } from '../envelope/envelope.js';
5
+ import {} from '../manifest/primitives.schema.js';
6
+ import { isoSeconds } from '../runtime/build-info.js';
5
7
  import {} from './health.schema.js';
6
8
  const RANK = { ok: 0, degraded: 1, unavailable: 2 };
7
9
  export const worstOf = (statuses) => statuses.reduce((worst, s) => (RANK[s] > RANK[worst] ? s : worst), 'ok');
10
+ // Under the recipe's HEALTHCHECK --timeout=3s: a hung check reads unavailable, never a hung probe.
11
+ export const CHECK_TIMEOUT_MS = 1000;
12
+ const settle = async (check) => {
13
+ let timer;
14
+ const expiry = new Promise((resolve) => {
15
+ timer = setTimeout(() => resolve('unavailable'), CHECK_TIMEOUT_MS).unref();
16
+ });
17
+ try {
18
+ return await Promise.race([check(), expiry]);
19
+ }
20
+ catch {
21
+ return 'unavailable';
22
+ }
23
+ finally {
24
+ clearTimeout(timer);
25
+ }
26
+ };
8
27
  const runChecks = async (checks) => {
9
- const entries = await Promise.all(Object.entries(checks).map(async ([name, check]) => {
10
- const status = await check().catch(() => 'unavailable');
11
- return [name, status];
12
- }));
28
+ const entries = await Promise.all(Object.entries(checks).map(async ([name, check]) => [name, await settle(check)]));
13
29
  return Object.fromEntries(entries);
14
30
  };
15
- const isoSeconds = (date) => `${date.toISOString().slice(0, 19)}Z`;
16
31
  export const isLoopback = (address) => address !== undefined && /^(127\.|::1$|::ffff:127\.)/.test(address);
17
32
  export const healthBody = async (options) => {
18
33
  const now = (options.now ?? (() => new Date()))();
19
34
  const checks = await runChecks(options.checks ?? {});
20
35
  const status = worstOf(Object.values(checks));
21
- const { extension, part, version, build } = options;
22
- const uptimeSeconds = Math.max(0, Math.floor((now.getTime() - (options.startedAt ?? 0)) / 1000));
23
- const data = { status, extension, part, version, ...build, instance: options.instance ?? '' };
36
+ const { extension, part, version, build, instance } = options;
37
+ const uptimeSeconds = Math.max(0, Math.floor((now.getTime() - options.startedAt) / 1000));
38
+ const data = { status, extension, part, version, ...build, instance };
24
39
  return {
25
40
  success: status !== 'unavailable',
26
41
  data: { ...data, uptimeSeconds, checkedAt: isoSeconds(now), checks },
@@ -1,17 +1,9 @@
1
1
  import { z } from 'zod';
2
- export declare const HealthStatusSchema: z.ZodEnum<{
2
+ declare const HealthStatusSchema: z.ZodEnum<{
3
3
  ok: "ok";
4
4
  degraded: "degraded";
5
5
  unavailable: "unavailable";
6
6
  }>;
7
- export declare const DeployedPartKindSchema: z.ZodEnum<{
8
- pages: "pages";
9
- ui: "ui";
10
- api: "api";
11
- mcp: "mcp";
12
- worker: "worker";
13
- store: "store";
14
- }>;
15
7
  export declare const HealthSchema: z.ZodObject<{
16
8
  success: z.ZodBoolean;
17
9
  data: z.ZodObject<{
@@ -44,3 +36,4 @@ export declare const HealthSchema: z.ZodObject<{
44
36
  }, z.core.$strict>;
45
37
  export type HealthStatus = z.infer<typeof HealthStatusSchema>;
46
38
  export type HealthBody = z.infer<typeof HealthSchema>;
39
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { ExtensionIdSchema, VersionSchema } from '../manifest/primitives.schema.js';
3
- export const HealthStatusSchema = z.enum(['ok', 'degraded', 'unavailable']);
4
- export const DeployedPartKindSchema = z.enum(['pages', 'ui', 'api', 'mcp', 'worker', 'store']);
3
+ const HealthStatusSchema = z.enum(['ok', 'degraded', 'unavailable']);
4
+ const DeployedPartKindSchema = z.enum(['pages', 'ui', 'api', 'mcp', 'worker', 'store']);
5
5
  // GET /health of every part container (api-standards section 7); never hostnames, IPs or env values.
6
6
  export const HealthSchema = z.strictObject({
7
7
  success: z.boolean(),
@@ -15,6 +15,6 @@ export const HealthSchema = z.strictObject({
15
15
  instance: z.string().regex(/^[0-9a-f]{8,32}$/),
16
16
  uptimeSeconds: z.int().min(0),
17
17
  checkedAt: z.iso.datetime(),
18
- checks: z.record(z.string().regex(/^[a-z][a-z0-9-]*$/), HealthStatusSchema),
18
+ checks: z.record(z.string().regex(/^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)?$/), HealthStatusSchema),
19
19
  }),
20
20
  });
package/dist/index.d.ts CHANGED
@@ -1,19 +1,26 @@
1
- export { AGCID_HEADER, agcidOf, isAgcid, uuidv7 } from './agcid/agcid.js';
2
- export { currentAgcid } from './agcid/scope.js';
3
- export { createContext, createTestContext, type ExtensionInfo, type LogEntry, type PartContext, type ServerPartKind, type SettingValue, type TestContext, type TestContextOptions, } from './context/context.js';
4
- export { DEFAULT_RECORD_FILE, discoveryDocument, loadRecord, recordOf, validateRecord, type BuildInfo, type PartImages, } from './discovery/discovery.js';
1
+ export { type ArgValue } from './command/args.js';
2
+ export { type CliContext, type CliCreate, type CommandExtension, type CommandHandler, } from './command/command.types.js';
3
+ export { type Out } from './command/out.js';
4
+ export { type ExtensionInfo, type PartContext, type ServerPartKind, type SettingValue, } from './context/context.js';
5
+ export { createTestContext, type LogEntry, type TestCommandContext, type TestCommandOptions, type TestContext, type TestContextOptions, } from './context/test-context.js';
5
6
  export { DiscoveryDocumentSchema, ExtensionRecordSchema, type DiscoveryDocument, type ExtensionRecord, } from './discovery/discovery.schema.js';
7
+ export { AGCID_HEADER, isAgcid } from './agcid/agcid.js';
6
8
  export { ERROR_CODES, ERROR_STATUS, type ErrorCode } from './envelope/codes.js';
7
- export { errorEnvelope, fail, isFailure, ok, type ErrorDetail, type ErrorEnvelope, type Failure, type FailOptions, type OkEnvelope, } from './envelope/envelope.js';
9
+ export { fail, isFailure, ok, type ErrorDetail, type ErrorEnvelope, type Failure, type FailOptions, type OkEnvelope, } from './envelope/envelope.js';
8
10
  export { ErrorEnvelopeSchema, OkEnvelopeSchema } from './envelope/envelope.schema.js';
9
11
  export { parse, type ParseSchema } from './envelope/parse.js';
10
- export { createHealthHandler, type HealthCheck, type HealthOptions } from './health/health.js';
11
12
  export { HealthSchema, type HealthBody, type HealthStatus } from './health/health.schema.js';
12
- export { createLog, type Log, type LogFields } from './log/log.js';
13
- export { PackageSchema, type ExtensionPackage } from './manifest/manifest.schema.js';
14
- export { entryOf, imageParts, normalizeParts } from './manifest/parts.js';
13
+ export { type Log, type LogFields } from './log/log.js';
14
+ export { PackageSchema, type CommandSpec, type ExtensionPackage, } from './manifest/manifest.schema.js';
15
+ export { imageParts } from './manifest/parts.js';
15
16
  export { readManifest, validateManifest } from './manifest/read-manifest.js';
16
- export { createApiApp, PUBLIC_CORS, type ApiAppOptions } from './server/app.js';
17
- export { serve, type ServeOptions } from './server/serve.js';
18
- export { startTestServer, type TestServer, type TestServerOptions } from './testing/test-server.js';
17
+ export { canonical, mcpSnapshot, PROTOCOL_VERSIONS, type McpSnapshot, type ProtocolVersion, } from './mcp/snapshot.js';
18
+ export { type McpContext, type ToolHandler, type ToolRegistrar, type ToolSpec, } from './mcp/tools.js';
19
+ export { versionPage, type PagesContext, type PagesSite } from './pages/pages.js';
19
20
  export { type ApiCreate, type ApiHandler, type ApiPart } from './server/part.types.js';
21
+ export { type QueryResult, type Row, type Store } from './store/store.types.js';
22
+ export { startTestMcp, startTestServer, type TestMcpOptions, type TestServer, type TestServerOptions, } from './testing/test-server.js';
23
+ export { type JobOptions } from './worker/job-options.js';
24
+ export { type JobRun, type RunStatus } from './worker/runs.js';
25
+ export { type Job, type Schedule } from './worker/scheduler.js';
26
+ export { type WorkerContext } from './worker/worker.types.js';
package/dist/index.js CHANGED
@@ -1,19 +1,26 @@
1
- export { AGCID_HEADER, agcidOf, isAgcid, uuidv7 } from './agcid/agcid.js';
2
- export { currentAgcid } from './agcid/scope.js';
3
- export { createContext, createTestContext, } from './context/context.js';
4
- export { DEFAULT_RECORD_FILE, discoveryDocument, loadRecord, recordOf, validateRecord, } from './discovery/discovery.js';
1
+ export {} from './command/args.js';
2
+ export {} from './command/command.types.js';
3
+ export {} from './command/out.js';
4
+ export {} from './context/context.js';
5
+ export { createTestContext, } from './context/test-context.js';
5
6
  export { DiscoveryDocumentSchema, ExtensionRecordSchema, } from './discovery/discovery.schema.js';
7
+ export { AGCID_HEADER, isAgcid } from './agcid/agcid.js';
6
8
  export { ERROR_CODES, ERROR_STATUS } from './envelope/codes.js';
7
- export { errorEnvelope, fail, isFailure, ok, } from './envelope/envelope.js';
9
+ export { fail, isFailure, ok, } from './envelope/envelope.js';
8
10
  export { ErrorEnvelopeSchema, OkEnvelopeSchema } from './envelope/envelope.schema.js';
9
11
  export { parse } from './envelope/parse.js';
10
- export { createHealthHandler } from './health/health.js';
11
12
  export { HealthSchema } from './health/health.schema.js';
12
- export { createLog } from './log/log.js';
13
- export { PackageSchema } from './manifest/manifest.schema.js';
14
- export { entryOf, imageParts, normalizeParts } from './manifest/parts.js';
13
+ export {} from './log/log.js';
14
+ export { PackageSchema, } from './manifest/manifest.schema.js';
15
+ export { imageParts } from './manifest/parts.js';
15
16
  export { readManifest, validateManifest } from './manifest/read-manifest.js';
16
- export { createApiApp, PUBLIC_CORS } from './server/app.js';
17
- export { serve } from './server/serve.js';
18
- export { startTestServer } from './testing/test-server.js';
17
+ export { canonical, mcpSnapshot, PROTOCOL_VERSIONS, } from './mcp/snapshot.js';
18
+ export {} from './mcp/tools.js';
19
+ export { versionPage } from './pages/pages.js';
19
20
  export {} from './server/part.types.js';
21
+ export {} from './store/store.types.js';
22
+ export { startTestMcp, startTestServer, } from './testing/test-server.js';
23
+ export {} from './worker/job-options.js';
24
+ export {} from './worker/runs.js';
25
+ export {} from './worker/scheduler.js';
26
+ export {} from './worker/worker.types.js';
package/dist/log/log.d.ts CHANGED
@@ -10,4 +10,5 @@ export interface LogTags {
10
10
  part: string;
11
11
  }
12
12
  export type LogWrite = (line: string) => void;
13
+ export declare const messageOf: (error: unknown) => string;
13
14
  export declare const createLog: (tags: LogTags, write?: LogWrite) => Log;
package/dist/log/log.js CHANGED
@@ -1,21 +1,20 @@
1
- import { currentAgcid } from '../agcid/scope.js';
1
+ import { currentAgcid } from '../agcid/current.js';
2
+ export const messageOf = (error) => error instanceof Error ? error.message : String(error);
2
3
  const errorFields = (error) => {
3
4
  if (!(error instanceof Error))
4
5
  return { err: { message: String(error) } };
5
6
  return { err: { type: error.name, message: error.message, stack: error.stack } };
6
7
  };
8
+ // Spread twice: the key order stays, and a field never overwrites time, level, msg, tags or agcid.
7
9
  const line = (level, message, tags, fields) => {
8
10
  const agcid = currentAgcid();
9
- const entry = { time: new Date().toISOString(), level, msg: message, ...tags, ...fields };
10
- return `${JSON.stringify(agcid ? { ...entry, agcid } : entry)}\n`;
11
+ const own = { time: new Date().toISOString(), level, msg: message, ...tags };
12
+ const fixed = agcid ? { ...own, agcid } : own;
13
+ return `${JSON.stringify({ ...fixed, ...fields, ...fixed })}\n`;
11
14
  };
12
15
  const stderrWrite = (text) => void process.stderr.write(text);
13
- // JSON lines on stderr, tagged with extension, part and the request's agcid.
14
16
  export const createLog = (tags, write = stderrWrite) => ({
15
17
  info: (message, fields = {}) => write(line('info', message, tags, fields)),
16
18
  warn: (message, fields = {}) => write(line('warn', message, tags, fields)),
17
- error: (error, fields = {}) => {
18
- const message = error instanceof Error ? error.message : String(error);
19
- write(line('error', message, tags, { ...errorFields(error), ...fields }));
20
- },
19
+ error: (error, fields = {}) => write(line('error', messageOf(error), tags, { ...fields, ...errorFields(error) })),
21
20
  });
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  declare const CodePartSchema: z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
3
3
  entry: z.ZodOptional<z.ZodString>;
4
4
  }, z.core.$strict>]>;
5
- export declare const PartsSchema: z.ZodObject<{
5
+ declare const PartsSchema: z.ZodObject<{
6
6
  pages: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
7
7
  entry: z.ZodOptional<z.ZodString>;
8
8
  }, z.core.$strict>]>>;
@@ -33,7 +33,7 @@ export declare const PartsSchema: z.ZodObject<{
33
33
  }>;
34
34
  }, z.core.$strict>]>>;
35
35
  }, z.core.$strict>;
36
- export declare const CommandSchema: z.ZodObject<{
36
+ declare const CommandSchema: z.ZodObject<{
37
37
  name: z.ZodString;
38
38
  summary: z.ZodString;
39
39
  args: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -44,82 +44,11 @@ export declare const CommandSchema: z.ZodObject<{
44
44
  boolean: "boolean";
45
45
  integer: "integer";
46
46
  }>;
47
+ optional: z.ZodOptional<z.ZodBoolean>;
47
48
  required: z.ZodOptional<z.ZodBoolean>;
48
49
  description: z.ZodOptional<z.ZodString>;
49
50
  }, z.core.$strict>>>;
50
51
  }, z.core.$strict>;
51
- export declare const SettingSchema: z.ZodObject<{
52
- type: z.ZodEnum<{
53
- string: "string";
54
- number: "number";
55
- boolean: "boolean";
56
- integer: "integer";
57
- }>;
58
- default: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>;
59
- enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
60
- description: z.ZodOptional<z.ZodString>;
61
- }, z.core.$strict>;
62
- export declare const AgentageSchema: z.ZodObject<{
63
- id: z.ZodString;
64
- parts: z.ZodObject<{
65
- pages: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
66
- entry: z.ZodOptional<z.ZodString>;
67
- }, z.core.$strict>]>>;
68
- ui: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
69
- entry: z.ZodOptional<z.ZodString>;
70
- }, z.core.$strict>]>>;
71
- api: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
72
- entry: z.ZodOptional<z.ZodString>;
73
- }, z.core.$strict>]>>;
74
- mcp: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
75
- entry: z.ZodOptional<z.ZodString>;
76
- }, z.core.$strict>]>>;
77
- worker: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
78
- entry: z.ZodOptional<z.ZodString>;
79
- }, z.core.$strict>]>>;
80
- cli: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
81
- entry: z.ZodOptional<z.ZodString>;
82
- }, z.core.$strict>]>>;
83
- store: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
84
- postgres: "postgres";
85
- git: "git";
86
- signoz: "signoz";
87
- }>, z.ZodObject<{
88
- kind: z.ZodEnum<{
89
- postgres: "postgres";
90
- git: "git";
91
- signoz: "signoz";
92
- }>;
93
- }, z.core.$strict>]>>;
94
- }, z.core.$strict>;
95
- commands: z.ZodOptional<z.ZodArray<z.ZodObject<{
96
- name: z.ZodString;
97
- summary: z.ZodString;
98
- args: z.ZodOptional<z.ZodArray<z.ZodObject<{
99
- name: z.ZodString;
100
- type: z.ZodEnum<{
101
- string: "string";
102
- number: "number";
103
- boolean: "boolean";
104
- integer: "integer";
105
- }>;
106
- required: z.ZodOptional<z.ZodBoolean>;
107
- description: z.ZodOptional<z.ZodString>;
108
- }, z.core.$strict>>>;
109
- }, z.core.$strict>>>;
110
- settings: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
111
- type: z.ZodEnum<{
112
- string: "string";
113
- number: "number";
114
- boolean: "boolean";
115
- integer: "integer";
116
- }>;
117
- default: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>;
118
- enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
119
- description: z.ZodOptional<z.ZodString>;
120
- }, z.core.$strict>>>;
121
- secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
122
- }, z.core.$strict>;
123
52
  export declare const PackageSchema: z.ZodObject<{
124
53
  name: z.ZodString;
125
54
  version: z.ZodString;
@@ -170,6 +99,7 @@ export declare const PackageSchema: z.ZodObject<{
170
99
  boolean: "boolean";
171
100
  integer: "integer";
172
101
  }>;
102
+ optional: z.ZodOptional<z.ZodBoolean>;
173
103
  required: z.ZodOptional<z.ZodBoolean>;
174
104
  description: z.ZodOptional<z.ZodString>;
175
105
  }, z.core.$strict>>>;
@@ -189,7 +119,7 @@ export declare const PackageSchema: z.ZodObject<{
189
119
  }, z.core.$strict>;
190
120
  }, z.core.$loose>;
191
121
  export type CodePart = z.infer<typeof CodePartSchema>;
122
+ export type CommandSpec = z.infer<typeof CommandSchema>;
192
123
  export type Parts = z.infer<typeof PartsSchema>;
193
- export type Agentage = z.infer<typeof AgentageSchema>;
194
124
  export type ExtensionPackage = z.infer<typeof PackageSchema>;
195
125
  export {};
@@ -6,7 +6,7 @@ const CodePartSchema = z.union([
6
6
  ]);
7
7
  const StorePartSchema = z.union([StoreKindSchema, z.strictObject({ kind: StoreKindSchema })]);
8
8
  const ROUTED = ['pages', 'ui', 'api', 'mcp'];
9
- export const PartsSchema = z
9
+ const PartsSchema = z
10
10
  .strictObject({
11
11
  pages: CodePartSchema.optional(),
12
12
  ui: CodePartSchema.optional(),
@@ -20,19 +20,20 @@ export const PartsSchema = z
20
20
  message: 'at least one routed part (pages, ui, api or mcp)',
21
21
  });
22
22
  const ArgTypeSchema = z.enum(['string', 'integer', 'number', 'boolean']);
23
- export const CommandSchema = z.strictObject({
23
+ const CommandSchema = z.strictObject({
24
24
  name: CommandNameSchema,
25
25
  summary: z.string().min(1).max(120),
26
26
  args: z
27
27
  .array(z.strictObject({
28
28
  name: CommandNameSchema,
29
29
  type: ArgTypeSchema,
30
+ optional: z.boolean().optional(),
30
31
  required: z.boolean().optional(),
31
32
  description: z.string().min(1).max(200).optional(),
32
33
  }))
33
34
  .optional(),
34
35
  });
35
- export const SettingSchema = z
36
+ const SettingSchema = z
36
37
  .strictObject({
37
38
  type: ArgTypeSchema,
38
39
  default: z.union([z.string(), z.number(), z.boolean()]),
@@ -41,6 +42,9 @@ export const SettingSchema = z
41
42
  })
42
43
  .refine((setting) => defaultFits(setting.type, setting.default), {
43
44
  message: 'default does not match type',
45
+ })
46
+ .refine((setting) => !setting.enum || setting.enum.includes(String(setting.default)), {
47
+ message: 'default is not one of enum',
44
48
  });
45
49
  const AgentageBaseSchema = z.strictObject({
46
50
  id: ExtensionIdSchema,
@@ -49,7 +53,7 @@ const AgentageBaseSchema = z.strictObject({
49
53
  settings: z.record(SettingKeySchema, SettingSchema).optional(),
50
54
  secrets: z.array(SecretNameSchema).optional(),
51
55
  });
52
- export const AgentageSchema = AgentageBaseSchema.superRefine(crossFieldRules);
56
+ const AgentageSchema = AgentageBaseSchema.superRefine(crossFieldRules);
53
57
  export const PackageSchema = z
54
58
  .looseObject({
55
59
  name: PackageNameSchema,
@@ -13,6 +13,7 @@ export declare const StoreKindSchema: z.ZodEnum<{
13
13
  git: "git";
14
14
  signoz: "signoz";
15
15
  }>;
16
+ export declare const FULL_SHA: RegExp;
16
17
  export declare const CommitSchema: z.ZodString;
17
18
  export declare const PrefixedToolNameSchema: z.ZodString;
18
19
  export declare const IMAGE_PART_KINDS: readonly ["pages", "ui", "api", "mcp", "worker"];
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ // Platform names and cli verbs, plus Windows device names: an id is a folder name on machines.
2
3
  const RESERVED_IDS = 'auth|www|api|sync|mail|mcp|ui|git|setup|status|update|extension|add|remove|help|con|prn|aux|nul|com[0-9]|lpt[0-9]';
3
4
  export const ExtensionIdSchema = z
4
5
  .string()
@@ -44,7 +45,8 @@ export const PackagePathSchema = z
44
45
  .max(256)
45
46
  .regex(/^\.\/[A-Za-z0-9._/-]+$/);
46
47
  export const StoreKindSchema = z.enum(['postgres', 'git', 'signoz']);
47
- export const CommitSchema = z.string().regex(/^[0-9a-f]{40}$/, { message: 'full 40-hex git sha' });
48
+ export const FULL_SHA = /^[0-9a-f]{40}$/;
49
+ export const CommitSchema = z.string().regex(FULL_SHA, { message: 'full 40-hex git sha' });
48
50
  export const PrefixedToolNameSchema = z
49
51
  .string()
50
52
  .max(64)
@@ -2,4 +2,5 @@ import { type z } from 'zod';
2
2
  import { type ExtensionPackage } from './manifest.schema.js';
3
3
  export declare const formatIssues: (issues: readonly z.core.$ZodIssue[]) => string;
4
4
  export declare const validateManifest: (value: unknown) => ExtensionPackage;
5
+ export declare const readJsonIfExists: (file: string) => Promise<unknown>;
5
6
  export declare const readManifest: (dir: string) => Promise<ExtensionPackage>;