@nospt/plugin-dev-ai-hub-common 0.3.1 → 1.0.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # @nospt/plugin-dev-ai-hub-common
2
+
3
+ Isomorphic contracts shared by the **Dev AI Hub** frontend and backend plugins.
4
+
5
+ > **Requires Backstage 1.51 or later.** The `AiResource` kind comes from Backstage's own alpha catalog module, which is not available before that.
6
+
7
+ **You do not install this package directly.** It arrives as a dependency of [`@nospt/plugin-dev-ai-hub`](https://www.npmjs.com/package/@nospt/plugin-dev-ai-hub) and [`@nospt/plugin-dev-ai-hub-backend`](https://www.npmjs.com/package/@nospt/plugin-dev-ai-hub-backend), and the three publish in lockstep at the same version.
8
+
9
+ ## Why it exists
10
+
11
+ A contract duplicated across two packages is a contract that will drift. Anything the frontend and backend must agree on lives here exactly once, and neither plugin imports the other.
12
+
13
+ It is genuinely isomorphic — no Node-only and no browser-only code — which is why the same package can back both halves.
14
+
15
+ ## The main contract
16
+
17
+ `ResourceSummary` is the flat shape the backend serves and the frontend consumes. The frontend never sees a raw catalog `Entity`; this is the whole of what it knows about a resource.
18
+
19
+ ```typescript
20
+ interface ResourceSummary {
21
+ entityRef: string; // "airesource:default/azure-devops-cli"
22
+ name: string;
23
+ title?: string;
24
+ description?: string;
25
+ tags: string[];
26
+ type: ResourceType;
27
+ lifecycle: string;
28
+ owner?: string;
29
+ sourceLocation?: string; // absent → browsable, not installable
30
+ frameworks: string[]; // "claude-code", "github-copilot", …
31
+ version?: string;
32
+ kind: string;
33
+ childCount?: number; // unpopulated until containment lands
34
+ helpText?: string;
35
+ annotations: Record<string, string>;
36
+ }
37
+ ```
38
+
39
+ `toResourceSummary(entity)` is the `Entity` → `ResourceSummary` mapping, exported here so the backend router and the test fixtures cannot disagree about it.
40
+
41
+ ## Also in here
42
+
43
+ - **The `ResourceType` vocabulary** — `skill`, `agent`, `hook`, `mcp-config`, `plugin`, `marketplace` — and the rules derived from it: which body shape a type renders as (`mcp-config` is JSON, the rest markdown), whether its body is a downloadable artifact or merely a pointer, and its per-framework install paths.
44
+ - **Framework tokens and normalisation**, so `claude-code` means the same thing on both sides.
45
+ - **Telemetry schemas** for the event contract.
46
+
47
+ ## Full documentation
48
+
49
+ See the [repository README](https://github.com/nosportugal/backstage-plugin-dev-ai-hub#readme) for setup, and [`docs/AIRESOURCE-SPEC.md`](https://github.com/nosportugal/backstage-plugin-dev-ai-hub/blob/main-nos/docs/AIRESOURCE-SPEC.md) for the full `AiResource` entity spec.
50
+
51
+ ## License
52
+
53
+ Apache-2.0
package/dist/index.cjs.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var resources = require('./resources.cjs.js');
4
4
  var telemetry = require('./telemetry.cjs.js');
5
+ var toResourceSummary = require('./toResourceSummary.cjs.js');
5
6
 
6
7
 
7
8
 
@@ -36,4 +37,5 @@ exports.normalizeFramework = resources.normalizeFramework;
36
37
  exports.resolveCapableFrameworks = resources.resolveCapableFrameworks;
37
38
  exports.TelemetryActionEnum = telemetry.TelemetryActionEnum;
38
39
  exports.TelemetryEventInputSchema = telemetry.TelemetryEventInputSchema;
40
+ exports.toResourceSummary = toResourceSummary.toResourceSummary;
39
41
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { Entity } from '@backstage/catalog-model';
2
3
 
3
4
  /**
4
5
  * The v2 read contract: AiResource vocabulary, the flat ResourceSummary
@@ -318,5 +319,19 @@ type TelemetryEventInput = z.infer<typeof TelemetryEventInputSchema>;
318
319
  /** Raw per-action counts for one resource, as returned by `GET /telemetry/:ref`. */
319
320
  type TelemetryCounts = Record<TelemetryAction, number>;
320
321
 
321
- export { AGENT_LINK_CAPABLE_FRAMEWORKS, ANNOTATION_COMPATIBLE_FRAMEWORKS, ANNOTATION_HELP, ANNOTATION_VERSION, DEVAIHUB_ANNOTATION_PREFIX, INSTALLABLE_FRAMEWORKS, KNOWN_FRAMEWORKS, MARKETPLACE_CAPABLE_FRAMEWORKS, MCP_LINK_CAPABLE_FRAMEWORKS, PROMPT_LINK_CAPABLE_FRAMEWORKS, RESOURCE_TYPES, RESOURCE_TYPE_REGISTRY, TelemetryActionEnum, TelemetryEventInputSchema, expandInstallFrameworks, getAgentInstallLinks, getBodyShape, getFrameworks, getInstallSteps, getMarketplaceAddCommands, getMarketplaceInstallTemplate, getMarketplaceRepoSlug, getMarketplaceTeamSnippet, getMcpInstallLinks, getPromptInstallLinks, getResourceInstallTarget, hasCopyableBody, hasDownloadableArtifact, isResourceType, normalizeFramework, resolveCapableFrameworks };
322
+ /**
323
+ * Map a catalog AiResource entity to the flat contract served to the
324
+ * frontend. Returns undefined for entities with an unsupported `spec.type`,
325
+ * which are silently dropped (ADR-0003).
326
+ *
327
+ * Lives in `common` rather than the backend because it is pure and
328
+ * isomorphic — `Entity` in, `ResourceSummary` out — and both the backend
329
+ * router and the frontend's e2e fixtures need it to agree. The e2e suite
330
+ * builds its mock `GET /resources` payload by running the real examples in
331
+ * `examples/catalog/` through this function, so a change to the mapping
332
+ * cannot silently diverge from what the tests assert against.
333
+ */
334
+ declare function toResourceSummary(entity: Entity): ResourceSummary | undefined;
335
+
336
+ export { AGENT_LINK_CAPABLE_FRAMEWORKS, ANNOTATION_COMPATIBLE_FRAMEWORKS, ANNOTATION_HELP, ANNOTATION_VERSION, DEVAIHUB_ANNOTATION_PREFIX, INSTALLABLE_FRAMEWORKS, KNOWN_FRAMEWORKS, MARKETPLACE_CAPABLE_FRAMEWORKS, MCP_LINK_CAPABLE_FRAMEWORKS, PROMPT_LINK_CAPABLE_FRAMEWORKS, RESOURCE_TYPES, RESOURCE_TYPE_REGISTRY, TelemetryActionEnum, TelemetryEventInputSchema, expandInstallFrameworks, getAgentInstallLinks, getBodyShape, getFrameworks, getInstallSteps, getMarketplaceAddCommands, getMarketplaceInstallTemplate, getMarketplaceRepoSlug, getMarketplaceTeamSnippet, getMcpInstallLinks, getPromptInstallLinks, getResourceInstallTarget, hasCopyableBody, hasDownloadableArtifact, isResourceType, normalizeFramework, resolveCapableFrameworks, toResourceSummary };
322
337
  export type { AiResourceEntityLike, BodyShape, FrameworkToken, InstallMode, MarketplaceAddCommand, ResourceDeepLink, ResourceInstallStep, ResourceInstallTarget, ResourceListResponse, ResourceSummary, ResourceType, ResourceTypeIcon, ResourceTypeInfo, TelemetryAction, TelemetryCounts, TelemetryEventInput };
package/dist/index.esm.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { AGENT_LINK_CAPABLE_FRAMEWORKS, ANNOTATION_COMPATIBLE_FRAMEWORKS, ANNOTATION_HELP, ANNOTATION_VERSION, DEVAIHUB_ANNOTATION_PREFIX, INSTALLABLE_FRAMEWORKS, KNOWN_FRAMEWORKS, MARKETPLACE_CAPABLE_FRAMEWORKS, MCP_LINK_CAPABLE_FRAMEWORKS, PROMPT_LINK_CAPABLE_FRAMEWORKS, RESOURCE_TYPES, RESOURCE_TYPE_REGISTRY, expandInstallFrameworks, getAgentInstallLinks, getBodyShape, getFrameworks, getInstallSteps, getMarketplaceAddCommands, getMarketplaceInstallTemplate, getMarketplaceRepoSlug, getMarketplaceTeamSnippet, getMcpInstallLinks, getPromptInstallLinks, getResourceInstallTarget, hasCopyableBody, hasDownloadableArtifact, isResourceType, normalizeFramework, resolveCapableFrameworks } from './resources.esm.js';
2
2
  export { TelemetryActionEnum, TelemetryEventInputSchema } from './telemetry.esm.js';
3
+ export { toResourceSummary } from './toResourceSummary.esm.js';
3
4
  //# sourceMappingURL=index.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
1
+ {"version":3,"file":"index.esm.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var catalogModel = require('@backstage/catalog-model');
4
+ var resources = require('./resources.cjs.js');
5
+
6
+ function toResourceSummary(entity) {
7
+ const type = entity.spec?.type;
8
+ if (!resources.isResourceType(type)) {
9
+ return void 0;
10
+ }
11
+ const annotations = entity.metadata.annotations ?? {};
12
+ return {
13
+ entityRef: catalogModel.stringifyEntityRef(entity),
14
+ name: entity.metadata.name,
15
+ title: entity.metadata.title,
16
+ description: entity.metadata.description,
17
+ tags: entity.metadata.tags ?? [],
18
+ type,
19
+ lifecycle: typeof entity.spec?.lifecycle === "string" ? entity.spec.lifecycle : "",
20
+ owner: typeof entity.spec?.owner === "string" ? entity.spec.owner : void 0,
21
+ sourceLocation: annotations[catalogModel.ANNOTATION_SOURCE_LOCATION],
22
+ frameworks: resources.getFrameworks(entity),
23
+ version: annotations[resources.ANNOTATION_VERSION],
24
+ kind: entity.kind,
25
+ helpText: annotations[resources.ANNOTATION_HELP],
26
+ annotations
27
+ };
28
+ }
29
+
30
+ exports.toResourceSummary = toResourceSummary;
31
+ //# sourceMappingURL=toResourceSummary.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toResourceSummary.cjs.js","sources":["../src/toResourceSummary.ts"],"sourcesContent":["import {\n ANNOTATION_SOURCE_LOCATION,\n stringifyEntityRef,\n type Entity,\n} from '@backstage/catalog-model';\nimport {\n ANNOTATION_HELP,\n ANNOTATION_VERSION,\n getFrameworks,\n isResourceType,\n type ResourceSummary,\n} from './resources';\n\n/**\n * Map a catalog AiResource entity to the flat contract served to the\n * frontend. Returns undefined for entities with an unsupported `spec.type`,\n * which are silently dropped (ADR-0003).\n *\n * Lives in `common` rather than the backend because it is pure and\n * isomorphic — `Entity` in, `ResourceSummary` out — and both the backend\n * router and the frontend's e2e fixtures need it to agree. The e2e suite\n * builds its mock `GET /resources` payload by running the real examples in\n * `examples/catalog/` through this function, so a change to the mapping\n * cannot silently diverge from what the tests assert against.\n */\nexport function toResourceSummary(entity: Entity): ResourceSummary | undefined {\n const type = entity.spec?.type;\n if (!isResourceType(type)) {\n return undefined;\n }\n\n const annotations = entity.metadata.annotations ?? {};\n\n return {\n entityRef: stringifyEntityRef(entity),\n name: entity.metadata.name,\n title: entity.metadata.title,\n description: entity.metadata.description,\n tags: entity.metadata.tags ?? [],\n type,\n lifecycle:\n typeof entity.spec?.lifecycle === 'string' ? entity.spec.lifecycle : '',\n owner:\n typeof entity.spec?.owner === 'string' ? entity.spec.owner : undefined,\n sourceLocation: annotations[ANNOTATION_SOURCE_LOCATION],\n frameworks: getFrameworks(entity),\n version: annotations[ANNOTATION_VERSION],\n kind: entity.kind,\n helpText: annotations[ANNOTATION_HELP],\n annotations,\n };\n}\n"],"names":["isResourceType","stringifyEntityRef","ANNOTATION_SOURCE_LOCATION","getFrameworks","ANNOTATION_VERSION","ANNOTATION_HELP"],"mappings":";;;;;AAyBO,SAAS,kBAAkB,MAAA,EAA6C;AAC7E,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,EAAM,IAAA;AAC1B,EAAA,IAAI,CAACA,wBAAA,CAAe,IAAI,CAAA,EAAG;AACzB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,IAAe,EAAC;AAEpD,EAAA,OAAO;AAAA,IACL,SAAA,EAAWC,gCAAmB,MAAM,CAAA;AAAA,IACpC,IAAA,EAAM,OAAO,QAAA,CAAS,IAAA;AAAA,IACtB,KAAA,EAAO,OAAO,QAAA,CAAS,KAAA;AAAA,IACvB,WAAA,EAAa,OAAO,QAAA,CAAS,WAAA;AAAA,IAC7B,IAAA,EAAM,MAAA,CAAO,QAAA,CAAS,IAAA,IAAQ,EAAC;AAAA,IAC/B,IAAA;AAAA,IACA,SAAA,EACE,OAAO,MAAA,CAAO,IAAA,EAAM,cAAc,QAAA,GAAW,MAAA,CAAO,KAAK,SAAA,GAAY,EAAA;AAAA,IACvE,KAAA,EACE,OAAO,MAAA,CAAO,IAAA,EAAM,UAAU,QAAA,GAAW,MAAA,CAAO,KAAK,KAAA,GAAQ,MAAA;AAAA,IAC/D,cAAA,EAAgB,YAAYC,uCAA0B,CAAA;AAAA,IACtD,UAAA,EAAYC,wBAAc,MAAM,CAAA;AAAA,IAChC,OAAA,EAAS,YAAYC,4BAAkB,CAAA;AAAA,IACvC,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,QAAA,EAAU,YAAYC,yBAAe,CAAA;AAAA,IACrC;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,29 @@
1
+ import { ANNOTATION_SOURCE_LOCATION, stringifyEntityRef } from '@backstage/catalog-model';
2
+ import { isResourceType, ANNOTATION_HELP, ANNOTATION_VERSION, getFrameworks } from './resources.esm.js';
3
+
4
+ function toResourceSummary(entity) {
5
+ const type = entity.spec?.type;
6
+ if (!isResourceType(type)) {
7
+ return void 0;
8
+ }
9
+ const annotations = entity.metadata.annotations ?? {};
10
+ return {
11
+ entityRef: stringifyEntityRef(entity),
12
+ name: entity.metadata.name,
13
+ title: entity.metadata.title,
14
+ description: entity.metadata.description,
15
+ tags: entity.metadata.tags ?? [],
16
+ type,
17
+ lifecycle: typeof entity.spec?.lifecycle === "string" ? entity.spec.lifecycle : "",
18
+ owner: typeof entity.spec?.owner === "string" ? entity.spec.owner : void 0,
19
+ sourceLocation: annotations[ANNOTATION_SOURCE_LOCATION],
20
+ frameworks: getFrameworks(entity),
21
+ version: annotations[ANNOTATION_VERSION],
22
+ kind: entity.kind,
23
+ helpText: annotations[ANNOTATION_HELP],
24
+ annotations
25
+ };
26
+ }
27
+
28
+ export { toResourceSummary };
29
+ //# sourceMappingURL=toResourceSummary.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toResourceSummary.esm.js","sources":["../src/toResourceSummary.ts"],"sourcesContent":["import {\n ANNOTATION_SOURCE_LOCATION,\n stringifyEntityRef,\n type Entity,\n} from '@backstage/catalog-model';\nimport {\n ANNOTATION_HELP,\n ANNOTATION_VERSION,\n getFrameworks,\n isResourceType,\n type ResourceSummary,\n} from './resources';\n\n/**\n * Map a catalog AiResource entity to the flat contract served to the\n * frontend. Returns undefined for entities with an unsupported `spec.type`,\n * which are silently dropped (ADR-0003).\n *\n * Lives in `common` rather than the backend because it is pure and\n * isomorphic — `Entity` in, `ResourceSummary` out — and both the backend\n * router and the frontend's e2e fixtures need it to agree. The e2e suite\n * builds its mock `GET /resources` payload by running the real examples in\n * `examples/catalog/` through this function, so a change to the mapping\n * cannot silently diverge from what the tests assert against.\n */\nexport function toResourceSummary(entity: Entity): ResourceSummary | undefined {\n const type = entity.spec?.type;\n if (!isResourceType(type)) {\n return undefined;\n }\n\n const annotations = entity.metadata.annotations ?? {};\n\n return {\n entityRef: stringifyEntityRef(entity),\n name: entity.metadata.name,\n title: entity.metadata.title,\n description: entity.metadata.description,\n tags: entity.metadata.tags ?? [],\n type,\n lifecycle:\n typeof entity.spec?.lifecycle === 'string' ? entity.spec.lifecycle : '',\n owner:\n typeof entity.spec?.owner === 'string' ? entity.spec.owner : undefined,\n sourceLocation: annotations[ANNOTATION_SOURCE_LOCATION],\n frameworks: getFrameworks(entity),\n version: annotations[ANNOTATION_VERSION],\n kind: entity.kind,\n helpText: annotations[ANNOTATION_HELP],\n annotations,\n };\n}\n"],"names":[],"mappings":";;;AAyBO,SAAS,kBAAkB,MAAA,EAA6C;AAC7E,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,EAAM,IAAA;AAC1B,EAAA,IAAI,CAAC,cAAA,CAAe,IAAI,CAAA,EAAG;AACzB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,WAAA,IAAe,EAAC;AAEpD,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,mBAAmB,MAAM,CAAA;AAAA,IACpC,IAAA,EAAM,OAAO,QAAA,CAAS,IAAA;AAAA,IACtB,KAAA,EAAO,OAAO,QAAA,CAAS,KAAA;AAAA,IACvB,WAAA,EAAa,OAAO,QAAA,CAAS,WAAA;AAAA,IAC7B,IAAA,EAAM,MAAA,CAAO,QAAA,CAAS,IAAA,IAAQ,EAAC;AAAA,IAC/B,IAAA;AAAA,IACA,SAAA,EACE,OAAO,MAAA,CAAO,IAAA,EAAM,cAAc,QAAA,GAAW,MAAA,CAAO,KAAK,SAAA,GAAY,EAAA;AAAA,IACvE,KAAA,EACE,OAAO,MAAA,CAAO,IAAA,EAAM,UAAU,QAAA,GAAW,MAAA,CAAO,KAAK,KAAA,GAAQ,MAAA;AAAA,IAC/D,cAAA,EAAgB,YAAY,0BAA0B,CAAA;AAAA,IACtD,UAAA,EAAY,cAAc,MAAM,CAAA;AAAA,IAChC,OAAA,EAAS,YAAY,kBAAkB,CAAA;AAAA,IACvC,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,QAAA,EAAU,YAAY,eAAe,CAAA;AAAA,IACrC;AAAA,GACF;AACF;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nospt/plugin-dev-ai-hub-common",
3
- "version": "0.3.1",
3
+ "version": "1.0.0-rc1",
4
4
  "description": "Common types and schemas for Dev AI Hub",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.cjs.js",
@@ -34,13 +34,13 @@
34
34
  "pluginPackages": [
35
35
  "@nospt/plugin-dev-ai-hub",
36
36
  "@nospt/plugin-dev-ai-hub-backend",
37
- "@nospt/plugin-dev-ai-hub-common",
38
- "@nospt/plugin-dev-ai-hub-node"
37
+ "@nospt/plugin-dev-ai-hub-common"
39
38
  ]
40
39
  },
41
40
  "sideEffects": false,
42
41
  "files": [
43
- "dist"
42
+ "dist",
43
+ "README.md"
44
44
  ],
45
45
  "scripts": {
46
46
  "build": "backstage-cli package build",
@@ -52,6 +52,7 @@
52
52
  "tsc": "tsc --noEmit"
53
53
  },
54
54
  "dependencies": {
55
+ "@backstage/catalog-model": "^1.9.0",
55
56
  "zod": "^3.22.0"
56
57
  },
57
58
  "devDependencies": {