@nebutra/play-marketplace 0.1.1 → 0.1.2

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.
@@ -1,4 +1,4 @@
1
- {"at":"2026-05-18T16:46:09.903Z","type":"reindex","tenantId":"tenant_a","files":0}
2
- {"at":"2026-05-18T16:46:09.936Z","type":"write","tenantId":"tenant_a","path":"marketplace/plays/cold_email_pro@1.0.0.json"}
3
- {"at":"2026-05-18T16:46:09.975Z","type":"write","tenantId":"tenant_a","path":"marketplace/installed/cold_email_pro@1.0.0.json"}
4
- {"at":"2026-05-18T16:46:10.014Z","type":"reindex","tenantId":"tenant_a","files":0}
1
+ {"at":"2026-05-19T08:15:26.928Z","type":"reindex","tenantId":"tenant_a","files":0}
2
+ {"at":"2026-05-19T08:15:26.980Z","type":"write","tenantId":"tenant_a","path":"marketplace/plays/cold_email_pro@1.0.0.json"}
3
+ {"at":"2026-05-19T08:15:27.029Z","type":"write","tenantId":"tenant_a","path":"marketplace/installed/cold_email_pro@1.0.0.json"}
4
+ {"at":"2026-05-19T08:15:27.133Z","type":"reindex","tenantId":"tenant_a","files":0}
@@ -1,2 +1,2 @@
1
- {"traceId":"play_marketplace_publish_cold_email_pro_1_0_0_mpbfrf2o","kind":"content_write","affected":["marketplace/plays/cold_email_pro@1.0.0.json"],"parent":null,"snapshot":{"marketplace/plays/cold_email_pro@1.0.0.json":"{\n \"playId\": \"cold_email_pro\",\n \"version\": \"1.0.0\",\n \"visibility\": \"public\",\n \"pricing\": {\n \"model\": \"free\"\n },\n \"quality\": {\n \"verified\": false,\n \"successRate\": 0,\n \"avgCostUsd\": 0,\n \"avgDurationMinutes\": 0\n },\n \"requiredSkills\": [\n \"content_store.write\"\n ],\n \"subAgents\": [\n \"writer\"\n ],\n \"signature\": \"play_sig_cold_email_pro_1_0_0_mpbfrf20\"\n}\n"},"id":"f80497c7830d801c2dc3ee526a0b73b9ec1549e6ad6af0d37169ef3125aae2d7","tenantId":"tenant_a","at":"2026-05-18T16:46:09.946Z","summary":"content_write touched 1 path(s)","objectHashes":["84610d4ee9a4a22e3f3a673f99083a907e52bc357f1a6a18e70df7c6ef186612"]}
2
- {"traceId":"play_marketplace_install_cold_email_pro_1_0_0_mpbfrf3t","kind":"content_write","affected":["marketplace/installed/cold_email_pro@1.0.0.json"],"parent":"f80497c7830d801c2dc3ee526a0b73b9ec1549e6ad6af0d37169ef3125aae2d7","snapshot":{"marketplace/installed/cold_email_pro@1.0.0.json":"{\n \"playId\": \"cold_email_pro\",\n \"version\": \"1.0.0\",\n \"status\": \"installed\",\n \"registeredSkill\": \"cold_email_pro\",\n \"installPath\": \"marketplace/installed/cold_email_pro@1.0.0.json\"\n}\n"},"id":"11b8f2ee9292d07c7fd5a432e1c4d929d02d5383741fdddc149f7e79bd752416","tenantId":"tenant_a","at":"2026-05-18T16:46:09.979Z","summary":"content_write touched 1 path(s)","objectHashes":["89fe9552893b352e9ca705cb34fe56dc9bf47789617cacf7cc0ba4a2db32b2d1"]}
1
+ {"at":"2026-05-19T08:15:27.005Z","traceId":"play_marketplace_publish_cold_email_pro_1_0_0_mpccyhhg","kind":"content_write","affected":["marketplace/plays/cold_email_pro@1.0.0.json"],"parent":null,"snapshot":{"marketplace/plays/cold_email_pro@1.0.0.json":"{\n \"playId\": \"cold_email_pro\",\n \"version\": \"1.0.0\",\n \"visibility\": \"public\",\n \"pricing\": {\n \"model\": \"free\"\n },\n \"quality\": {\n \"verified\": false,\n \"successRate\": 0,\n \"avgCostUsd\": 0,\n \"avgDurationMinutes\": 0\n },\n \"requiredSkills\": [\n \"content_store.write\"\n ],\n \"subAgents\": [\n \"writer\"\n ],\n \"signature\": \"play_sig_cold_email_pro_1_0_0_mpccyhgd\"\n}\n"},"id":"2bf37be746ebd2256f0b42cf7d89b6dc8612fadf1dfb9c4570c7b7fda4395742","tenantId":"tenant_a","summary":"content_write touched 1 path(s)","objectHashes":["79ba0d2d388aa435df8a48ed314d03e99efa99e640e58f3599983c7a3c566e6a"]}
2
+ {"at":"2026-05-19T08:15:27.035Z","traceId":"play_marketplace_install_cold_email_pro_1_0_0_mpccyhit","kind":"content_write","affected":["marketplace/installed/cold_email_pro@1.0.0.json"],"parent":"2bf37be746ebd2256f0b42cf7d89b6dc8612fadf1dfb9c4570c7b7fda4395742","snapshot":{"marketplace/installed/cold_email_pro@1.0.0.json":"{\n \"playId\": \"cold_email_pro\",\n \"version\": \"1.0.0\",\n \"status\": \"installed\",\n \"registeredSkill\": \"cold_email_pro\",\n \"installPath\": \"marketplace/installed/cold_email_pro@1.0.0.json\"\n}\n"},"id":"b54c68996b301976e6ae795eab7ab9e177008d707b19497d7ed255b96bf5ef0f","tenantId":"tenant_a","summary":"content_write touched 1 path(s)","objectHashes":["89fe9552893b352e9ca705cb34fe56dc9bf47789617cacf7cc0ba4a2db32b2d1"]}
@@ -1,3 +1,3 @@
1
- {"at":"2026-05-18T16:46:09.950Z","type":"publish","tenantId":"tenant_a","playId":"cold_email_pro","version":"1.0.0"}
2
- {"at":"2026-05-18T16:46:09.956Z","type":"search","tenantId":"tenant_a","query":"email","hits":1}
3
- {"at":"2026-05-18T16:46:09.979Z","type":"install","tenantId":"tenant_a","playId":"cold_email_pro","version":"1.0.0"}
1
+ {"at":"2026-05-19T08:15:27.019Z","type":"publish","tenantId":"tenant_a","playId":"cold_email_pro","version":"1.0.0"}
2
+ {"at":"2026-05-19T08:15:27.020Z","type":"search","tenantId":"tenant_a","query":"email","hits":1}
3
+ {"at":"2026-05-19T08:15:27.041Z","type":"install","tenantId":"tenant_a","playId":"cold_email_pro","version":"1.0.0"}
@@ -1,5 +1,5 @@
1
1
 
