@adea-ai/plugins 4.0.1 → 4.0.7

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 (142) hide show
  1. package/dist/agent-plugins-catalog.d.ts +2 -4
  2. package/dist/agent-plugins-catalog.js +42 -50
  3. package/dist/agent-plugins-catalog.js.map +1 -1
  4. package/dist/agent-plugins-schema.d.ts +8 -0
  5. package/dist/agent-plugins-schema.js +10 -1
  6. package/dist/agent-plugins-schema.js.map +1 -1
  7. package/dist/artifacts.d.ts +57 -0
  8. package/dist/artifacts.js +159 -0
  9. package/dist/artifacts.js.map +1 -0
  10. package/dist/build.d.ts +20 -0
  11. package/dist/build.js +103 -0
  12. package/dist/build.js.map +1 -0
  13. package/dist/capabilities.d.ts +7 -0
  14. package/dist/capabilities.js +116 -0
  15. package/dist/capabilities.js.map +1 -0
  16. package/dist/catalog-store.d.ts +0 -5
  17. package/dist/catalog-store.js +1 -25
  18. package/dist/catalog-store.js.map +1 -1
  19. package/dist/concurrency.d.ts +1 -0
  20. package/dist/concurrency.js +15 -0
  21. package/dist/concurrency.js.map +1 -0
  22. package/dist/consumer-index.d.ts +6 -28
  23. package/dist/consumer-index.js +7 -8
  24. package/dist/consumer-index.js.map +1 -1
  25. package/dist/digest.d.ts +13 -0
  26. package/dist/digest.js +47 -0
  27. package/dist/digest.js.map +1 -0
  28. package/dist/fs-atomic.d.ts +7 -0
  29. package/dist/fs-atomic.js +30 -0
  30. package/dist/fs-atomic.js.map +1 -0
  31. package/dist/harness.js +2 -1
  32. package/dist/harness.js.map +1 -1
  33. package/dist/icon-mirror.d.ts +3 -2
  34. package/dist/icon-mirror.js +51 -63
  35. package/dist/icon-mirror.js.map +1 -1
  36. package/dist/icons.d.ts +2 -2
  37. package/dist/icons.js +4 -12
  38. package/dist/icons.js.map +1 -1
  39. package/dist/index.d.ts +16 -315
  40. package/dist/index.js +12 -1905
  41. package/dist/index.js.map +1 -1
  42. package/dist/integrity-manifest.d.ts +43 -13
  43. package/dist/integrity-manifest.js +28 -17
  44. package/dist/integrity-manifest.js.map +1 -1
  45. package/dist/json-values.d.ts +3 -0
  46. package/dist/json-values.js +10 -0
  47. package/dist/json-values.js.map +1 -0
  48. package/dist/plugin-release.d.ts +38 -0
  49. package/dist/plugin-release.js +321 -0
  50. package/dist/plugin-release.js.map +1 -0
  51. package/dist/plugin-skips.d.ts +19 -0
  52. package/dist/plugin-skips.js +65 -0
  53. package/dist/plugin-skips.js.map +1 -0
  54. package/dist/policy.d.ts +13 -0
  55. package/dist/policy.js +26 -0
  56. package/dist/policy.js.map +1 -0
  57. package/dist/portable-catalog.d.ts +4 -4
  58. package/dist/portable-catalog.js +14 -126
  59. package/dist/portable-catalog.js.map +1 -1
  60. package/dist/portable-verify.d.ts +2 -0
  61. package/dist/portable-verify.js +68 -0
  62. package/dist/portable-verify.js.map +1 -0
  63. package/dist/publication.d.ts +6 -3
  64. package/dist/publication.js +25 -12
  65. package/dist/publication.js.map +1 -1
  66. package/dist/published-output.d.ts +17 -0
  67. package/dist/published-output.js +49 -0
  68. package/dist/published-output.js.map +1 -0
  69. package/dist/site-icons.d.ts +2 -3
  70. package/dist/site-icons.js +4 -3
  71. package/dist/site-icons.js.map +1 -1
  72. package/dist/snapshots.d.ts +39 -0
  73. package/dist/snapshots.js +238 -0
  74. package/dist/snapshots.js.map +1 -0
  75. package/dist/source-resolution.d.ts +28 -0
  76. package/dist/source-resolution.js +158 -0
  77. package/dist/source-resolution.js.map +1 -0
  78. package/dist/sources.d.ts +5 -1
  79. package/dist/sources.js +21 -27
  80. package/dist/sources.js.map +1 -1
  81. package/dist/synchronize.d.ts +44 -0
  82. package/dist/synchronize.js +118 -0
  83. package/dist/synchronize.js.map +1 -0
  84. package/dist/taxonomy.d.ts +23 -0
  85. package/dist/taxonomy.js +62 -0
  86. package/dist/taxonomy.js.map +1 -0
  87. package/dist/upstream.d.ts +42 -0
  88. package/dist/upstream.js +179 -0
  89. package/dist/upstream.js.map +1 -0
  90. package/dist/verify-artifacts.d.ts +36 -0
  91. package/dist/verify-artifacts.js +286 -0
  92. package/dist/verify-artifacts.js.map +1 -0
  93. package/native/build-provenance.txt +5 -5
  94. package/native/staged-reader-win32-arm64.node +0 -0
  95. package/native/staged-reader-win32-x64.node +0 -0
  96. package/package.json +2 -4
  97. package/src/agent-plugins-catalog.test.ts +2 -2
  98. package/src/agent-plugins-catalog.ts +46 -49
  99. package/src/agent-plugins-schema.ts +11 -1
  100. package/src/artifacts.ts +234 -0
  101. package/src/build.ts +131 -0
  102. package/src/capabilities.ts +153 -0
  103. package/src/catalog-store.ts +1 -28
  104. package/src/concurrency.ts +19 -0
  105. package/src/consumer-index.test.ts +27 -21
  106. package/src/consumer-index.ts +12 -35
  107. package/src/digest.ts +55 -0
  108. package/src/fs-atomic.ts +32 -0
  109. package/src/harness.test.ts +4 -32
  110. package/src/harness.ts +2 -1
  111. package/src/icon-mirror.ts +57 -64
  112. package/src/icons.test.ts +0 -4
  113. package/src/icons.ts +4 -4
  114. package/src/index.test.ts +52 -48
  115. package/src/index.ts +50 -2583
  116. package/src/integrity-manifest.ts +41 -21
  117. package/src/json-values.ts +11 -0
  118. package/src/plugin-release.ts +457 -0
  119. package/src/plugin-skips.ts +110 -0
  120. package/src/policy.ts +39 -0
  121. package/src/portable-catalog.test.ts +0 -5
  122. package/src/portable-catalog.ts +16 -143
  123. package/src/portable-verify.ts +71 -0
  124. package/src/publication.test.ts +29 -1
  125. package/src/publication.ts +32 -13
  126. package/src/published-output.ts +60 -0
  127. package/src/site-icons.test.ts +0 -1
  128. package/src/site-icons.ts +4 -4
  129. package/src/snapshots.ts +287 -0
  130. package/src/source-digest.test.ts +3 -7
  131. package/src/source-resolution.ts +233 -0
  132. package/src/sources-json.test.ts +0 -1
  133. package/src/sources.ts +27 -33
  134. package/src/synchronize.ts +213 -0
  135. package/src/taxonomy.ts +87 -0
  136. package/src/upstream.ts +194 -0
  137. package/src/verify-artifacts.ts +365 -0
  138. package/src/write-artifacts.test.ts +0 -1
  139. package/dist/source-digest.d.ts +0 -2
  140. package/dist/source-digest.js +0 -12
  141. package/dist/source-digest.js.map +0 -1
  142. package/src/source-digest.ts +0 -14
