@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.
- package/.nebutra/debug/content-store.jsonl +4 -4
- package/.nebutra/debug/event-log.jsonl +2 -2
- package/.nebutra/debug/play-marketplace.jsonl +3 -3
- package/.turbo/turbo-build.log +5 -5
- package/.turbo/turbo-test.log +5 -6
- package/.turbo/turbo-typecheck.log +1 -1
- package/CHANGELOG.md +14 -0
- package/dist/{chunk-2SUUBIJC.js → chunk-BRGFNH5O.js} +13 -22
- package/dist/chunk-BRGFNH5O.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -6
- package/src/index.ts +9 -11
- package/dist/chunk-2SUUBIJC.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{"at":"2026-05-
|
|
2
|
-
{"at":"2026-05-
|
|
3
|
-
{"at":"2026-05-
|
|
4
|
-
{"at":"2026-05-
|
|
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":"
|
|
2
|
-
{"traceId":"
|
|
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-
|
|
2
|
-
{"at":"2026-05-
|
|
3
|
-
{"at":"2026-05-
|
|
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"}
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @nebutra/play-marketplace@0.1.
|
|
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
|
[34mCLI[39m Building entry: src/cli.ts, src/index.ts
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[32mESM[39m [1mdist/cli.js [22m[32m1.06 KB[39m
|
|
13
13
|
[32mESM[39m [1mdist/index.js [22m[32m222.00 B[39m
|
|
14
|
-
[32mESM[39m [1mdist/chunk-
|
|
14
|
+
[32mESM[39m [1mdist/chunk-BRGFNH5O.js [22m[32m6.30 KB[39m
|
|
15
15
|
[32mESM[39m [1mdist/cli.js.map [22m[32m1.87 KB[39m
|
|
16
16
|
[32mESM[39m [1mdist/index.js.map [22m[32m71.00 B[39m
|
|
17
|
-
[32mESM[39m [1mdist/chunk-
|
|
18
|
-
[32mESM[39m ⚡️ Build success in
|
|
17
|
+
[32mESM[39m [1mdist/chunk-BRGFNH5O.js.map [22m[32m13.50 KB[39m
|
|
18
|
+
[32mESM[39m ⚡️ Build success in 92ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 10539ms
|
|
21
21
|
[32mDTS[39m [1mdist/cli.d.ts [22m[32m13.00 B[39m
|
|
22
22
|
[32mDTS[39m [1mdist/index.d.ts [22m[32m3.07 KB[39m
|
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
|
|
2
|
-
> @nebutra/play-marketplace@0.1.
|
|
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
|
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.4 [39m[90m/home/runner/work/Nebutra-Sailor/Nebutra-Sailor/packages/ai/play-marketplace[39m
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
[32m✓[39m src/index.test.ts [2m([22m[2m3 tests[22m[2m)[22m[33m 341[2mms[22m[39m
|
|
8
|
+
[32m✓[39m src/index.test.ts [2m([22m[2m3 tests[22m[2m)[22m[33m 491[2mms[22m[39m
|
|
9
|
+
[33m[2m✓[22m[39m publishes, searches, and installs signed Play registry records [33m 343[2mms[22m[39m
|
|
11
10
|
|
|
12
11
|
[2m Test Files [22m [1m[32m1 passed[39m[22m[90m (1)[39m
|
|
13
12
|
[2m Tests [22m [1m[32m3 passed[39m[22m[90m (3)[39m
|
|
14
|
-
[2m Start at [22m
|
|
15
|
-
[2m Duration [22m 2.
|
|
13
|
+
[2m Start at [22m 08:15:24
|
|
14
|
+
[2m Duration [22m 2.95s[2m (transform 1.52s, setup 0ms, import 1.84s, tests 491ms, environment 0ms)[22m
|
|
16
15
|
|
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
|
-
|
|
12
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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-
|
|
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
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nebutra/play-marketplace",
|
|
3
|
-
"version": "0.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.
|
|
33
|
-
"@nebutra/content-store": "0.1.
|
|
34
|
-
"@nebutra/errors": "0.1.
|
|
35
|
-
"@nebutra/event-log": "0.1.
|
|
36
|
-
"@nebutra/
|
|
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 =
|
|
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"]}
|