2
- > @nebutra/play-marketplace@0.1.1 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
2
+ > @nebutra/play-marketplace@0.1.2 build /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
3
3
  > tsup
4
4
 
5
5
  CLI Building entry: src/cli.ts, src/index.ts
@@ -11,12 +11,12 @@
11
11
  ESM Build start
12
12
  ESM dist/cli.js 1.06 KB
13
13
  ESM dist/index.js 222.00 B
14
- ESM dist/chunk-2SUUBIJC.js 6.50 KB
14
+ ESM dist/chunk-BRGFNH5O.js 6.30 KB
15
15
  ESM dist/cli.js.map 1.87 KB
16
16
  ESM dist/index.js.map 71.00 B
17
- ESM dist/chunk-2SUUBIJC.js.map 18.01 KB
18
- ESM ⚡️ Build success in 60ms
17
+ ESM dist/chunk-BRGFNH5O.js.map 13.50 KB
18
+ ESM ⚡️ Build success in 92ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 7893ms
20
+ DTS ⚡️ Build success in 10539ms
21
21
  DTS dist/cli.d.ts 13.00 B
22
22
  DTS dist/index.d.ts 3.07 KB
@@ -1,16 +1,15 @@
1
1
 
2
- > @nebutra/play-marketplace@0.1.1 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
2
+ > @nebutra/play-marketplace@0.1.2 test /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
3
3
  > vitest run
4
4
 
5
5
 
6
6
   RUN  v4.1.4 /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
7
7
 
8
- (node:11758) ExperimentalWarning: SQLite is an experimental feature and might change at any time
9
- (Use `node --trace-warnings ...` to show where the warning was created)
10
- ✓ src/index.test.ts (3 tests) 341ms
8
+ ✓ src/index.test.ts (3 tests) 491ms
9
+ ✓ publishes, searches, and installs signed Play registry records  343ms
11
10
 
12
11
   Test Files  1 passed (1)
13
12
   Tests  3 passed (3)
14
-  Start at  16:46:07
15
-  Duration  2.33s (transform 870ms, setup 0ms, import 1.23s, tests 341ms, environment 0ms)
13
+  Start at  08:15:24
14
+  Duration  2.95s (transform 1.52s, setup 0ms, import 1.84s, tests 491ms, environment 0ms)
16
15
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @nebutra/play-marketplace@0.1.1 typecheck /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
2
+ > @nebutra/play-marketplace@0.1.2 typecheck /home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace
3
3
  > tsc --noEmit
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @nebutra/play-marketplace
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Publish registry package metadata under the MIT license.
8
+
9
+ - Updated dependencies []:
10
+ - @nebutra/capability-kit@0.2.1
11
+ - @nebutra/content-store@0.1.1
12
+ - @nebutra/errors@0.1.1
13
+ - @nebutra/event-log@0.1.1
14
+ - @nebutra/generation-context@0.1.1
15
+ - @nebutra/play-loader@0.1.1
16
+
3
17
  ## 0.1.1
4
18
 
5
19
  ### Patch Changes
@@ -1,28 +1,13 @@
1
1
  // src/index.ts
2
2
  import { mkdir } from "fs/promises";
3
3
  import { join } from "path";
