@databricks/appkit 0.36.0 → 0.38.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 (160) hide show
  1. package/CLAUDE.md +3 -2
  2. package/NOTICE.md +1 -0
  3. package/dist/appkit/package.js +1 -1
  4. package/dist/cache/index.js +1 -2
  5. package/dist/cache/index.js.map +1 -1
  6. package/dist/cache/storage/persistent.js +1 -2
  7. package/dist/cache/storage/persistent.js.map +1 -1
  8. package/dist/cli/commands/plugin/add-resource/add-resource.js.map +1 -1
  9. package/dist/cli/commands/plugin/create/resource-defaults.js +2 -1
  10. package/dist/cli/commands/plugin/create/resource-defaults.js.map +1 -1
  11. package/dist/cli/commands/plugin/schema-resources.js +34 -51
  12. package/dist/cli/commands/plugin/schema-resources.js.map +1 -1
  13. package/dist/cli/commands/plugin/sync/sync.js +20 -6
  14. package/dist/cli/commands/plugin/sync/sync.js.map +1 -1
  15. package/dist/cli/commands/plugin/validate/validate-manifest.js +71 -157
  16. package/dist/cli/commands/plugin/validate/validate-manifest.js.map +1 -1
  17. package/dist/cli/commands/plugin/validate/validate.js +2 -2
  18. package/dist/cli/commands/plugin/validate/validate.js.map +1 -1
  19. package/dist/cli/commands/setup.js +2 -2
  20. package/dist/cli/commands/setup.js.map +1 -1
  21. package/dist/connectors/index.js +0 -1
  22. package/dist/connectors/jobs/client.js +1 -2
  23. package/dist/connectors/jobs/client.js.map +1 -1
  24. package/dist/connectors/lakebase/routing-pool.js +1 -2
  25. package/dist/connectors/lakebase/routing-pool.js.map +1 -1
  26. package/dist/connectors/sql-warehouse/client.js +1 -2
  27. package/dist/connectors/sql-warehouse/client.js.map +1 -1
  28. package/dist/context/execution-context.js +9 -13
  29. package/dist/context/execution-context.js.map +1 -1
  30. package/dist/context/index.js +3 -13
  31. package/dist/context/service-context.js +137 -136
  32. package/dist/context/service-context.js.map +1 -1
  33. package/dist/context/user-context.js +1 -5
  34. package/dist/context/user-context.js.map +1 -1
  35. package/dist/core/agent/create-agent.js +1 -2
  36. package/dist/core/agent/create-agent.js.map +1 -1
  37. package/dist/core/appkit.d.ts.map +1 -1
  38. package/dist/core/appkit.js +9 -37
  39. package/dist/core/appkit.js.map +1 -1
  40. package/dist/errors/authentication.js +44 -40
  41. package/dist/errors/authentication.js.map +1 -1
  42. package/dist/errors/base.js +86 -70
  43. package/dist/errors/base.js.map +1 -1
  44. package/dist/errors/configuration.js +70 -66
  45. package/dist/errors/configuration.js.map +1 -1
  46. package/dist/errors/connection.js +50 -46
  47. package/dist/errors/connection.js.map +1 -1
  48. package/dist/errors/execution.js +47 -43
  49. package/dist/errors/execution.js.map +1 -1
  50. package/dist/errors/index.js +10 -27
  51. package/dist/errors/initialization.js +38 -34
  52. package/dist/errors/initialization.js.map +1 -1
  53. package/dist/errors/server.js +34 -31
  54. package/dist/errors/server.js.map +1 -1
  55. package/dist/errors/tunnel.js +47 -43
  56. package/dist/errors/tunnel.js.map +1 -1
  57. package/dist/errors/validation.js +41 -37
  58. package/dist/errors/validation.js.map +1 -1
  59. package/dist/index.d.ts +1 -1
  60. package/dist/index.js +3 -9
  61. package/dist/plugin/dev-reader.js +1 -2
  62. package/dist/plugin/dev-reader.js.map +1 -1
  63. package/dist/plugin/interceptors/retry.js +1 -2
  64. package/dist/plugin/interceptors/retry.js.map +1 -1
  65. package/dist/plugin/interceptors/telemetry.js +1 -2
  66. package/dist/plugin/interceptors/telemetry.js.map +1 -1
  67. package/dist/plugin/plugin.d.ts +12 -4
  68. package/dist/plugin/plugin.d.ts.map +1 -1
  69. package/dist/plugin/plugin.js +59 -28
  70. package/dist/plugin/plugin.js.map +1 -1
  71. package/dist/plugins/agents/agents.d.ts +56 -3
  72. package/dist/plugins/agents/agents.d.ts.map +1 -1
  73. package/dist/plugins/agents/agents.js +160 -8
  74. package/dist/plugins/agents/agents.js.map +1 -1
  75. package/dist/plugins/agents/schemas.js +0 -1
  76. package/dist/plugins/agents/schemas.js.map +1 -1
  77. package/dist/plugins/analytics/analytics.js +1 -2
  78. package/dist/plugins/analytics/analytics.js.map +1 -1
  79. package/dist/plugins/analytics/manifest.js +9 -1
  80. package/dist/plugins/analytics/query.js +2 -4
  81. package/dist/plugins/analytics/query.js.map +1 -1
  82. package/dist/plugins/files/manifest.js +7 -1
  83. package/dist/plugins/files/plugin.js +3 -6
  84. package/dist/plugins/files/plugin.js.map +1 -1
  85. package/dist/plugins/genie/genie.js +1 -2
  86. package/dist/plugins/genie/genie.js.map +1 -1
  87. package/dist/plugins/genie/manifest.js +7 -1
  88. package/dist/plugins/jobs/plugin.js +2 -4
  89. package/dist/plugins/jobs/plugin.js.map +1 -1
  90. package/dist/plugins/lakebase/lakebase.js +1 -2
  91. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  92. package/dist/plugins/lakebase/manifest.js +26 -4
  93. package/dist/plugins/server/index.js +1 -2
  94. package/dist/plugins/server/index.js.map +1 -1
  95. package/dist/plugins/server/vite-dev-server.js +1 -2
  96. package/dist/plugins/server/vite-dev-server.js.map +1 -1
  97. package/dist/plugins/serving/serving.js +1 -2
  98. package/dist/plugins/serving/serving.js.map +1 -1
  99. package/dist/registry/index.d.ts +1 -1
  100. package/dist/registry/manifest-loader.d.ts +4 -4
  101. package/dist/registry/manifest-loader.d.ts.map +1 -1
  102. package/dist/registry/manifest-loader.js +1 -2
  103. package/dist/registry/manifest-loader.js.map +1 -1
  104. package/dist/registry/resource-registry.js +1 -2
  105. package/dist/registry/resource-registry.js.map +1 -1
  106. package/dist/registry/types.d.ts +21 -7
  107. package/dist/registry/types.d.ts.map +1 -1
  108. package/dist/registry/types.generated.d.ts +1 -1
  109. package/dist/registry/types.generated.js +1 -1
  110. package/dist/registry/types.generated.js.map +1 -1
  111. package/dist/registry/types.js +3 -3
  112. package/dist/registry/types.js.map +1 -1
  113. package/dist/schemas/manifest.d.ts +1139 -0
  114. package/dist/schemas/manifest.d.ts.map +1 -0
  115. package/dist/schemas/manifest.js +524 -0
  116. package/dist/schemas/manifest.js.map +1 -0
  117. package/dist/shared/src/index.d.ts +1 -1
  118. package/dist/shared/src/plugin.d.ts +38 -7
  119. package/dist/shared/src/plugin.d.ts.map +1 -1
  120. package/dist/shared/src/schemas/manifest.d.ts +1110 -0
  121. package/dist/shared/src/schemas/manifest.d.ts.map +1 -0
  122. package/dist/stream/arrow-stream-processor.js +1 -2
  123. package/dist/stream/arrow-stream-processor.js.map +1 -1
  124. package/dist/stream/buffers.js +1 -2
  125. package/dist/stream/buffers.js.map +1 -1
  126. package/docs/api/appkit/Enumeration.ResourceType.md +1 -1
  127. package/docs/api/appkit/Interface.PluginManifest.md +57 -3
  128. package/docs/api/appkit/Interface.ResourceEntry.md +6 -4
  129. package/docs/api/appkit/Interface.ResourceRequirement.md +7 -61
  130. package/docs/api/appkit/TypeAlias.ResourceFieldEntry.md +6 -0
  131. package/docs/api/appkit/Variable.agents.md +1 -1
  132. package/docs/api/appkit.md +12 -12
  133. package/docs/app-management.md +1 -1
  134. package/docs/development/ai-assisted-development.md +2 -2
  135. package/docs/development/local-development.md +1 -1
  136. package/docs/development/remote-bridge.md +1 -1
  137. package/docs/development/templates.md +118 -12
  138. package/docs/development.md +1 -1
  139. package/docs/plugins/agents.md +8 -4
  140. package/docs/plugins/custom-plugins.md +33 -23
  141. package/docs/plugins/lakebase.md +1 -1
  142. package/docs/plugins/manifest.md +293 -0
  143. package/docs.md +2 -2
  144. package/llms.txt +3 -2
  145. package/package.json +3 -3
  146. package/sbom.cdx.json +1 -1
  147. package/dist/_virtual/_rolldown/runtime.js +0 -7
  148. package/dist/connectors/lakebase-v1/client.js +0 -15
  149. package/dist/connectors/lakebase-v1/client.js.map +0 -1
  150. package/dist/connectors/lakebase-v1/index.js +0 -3
  151. package/dist/context/index.js.map +0 -1
  152. package/dist/errors/index.js.map +0 -1
  153. package/dist/index.js.map +0 -1
  154. package/dist/schemas/plugin-manifest.generated.d.ts +0 -182
  155. package/dist/schemas/plugin-manifest.generated.d.ts.map +0 -1
  156. package/dist/schemas/plugin-manifest.schema.json +0 -489
  157. package/dist/schemas/template-plugins.schema.json +0 -113
  158. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts +0 -182
  159. package/dist/shared/src/schemas/plugin-manifest.generated.d.ts.map +0 -1
  160. package/docs/api/appkit/Interface.ResourceFieldEntry.md +0 -82
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","names":[],"sources":["../../../../../shared/src/schemas/manifest.ts"],"mappings":";;;cAoVa,wBAAA,EAAwB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAsUxB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+frB,kBAAA,GAAqB,CAAA,CAAE,KAAA,QAAa,wBAAA;AAAA,KAOpC,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA"}
@@ -1,10 +1,9 @@
1
1
  import { createLogger } from "../logging/logger.js";