package/src/index.test.ts CHANGED
@@ -108,6 +108,9 @@ const policy: CatalogPolicy = {
108
108
  ],
109
109
  }
110
110
 
111
+ /** Upstream failures retry immediately, so retry tests do not wait out real backoff. */
112
+ const RETRY_NOW = { 'retry-after': '0' }
113
+
111
114
  function stubFetch(handler: (url: string) => Response | Promise<Response>) {
112
115
  const original = globalThis.fetch
113
116
  const calls: string[] = []
@@ -233,6 +236,23 @@ describe('source adapters', () => {
233
236
  expect(gitSource.kind === 'git' ? gitSource.subdirectory : undefined).toBe('plugins/demo')
234
237
  })
235
238
 
239
+ test('leaves out entries with an unsupported source kind and keeps the rest', () => {
240
+ const parsed = parseMarketplaceManifest(
241
+ {
242
+ plugins: [
243
+ { name: 'xcode', source: { source: 'command', command: 'install-xcode-plugin' } },
244
+ { name: 'demo', source: './plugins/demo' },
245
+ ],
246
+ },
247
+ sources[0]!
248
+ )
249
+ expect(parsed.entries.map((entry) => entry.name)).toEqual(['demo'])
250
+ expect(parsed.unsupportedEntries).toEqual(['xcode: command'])
251
+ expect(() => parseSourceSpec({ source: 'command' }, sources[0]!, 'xcode')).toThrow(
252
+ 'PLUGIN_SOURCE_KIND_UNSUPPORTED'
253
+ )
254
+ })
255
+
236
256
  test('rejects duplicate keys, traversal, and unsupported URL schemes', () => {
237
257
  expect(() => parseJsonDocument('{"plugins":[],"plugins":[]}')).toThrow('JSON_DUPLICATE_KEY')
238
258
  expect(() => parseSourceSpec({ source: 'local', path: '../outside' }, sources[0]!)).toThrow(
@@ -723,37 +743,6 @@ describe('deterministic catalog synchronization', () => {
723
743
  await rm(parent, { recursive: true, force: true })
724
744
  }
725
745
  })
726
-
727
- test('keeps a failed build from producing a new artifact set', async () => {
728
- const first = await synchronize({
729
- sources,
730
- categoryMap,
731
- productAliases,
732
- policy,
733
- mode: 'offline',
734
- fixtureRoot: join(process.cwd(), 'fixtures'),
735
- })
736
- const outputDirectory = join(await mkdtemp(join(tmpdir(), 'plugin-lkg-')), 'generated')
737
- await writeArtifacts(outputDirectory, first.artifacts!)
738
- const previousCatalog = await readFile(join(outputDirectory, 'catalog.v1.json'), 'utf8')
739
- await expect(
740
- synchronize({
741
- sources,
742
- categoryMap,
743
- productAliases,
744
- policy,
745
- mode: 'offline',
746
- fixtureRoot: join(process.cwd(), 'fixtures'),
747
- snapshotLoader: {
748
- load: async () => {
749
- throw new Error('UPSTREAM_FETCH_FAILED')
750
- },
751
- },
752
- })
753
- ).rejects.toThrow('UPSTREAM_FETCH_FAILED')
754
- expect(first.artifacts?.['catalog.v1.json']).toContain(first.catalog?.catalogId)
755
- expect(await readFile(join(outputDirectory, 'catalog.v1.json'), 'utf8')).toBe(previousCatalog)
756
- })
757
746
  })
758
747
 
759
748
  describe('identity, classification, and harness contracts', () => {
@@ -762,11 +751,16 @@ describe('identity, classification, and harness contracts', () => {
762
751
  stablePluginId('cursor-official', 'gmail')
763
752
  )
764
753
  expect(stablePluginId('--OpenAI--', '---Gmail---')).toBe('plugin:openai:gmail')
765
- expect(
766
- stableReleaseId('https://github.com/acme/a', 'plugins/x', 'a'.repeat(40), digest('same'))
767
- ).toBe(
768
- stableReleaseId('https://github.com/acme/a', 'plugins/x', 'a'.repeat(40), digest('same'))
754
+ const releaseId = stableReleaseId(
755
+ 'https://github.com/acme/a',
756
+ 'plugins/x',
757
+ 'a'.repeat(40),
758
+ digest('same')
769
759
  )
760
+ expect(releaseId).toMatch(/^release:[a-f0-9]{64}$/)
761
+ expect(
762
+ stableReleaseId('https://github.com/acme/a', 'plugins/x', 'a'.repeat(40), digest('other'))
763
+ ).not.toBe(releaseId)
770
764
  expect(
771
765
  bytesDigest(
772
766
  new Map([
@@ -796,15 +790,25 @@ describe('filesystem safety', () => {
796
790
  expect(snapshot.symlinks).toEqual(['plugin'])
797
791
  })
798
792
 
799
- test('enforces file and archive-like size limits', async () => {
800
- const root = await mkdtemp(join(tmpdir(), 'plugins-size-'))
801
- await mkdir(join(root, 'plugin'), { recursive: true })
802
- await writeFile(join(root, 'plugin', 'large.txt'), '1234567890')
803
- const snapshot = await snapshotFromDirectory(root, 'plugin')
804
- expect(snapshot.files.size).toBe(1)
805
- expect(() => {
806
- if ([...snapshot.files.values()][0]!.byteLength > 5) throw new Error('PLUGIN_FILE_TOO_LARGE')
807
- }).toThrow('PLUGIN_FILE_TOO_LARGE')
793
+ test('skips a plugin with a file over the size limit', async () => {
794
+ const result = await synchronize({
795
+ sources,
796
+ categoryMap,
797
+ productAliases,
798
+ policy: { ...policy, maxFileBytes: 5 },
799
+ mode: 'offline',
800
+ fixtureRoot: join(process.cwd(), 'fixtures'),
801
+ snapshotLoader: {
802
+ load: async () => ({
803
+ files: new Map([['large.txt', new TextEncoder().encode('1234567890')]]),
804
+ symlinks: [],
805
+ }),
806
+ },
807
+ })
808
+ const reasons = result.changeReport.skippedPlugins.map((skipped) => skipped.reasonCode)
809
+ expect(reasons.length).toBeGreaterThan(0)
810
+ expect(new Set(reasons)).toEqual(new Set(['PLUGIN_FILE_TOO_LARGE']))
811
+ expect(result.catalog?.plugins).toEqual([])
808
812
  })
809
813
  })
810
814
 
@@ -858,7 +862,7 @@ describe('upstream fetch quarantine', () => {
858
862
  const stub = stubFetch(async (url) => {
859
863
  if (url === treeUrl) {
860
864
  treeCalls += 1
861
- if (treeCalls < 3) return new Response('busy', { status: 500 })
865
+ if (treeCalls < 3) return new Response('busy', { status: 500, headers: RETRY_NOW })
862
866
  return jsonResponse(treePayload(['plugins/demo/plugin.json']))
863
867
  }
864
868
  if (isArchive(url))
@@ -877,7 +881,7 @@ describe('upstream fetch quarantine', () => {
877
881
 
878
882
  test('quarantines a plugin when the repository tree stays unavailable', async () => {
879
883
  const stub = stubFetch((url) => {
880
- if (url === treeUrl) return new Response('down', { status: 500 })
884
+ if (url === treeUrl) return new Response('down', { status: 500, headers: RETRY_NOW })
881
885
  return new Response('unexpected', { status: 500 })
882
886
  })
883
887
  try {
@@ -921,7 +925,7 @@ describe('upstream fetch quarantine', () => {
921
925
  if (isArchive(url))
922
926
  return recovered
923
927
  ? tarballResponse([{ path: 'plugins/demo/plugin.json', body: manifestBytes }])
924
- : new Response('broken', { status: 500 })
928
+ : new Response('broken', { status: 500, headers: RETRY_NOW })
925
929
  return new Response('unexpected', { status: 200 })
926
930
  })
927
931
  try {
@@ -1153,7 +1157,7 @@ describe('upstream fetch quarantine', () => {
1153
1157
  })
1154
1158
 
1155
1159
  test('fails closed when every plugin in a source is unreachable', async () => {
1156
- const stub = stubFetch(() => new Response('down', { status: 500 }))
1160
+ const stub = stubFetch(() => new Response('down', { status: 500, headers: RETRY_NOW }))
1157
1161
  try {
1158
1162
  await expect(
1159
1163
  buildCatalog({