4
+ import { requireCapabilityTenant } from "@nebutra/capability-kit";
4
5
  import { appendCapabilityDebug, readCapabilityDebug } from "@nebutra/capability-kit/debug";
5
6
  import { ContentStore } from "@nebutra/content-store";
6
- import { CapabilityError as CapabilityError2 } from "@nebutra/errors";
7
- import { EventLog } from "@nebutra/event-log";
8
-
9
- // ../generation-context/src/index.ts
10
7
  import { CapabilityError } from "@nebutra/errors";
11
- function assetId(prefix, seed) {
12
- return `${prefix}_${seed.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40)}_${Date.now().toString(36)}`;
13
- }
14
-
15
- // src/index.ts
8
+ import { EventLog } from "@nebutra/event-log";
9
+ import { assetId } from "@nebutra/generation-context";
16
10
  import { parsePlayMarkdown } from "@nebutra/play-loader";
17
- function requireTenant(value) {
18
- if (!value?.trim()) {
19
- throw new CapabilityError2("play-marketplace", "Play Marketplace requires tenant context", {
20
- suggestion: "Pass tenantId so registry and install artifacts stay tenant-scoped.",
21
- statusCode: 400
22
- });
23
- }
24
- return value;
25
- }
26
11
  function isPaid(pricing) {
27
12
  return pricing.model !== "free";
28
13
  }
@@ -43,7 +28,13 @@ var PlayMarketplace = class _PlayMarketplace {
43
28
  #eventLog;
44
29
  #plays = /* @__PURE__ */ new Map();
45
30
  constructor(options) {
46
- this.#tenantId = requireTenant(options.tenantId);
31
+ this.#tenantId = requireCapabilityTenant({
32
+ explicit: options.tenantId,
33
+ onMissing: () => new CapabilityError("play-marketplace", "Play Marketplace requires tenant context", {
34
+ suggestion: "Pass tenantId so registry and install artifacts stay tenant-scoped.",
35
+ statusCode: 400
36
+ })
37
+ });
47
38
  this.#debugRoot = options.debugRoot ?? process.cwd();
48
39
  this.#contentStore = options.contentStore;
49
40
  this.#eventLog = options.eventLog;
@@ -57,7 +48,7 @@ var PlayMarketplace = class _PlayMarketplace {
57
48
  }