2
2
  import { ExecutionError } from "../errors/execution.js";
3
3
  import { ValidationError } from "../errors/validation.js";
4
- import { init_errors } from "../errors/index.js";
4
+ import "../errors/index.js";
5
5
 
6
6
  //#region src/stream/arrow-stream-processor.ts
7
- init_errors();
8
7
  const logger = createLogger("stream:arrow");
9
8
  const BACKOFF_MULTIPLIER = 1e3;
10
9
  var ArrowStreamProcessor = class ArrowStreamProcessor {
@@ -1 +1 @@
1
- {"version":3,"file":"arrow-stream-processor.js","names":[],"sources":["../../src/stream/arrow-stream-processor.ts"],"sourcesContent":["import type { sql } from \"@databricks/sdk-experimental\";\nimport { ExecutionError, ValidationError } from \"../errors\";\nimport { createLogger } from \"../logging/logger\";\n\nconst logger = createLogger(\"stream:arrow\");\n\ntype ResultManifest = sql.ResultManifest;\ntype ExternalLink = sql.ExternalLink;\n\ninterface ArrowStreamOptions {\n maxConcurrentDownloads: number;\n timeout: number;\n retries: number;\n}\n\n/**\n * Result from zero-copy Arrow chunk processing.\n * Contains raw IPC bytes without server-side parsing.\n */\ninterface ArrowRawResult {\n /** Concatenated raw Arrow IPC bytes */\n data: Uint8Array;\n /** Schema from Databricks manifest (not parsed from Arrow) */\n schema: ResultManifest[\"schema\"];\n}\n\nconst BACKOFF_MULTIPLIER = 1000;\n\nexport class ArrowStreamProcessor {\n static readonly DEFAULT_MAX_CONCURRENT_DOWNLOADS = 5;\n static readonly DEFAULT_TIMEOUT = 30000;\n static readonly DEFAULT_RETRIES = 3;\n\n constructor(\n private options: ArrowStreamOptions = {\n maxConcurrentDownloads:\n ArrowStreamProcessor.DEFAULT_MAX_CONCURRENT_DOWNLOADS,\n timeout: ArrowStreamProcessor.DEFAULT_TIMEOUT,\n retries: ArrowStreamProcessor.DEFAULT_RETRIES,\n },\n ) {\n this.options = {\n maxConcurrentDownloads:\n options.maxConcurrentDownloads ??\n ArrowStreamProcessor.DEFAULT_MAX_CONCURRENT_DOWNLOADS,\n timeout: options.timeout ?? ArrowStreamProcessor.DEFAULT_TIMEOUT,\n retries: options.retries ?? ArrowStreamProcessor.DEFAULT_RETRIES,\n };\n }\n\n /**\n * Process Arrow chunks using zero-copy proxy pattern.\n *\n * Downloads raw IPC bytes from external links and concatenates them\n * without parsing into Arrow Tables on the server. This reduces:\n * - Memory usage by ~50% (no parsed Table representation)\n * - CPU usage (no tableFromIPC/tableToIPC calls)\n *\n * The client is responsible for parsing the IPC bytes.\n *\n * @param chunks - External links to Arrow IPC data\n * @param schema - Schema from Databricks manifest\n * @param signal - Optional abort signal\n * @returns Raw concatenated IPC bytes with schema\n */\n async processChunks(\n chunks: ExternalLink[],\n schema: ResultManifest[\"schema\"],\n signal?: AbortSignal,\n ): Promise<ArrowRawResult> {\n if (chunks.length === 0) {\n throw ValidationError.missingField(\"chunks\");\n }\n\n const buffers = await this.downloadChunksRaw(chunks, signal);\n const data = this.concatenateBuffers(buffers);\n\n return { data, schema };\n }\n\n /**\n * Download all chunks as raw bytes with concurrency control.\n */\n private async downloadChunksRaw(\n chunks: ExternalLink[],\n signal?: AbortSignal,\n ): Promise<Uint8Array[]> {\n const semaphore = new Semaphore(this.options.maxConcurrentDownloads);\n\n const downloadPromises = chunks.map(async (chunk) => {\n await semaphore.acquire();\n try {\n return await this.downloadChunkRaw(chunk, signal);\n } finally {\n semaphore.release();\n }\n });\n\n return Promise.all(downloadPromises);\n }\n\n /**\n * Download a single chunk as raw bytes with retry logic.\n */\n private async downloadChunkRaw(\n chunk: ExternalLink,\n signal?: AbortSignal,\n ): Promise<Uint8Array> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.options.retries; attempt++) {\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(() => {\n timeoutController.abort();\n }, this.options.timeout);\n\n const combinedSignal = signal\n ? this.combineAbortSignals(signal, timeoutController.signal)\n : timeoutController.signal;\n\n try {\n const externalLink = chunk.external_link;\n if (!externalLink) {\n logger.error(\"External link is required for chunk: %O\", chunk);\n continue;\n }\n\n const response = await fetch(externalLink, {\n signal: combinedSignal,\n });\n\n if (!response.ok) {\n throw ExecutionError.statementFailed(\n `Failed to download chunk ${chunk.chunk_index}: ${response.status} ${response.statusText}`,\n );\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n } catch (error) {\n lastError = error as Error;\n\n if (timeoutController.signal.aborted) {\n lastError = new Error(\n `Chunk ${chunk.chunk_index} download timed out after ${this.options.timeout}ms`,\n );\n }\n\n if (signal?.aborted) {\n throw ExecutionError.canceled();\n }\n\n if (attempt < this.options.retries - 1) {\n await this.delay(2 ** attempt * BACKOFF_MULTIPLIER);\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n throw ExecutionError.statementFailed(\n `Failed to download chunk ${chunk.chunk_index} after ${this.options.retries} attempts: ${lastError?.message}`,\n );\n }\n\n /**\n * Concatenate multiple Uint8Array buffers into a single buffer.\n * Pre-allocates the result array for efficiency.\n */\n private concatenateBuffers(buffers: Uint8Array[]): Uint8Array {\n if (buffers.length === 0) {\n throw ValidationError.missingField(\"buffers\");\n }\n\n if (buffers.length === 1) {\n return buffers[0];\n }\n\n const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0);\n const result = new Uint8Array(totalLength);\n\n let offset = 0;\n for (const buffer of buffers) {\n result.set(buffer, offset);\n offset += buffer.length;\n }\n\n return result;\n }\n\n /**\n * Combines multiple AbortSignals into one.\n * The combined signal aborts when any of the input signals abort.\n */\n private combineAbortSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort();\n return controller.signal;\n }\n signal.addEventListener(\"abort\", () => controller.abort(), {\n once: true,\n });\n }\n\n return controller.signal;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nclass Semaphore {\n private permits: number;\n private waiting: (() => void)[] = [];\n\n constructor(permits: number) {\n this.permits = permits;\n }\n\n async acquire(): Promise<void> {\n if (this.permits > 0) {\n this.permits--;\n return;\n }\n\n return new Promise<void>((resolve) => {\n this.waiting.push(resolve);\n });\n }\n\n release(): void {\n if (this.waiting.length > 0) {\n const next = this.waiting.shift();\n\n if (next) {\n next();\n }\n } else {\n this.permits++;\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"arrow-stream-processor.js","names":[],"sources":["../../src/stream/arrow-stream-processor.ts"],"sourcesContent":["import type { sql } from \"@databricks/sdk-experimental\";\nimport { ExecutionError, ValidationError } from \"../errors\";\nimport { createLogger } from \"../logging/logger\";\n\nconst logger = createLogger(\"stream:arrow\");\n\ntype ResultManifest = sql.ResultManifest;\ntype ExternalLink = sql.ExternalLink;\n\ninterface ArrowStreamOptions {\n maxConcurrentDownloads: number;\n timeout: number;\n retries: number;\n}\n\n/**\n * Result from zero-copy Arrow chunk processing.\n * Contains raw IPC bytes without server-side parsing.\n */\ninterface ArrowRawResult {\n /** Concatenated raw Arrow IPC bytes */\n data: Uint8Array;\n /** Schema from Databricks manifest (not parsed from Arrow) */\n schema: ResultManifest[\"schema\"];\n}\n\nconst BACKOFF_MULTIPLIER = 1000;\n\nexport class ArrowStreamProcessor {\n static readonly DEFAULT_MAX_CONCURRENT_DOWNLOADS = 5;\n static readonly DEFAULT_TIMEOUT = 30000;\n static readonly DEFAULT_RETRIES = 3;\n\n constructor(\n private options: ArrowStreamOptions = {\n maxConcurrentDownloads:\n ArrowStreamProcessor.DEFAULT_MAX_CONCURRENT_DOWNLOADS,\n timeout: ArrowStreamProcessor.DEFAULT_TIMEOUT,\n retries: ArrowStreamProcessor.DEFAULT_RETRIES,\n },\n ) {\n this.options = {\n maxConcurrentDownloads:\n options.maxConcurrentDownloads ??\n ArrowStreamProcessor.DEFAULT_MAX_CONCURRENT_DOWNLOADS,\n timeout: options.timeout ?? ArrowStreamProcessor.DEFAULT_TIMEOUT,\n retries: options.retries ?? ArrowStreamProcessor.DEFAULT_RETRIES,\n };\n }\n\n /**\n * Process Arrow chunks using zero-copy proxy pattern.\n *\n * Downloads raw IPC bytes from external links and concatenates them\n * without parsing into Arrow Tables on the server. This reduces:\n * - Memory usage by ~50% (no parsed Table representation)\n * - CPU usage (no tableFromIPC/tableToIPC calls)\n *\n * The client is responsible for parsing the IPC bytes.\n *\n * @param chunks - External links to Arrow IPC data\n * @param schema - Schema from Databricks manifest\n * @param signal - Optional abort signal\n * @returns Raw concatenated IPC bytes with schema\n */\n async processChunks(\n chunks: ExternalLink[],\n schema: ResultManifest[\"schema\"],\n signal?: AbortSignal,\n ): Promise<ArrowRawResult> {\n if (chunks.length === 0) {\n throw ValidationError.missingField(\"chunks\");\n }\n\n const buffers = await this.downloadChunksRaw(chunks, signal);\n const data = this.concatenateBuffers(buffers);\n\n return { data, schema };\n }\n\n /**\n * Download all chunks as raw bytes with concurrency control.\n */\n private async downloadChunksRaw(\n chunks: ExternalLink[],\n signal?: AbortSignal,\n ): Promise<Uint8Array[]> {\n const semaphore = new Semaphore(this.options.maxConcurrentDownloads);\n\n const downloadPromises = chunks.map(async (chunk) => {\n await semaphore.acquire();\n try {\n return await this.downloadChunkRaw(chunk, signal);\n } finally {\n semaphore.release();\n }\n });\n\n return Promise.all(downloadPromises);\n }\n\n /**\n * Download a single chunk as raw bytes with retry logic.\n */\n private async downloadChunkRaw(\n chunk: ExternalLink,\n signal?: AbortSignal,\n ): Promise<Uint8Array> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.options.retries; attempt++) {\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(() => {\n timeoutController.abort();\n }, this.options.timeout);\n\n const combinedSignal = signal\n ? this.combineAbortSignals(signal, timeoutController.signal)\n : timeoutController.signal;\n\n try {\n const externalLink = chunk.external_link;\n if (!externalLink) {\n logger.error(\"External link is required for chunk: %O\", chunk);\n continue;\n }\n\n const response = await fetch(externalLink, {\n signal: combinedSignal,\n });\n\n if (!response.ok) {\n throw ExecutionError.statementFailed(\n `Failed to download chunk ${chunk.chunk_index}: ${response.status} ${response.statusText}`,\n );\n }\n\n const arrayBuffer = await response.arrayBuffer();\n return new Uint8Array(arrayBuffer);\n } catch (error) {\n lastError = error as Error;\n\n if (timeoutController.signal.aborted) {\n lastError = new Error(\n `Chunk ${chunk.chunk_index} download timed out after ${this.options.timeout}ms`,\n );\n }\n\n if (signal?.aborted) {\n throw ExecutionError.canceled();\n }\n\n if (attempt < this.options.retries - 1) {\n await this.delay(2 ** attempt * BACKOFF_MULTIPLIER);\n }\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n throw ExecutionError.statementFailed(\n `Failed to download chunk ${chunk.chunk_index} after ${this.options.retries} attempts: ${lastError?.message}`,\n );\n }\n\n /**\n * Concatenate multiple Uint8Array buffers into a single buffer.\n * Pre-allocates the result array for efficiency.\n */\n private concatenateBuffers(buffers: Uint8Array[]): Uint8Array {\n if (buffers.length === 0) {\n throw ValidationError.missingField(\"buffers\");\n }\n\n if (buffers.length === 1) {\n return buffers[0];\n }\n\n const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0);\n const result = new Uint8Array(totalLength);\n\n let offset = 0;\n for (const buffer of buffers) {\n result.set(buffer, offset);\n offset += buffer.length;\n }\n\n return result;\n }\n\n /**\n * Combines multiple AbortSignals into one.\n * The combined signal aborts when any of the input signals abort.\n */\n private combineAbortSignals(...signals: AbortSignal[]): AbortSignal {\n const controller = new AbortController();\n\n for (const signal of signals) {\n if (signal.aborted) {\n controller.abort();\n return controller.signal;\n }\n signal.addEventListener(\"abort\", () => controller.abort(), {\n once: true,\n });\n }\n\n return controller.signal;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\nclass Semaphore {\n private permits: number;\n private waiting: (() => void)[] = [];\n\n constructor(permits: number) {\n this.permits = permits;\n }\n\n async acquire(): Promise<void> {\n if (this.permits > 0) {\n this.permits--;\n return;\n }\n\n return new Promise<void>((resolve) => {\n this.waiting.push(resolve);\n });\n }\n\n release(): void {\n if (this.waiting.length > 0) {\n const next = this.waiting.shift();\n\n if (next) {\n next();\n }\n } else {\n this.permits++;\n }\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,7 @@
1
1
  import { ValidationError } from "../errors/validation.js";
2
- import { init_errors } from "../errors/index.js";
2
+ import "../errors/index.js";
3
3
 
4
4
  //#region src/stream/buffers.ts
5
- init_errors();
6
5
  var RingBuffer = class {
7
6
  buffer;
8
7
  capacity;
@@ -1 +1 @@
1
- {"version":3,"file":"buffers.js","names":[],"sources":["../../src/stream/buffers.ts"],"sourcesContent":["import { ValidationError } from \"../errors\";\nimport type { BufferedEvent } from \"./types\";\n\n// generic ring buffer implementation\nexport class RingBuffer<T> {\n public buffer: (T | null)[];\n public capacity: number;\n private writeIndex: number;\n private size: number;\n private keyExtractor: (item: T) => string;\n private keyIndex: Map<string, number>;\n\n constructor(capacity: number, keyExtractor: (item: T) => string) {\n if (capacity <= 0) {\n throw ValidationError.invalidValue(\n \"capacity\",\n capacity,\n \"greater than 0\",\n );\n }\n\n this.capacity = capacity;\n this.buffer = new Array(capacity).fill(null);\n this.writeIndex = 0;\n this.size = 0;\n this.keyExtractor = keyExtractor;\n this.keyIndex = new Map();\n }\n\n // add an item to the buffer\n add(item: T): void {\n const key = this.keyExtractor(item);\n\n // check if item already exists\n const existingIndex = this.keyIndex.get(key);\n if (existingIndex !== undefined) {\n // update existing item\n this.buffer[existingIndex] = item;\n return;\n }\n\n // evict least recently used item if at capacity\n const evicted = this.buffer[this.writeIndex];\n if (evicted !== null) {\n const evictedKey = this.keyExtractor(evicted);\n this.keyIndex.delete(evictedKey);\n }\n\n // add new item\n this.buffer[this.writeIndex] = item;\n this.keyIndex.set(key, this.writeIndex);\n\n // update write index and size\n this.writeIndex = (this.writeIndex + 1) % this.capacity;\n this.size = Math.min(this.size + 1, this.capacity);\n }\n\n // get an item from the buffer\n get(key: string): T | null {\n const index = this.keyIndex.get(key);\n if (index === undefined) return null;\n\n return this.buffer[index];\n }\n\n // check if an item exists in the buffer\n has(key: string): boolean {\n return this.keyIndex.has(key);\n }\n\n // remove an item from the buffer\n remove(key: string): void {\n const index = this.keyIndex.get(key);\n if (index === undefined) return;\n\n // remove item from buffer\n this.buffer[index] = null;\n this.keyIndex.delete(key);\n\n // update size\n this.size = Math.max(this.size - 1, 0);\n }\n\n // get all items from the buffer\n getAll(): T[] {\n const result: T[] = [];\n\n // iterate over buffer in order of insertion\n for (let i = 0; i < this.size; i++) {\n // calculate index of item in buffer\n const index =\n (this.writeIndex - this.size + i + this.capacity) % this.capacity;\n // add item to result if not null\n const item = this.buffer[index];\n if (item !== null) {\n result.push(item);\n }\n }\n return result;\n }\n\n // get the size of the buffer\n getSize(): number {\n return this.size;\n }\n\n // clear the buffer\n clear(): void {\n this.buffer = new Array(this.capacity).fill(null);\n this.keyIndex.clear();\n this.writeIndex = 0;\n this.size = 0;\n }\n}\n\n// event ring buffer implementation\nexport class EventRingBuffer {\n private buffer: RingBuffer<BufferedEvent>;\n\n constructor(capacity: number = 100) {\n this.buffer = new RingBuffer<BufferedEvent>(capacity, (event) => event.id);\n }\n\n // add an event to the buffer\n add(event: BufferedEvent): void {\n this.buffer.add(event);\n }\n\n // check if an event exists in the buffer\n has(eventId: string): boolean {\n return this.buffer.has(eventId);\n }\n\n // get all events since a given event id\n getEventsSince(lastEventId: string): BufferedEvent[] {\n const allEvents = this.buffer.getAll();\n const result: BufferedEvent[] = [];\n // flag to track if we've found the last event\n let foundLastEvent = false;\n\n // iterate over all events\n for (const event of allEvents) {\n // if found, add to result\n if (foundLastEvent) {\n result.push(event);\n // if not found, check if it's the last event\n } else if (event.id === lastEventId) {\n foundLastEvent = true;\n }\n }\n return result;\n }\n\n clear(): void {\n this.buffer.clear();\n }\n}\n"],"mappings":";;;;aAA4C;AAI5C,IAAa,aAAb,MAA2B;CACzB,AAAO;CACP,AAAO;CACP,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YAAY,UAAkB,cAAmC;AAC/D,MAAI,YAAY,EACd,OAAM,gBAAgB,aACpB,YACA,UACA,iBACD;AAGH,OAAK,WAAW;AAChB,OAAK,SAAS,IAAI,MAAM,SAAS,CAAC,KAAK,KAAK;AAC5C,OAAK,aAAa;AAClB,OAAK,OAAO;AACZ,OAAK,eAAe;AACpB,OAAK,2BAAW,IAAI,KAAK;;CAI3B,IAAI,MAAe;EACjB,MAAM,MAAM,KAAK,aAAa,KAAK;EAGnC,MAAM,gBAAgB,KAAK,SAAS,IAAI,IAAI;AAC5C,MAAI,kBAAkB,QAAW;AAE/B,QAAK,OAAO,iBAAiB;AAC7B;;EAIF,MAAM,UAAU,KAAK,OAAO,KAAK;AACjC,MAAI,YAAY,MAAM;GACpB,MAAM,aAAa,KAAK,aAAa,QAAQ;AAC7C,QAAK,SAAS,OAAO,WAAW;;AAIlC,OAAK,OAAO,KAAK,cAAc;AAC/B,OAAK,SAAS,IAAI,KAAK,KAAK,WAAW;AAGvC,OAAK,cAAc,KAAK,aAAa,KAAK,KAAK;AAC/C,OAAK,OAAO,KAAK,IAAI,KAAK,OAAO,GAAG,KAAK,SAAS;;CAIpD,IAAI,KAAuB;EACzB,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AACpC,MAAI,UAAU,OAAW,QAAO;AAEhC,SAAO,KAAK,OAAO;;CAIrB,IAAI,KAAsB;AACxB,SAAO,KAAK,SAAS,IAAI,IAAI;;CAI/B,OAAO,KAAmB;EACxB,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AACpC,MAAI,UAAU,OAAW;AAGzB,OAAK,OAAO,SAAS;AACrB,OAAK,SAAS,OAAO,IAAI;AAGzB,OAAK,OAAO,KAAK,IAAI,KAAK,OAAO,GAAG,EAAE;;CAIxC,SAAc;EACZ,MAAM,SAAc,EAAE;AAGtB,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,KAAK;GAElC,MAAM,SACH,KAAK,aAAa,KAAK,OAAO,IAAI,KAAK,YAAY,KAAK;GAE3D,MAAM,OAAO,KAAK,OAAO;AACzB,OAAI,SAAS,KACX,QAAO,KAAK,KAAK;;AAGrB,SAAO;;CAIT,UAAkB;AAChB,SAAO,KAAK;;CAId,QAAc;AACZ,OAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC,KAAK,KAAK;AACjD,OAAK,SAAS,OAAO;AACrB,OAAK,aAAa;AAClB,OAAK,OAAO;;;AAKhB,IAAa,kBAAb,MAA6B;CAC3B,AAAQ;CAER,YAAY,WAAmB,KAAK;AAClC,OAAK,SAAS,IAAI,WAA0B,WAAW,UAAU,MAAM,GAAG;;CAI5E,IAAI,OAA4B;AAC9B,OAAK,OAAO,IAAI,MAAM;;CAIxB,IAAI,SAA0B;AAC5B,SAAO,KAAK,OAAO,IAAI,QAAQ;;CAIjC,eAAe,aAAsC;EACnD,MAAM,YAAY,KAAK,OAAO,QAAQ;EACtC,MAAM,SAA0B,EAAE;EAElC,IAAI,iBAAiB;AAGrB,OAAK,MAAM,SAAS,UAElB,KAAI,eACF,QAAO,KAAK,MAAM;WAET,MAAM,OAAO,YACtB,kBAAiB;AAGrB,SAAO;;CAGT,QAAc;AACZ,OAAK,OAAO,OAAO"}
1
+ {"version":3,"file":"buffers.js","names":[],"sources":["../../src/stream/buffers.ts"],"sourcesContent":["import { ValidationError } from \"../errors\";\nimport type { BufferedEvent } from \"./types\";\n\n// generic ring buffer implementation\nexport class RingBuffer<T> {\n public buffer: (T | null)[];\n public capacity: number;\n private writeIndex: number;\n private size: number;\n private keyExtractor: (item: T) => string;\n private keyIndex: Map<string, number>;\n\n constructor(capacity: number, keyExtractor: (item: T) => string) {\n if (capacity <= 0) {\n throw ValidationError.invalidValue(\n \"capacity\",\n capacity,\n \"greater than 0\",\n );\n }\n\n this.capacity = capacity;\n this.buffer = new Array(capacity).fill(null);\n this.writeIndex = 0;\n this.size = 0;\n this.keyExtractor = keyExtractor;\n this.keyIndex = new Map();\n }\n\n // add an item to the buffer\n add(item: T): void {\n const key = this.keyExtractor(item);\n\n // check if item already exists\n const existingIndex = this.keyIndex.get(key);\n if (existingIndex !== undefined) {\n // update existing item\n this.buffer[existingIndex] = item;\n return;\n }\n\n // evict least recently used item if at capacity\n const evicted = this.buffer[this.writeIndex];\n if (evicted !== null) {\n const evictedKey = this.keyExtractor(evicted);\n this.keyIndex.delete(evictedKey);\n }\n\n // add new item\n this.buffer[this.writeIndex] = item;\n this.keyIndex.set(key, this.writeIndex);\n\n // update write index and size\n this.writeIndex = (this.writeIndex + 1) % this.capacity;\n this.size = Math.min(this.size + 1, this.capacity);\n }\n\n // get an item from the buffer\n get(key: string): T | null {\n const index = this.keyIndex.get(key);\n if (index === undefined) return null;\n\n return this.buffer[index];\n }\n\n // check if an item exists in the buffer\n has(key: string): boolean {\n return this.keyIndex.has(key);\n }\n\n // remove an item from the buffer\n remove(key: string): void {\n const index = this.keyIndex.get(key);\n if (index === undefined) return;\n\n // remove item from buffer\n this.buffer[index] = null;\n this.keyIndex.delete(key);\n\n // update size\n this.size = Math.max(this.size - 1, 0);\n }\n\n // get all items from the buffer\n getAll(): T[] {\n const result: T[] = [];\n\n // iterate over buffer in order of insertion\n for (let i = 0; i < this.size; i++) {\n // calculate index of item in buffer\n const index =\n (this.writeIndex - this.size + i + this.capacity) % this.capacity;\n // add item to result if not null\n const item = this.buffer[index];\n if (item !== null) {\n result.push(item);\n }\n }\n return result;\n }\n\n // get the size of the buffer\n getSize(): number {\n return this.size;\n }\n\n // clear the buffer\n clear(): void {\n this.buffer = new Array(this.capacity).fill(null);\n this.keyIndex.clear();\n this.writeIndex = 0;\n this.size = 0;\n }\n}\n\n// event ring buffer implementation\nexport class EventRingBuffer {\n private buffer: RingBuffer<BufferedEvent>;\n\n constructor(capacity: number = 100) {\n this.buffer = new RingBuffer<BufferedEvent>(capacity, (event) => event.id);\n }\n\n // add an event to the buffer\n add(event: BufferedEvent): void {\n this.buffer.add(event);\n }\n\n // check if an event exists in the buffer\n has(eventId: string): boolean {\n return this.buffer.has(eventId);\n }\n\n // get all events since a given event id\n getEventsSince(lastEventId: string): BufferedEvent[] {\n const allEvents = this.buffer.getAll();\n const result: BufferedEvent[] = [];\n // flag to track if we've found the last event\n let foundLastEvent = false;\n\n // iterate over all events\n for (const event of allEvents) {\n // if found, add to result\n if (foundLastEvent) {\n result.push(event);\n // if not found, check if it's the last event\n } else if (event.id === lastEventId) {\n foundLastEvent = true;\n }\n }\n return result;\n }\n\n clear(): void {\n this.buffer.clear();\n }\n}\n"],"mappings":";;;;AAIA,IAAa,aAAb,MAA2B;CACzB,AAAO;CACP,AAAO;CACP,AAAQ;CACR,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YAAY,UAAkB,cAAmC;AAC/D,MAAI,YAAY,EACd,OAAM,gBAAgB,aACpB,YACA,UACA,iBACD;AAGH,OAAK,WAAW;AAChB,OAAK,SAAS,IAAI,MAAM,SAAS,CAAC,KAAK,KAAK;AAC5C,OAAK,aAAa;AAClB,OAAK,OAAO;AACZ,OAAK,eAAe;AACpB,OAAK,2BAAW,IAAI,KAAK;;CAI3B,IAAI,MAAe;EACjB,MAAM,MAAM,KAAK,aAAa,KAAK;EAGnC,MAAM,gBAAgB,KAAK,SAAS,IAAI,IAAI;AAC5C,MAAI,kBAAkB,QAAW;AAE/B,QAAK,OAAO,iBAAiB;AAC7B;;EAIF,MAAM,UAAU,KAAK,OAAO,KAAK;AACjC,MAAI,YAAY,MAAM;GACpB,MAAM,aAAa,KAAK,aAAa,QAAQ;AAC7C,QAAK,SAAS,OAAO,WAAW;;AAIlC,OAAK,OAAO,KAAK,cAAc;AAC/B,OAAK,SAAS,IAAI,KAAK,KAAK,WAAW;AAGvC,OAAK,cAAc,KAAK,aAAa,KAAK,KAAK;AAC/C,OAAK,OAAO,KAAK,IAAI,KAAK,OAAO,GAAG,KAAK,SAAS;;CAIpD,IAAI,KAAuB;EACzB,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AACpC,MAAI,UAAU,OAAW,QAAO;AAEhC,SAAO,KAAK,OAAO;;CAIrB,IAAI,KAAsB;AACxB,SAAO,KAAK,SAAS,IAAI,IAAI;;CAI/B,OAAO,KAAmB;EACxB,MAAM,QAAQ,KAAK,SAAS,IAAI,IAAI;AACpC,MAAI,UAAU,OAAW;AAGzB,OAAK,OAAO,SAAS;AACrB,OAAK,SAAS,OAAO,IAAI;AAGzB,OAAK,OAAO,KAAK,IAAI,KAAK,OAAO,GAAG,EAAE;;CAIxC,SAAc;EACZ,MAAM,SAAc,EAAE;AAGtB,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,KAAK;GAElC,MAAM,SACH,KAAK,aAAa,KAAK,OAAO,IAAI,KAAK,YAAY,KAAK;GAE3D,MAAM,OAAO,KAAK,OAAO;AACzB,OAAI,SAAS,KACX,QAAO,KAAK,KAAK;;AAGrB,SAAO;;CAIT,UAAkB;AAChB,SAAO,KAAK;;CAId,QAAc;AACZ,OAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC,KAAK,KAAK;AACjD,OAAK,SAAS,OAAO;AACrB,OAAK,aAAa;AAClB,OAAK,OAAO;;;AAKhB,IAAa,kBAAb,MAA6B;CAC3B,AAAQ;CAER,YAAY,WAAmB,KAAK;AAClC,OAAK,SAAS,IAAI,WAA0B,WAAW,UAAU,MAAM,GAAG;;CAI5E,IAAI,OAA4B;AAC9B,OAAK,OAAO,IAAI,MAAM;;CAIxB,IAAI,SAA0B;AAC5B,SAAO,KAAK,OAAO,IAAI,QAAQ;;CAIjC,eAAe,aAAsC;EACnD,MAAM,YAAY,KAAK,OAAO,QAAQ;EACtC,MAAM,SAA0B,EAAE;EAElC,IAAI,iBAAiB;AAGrB,OAAK,MAAM,SAAS,UAElB,KAAI,eACF,QAAO,KAAK,MAAM;WAET,MAAM,OAAO,YACtB,kBAAiB;AAGrB,SAAO;;CAGT,QAAc;AACZ,OAAK,OAAO,OAAO"}
@@ -1,6 +1,6 @@
1
1
  # Enumeration: ResourceType
2
2
 
3
- Resource types from schema $defs.resourceType.enum
3
+ Resource types from resourceTypeSchema.options
4
4
 
5
5
  ## Enumeration Members[​](#enumeration-members "Direct link to Enumeration Members")
6
6
 
@@ -4,7 +4,7 @@ Plugin manifest that declares metadata and resource requirements. Attached to pl
4
4
 
5
5
  ## See[​](#see "Direct link to See")
6
6
 
7
- * `packages/shared/src/schemas/plugin-manifest.generated.ts` `PluginManifest` — generated base
7
+ * `packages/shared/src/schemas/manifest.ts` `pluginManifestSchema` — Zod source of truth
8
8
  * SharedPluginManifest — shared re-export with JSONSchema7 config
9
9
 
10
10
  ## Extends[​](#extends "Direct link to Extends")
@@ -233,6 +233,60 @@ Resources that must be available for the plugin to function
233
233
 
234
234
  ***
235
235
 
236
+ ### scaffolding?[​](#scaffolding "Direct link to scaffolding?")
237
+
238
+ ```ts
239
+ optional scaffolding: {
240
+ rules?: {
241
+ must?: string[];
242
+ never?: string[];
243
+ should?: string[];
244
+ };
245
+ };
246
+
247
+ ```
248
+
249
+ #### rules?[​](#rules "Direct link to rules?")
250
+
251
+ ```ts
252
+ optional rules: {
253
+ must?: string[];
254
+ never?: string[];
255
+ should?: string[];
256
+ };
257
+
258
+ ```
259
+
260
+ ##### rules.must?[​](#rulesmust "Direct link to rules.must?")
261
+
262
+ ```ts
263
+ optional must: string[];
264
+
265
+ ```
266
+
267
+ ##### rules.never?[​](#rulesnever "Direct link to rules.never?")
268
+
269
+ ```ts
270
+ optional never: string[];
271
+
272
+ ```
273
+
274
+ ##### rules.should?[​](#rulesshould "Direct link to rules.should?")
275
+
276
+ ```ts
277
+ optional should: string[];
278
+
279
+ ```
280
+
281
+ #### Inherited from[​](#inherited-from-8 "Direct link to Inherited from")
282
+
283
+ ```ts
284
+ Omit.scaffolding
285
+
286
+ ```
287
+
288
+ ***
289
+
236
290
  ### stability?[​](#stability "Direct link to stability?")
237
291
 
238
292
  ```ts
@@ -242,7 +296,7 @@ optional stability: "beta" | "ga";
242
296
 
243
297
  Plugin stability level. Beta plugins may have breaking API changes between minor releases but are on a path to GA. GA (general availability) plugins follow semver strictly.
244
298
 
245
- #### Inherited from[​](#inherited-from-8 "Direct link to Inherited from")
299
+ #### Inherited from[​](#inherited-from-9 "Direct link to Inherited from")
246
300
 
247
301
  ```ts
248
302
  Omit.stability
@@ -260,7 +314,7 @@ optional version: string;
260
314
 
261
315
  Plugin version (semver format)
262
316
 
263
- #### Inherited from[​](#inherited-from-9 "Direct link to Inherited from")
317
+ #### Inherited from[​](#inherited-from-10 "Direct link to Inherited from")
264
318
 
265
319
  ```ts
266
320
  Omit.version
@@ -15,7 +15,7 @@ alias: string;
15
15
 
16
16
  ```
17
17
 
18
- Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.
18
+ Human-readable label for UI/display only.
19
19
 
20
20
  #### Inherited from[​](#inherited-from "Direct link to Inherited from")
21
21
 
@@ -30,7 +30,7 @@ description: string;
30
30
 
31
31
  ```
32
32
 
33
- Human-readable description of why this resource is needed
33
+ Human-readable description of why this resource is needed.
34
34
 
35
35
  #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from")
36
36
 
@@ -45,7 +45,7 @@ fields: Record<string, ResourceFieldEntry>;
45
45
 
46
46
  ```
47
47
 
48
- Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance\_name, database\_name or scope, key).
48
+ Map of field name to field entry. Required at runtime.
49
49
 
50
50
  #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from")
51
51
 
@@ -97,6 +97,8 @@ required: boolean;
97
97
 
98
98
  ```
99
99
 
100
+ Whether the resource is mandatory at runtime.
101
+
100
102
  #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from")
101
103
 
102
104
  [`ResourceRequirement`](./docs/api/appkit/Interface.ResourceRequirement.md).[`required`](./docs/api/appkit/Interface.ResourceRequirement.md#required)
@@ -121,7 +123,7 @@ resourceKey: string;
121
123
 
122
124
  ```
123
125
 
124
- Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.
126
+ Stable key for machine use: deduplication, env naming, composite keys, app.yaml.
125
127
 
126
128
  #### Inherited from[​](#inherited-from-5 "Direct link to Inherited from")
127
129
 
@@ -1,15 +1,8 @@
1
1
  # Interface: ResourceRequirement
2
2
 
3
- Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements(). Narrows the generated base: type → ResourceType enum, permission → ResourcePermission union.
3
+ Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements().
4
4
 
5
- ## See[​](#see "Direct link to See")
6
-
7
- * `packages/shared/src/schemas/plugin-manifest.generated.ts` `ResourceRequirement` — generated base
8
- * SharedResourceRequirement — shared re-export with runtime `fields` and `required`
9
-
10
- ## Extends[​](#extends "Direct link to Extends")
11
-
12
- * `ResourceRequirement`
5
+ Defined as a flat structural shape rather than narrowing the shared discriminated-union `ResourceRequirement`. The registry needs to construct and pass these values around at runtime where `type` and `permission` are looked up dynamically from a string; preserving per-variant tightness here would force every constructor to thread variant types end-to-end. The runtime guarantee (permission valid for type) is enforced by the manifest schema's parse, not by the registry's static types.
13
6
 
14
7
  ## Extended by[​](#extended-by "Direct link to Extended by")
15
8
 
@@ -24,14 +17,7 @@ alias: string;
24
17
 
25
18
  ```
26
19
 
27
- Human-readable label for UI/display only. Deduplication uses resourceKey, not alias.
28
-
29
- #### Inherited from[​](#inherited-from "Direct link to Inherited from")
30
-
31
- ```ts
32
- SharedResourceRequirement.alias
33
-
34
- ```
20
+ Human-readable label for UI/display only.
35
21
 
36
22
  ***
37
23
 
@@ -42,14 +28,7 @@ description: string;
42
28
 
43
29
  ```
44
30
 
45
- Human-readable description of why this resource is needed
46
-
47
- #### Inherited from[​](#inherited-from-1 "Direct link to Inherited from")
48
-
49
- ```ts
50
- SharedResourceRequirement.description
51
-
52
- ```
31
+ Human-readable description of why this resource is needed.
53
32
 
54
33
  ***
55
34
 
@@ -60,14 +39,7 @@ fields: Record<string, ResourceFieldEntry>;
60
39
 
61
40
  ```
62
41
 
63
- Map of field name to env and optional description. Single-value types use one key (e.g. id); multi-value (database, secret) use multiple (e.g. instance\_name, database\_name or scope, key).
64
-
65
- #### Inherited from[​](#inherited-from-2 "Direct link to Inherited from")
66
-
67
- ```ts
68
- SharedResourceRequirement.fields
69
-
70
- ```
42
+ Map of field name to field entry. Required at runtime.
71
43
 
72
44
  ***
73
45
 
@@ -80,13 +52,6 @@ permission: ResourcePermission;
80
52
 
81
53
  Required permission level for the resource (narrowed to union)
82
54
 
83
- #### Overrides[​](#overrides "Direct link to Overrides")
84
-
85
- ```ts
86
- SharedResourceRequirement.permission
87
-
88
- ```
89
-
90
55
  ***
91
56
 
92
57
  ### required[​](#required "Direct link to required")
@@ -96,12 +61,7 @@ required: boolean;
96
61
 
97
62
  ```
98
63
 
99
- #### Inherited from[​](#inherited-from-3 "Direct link to Inherited from")
100
-
101
- ```ts
102
- SharedResourceRequirement.required
103
-
104
- ```
64
+ Whether the resource is mandatory at runtime.
105
65
 
106
66
  ***
107
67
 
@@ -112,14 +72,7 @@ resourceKey: string;
112
72
 
113
73
  ```
114
74
 
115
- Stable key for machine use: deduplication, env naming, composite keys, app.yaml. Required for registry lookup.
116
-
117
- #### Inherited from[​](#inherited-from-4 "Direct link to Inherited from")
118
-
119
- ```ts
120
- SharedResourceRequirement.resourceKey
121
-
122
- ```
75
+ Stable key for machine use: deduplication, env naming, composite keys, app.yaml.
123
76
 
124
77
  ***
125
78
 
@@ -131,10 +84,3 @@ type: ResourceType;
131
84
  ```
132
85
 
133
86
  Type of Databricks resource required (narrowed to enum)
134
-
135
- #### Overrides[​](#overrides-1 "Direct link to Overrides")
136
-
137
- ```ts
138
- SharedResourceRequirement.type
139
-
140
- ```
@@ -0,0 +1,6 @@
1
+ # Type Alias: ResourceFieldEntry
2
+
3
+ ```ts
4
+ type ResourceFieldEntry = z.infer<typeof resourceFieldEntrySchema>;
5
+
6
+ ```
@@ -5,7 +5,7 @@ const agents: ToPlugin<typeof AgentsPlugin, AgentsPluginConfig, string>;
5
5
 
6
6
  ```
7
7
 
8
- Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts `/invocations`.
8
+ Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts `POST /invocations` and `POST /responses` (aliased non-streaming invoke endpoints) plus `POST /chat` (streaming, HITL-capable).
9
9
 
10
10
  ## Example[​](#example "Direct link to Example")
11
11
 
@@ -4,10 +4,10 @@ Documentation merge entry for Typedoc — combines the stable `@databricks/appki
4
4
 
5
5
  ## Enumerations[​](#enumerations "Direct link to Enumerations")
6
6
 
7
- | Enumeration | Description |
8
- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
9
- | [RequestedClaimsPermissionSet](./docs/api/appkit/Enumeration.RequestedClaimsPermissionSet.md) | Permission set for Unity Catalog table access |
10
- | [ResourceType](./docs/api/appkit/Enumeration.ResourceType.md) | Resource types from schema $defs.resourceType.enum |
7
+ | Enumeration | Description |
8
+ | --------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
9
+ | [RequestedClaimsPermissionSet](./docs/api/appkit/Enumeration.RequestedClaimsPermissionSet.md) | Permission set for Unity Catalog table access |
10
+ | [ResourceType](./docs/api/appkit/Enumeration.ResourceType.md) | Resource types from resourceTypeSchema.options |
11
11
 
12
12
  ## Classes[​](#classes "Direct link to Classes")
13
13
 
@@ -64,8 +64,7 @@ Documentation merge entry for Typedoc — combines the stable `@databricks/appki
64
64
  | [RequestedClaims](./docs/api/appkit/Interface.RequestedClaims.md) | Optional claims for fine-grained Unity Catalog table permissions When specified, the returned token will be scoped to only the requested tables |
65
65
  | [RequestedResource](./docs/api/appkit/Interface.RequestedResource.md) | Resource to request permissions for in Unity Catalog |
66
66
  | [ResourceEntry](./docs/api/appkit/Interface.ResourceEntry.md) | Internal representation of a resource in the registry. Extends ResourceRequirement with resolution state and plugin ownership. |
67
- | [ResourceFieldEntry](./docs/api/appkit/Interface.ResourceFieldEntry.md) | Defines a single field for a resource. Each field has its own environment variable and optional description. Single-value types use one key (e.g. id); multi-value types (database, secret) use multiple (e.g. instance\_name, database\_name or scope, key). |
68
- | [ResourceRequirement](./docs/api/appkit/Interface.ResourceRequirement.md) | Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements(). Narrows the generated base: type → ResourceType enum, permission → ResourcePermission union. |
67
+ | [ResourceRequirement](./docs/api/appkit/Interface.ResourceRequirement.md) | Declares a resource requirement for a plugin. Can be defined statically in a manifest or dynamically via getResourceRequirements(). |
69
68
  | [RunAgentInput](./docs/api/appkit/Interface.RunAgentInput.md) | - |
70
69
  | [RunAgentResult](./docs/api/appkit/Interface.RunAgentResult.md) | - |
71
70
  | [ServingEndpointEntry](./docs/api/appkit/Interface.ServingEndpointEntry.md) | Shape of a single registry entry. |
@@ -102,6 +101,7 @@ Documentation merge entry for Typedoc — combines the stable `@databricks/appki
102
101
  | [PluginData](./docs/api/appkit/TypeAlias.PluginData.md) | Tuple of plugin class, config, and name. Created by `toPlugin()` and passed to `createApp()`. |
103
102
  | [Plugins](./docs/api/appkit/TypeAlias.Plugins.md) | Plugin map passed to the function form of [AgentDefinition.tools](./docs/api/appkit/Interface.AgentDefinition.md#tools). Each entry exposes a `.toolkit(opts?)` method that returns a record of [ToolkitEntry](./docs/api/appkit/Interface.ToolkitEntry.md) markers ready to be spread into a tool record. |
104
103
  | [ResolvedToolEntry](./docs/api/appkit/TypeAlias.ResolvedToolEntry.md) | Internal tool-index entry after a tool record has been resolved to a dispatchable form. |
104
+ | [ResourceFieldEntry](./docs/api/appkit/TypeAlias.ResourceFieldEntry.md) | - |
105
105
  | [ResourcePermission](./docs/api/appkit/TypeAlias.ResourcePermission.md) | Union of all possible permission levels across all resource types. |
106
106
  | [ServingFactory](./docs/api/appkit/TypeAlias.ServingFactory.md) | Factory function returned by `AppKit.serving`. |
107
107
  | [ToolRegistry](./docs/api/appkit/TypeAlias.ToolRegistry.md) | - |
@@ -109,12 +109,12 @@ Documentation merge entry for Typedoc — combines the stable `@databricks/appki
109
109
 
110
110
  ## Variables[​](#variables "Direct link to Variables")
111
111
 
112
- | Variable | Description |
113
- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
114
- | [agents](./docs/api/appkit/Variable.agents.md) | Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts `/invocations`. |
115
- | [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data. |
116
- | [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace |
117
- | [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data. |
112
+ | Variable | Description |
113
+ | ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
114
+ | [agents](./docs/api/appkit/Variable.agents.md) | Plugin factory for the agents plugin. Reads `config/agents/*.md` by default, resolves toolkits/tools from registered plugins, exposes `appkit.agents.*` runtime API and mounts `POST /invocations` and `POST /responses` (aliased non-streaming invoke endpoints) plus `POST /chat` (streaming, HITL-capable). |
115
+ | [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data. |
116
+ | [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace |
117
+ | [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data. |
118
118
 
119
119
  ## Functions[​](#functions "Direct link to Functions")
120
120
 
@@ -5,7 +5,7 @@ Manage your AppKit application throughout its lifecycle using the Databricks CLI
5
5
  ## Prerequisites[​](#prerequisites "Direct link to Prerequisites")
6
6
 
7
7
  * [Node.js](https://nodejs.org) v22+ environment with `npm`
8
- * Databricks CLI (v0.295.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
8
+ * Databricks CLI (v1.0.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
9
9
 
10
10
  ## Create app[​](#create-app "Direct link to Create app")
11
11
 
@@ -3,7 +3,7 @@
3
3
  ## Prerequisites[​](#prerequisites "Direct link to Prerequisites")
4
4
 
5
5
  * [Node.js](https://nodejs.org) v22+ environment with `npm`
6
- * Databricks CLI (v0.295.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
6
+ * Databricks CLI (v1.0.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
7
7
  * A new Databricks app with AppKit installed. See [Bootstrap a new Databricks app](./docs.md#quick-start-options) for more details.
8
8
 
9
9
  AppKit integrates with AI coding assistants through the Agent Skills.
@@ -13,7 +13,7 @@ AppKit integrates with AI coding assistants through the Agent Skills.
13
13
  To install the Databricks Agent Skills for your preferred AI assistant, run:
14
14
 
15
15
  ```bash
16
- databricks experimental aitools install
16
+ databricks aitools install
17
17
 
18
18
  ```
19
19
 
@@ -3,7 +3,7 @@
3
3
  ## Prerequisites[​](#prerequisites "Direct link to Prerequisites")
4
4
 
5
5
  * [Node.js](https://nodejs.org) v22+ environment with `npm`
6
- * Databricks CLI (v0.295.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
6
+ * Databricks CLI (v1.0.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
7
7
  * A new Databricks app with AppKit installed. See [Bootstrap a new Databricks app](./docs.md#quick-start-options) for more details.
8
8
 
9
9
  Once your app is bootstrapped according to the [Manual quick start](./docs.md#manual-quick-start) guide, you can start the development server with hot reload for both UI and backend code.
@@ -3,7 +3,7 @@
3
3
  ## Prerequisites[​](#prerequisites "Direct link to Prerequisites")
4
4
 
5
5
  * [Node.js](https://nodejs.org) v22+ environment with `npm`
6
- * Databricks CLI (v0.295.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
6
+ * Databricks CLI (v1.0.0 or higher): install and configure it according to the [official tutorial](https://docs.databricks.com/aws/en/dev-tools/cli/tutorial).
7
7
  * A new Databricks app with AppKit installed. See [Bootstrap a new Databricks app](./docs.md#quick-start-options) for more details.
8
8
 
9
9
  Remote bridge allows you to develop against a deployed backend while keeping your UI and queries local. This is useful for testing against production data or debugging deployed backend code without redeploying your app.