58
49
  async publish(request) {
59
50
  if (isPaid(request.pricing) && !request.invitedAuthor) {
60
- throw new CapabilityError2(
51
+ throw new CapabilityError(
61
52
  "play-marketplace",
62
53
  "Paid Play publishing is limited during controlled launch",
63
54
  {
@@ -132,7 +123,7 @@ var PlayMarketplace = class _PlayMarketplace {
132
123
  const key = `${playId}@${version}`;
133
124
  const play = this.#plays.get(key);
134
125
  if (!play) {
135
- throw new CapabilityError2("play-marketplace", "Play registry record not found", {
126
+ throw new CapabilityError("play-marketplace", "Play registry record not found", {
136
127
  suggestion: "Search the marketplace and install an available version.",
137
128
  metadata: { playId, version },
138
129
  statusCode: 404
@@ -186,4 +177,4 @@ export {
186
177
  PlayMarketplace,
187
178
  readPlayMarketplaceDebug
188
179
  };
189
- //# sourceMappingURL=chunk-2SUUBIJC.js.map
180
+ //# sourceMappingURL=chunk-BRGFNH5O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { requireCapabilityTenant } from \"@nebutra/capability-kit\";\nimport { appendCapabilityDebug, readCapabilityDebug } from \"@nebutra/capability-kit/debug\";\nimport { ContentStore } from \"@nebutra/content-store\";\nimport { CapabilityError } from \"@nebutra/errors\";\nimport { EventLog } from \"@nebutra/event-log\";\nimport { assetId } from \"@nebutra/generation-context\";\nimport { parsePlayMarkdown } from \"@nebutra/play-loader\";\n\nexport type Visibility = \"private\" | \"public\";\nexport type Pricing =\n | { readonly model: \"free\" }\n | { readonly model: \"one_time\"; readonly amountUsd: number }\n | {\n readonly model: \"subscription\";\n readonly amountUsd: number;\n readonly interval: \"month\" | \"year\";\n }\n | { readonly model: \"per_run\"; readonly amountUsd: number };\n\nexport interface ValidatePlayPackageRequest {\n readonly skillMarkdown: string;\n}\n\nexport interface PlayValidationReport {\n readonly ok: boolean;\n readonly playName: string;\n readonly version: string;\n readonly requiredSkills: readonly string[];\n readonly subAgents: readonly string[];\n}\n\nexport interface PublishPlayRequest {\n readonly skillMarkdown: string;\n readonly visibility: Visibility;\n readonly pricing: Pricing;\n readonly invitedAuthor: boolean;\n}\n\nexport interface PublishedPlay {\n readonly playId: string;\n readonly version: string;\n readonly registryPath: string;\n readonly visibility: Visibility;\n readonly pricing: Pricing;\n readonly quality: {\n readonly verified: boolean;\n readonly successRate: number;\n readonly avgCostUsd: number;\n readonly avgDurationMinutes: number;\n };\n readonly eventId: string;\n}\n\nexport interface MarketplaceSearchRequest {\n readonly query: string;\n readonly sort: \"success_rate\" | \"new\";\n}\n\nexport interface MarketplaceSearchResult {\n readonly items: readonly PublishedPlay[];\n}\n\nexport interface InstalledPlay {\n readonly playId: string;\n readonly version: string;\n readonly status: \"installed\";\n readonly registeredSkill: string;\n readonly installPath: string;\n}\n\nexport interface PlayMarketplaceDoctorReport {\n readonly capability: \"play-marketplace\";\n readonly ok: boolean;\n readonly checkedAt: string;\n readonly features: readonly string[];\n readonly suggestion?: string;\n}\n\nexport interface PlayMarketplaceOptions {\n readonly tenantId?: string;\n readonly debugRoot?: string;\n readonly contentStore?: ContentStore;\n readonly eventLog?: EventLog;\n}\n\nfunction isPaid(pricing: Pricing): boolean {\n return pricing.model !== \"free\";\n}\n\nexport function validatePlayPackage(request: ValidatePlayPackageRequest): PlayValidationReport {\n const play = parsePlayMarkdown(request.skillMarkdown);\n return {\n ok: true,\n playName: play.meta.name,\n version: play.meta.version,\n requiredSkills: play.requiredSkills,\n subAgents: play.subAgents.map((agent) => agent.role),\n };\n}\n\nexport class PlayMarketplace {\n readonly #tenantId: string;\n readonly #debugRoot: string;\n readonly #contentStore: ContentStore;\n readonly #eventLog: EventLog;\n readonly #plays = new Map<string, PublishedPlay & { readonly skillMarkdown: string }>();\n\n private constructor(\n options: Required<Pick<PlayMarketplaceOptions, \"tenantId\" | \"contentStore\" | \"eventLog\">> &\n Pick<PlayMarketplaceOptions, \"debugRoot\">,\n ) {\n this.#tenantId = requireCapabilityTenant({\n explicit: options.tenantId,\n onMissing: () =>\n new CapabilityError(\"play-marketplace\", \"Play Marketplace requires tenant context\", {\n suggestion: \"Pass tenantId so registry and install artifacts stay tenant-scoped.\",\n statusCode: 400,\n }),\n });\n this.#debugRoot = options.debugRoot ?? process.cwd();\n this.#contentStore = options.contentStore;\n this.#eventLog = options.eventLog;\n }\n\n static async open(\n root = \".nebutra/play-marketplace\",\n options: Omit<PlayMarketplaceOptions, \"contentStore\" | \"eventLog\"> = {},\n ): Promise<PlayMarketplace> {\n const tenantId = options.tenantId ?? \"local\";\n await mkdir(root, { recursive: true });\n const contentStore = await ContentStore.open(join(root, \"content\"), { tenantId });\n const eventLog = await EventLog.open(join(root, \"event-log\"), { tenantId });\n return new PlayMarketplace({ ...options, tenantId, contentStore, eventLog });\n }\n\n async publish(request: PublishPlayRequest): Promise<PublishedPlay> {\n if (isPaid(request.pricing) && !request.invitedAuthor) {\n throw new CapabilityError(\n \"play-marketplace\",\n \"Paid Play publishing is limited during controlled launch\",\n {\n suggestion:\n \"Use an invited author account or publish a free Play until paid publishing opens.\",\n statusCode: 403,\n },\n );\n }\n\n const validation = validatePlayPackage({ skillMarkdown: request.skillMarkdown });\n const playId = validation.playName;\n const registryPath = `marketplace/plays/${playId}@${validation.version}.json`;\n const record = {\n playId,\n version: validation.version,\n visibility: request.visibility,\n pricing: request.pricing,\n quality: {\n verified: false,\n successRate: 0,\n avgCostUsd: 0,\n avgDurationMinutes: 0,\n },\n requiredSkills: validation.requiredSkills,\n subAgents: validation.subAgents,\n signature: assetId(\"play_sig\", `${playId}_${validation.version}`),\n };\n const snapshot = `${JSON.stringify(record, null, 2)}\\n`;\n await this.#contentStore.write(registryPath, snapshot);\n const eventId = await this.#eventLog.commit({\n traceId: assetId(\"play_marketplace_publish\", `${playId}_${validation.version}`),\n kind: \"content_write\",\n affected: [registryPath],\n parent: null,\n snapshot: { [registryPath]: snapshot },\n });\n const published: PublishedPlay & { readonly skillMarkdown: string } = {\n playId,\n version: validation.version,\n registryPath,\n visibility: request.visibility,\n pricing: request.pricing,\n quality: record.quality,\n eventId,\n skillMarkdown: request.skillMarkdown,\n };\n this.#plays.set(`${playId}@${validation.version}`, published);\n await this.#debug({\n type: \"publish\",\n tenantId: this.#tenantId,\n playId,\n version: validation.version,\n });\n return published;\n }\n\n async search(request: MarketplaceSearchRequest): Promise<MarketplaceSearchResult> {\n const probe = request.query.toLowerCase();\n const items = [...this.#plays.values()]\n .filter(\n (play) =>\n play.playId.toLowerCase().includes(probe) ||\n play.skillMarkdown.toLowerCase().includes(probe),\n )\n .sort((left, right) =>\n request.sort === \"success_rate\"\n ? right.quality.successRate - left.quality.successRate ||\n left.playId.localeCompare(right.playId)\n : right.eventId.localeCompare(left.eventId),\n );\n await this.#debug({\n type: \"search\",\n tenantId: this.#tenantId,\n query: request.query,\n hits: items.length,\n });\n return { items };\n }\n\n async install(playId: string, version: string): Promise<InstalledPlay> {\n const key = `${playId}@${version}`;\n const play = this.#plays.get(key);\n if (!play) {\n throw new CapabilityError(\"play-marketplace\", \"Play registry record not found\", {\n suggestion: \"Search the marketplace and install an available version.\",\n metadata: { playId, version },\n statusCode: 404,\n });\n }\n const installPath = `marketplace/installed/${playId}@${version}.json`;\n const install: InstalledPlay = {\n playId,\n version,\n status: \"installed\",\n registeredSkill: playId,\n installPath,\n };\n const snapshot = `${JSON.stringify(install, null, 2)}\\n`;\n await this.#contentStore.write(installPath, snapshot);\n await this.#eventLog.commit({\n traceId: assetId(\"play_marketplace_install\", `${playId}_${version}`),\n kind: \"content_write\",\n affected: [installPath],\n parent: play.eventId,\n snapshot: { [installPath]: snapshot },\n });\n await this.#debug({ type: \"install\", tenantId: this.#tenantId, playId, version });\n return install;\n }\n\n async doctor(): Promise<PlayMarketplaceDoctorReport> {\n const report: PlayMarketplaceDoctorReport = {\n capability: \"play-marketplace\",\n ok: true,\n checkedAt: new Date().toISOString(),\n features: [\"validate-skill\", \"publish\", \"search\", \"install\", \"paid-launch-gate\"],\n suggestion:\n \"Local registry artifacts are active; remote registry, billing, and verified review queues remain handoffs.\",\n };\n await this.#debug({ type: \"doctor\", tenantId: this.#tenantId, plays: this.#plays.size });\n return report;\n }\n\n async close(): Promise<void> {\n await this.#contentStore.close();\n }\n\n async #debug(entry: Record<string, unknown>): Promise<void> {\n await appendCapabilityDebug(\"play-marketplace\", entry, { root: this.#debugRoot });\n }\n}\n\nexport async function readPlayMarketplaceDebug(\n root = process.cwd(),\n limit = 20,\n): Promise<unknown[]> {\n return readCapabilityDebug(\"play-marketplace\", { root, limit });\n}\n"],"mappings":"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","names":[]}
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  PlayMarketplace,
3
3
  readPlayMarketplaceDebug
4
- } from "./chunk-2SUUBIJC.js";
4
+ } from "./chunk-BRGFNH5O.js";
5
5
 
6
6
  // src/cli.ts
7
7
  var command = process.argv[2] ?? "doctor";
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  PlayMarketplace,
3
3
  readPlayMarketplaceDebug,
4
4
  validatePlayPackage
5
- } from "./chunk-2SUUBIJC.js";
5
+ } from "./chunk-BRGFNH5O.js";
6
6
  export {
7
7
  PlayMarketplace,
8
8
  readPlayMarketplaceDebug,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebutra/play-marketplace",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Local registry, publishing, install, metrics, and billing handoff surface for SKILL.md Plays",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -29,11 +29,12 @@
29
29
  ".": "./src/index.ts"
30
30
  },
31
31
  "dependencies": {
32
- "@nebutra/capability-kit": "0.2.0",
33
- "@nebutra/content-store": "0.1.0",
34
- "@nebutra/errors": "0.1.0",
35
- "@nebutra/event-log": "0.1.0",
36
- "@nebutra/play-loader": "0.1.0"
32
+ "@nebutra/capability-kit": "0.2.1",
33
+ "@nebutra/content-store": "0.1.1",
34
+ "@nebutra/errors": "0.1.1",
35
+ "@nebutra/event-log": "0.1.1",
36
+ "@nebutra/generation-context": "0.1.1",
37
+ "@nebutra/play-loader": "0.1.1"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/node": "^22.19.15",
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { mkdir } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
+ import { requireCapabilityTenant } from "@nebutra/capability-kit";
3
4
  import { appendCapabilityDebug, readCapabilityDebug } from "@nebutra/capability-kit/debug";
4
5
  import { ContentStore } from "@nebutra/content-store";
5
6
  import { CapabilityError } from "@nebutra/errors";
@@ -84,16 +85,6 @@ export interface PlayMarketplaceOptions {
84
85
  readonly eventLog?: EventLog;
85
86
  }
86
87
 
87
- function requireTenant(value: string | undefined): string {
88
- if (!value?.trim()) {
89
- throw new CapabilityError("play-marketplace", "Play Marketplace requires tenant context", {
90
- suggestion: "Pass tenantId so registry and install artifacts stay tenant-scoped.",
91
- statusCode: 400,
92
- });
93
- }
94
- return value;
95
- }
96
-
97
88
  function isPaid(pricing: Pricing): boolean {
98
89
  return pricing.model !== "free";
99
90
  }
@@ -120,7 +111,14 @@ export class PlayMarketplace {
120
111
  options: Required<Pick<PlayMarketplaceOptions, "tenantId" | "contentStore" | "eventLog">> &
121
112
  Pick<PlayMarketplaceOptions, "debugRoot">,
122
113
  ) {
123
- this.#tenantId = requireTenant(options.tenantId);
114
+ this.#tenantId = requireCapabilityTenant({
115
+ explicit: options.tenantId,
116
+ onMissing: () =>
117
+ new CapabilityError("play-marketplace", "Play Marketplace requires tenant context", {
118
+ suggestion: "Pass tenantId so registry and install artifacts stay tenant-scoped.",
119
+ statusCode: 400,
120
+ }),
121
+ });
124
122
  this.#debugRoot = options.debugRoot ?? process.cwd();
125
123
  this.#contentStore = options.contentStore;
126
124
  this.#eventLog = options.eventLog;
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts","../../generation-context/src/index.ts"],"sourcesContent":["import { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { appendCapabilityDebug, readCapabilityDebug } from \"@nebutra/capability-kit/debug\";\nimport { ContentStore } from \"@nebutra/content-store\";\nimport { CapabilityError } from \"@nebutra/errors\";\nimport { EventLog } from \"@nebutra/event-log\";\nimport { assetId } from \"@nebutra/generation-context\";\nimport { parsePlayMarkdown } from \"@nebutra/play-loader\";\n\nexport type Visibility = \"private\" | \"public\";\nexport type Pricing =\n | { readonly model: \"free\" }\n | { readonly model: \"one_time\"; readonly amountUsd: number }\n | {\n readonly model: \"subscription\";\n readonly amountUsd: number;\n readonly interval: \"month\" | \"year\";\n }\n | { readonly model: \"per_run\"; readonly amountUsd: number };\n\nexport interface ValidatePlayPackageRequest {\n readonly skillMarkdown: string;\n}\n\nexport interface PlayValidationReport {\n readonly ok: boolean;\n readonly playName: string;\n readonly version: string;\n readonly requiredSkills: readonly string[];\n readonly subAgents: readonly string[];\n}\n\nexport interface PublishPlayRequest {\n readonly skillMarkdown: string;\n readonly visibility: Visibility;\n readonly pricing: Pricing;\n readonly invitedAuthor: boolean;\n}\n\nexport interface PublishedPlay {\n readonly playId: string;\n readonly version: string;\n readonly registryPath: string;\n readonly visibility: Visibility;\n readonly pricing: Pricing;\n readonly quality: {\n readonly verified: boolean;\n readonly successRate: number;\n readonly avgCostUsd: number;\n readonly avgDurationMinutes: number;\n };\n readonly eventId: string;\n}\n\nexport interface MarketplaceSearchRequest {\n readonly query: string;\n readonly sort: \"success_rate\" | \"new\";\n}\n\nexport interface MarketplaceSearchResult {\n readonly items: readonly PublishedPlay[];\n}\n\nexport interface InstalledPlay {\n readonly playId: string;\n readonly version: string;\n readonly status: \"installed\";\n readonly registeredSkill: string;\n readonly installPath: string;\n}\n\nexport interface PlayMarketplaceDoctorReport {\n readonly capability: \"play-marketplace\";\n readonly ok: boolean;\n readonly checkedAt: string;\n readonly features: readonly string[];\n readonly suggestion?: string;\n}\n\nexport interface PlayMarketplaceOptions {\n readonly tenantId?: string;\n readonly debugRoot?: string;\n readonly contentStore?: ContentStore;\n readonly eventLog?: EventLog;\n}\n\nfunction requireTenant(value: string | undefined): string {\n if (!value?.trim()) {\n throw new CapabilityError(\"play-marketplace\", \"Play Marketplace requires tenant context\", {\n suggestion: \"Pass tenantId so registry and install artifacts stay tenant-scoped.\",\n statusCode: 400,\n });\n }\n return value;\n}\n\nfunction isPaid(pricing: Pricing): boolean {\n return pricing.model !== \"free\";\n}\n\nexport function validatePlayPackage(request: ValidatePlayPackageRequest): PlayValidationReport {\n const play = parsePlayMarkdown(request.skillMarkdown);\n return {\n ok: true,\n playName: play.meta.name,\n version: play.meta.version,\n requiredSkills: play.requiredSkills,\n subAgents: play.subAgents.map((agent) => agent.role),\n };\n}\n\nexport class PlayMarketplace {\n readonly #tenantId: string;\n readonly #debugRoot: string;\n readonly #contentStore: ContentStore;\n readonly #eventLog: EventLog;\n readonly #plays = new Map<string, PublishedPlay & { readonly skillMarkdown: string }>();\n\n private constructor(\n options: Required<Pick<PlayMarketplaceOptions, \"tenantId\" | \"contentStore\" | \"eventLog\">> &\n Pick<PlayMarketplaceOptions, \"debugRoot\">,\n ) {\n this.#tenantId = requireTenant(options.tenantId);\n this.#debugRoot = options.debugRoot ?? process.cwd();\n this.#contentStore = options.contentStore;\n this.#eventLog = options.eventLog;\n }\n\n static async open(\n root = \".nebutra/play-marketplace\",\n options: Omit<PlayMarketplaceOptions, \"contentStore\" | \"eventLog\"> = {},\n ): Promise<PlayMarketplace> {\n const tenantId = options.tenantId ?? \"local\";\n await mkdir(root, { recursive: true });\n const contentStore = await ContentStore.open(join(root, \"content\"), { tenantId });\n const eventLog = await EventLog.open(join(root, \"event-log\"), { tenantId });\n return new PlayMarketplace({ ...options, tenantId, contentStore, eventLog });\n }\n\n async publish(request: PublishPlayRequest): Promise<PublishedPlay> {\n if (isPaid(request.pricing) && !request.invitedAuthor) {\n throw new CapabilityError(\n \"play-marketplace\",\n \"Paid Play publishing is limited during controlled launch\",\n {\n suggestion:\n \"Use an invited author account or publish a free Play until paid publishing opens.\",\n statusCode: 403,\n },\n );\n }\n\n const validation = validatePlayPackage({ skillMarkdown: request.skillMarkdown });\n const playId = validation.playName;\n const registryPath = `marketplace/plays/${playId}@${validation.version}.json`;\n const record = {\n playId,\n version: validation.version,\n visibility: request.visibility,\n pricing: request.pricing,\n quality: {\n verified: false,\n successRate: 0,\n avgCostUsd: 0,\n avgDurationMinutes: 0,\n },\n requiredSkills: validation.requiredSkills,\n subAgents: validation.subAgents,\n signature: assetId(\"play_sig\", `${playId}_${validation.version}`),\n };\n const snapshot = `${JSON.stringify(record, null, 2)}\\n`;\n await this.#contentStore.write(registryPath, snapshot);\n const eventId = await this.#eventLog.commit({\n traceId: assetId(\"play_marketplace_publish\", `${playId}_${validation.version}`),\n kind: \"content_write\",\n affected: [registryPath],\n parent: null,\n snapshot: { [registryPath]: snapshot },\n });\n const published: PublishedPlay & { readonly skillMarkdown: string } = {\n playId,\n version: validation.version,\n registryPath,\n visibility: request.visibility,\n pricing: request.pricing,\n quality: record.quality,\n eventId,\n skillMarkdown: request.skillMarkdown,\n };\n this.#plays.set(`${playId}@${validation.version}`, published);\n await this.#debug({\n type: \"publish\",\n tenantId: this.#tenantId,\n playId,\n version: validation.version,\n });\n return published;\n }\n\n async search(request: MarketplaceSearchRequest): Promise<MarketplaceSearchResult> {\n const probe = request.query.toLowerCase();\n const items = [...this.#plays.values()]\n .filter(\n (play) =>\n play.playId.toLowerCase().includes(probe) ||\n play.skillMarkdown.toLowerCase().includes(probe),\n )\n .sort((left, right) =>\n request.sort === \"success_rate\"\n ? right.quality.successRate - left.quality.successRate ||\n left.playId.localeCompare(right.playId)\n : right.eventId.localeCompare(left.eventId),\n );\n await this.#debug({\n type: \"search\",\n tenantId: this.#tenantId,\n query: request.query,\n hits: items.length,\n });\n return { items };\n }\n\n async install(playId: string, version: string): Promise<InstalledPlay> {\n const key = `${playId}@${version}`;\n const play = this.#plays.get(key);\n if (!play) {\n throw new CapabilityError(\"play-marketplace\", \"Play registry record not found\", {\n suggestion: \"Search the marketplace and install an available version.\",\n metadata: { playId, version },\n statusCode: 404,\n });\n }\n const installPath = `marketplace/installed/${playId}@${version}.json`;\n const install: InstalledPlay = {\n playId,\n version,\n status: \"installed\",\n registeredSkill: playId,\n installPath,\n };\n const snapshot = `${JSON.stringify(install, null, 2)}\\n`;\n await this.#contentStore.write(installPath, snapshot);\n await this.#eventLog.commit({\n traceId: assetId(\"play_marketplace_install\", `${playId}_${version}`),\n kind: \"content_write\",\n affected: [installPath],\n parent: play.eventId,\n snapshot: { [installPath]: snapshot },\n });\n await this.#debug({ type: \"install\", tenantId: this.#tenantId, playId, version });\n return install;\n }\n\n async doctor(): Promise<PlayMarketplaceDoctorReport> {\n const report: PlayMarketplaceDoctorReport = {\n capability: \"play-marketplace\",\n ok: true,\n checkedAt: new Date().toISOString(),\n features: [\"validate-skill\", \"publish\", \"search\", \"install\", \"paid-launch-gate\"],\n suggestion:\n \"Local registry artifacts are active; remote registry, billing, and verified review queues remain handoffs.\",\n };\n await this.#debug({ type: \"doctor\", tenantId: this.#tenantId, plays: this.#plays.size });\n return report;\n }\n\n async close(): Promise<void> {\n await this.#contentStore.close();\n }\n\n async #debug(entry: Record<string, unknown>): Promise<void> {\n await appendCapabilityDebug(\"play-marketplace\", entry, { root: this.#debugRoot });\n }\n}\n\nexport async function readPlayMarketplaceDebug(\n root = process.cwd(),\n limit = 20,\n): Promise<unknown[]> {\n return readCapabilityDebug(\"play-marketplace\", { root, limit });\n}\n","import { CapabilityError } from \"@nebutra/errors\";\n\nexport interface PathRef {\n readonly path: string;\n readonly tenantId?: string;\n readonly mediaType?: string;\n}\n\nexport interface BrandColor {\n readonly name: string;\n readonly hex: string;\n readonly role?: \"primary\" | \"secondary\" | \"accent\" | \"neutral\" | \"background\";\n}\n\nexport interface TypographySpec {\n readonly heading: string;\n readonly body: string;\n readonly accent?: string;\n}\n\nexport interface VisualStyle {\n readonly name: string;\n readonly keywords: readonly string[];\n readonly avoid?: readonly string[];\n}\n\nexport interface BrandContext {\n readonly tenantId: string;\n readonly brandId: string;\n readonly name: string;\n readonly palette: readonly BrandColor[];\n readonly typography: TypographySpec;\n readonly visualStyle: VisualStyle;\n readonly referenceImages: readonly PathRef[];\n readonly forbidden: readonly string[];\n readonly toneKeywords: readonly string[];\n readonly sourcePath: string;\n}\n\nexport type LicenseStatus = \"commercial-ok\" | \"non-commercial\" | \"requires-attribution\" | \"unknown\";\n\nexport interface LicenseMetadata {\n readonly status: LicenseStatus;\n readonly source: string;\n readonly suggestion?: string;\n}\n\nexport interface GeneratedAsset {\n readonly id: string;\n readonly tenantId: string;\n readonly kind: \"image\" | \"video\" | \"audio\" | \"voice\" | \"mesh\";\n readonly path: string;\n readonly brandId: string;\n readonly provider: string;\n readonly model: string;\n readonly createdAt: string;\n readonly license: LicenseMetadata;\n readonly metadata?: Record<string, unknown>;\n}\n\nexport function requireBrandContext(\n brand: BrandContext | undefined,\n capability: string,\n): BrandContext {\n if (!brand) {\n throw new CapabilityError(capability, \"BrandContext is required for generation\", {\n suggestion:\n \"Load company/BRAND.md through content-store and pass the parsed BrandContext into this call.\",\n statusCode: 400,\n });\n }\n\n const missing: string[] = [];\n if (!brand.tenantId) missing.push(\"tenantId\");\n if (!brand.brandId) missing.push(\"brandId\");\n if (!brand.name) missing.push(\"name\");\n if (brand.palette.length === 0) missing.push(\"palette\");\n if (!brand.typography.heading || !brand.typography.body) missing.push(\"typography\");\n if (!brand.visualStyle.name || brand.visualStyle.keywords.length === 0) {\n missing.push(\"visualStyle\");\n }\n if (brand.toneKeywords.length === 0) missing.push(\"toneKeywords\");\n if (!brand.sourcePath) missing.push(\"sourcePath\");\n\n if (missing.length > 0) {\n throw new CapabilityError(capability, \"BrandContext is incomplete\", {\n suggestion: `Fill these BrandContext fields before generation: ${missing.join(\", \")}.`,\n metadata: { missing },\n statusCode: 400,\n });\n }\n\n return brand;\n}\n\nexport function summarizeBrandContext(brand: BrandContext): string {\n return [\n brand.name,\n `style=${brand.visualStyle.name}`,\n `tone=${brand.toneKeywords.join(\", \")}`,\n `palette=${brand.palette.map((color) => `${color.name}:${color.hex}`).join(\", \")}`,\n ].join(\"; \");\n}\n\nexport function createDemoBrandContext(overrides: Partial<BrandContext> = {}): BrandContext {\n return {\n tenantId: \"demo_tenant\",\n brandId: \"loop\",\n name: \"Loop\",\n palette: [\n { name: \"signal\", hex: \"#00A693\", role: \"primary\" },\n { name: \"ink\", hex: \"#151719\", role: \"neutral\" },\n { name: \"spark\", hex: \"#F3C14B\", role: \"accent\" },\n ],\n typography: { heading: \"Geist Sans\", body: \"Geist Sans Mono\" },\n visualStyle: {\n name: \"focused technical optimism\",\n keywords: [\"precise\", \"calm\", \"developer-native\"],\n avoid: [\"dark horror\", \"generic stock\"],\n },\n referenceImages: [],\n forbidden: [\"dark horror\", \"skeletal imagery\"],\n toneKeywords: [\"technical\", \"warm\", \"direct\"],\n sourcePath: \"company/BRAND.md\",\n ...overrides,\n };\n}\n\nexport function assetId(prefix: string, seed: string): string {\n return `${prefix}_${seed\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .slice(0, 40)}_${Date.now().toString(36)}`;\n}\n"],"mappings":"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","names":["CapabilityError","CapabilityError"]}