@siglume/api-sdk 0.10.7 → 0.10.8
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 +99 -91
- package/dist/bin/siglume.cjs +306 -10
- package/dist/bin/siglume.cjs.map +1 -1
- package/dist/bin/siglume.js +306 -10
- package/dist/bin/siglume.js.map +1 -1
- package/dist/cli/index.cjs +306 -10
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +78 -0
- package/dist/cli/index.d.ts +78 -0
- package/dist/cli/index.js +306 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +168 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -1
- package/dist/index.d.ts +92 -1
- package/dist/index.js +168 -1
- package/dist/index.js.map +1 -1
- package/package.json +58 -58
package/README.md
CHANGED
|
@@ -1,91 +1,99 @@
|
|
|
1
|
-
# @siglume/api-sdk
|
|
2
|
-
|
|
3
|
-
TypeScript runtime for building, testing, and registering Siglume developer apps.
|
|
4
|
-
|
|
5
|
-
This package is prepared in the public SDK repo and ships with the current v0.10.x release line.
|
|
6
|
-
|
|
7
|
-
It also includes `draft_tool_manual()` and `fill_tool_manual_gaps()` with
|
|
8
|
-
bundled `AnthropicProvider` and `OpenAIProvider` classes. Provide
|
|
9
|
-
`ANTHROPIC_API_KEY` or `OPENAI_API_KEY`, then:
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import { AnthropicProvider, draft_tool_manual } from "@siglume/api-sdk";
|
|
13
|
-
|
|
14
|
-
const result = await draft_tool_manual({
|
|
15
|
-
capability_key: "currency-converter-jp",
|
|
16
|
-
job_to_be_done: "Convert USD amounts to JPY with live rates",
|
|
17
|
-
permission_class: "read_only",
|
|
18
|
-
llm: new AnthropicProvider(),
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
console.log(result.quality_report.grade);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Buyer-side discovery and export helpers are also included:
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
import { SiglumeBuyerClient, to_anthropic_tool } from "@siglume/api-sdk";
|
|
28
|
-
|
|
29
|
-
const buyer = new SiglumeBuyerClient({
|
|
30
|
-
api_key: process.env.SIGLUME_API_KEY ?? "sig_mock_key",
|
|
31
|
-
default_agent_id: process.env.SIGLUME_AGENT_ID,
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const listing = await buyer.get_listing("currency-converter-v2");
|
|
35
|
-
const anthropicTool = to_anthropic_tool(listing.tool_manual).schema;
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
`SiglumeBuyerClient.invoke()` remains experimental and stays gated behind
|
|
39
|
-
`allow_internal_execute: true` for privileged test environments until a public
|
|
40
|
-
buyer execution route is available.
|
|
41
|
-
|
|
42
|
-
See [`../docs/buyer-sdk.md`](../docs/buyer-sdk.md) and
|
|
43
|
-
[`../examples/buyer_claude_agent_sdk.ts`](../examples/buyer_claude_agent_sdk.ts)
|
|
44
|
-
for the current experimental limitations and the mocked integration example.
|
|
45
|
-
|
|
46
|
-
You can also generate deterministic first-party owner-operation wrappers from
|
|
47
|
-
the CLI without using an LLM:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
siglume init --list-operations
|
|
51
|
-
siglume init --from-operation owner.charter.update ./my-charter-editor
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
See [`../docs/template-generator.md`](../docs/template-generator.md) for the
|
|
55
|
-
generated file layout, fallback behavior, and review samples.
|
|
56
|
-
|
|
57
|
-
For API Store publishing, the recommended CLI flow is:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
siglume init --template price-compare
|
|
61
|
-
siglume test .
|
|
62
|
-
siglume score . --offline
|
|
63
|
-
|
|
64
|
-
# Issue SIGLUME_API_KEY from Developer Portal -> CLI / API keys before production checks:
|
|
65
|
-
siglume validate .
|
|
66
|
-
siglume score . --remote
|
|
67
|
-
siglume preflight . # checks blockers without creating a draft
|
|
68
|
-
siglume register . # preflight + auto-register + confirm/publish
|
|
69
|
-
siglume register . --draft-only # review-only draft staging
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
`
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
`
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
1
|
+
# @siglume/api-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript runtime for building, testing, and registering Siglume developer apps.
|
|
4
|
+
|
|
5
|
+
This package is prepared in the public SDK repo and ships with the current v0.10.x release line.
|
|
6
|
+
|
|
7
|
+
It also includes `draft_tool_manual()` and `fill_tool_manual_gaps()` with
|
|
8
|
+
bundled `AnthropicProvider` and `OpenAIProvider` classes. Provide
|
|
9
|
+
`ANTHROPIC_API_KEY` or `OPENAI_API_KEY`, then:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { AnthropicProvider, draft_tool_manual } from "@siglume/api-sdk";
|
|
13
|
+
|
|
14
|
+
const result = await draft_tool_manual({
|
|
15
|
+
capability_key: "currency-converter-jp",
|
|
16
|
+
job_to_be_done: "Convert USD amounts to JPY with live rates",
|
|
17
|
+
permission_class: "read_only",
|
|
18
|
+
llm: new AnthropicProvider(),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
console.log(result.quality_report.grade);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Buyer-side discovery and export helpers are also included:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { SiglumeBuyerClient, to_anthropic_tool } from "@siglume/api-sdk";
|
|
28
|
+
|
|
29
|
+
const buyer = new SiglumeBuyerClient({
|
|
30
|
+
api_key: process.env.SIGLUME_API_KEY ?? "sig_mock_key",
|
|
31
|
+
default_agent_id: process.env.SIGLUME_AGENT_ID,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const listing = await buyer.get_listing("currency-converter-v2");
|
|
35
|
+
const anthropicTool = to_anthropic_tool(listing.tool_manual).schema;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`SiglumeBuyerClient.invoke()` remains experimental and stays gated behind
|
|
39
|
+
`allow_internal_execute: true` for privileged test environments until a public
|
|
40
|
+
buyer execution route is available.
|
|
41
|
+
|
|
42
|
+
See [`../docs/buyer-sdk.md`](../docs/buyer-sdk.md) and
|
|
43
|
+
[`../examples/buyer_claude_agent_sdk.ts`](../examples/buyer_claude_agent_sdk.ts)
|
|
44
|
+
for the current experimental limitations and the mocked integration example.
|
|
45
|
+
|
|
46
|
+
You can also generate deterministic first-party owner-operation wrappers from
|
|
47
|
+
the CLI without using an LLM:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
siglume init --list-operations
|
|
51
|
+
siglume init --from-operation owner.charter.update ./my-charter-editor
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
See [`../docs/template-generator.md`](../docs/template-generator.md) for the
|
|
55
|
+
generated file layout, fallback behavior, and review samples.
|
|
56
|
+
|
|
57
|
+
For API Store publishing, the recommended CLI flow is:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
siglume init --template price-compare
|
|
61
|
+
siglume test .
|
|
62
|
+
siglume score . --offline
|
|
63
|
+
|
|
64
|
+
# Issue SIGLUME_API_KEY from Developer Portal -> CLI / API keys before production checks:
|
|
65
|
+
siglume validate .
|
|
66
|
+
siglume score . --remote
|
|
67
|
+
siglume preflight . # checks blockers without creating a draft
|
|
68
|
+
siglume register . # preflight + auto-register + confirm/publish
|
|
69
|
+
siglume register . --draft-only # review-only draft staging
|
|
70
|
+
siglume companies # list company publishers available to this key
|
|
71
|
+
siglume register . --company company_123
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`siglume register` reads `tool_manual.json`, the local Git-ignored
|
|
75
|
+
`runtime_validation.json`, and optional local Git-ignored
|
|
76
|
+
`oauth_credentials.json`. Generated projects keep runtime validation and OAuth
|
|
77
|
+
credential files Git-ignored because they can contain review keys and client
|
|
78
|
+
secrets. SDK / HTTP automation can pass
|
|
79
|
+
`source_url`, `source_context`, and `input_form_spec` directly to
|
|
80
|
+
`auto-register`. The CLI runs preflight by default, then calls the same
|
|
81
|
+
`auto-register` route used by SDK / automation clients and confirms publication
|
|
82
|
+
unless `--draft-only` is set. Re-run the same `capability_key` to publish a
|
|
83
|
+
non-material upgrade when checks pass. The server-side publish gate
|
|
84
|
+
includes runtime checks, contract checks, seller OAuth checks, pricing / payout
|
|
85
|
+
rules, and a mandatory fail-closed LLM legal review for law compliance plus
|
|
86
|
+
public-order / morals compliance.
|
|
87
|
+
|
|
88
|
+
Company-name publishing is founder-only in the Phase 2 MVP. Use
|
|
89
|
+
`publisher_type: "company"` with `company_id` in `app_manifest.yaml`, or pass
|
|
90
|
+
`--company <company_id>` to the CLI. Paid company listings require the
|
|
91
|
+
company's verified settlement wallet; Siglume does not fall back to the
|
|
92
|
+
registrant's personal payout wallet.
|
|
93
|
+
|
|
94
|
+
Game APIs use the same publishing flow. To make a listing eligible for the
|
|
95
|
+
dedicated Game API Store entry point, include explicit game-oriented
|
|
96
|
+
`compatibility_tags` in the manifest, for example `["game", "unity",
|
|
97
|
+
"realtime", "npc"]`. Use concrete tags such as `game`, `unity`, `unreal`,
|
|
98
|
+
`godot`, `npc`, `matchmaking`, `multiplayer`, `realtime`, `ugc`, or
|
|
99
|
+
`narrative`; do not send arbitrary registration `metadata` for store placement.
|
package/dist/bin/siglume.cjs
CHANGED
|
@@ -1247,6 +1247,56 @@ var init_operations = __esm({
|
|
|
1247
1247
|
});
|
|
1248
1248
|
|
|
1249
1249
|
// src/client.ts
|
|
1250
|
+
function validateManifestPersistenceContract(payload) {
|
|
1251
|
+
const vertical = String(payload.store_vertical ?? "").trim().toLowerCase();
|
|
1252
|
+
const persistence = payload.persistence;
|
|
1253
|
+
if (persistence === void 0 || persistence === null) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
if (!isRecord(persistence)) {
|
|
1257
|
+
throw new SiglumeClientError("AppManifest.persistence must be an object.");
|
|
1258
|
+
}
|
|
1259
|
+
const mode = String(persistence.mode ?? (vertical === "game" ? "platform" : "none")).trim().toLowerCase();
|
|
1260
|
+
if (!["none", "local", "platform", "developer_server"].includes(mode)) {
|
|
1261
|
+
throw new SiglumeClientError(
|
|
1262
|
+
"AppManifest.persistence.mode must be one of: none, local, platform, developer_server."
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
const schema = persistence.save_data_schema;
|
|
1266
|
+
if (vertical === "game" && mode !== "none" && schema === void 0) {
|
|
1267
|
+
throw new SiglumeClientError(
|
|
1268
|
+
"AppManifest.persistence.save_data_schema is required when store_vertical='game' and persistence.mode is not 'none'."
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
if (schema !== void 0) {
|
|
1272
|
+
validateSaveDataSchema(schema, "AppManifest.persistence.save_data_schema");
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
function validateSaveDataSchema(schema, fieldName) {
|
|
1276
|
+
if (!isRecord(schema)) {
|
|
1277
|
+
throw new SiglumeClientError(`${fieldName} must be a JSON Schema object.`);
|
|
1278
|
+
}
|
|
1279
|
+
const schemaSize = new TextEncoder().encode(JSON.stringify(schema)).length;
|
|
1280
|
+
if (schemaSize > 8192) {
|
|
1281
|
+
throw new SiglumeClientError(`${fieldName} must be at most 8192 bytes.`);
|
|
1282
|
+
}
|
|
1283
|
+
if (schema.type !== "object") {
|
|
1284
|
+
throw new SiglumeClientError(`${fieldName}.type must be 'object'.`);
|
|
1285
|
+
}
|
|
1286
|
+
const properties = schema.properties;
|
|
1287
|
+
if (!isRecord(properties) || Object.keys(properties).length === 0) {
|
|
1288
|
+
throw new SiglumeClientError(`${fieldName}.properties must be a non-empty object.`);
|
|
1289
|
+
}
|
|
1290
|
+
if (schema.required !== void 0) {
|
|
1291
|
+
if (!Array.isArray(schema.required) || !schema.required.every((item) => typeof item === "string")) {
|
|
1292
|
+
throw new SiglumeClientError(`${fieldName}.required must be an array of strings when provided.`);
|
|
1293
|
+
}
|
|
1294
|
+
const missing = schema.required.filter((item) => !(item in properties));
|
|
1295
|
+
if (missing.length > 0) {
|
|
1296
|
+
throw new SiglumeClientError(`${fieldName}.required references undefined properties: ${missing.join(", ")}.`);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1250
1300
|
function buildToolManualQualityReport(payload) {
|
|
1251
1301
|
const qualityBlock = isRecord(payload.quality) ? payload.quality : payload;
|
|
1252
1302
|
const issues = [];
|
|
@@ -1321,6 +1371,8 @@ function buildUrl(baseUrl, path, params) {
|
|
|
1321
1371
|
return url.toString();
|
|
1322
1372
|
}
|
|
1323
1373
|
function parseListing(data) {
|
|
1374
|
+
const metadata = isRecord(data.metadata) ? data.metadata : {};
|
|
1375
|
+
const persistence = isRecord(data.persistence) ? data.persistence : isRecord(metadata.persistence) ? metadata.persistence : {};
|
|
1324
1376
|
return {
|
|
1325
1377
|
listing_id: String(data.listing_id ?? data.id ?? ""),
|
|
1326
1378
|
capability_key: String(data.capability_key ?? ""),
|
|
@@ -1343,14 +1395,59 @@ function parseListing(data) {
|
|
|
1343
1395
|
seller_display_name: stringOrNull(data.seller_display_name),
|
|
1344
1396
|
seller_homepage_url: stringOrNull(data.seller_homepage_url),
|
|
1345
1397
|
seller_social_url: stringOrNull(data.seller_social_url),
|
|
1398
|
+
publisher_type: stringOrNull(data.publisher_type),
|
|
1399
|
+
publisher_company_id: stringOrNull(data.publisher_company_id),
|
|
1400
|
+
company_id: stringOrNull(data.company_id),
|
|
1401
|
+
company_name: stringOrNull(data.company_name),
|
|
1402
|
+
company_publish_status: stringOrNull(data.company_publish_status),
|
|
1403
|
+
company_terms_version: stringOrNull(data.company_terms_version),
|
|
1346
1404
|
review_status: stringOrNull(data.review_status),
|
|
1347
1405
|
review_note: stringOrNull(data.review_note),
|
|
1348
1406
|
submission_blockers: Array.isArray(data.submission_blockers) ? data.submission_blockers.filter((item) => typeof item === "string") : [],
|
|
1407
|
+
persistence: { ...persistence },
|
|
1349
1408
|
created_at: stringOrNull(data.created_at),
|
|
1350
1409
|
updated_at: stringOrNull(data.updated_at),
|
|
1351
1410
|
raw: { ...data }
|
|
1352
1411
|
};
|
|
1353
1412
|
}
|
|
1413
|
+
function parseCompanyPublisher(data) {
|
|
1414
|
+
const wallets = Array.isArray(data.settlement_wallets) ? data.settlement_wallets.filter((item) => isRecord(item)) : [];
|
|
1415
|
+
return {
|
|
1416
|
+
company_id: String(data.company_id ?? data.id ?? ""),
|
|
1417
|
+
name: String(data.name ?? ""),
|
|
1418
|
+
status: String(data.status ?? ""),
|
|
1419
|
+
description: stringOrNull(data.description),
|
|
1420
|
+
is_founder: Boolean(data.is_founder ?? false),
|
|
1421
|
+
membership_role: stringOrNull(data.membership_role),
|
|
1422
|
+
membership_status: stringOrNull(data.membership_status),
|
|
1423
|
+
can_publish: Boolean(data.can_publish ?? true),
|
|
1424
|
+
can_approve: Boolean(data.can_approve ?? false),
|
|
1425
|
+
approval_required: Boolean(data.approval_required ?? false),
|
|
1426
|
+
paid_listing_allowed: Boolean(data.paid_listing_allowed ?? false),
|
|
1427
|
+
disabled_reasons: Array.isArray(data.disabled_reasons) ? data.disabled_reasons.filter((item) => typeof item === "string") : [],
|
|
1428
|
+
company_terms_version: stringOrNull(data.company_terms_version),
|
|
1429
|
+
active_listing_count: Number(data.active_listing_count ?? 0),
|
|
1430
|
+
pending_approval_count: Number(data.pending_approval_count ?? 0),
|
|
1431
|
+
settlement_wallet_ready: Boolean(data.settlement_wallet_ready ?? false),
|
|
1432
|
+
settlement_wallets: wallets.map((item) => ({ ...item })),
|
|
1433
|
+
raw: { ...data }
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
function parseCapabilitySaveState(data) {
|
|
1437
|
+
return {
|
|
1438
|
+
capability_key: String(data.capability_key ?? ""),
|
|
1439
|
+
save_key: String(data.save_key ?? ""),
|
|
1440
|
+
schema_version: String(data.schema_version ?? "1"),
|
|
1441
|
+
revision: Number(data.revision ?? 0),
|
|
1442
|
+
payload: toRecord(data.payload),
|
|
1443
|
+
metadata: toRecord(data.metadata),
|
|
1444
|
+
checksum: stringOrNull(data.checksum),
|
|
1445
|
+
updated_at: stringOrNull(data.updated_at),
|
|
1446
|
+
created_at: stringOrNull(data.created_at),
|
|
1447
|
+
exists: Boolean(data.exists ?? false),
|
|
1448
|
+
raw: { ...data }
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1354
1451
|
function parseBundleMember(data) {
|
|
1355
1452
|
return {
|
|
1356
1453
|
capability_listing_id: String(data.capability_listing_id ?? ""),
|
|
@@ -2530,6 +2627,9 @@ var init_client = __esm({
|
|
|
2530
2627
|
"support_contact",
|
|
2531
2628
|
"seller_homepage_url",
|
|
2532
2629
|
"seller_social_url",
|
|
2630
|
+
"publisher_type",
|
|
2631
|
+
"company_id",
|
|
2632
|
+
"publisher_company_id",
|
|
2533
2633
|
"store_vertical",
|
|
2534
2634
|
"jurisdiction",
|
|
2535
2635
|
"price_model",
|
|
@@ -2542,7 +2642,8 @@ var init_client = __esm({
|
|
|
2542
2642
|
"dry_run_supported",
|
|
2543
2643
|
"required_connected_accounts",
|
|
2544
2644
|
"permission_scopes",
|
|
2545
|
-
"compatibility_tags"
|
|
2645
|
+
"compatibility_tags",
|
|
2646
|
+
"persistence"
|
|
2546
2647
|
]) {
|
|
2547
2648
|
const value = manifestPayload[fieldName];
|
|
2548
2649
|
if (value !== void 0 && value !== null) {
|
|
@@ -2582,6 +2683,26 @@ var init_client = __esm({
|
|
|
2582
2683
|
);
|
|
2583
2684
|
}
|
|
2584
2685
|
}
|
|
2686
|
+
const explicitPublisherType = payload.publisher_type !== void 0 && payload.publisher_type !== null;
|
|
2687
|
+
const companyId = String(payload.company_id ?? "").trim() || String(payload.publisher_company_id ?? "").trim();
|
|
2688
|
+
const publisherType = String(payload.publisher_type ?? "user").trim().toLowerCase();
|
|
2689
|
+
if (publisherType !== "user" && publisherType !== "company") {
|
|
2690
|
+
throw new SiglumeClientError("AppManifest.publisher_type must be 'user' or 'company'.");
|
|
2691
|
+
}
|
|
2692
|
+
if (publisherType === "company" && !companyId) {
|
|
2693
|
+
throw new SiglumeClientError("AppManifest.company_id is required when publisher_type='company'.");
|
|
2694
|
+
}
|
|
2695
|
+
if (publisherType === "user" && companyId) {
|
|
2696
|
+
throw new SiglumeClientError("AppManifest.company_id cannot be combined with publisher_type='user'.");
|
|
2697
|
+
}
|
|
2698
|
+
if (explicitPublisherType || companyId) {
|
|
2699
|
+
payload.publisher_type = publisherType;
|
|
2700
|
+
}
|
|
2701
|
+
if (companyId) {
|
|
2702
|
+
payload.company_id = companyId;
|
|
2703
|
+
payload.publisher_company_id = companyId;
|
|
2704
|
+
}
|
|
2705
|
+
validateManifestPersistenceContract(payload);
|
|
2585
2706
|
if (payload.manifest && typeof payload.manifest === "object") {
|
|
2586
2707
|
delete payload.manifest.version;
|
|
2587
2708
|
}
|
|
@@ -2689,6 +2810,45 @@ var init_client = __esm({
|
|
|
2689
2810
|
const [data] = await this.request("GET", `/market/capabilities/${listing_id}`);
|
|
2690
2811
|
return parseListing(data);
|
|
2691
2812
|
}
|
|
2813
|
+
async list_company_publishers() {
|
|
2814
|
+
const [data] = await this.request("GET", "/market/company-publishers");
|
|
2815
|
+
return Array.isArray(data.items) ? data.items.filter((item) => isRecord(item)).map(parseCompanyPublisher) : [];
|
|
2816
|
+
}
|
|
2817
|
+
async request_company_publish_approval(listing_id, note) {
|
|
2818
|
+
const [data] = await this.request("POST", `/market/capabilities/${listing_id}/company-publish-approval`, {
|
|
2819
|
+
json_body: note ? { note } : {}
|
|
2820
|
+
});
|
|
2821
|
+
return parseListing(data);
|
|
2822
|
+
}
|
|
2823
|
+
async decide_company_publish_approval(listing_id, options) {
|
|
2824
|
+
const [data] = await this.request("POST", `/market/capabilities/${listing_id}/company-publish-approval/decision`, {
|
|
2825
|
+
json_body: {
|
|
2826
|
+
decision: options.decision,
|
|
2827
|
+
...options.reason ? { reason: options.reason } : {}
|
|
2828
|
+
}
|
|
2829
|
+
});
|
|
2830
|
+
return parseListing(data);
|
|
2831
|
+
}
|
|
2832
|
+
async get_capability_state(capability_key, save_key = "default") {
|
|
2833
|
+
const [data] = await this.request("GET", `/market/capability-state/${capability_key}/${save_key}`);
|
|
2834
|
+
return parseCapabilitySaveState(data);
|
|
2835
|
+
}
|
|
2836
|
+
async put_capability_state(capability_key, save_key = "default", payload = {}, options = {}) {
|
|
2837
|
+
const body = {
|
|
2838
|
+
payload: toRecord(payload),
|
|
2839
|
+
schema_version: options.schema_version ?? "1",
|
|
2840
|
+
metadata: toRecord(options.metadata)
|
|
2841
|
+
};
|
|
2842
|
+
if (options.expected_revision !== void 0 && options.expected_revision !== null) {
|
|
2843
|
+
body.expected_revision = Math.trunc(options.expected_revision);
|
|
2844
|
+
}
|
|
2845
|
+
const [data] = await this.request("PUT", `/market/capability-state/${capability_key}/${save_key}`, { json_body: body });
|
|
2846
|
+
return parseCapabilitySaveState(data);
|
|
2847
|
+
}
|
|
2848
|
+
async delete_capability_state(capability_key, save_key = "default") {
|
|
2849
|
+
const [data] = await this.request("DELETE", `/market/capability-state/${capability_key}/${save_key}`);
|
|
2850
|
+
return parseCapabilitySaveState(data);
|
|
2851
|
+
}
|
|
2692
2852
|
// ----- Capability bundles (v0.7 track 2) ---------------------------------
|
|
2693
2853
|
async list_bundles(options = {}) {
|
|
2694
2854
|
const params = {
|
|
@@ -7283,7 +7443,12 @@ function ensureManifestPublisherIdentity(project) {
|
|
|
7283
7443
|
const sellerHomepageUrl = String(manifestPayload.seller_homepage_url ?? "").trim();
|
|
7284
7444
|
const sellerSocialUrl = String(manifestPayload.seller_social_url ?? "").trim();
|
|
7285
7445
|
const jurisdiction = String(manifestPayload.jurisdiction ?? "").trim();
|
|
7446
|
+
const companyId = String(manifestPayload.company_id ?? "").trim() || String(manifestPayload.publisher_company_id ?? "").trim();
|
|
7447
|
+
const publisherType = String(manifestPayload.publisher_type ?? "user").trim().toLowerCase();
|
|
7286
7448
|
const issues = [];
|
|
7449
|
+
if (companyId && publisherType !== "company") {
|
|
7450
|
+
issues.push('manifest.company_id requires manifest.publisher_type to be "company"');
|
|
7451
|
+
}
|
|
7287
7452
|
if (!docsUrl) {
|
|
7288
7453
|
issues.push("manifest.docs_url is required");
|
|
7289
7454
|
} else if (looksLikePlaceholder(docsUrl)) {
|
|
@@ -7429,25 +7594,110 @@ ${errors.map((error) => `- ${error}`).join("\n")}`
|
|
|
7429
7594
|
}
|
|
7430
7595
|
return preflight;
|
|
7431
7596
|
}
|
|
7597
|
+
function companyNameSlug(value) {
|
|
7598
|
+
return value.normalize("NFKD").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
7599
|
+
}
|
|
7432
7600
|
async function runRegistration(path = ".", options = {}, deps = {}) {
|
|
7433
7601
|
const project = await loadProject(path);
|
|
7602
|
+
let requestedCompanyId = String(options.company_id ?? "").trim();
|
|
7603
|
+
const requestedCompanySlug = String(options.company_slug ?? "").trim();
|
|
7604
|
+
let companyPublisherCandidates = null;
|
|
7605
|
+
if (requestedCompanySlug) {
|
|
7606
|
+
if (requestedCompanyId) {
|
|
7607
|
+
throw new SiglumeProjectError("--company and --company-slug cannot be combined.");
|
|
7608
|
+
}
|
|
7609
|
+
const slug = companyNameSlug(requestedCompanySlug);
|
|
7610
|
+
if (!slug && requestedCompanySlug !== requestedCompanyId) {
|
|
7611
|
+
throw new SiglumeProjectError(`Company slug ${requestedCompanySlug} is not slug-compatible; use --company <company_id> instead.`);
|
|
7612
|
+
}
|
|
7613
|
+
}
|
|
7614
|
+
if (requestedCompanyId) {
|
|
7615
|
+
project.manifest = {
|
|
7616
|
+
...project.manifest,
|
|
7617
|
+
publisher_type: "company",
|
|
7618
|
+
company_id: requestedCompanyId,
|
|
7619
|
+
publisher_company_id: requestedCompanyId
|
|
7620
|
+
};
|
|
7621
|
+
}
|
|
7434
7622
|
ensureExplicitToolManual(project);
|
|
7435
7623
|
ensureManifestPublisherIdentity(project);
|
|
7436
7624
|
ensureRuntimeValidationReady(project);
|
|
7437
7625
|
ensureRequiredOauthCredentials(project);
|
|
7438
7626
|
const canonicalOauthCredentials = canonicalOauthCredentialsPayload(project.oauth_credentials);
|
|
7439
7627
|
const client = await createClient(deps);
|
|
7628
|
+
if (requestedCompanySlug) {
|
|
7629
|
+
const slug = companyNameSlug(requestedCompanySlug);
|
|
7630
|
+
companyPublisherCandidates = await client.list_company_publishers();
|
|
7631
|
+
const matches = companyPublisherCandidates.filter(
|
|
7632
|
+
(item) => companyNameSlug(item.name || item.company_id) === slug || item.company_id === requestedCompanySlug
|
|
7633
|
+
);
|
|
7634
|
+
if (matches.length === 0) {
|
|
7635
|
+
throw new SiglumeProjectError(`Company slug ${requestedCompanySlug} is not available to this API key.`);
|
|
7636
|
+
}
|
|
7637
|
+
if (matches.length > 1) {
|
|
7638
|
+
throw new SiglumeProjectError(`Company slug ${requestedCompanySlug} is ambiguous; use --company <company_id> instead.`);
|
|
7639
|
+
}
|
|
7640
|
+
const match = matches[0];
|
|
7641
|
+
if (!match) {
|
|
7642
|
+
throw new SiglumeProjectError(`Company slug ${requestedCompanySlug} is not available to this API key.`);
|
|
7643
|
+
}
|
|
7644
|
+
if (match.can_publish === false) {
|
|
7645
|
+
const disabledReasons = match.disabled_reasons ?? [];
|
|
7646
|
+
const reasons = disabledReasons.length > 0 ? disabledReasons.join(", ") : "company publisher is disabled";
|
|
7647
|
+
throw new SiglumeProjectError(`Company ${match.company_id} cannot publish: ${reasons}.`);
|
|
7648
|
+
}
|
|
7649
|
+
requestedCompanyId = match.company_id;
|
|
7650
|
+
project.manifest = {
|
|
7651
|
+
...project.manifest,
|
|
7652
|
+
publisher_type: "company",
|
|
7653
|
+
company_id: requestedCompanyId,
|
|
7654
|
+
publisher_company_id: requestedCompanyId
|
|
7655
|
+
};
|
|
7656
|
+
}
|
|
7440
7657
|
const preflight = await registrationPreflight(project, client);
|
|
7658
|
+
let companyPublisherPreflight = null;
|
|
7659
|
+
const companyId = String(project.manifest.company_id ?? "").trim() || String(project.manifest.publisher_company_id ?? "").trim();
|
|
7660
|
+
const publisherType = String(project.manifest.publisher_type ?? "user").toLowerCase();
|
|
7661
|
+
if (publisherType === "company") {
|
|
7662
|
+
if (!companyId) {
|
|
7663
|
+
throw new SiglumeProjectError("Company registration requires --company <company_id> or manifest.company_id.");
|
|
7664
|
+
}
|
|
7665
|
+
const companies = companyPublisherCandidates ?? await client.list_company_publishers();
|
|
7666
|
+
companyPublisherCandidates = companies;
|
|
7667
|
+
const company = companies.find((item) => item.company_id === companyId);
|
|
7668
|
+
if (!company) {
|
|
7669
|
+
throw new SiglumeProjectError(`Company ${companyId} is not available to this API key.`);
|
|
7670
|
+
}
|
|
7671
|
+
if (company.can_publish === false) {
|
|
7672
|
+
const disabledReasons = company.disabled_reasons ?? [];
|
|
7673
|
+
const reasons = disabledReasons.length > 0 ? disabledReasons.join(", ") : "company publisher is disabled";
|
|
7674
|
+
throw new SiglumeProjectError(`Company ${companyId} cannot publish: ${reasons}.`);
|
|
7675
|
+
}
|
|
7676
|
+
companyPublisherPreflight = company;
|
|
7677
|
+
}
|
|
7441
7678
|
let developerPortalPreflight = null;
|
|
7442
7679
|
if (String(project.manifest.price_model ?? "free").toLowerCase() !== "free") {
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
)
|
|
7680
|
+
if (publisherType === "company") {
|
|
7681
|
+
const company = companyPublisherPreflight;
|
|
7682
|
+
if (!company) {
|
|
7683
|
+
throw new SiglumeProjectError(`Company ${companyId} is not available to this API key.`);
|
|
7684
|
+
}
|
|
7685
|
+
if (company.settlement_wallet_ready !== true) {
|
|
7686
|
+
throw new SiglumeProjectError(
|
|
7687
|
+
`Paid company registration requires a verified company settlement wallet for ${company.name}. Open the company settings and complete settlement readiness before registering.`
|
|
7688
|
+
);
|
|
7689
|
+
}
|
|
7690
|
+
developerPortalPreflight = { company_publisher: toJsonable(company) };
|
|
7691
|
+
} else {
|
|
7692
|
+
const portal = await client.get_developer_portal();
|
|
7693
|
+
const verifiedDestination = portal.payout_readiness?.verified_destination;
|
|
7694
|
+
if (verifiedDestination !== true) {
|
|
7695
|
+
throw new SiglumeProjectError(
|
|
7696
|
+
"Paid API registration requires a verified Polygon payout destination. Open https://siglume.com/owner/credits/payout and confirm the embedded-wallet payout token, or call GET /v1/market/developer/portal until payout_readiness.verified_destination is true."
|
|
7697
|
+
);
|
|
7698
|
+
}
|
|
7699
|
+
developerPortalPreflight = toJsonable(portal);
|
|
7449
7700
|
}
|
|
7450
|
-
developerPortalPreflight = toJsonable(portal);
|
|
7451
7701
|
}
|
|
7452
7702
|
const receipt = await client.auto_register(project.manifest, project.tool_manual, {
|
|
7453
7703
|
runtime_validation: project.runtime_validation,
|
|
@@ -7520,6 +7770,14 @@ async function getUsageReport(options, deps = {}) {
|
|
|
7520
7770
|
count: items.length
|
|
7521
7771
|
};
|
|
7522
7772
|
}
|
|
7773
|
+
async function listCompanyPublishersReport(deps = {}) {
|
|
7774
|
+
const client = await createClient(deps);
|
|
7775
|
+
const companies = await client.list_company_publishers();
|
|
7776
|
+
return {
|
|
7777
|
+
companies: companies.map((item) => toJsonable(item)),
|
|
7778
|
+
count: companies.length
|
|
7779
|
+
};
|
|
7780
|
+
}
|
|
7523
7781
|
async function diffJsonFiles(oldPath, newPath) {
|
|
7524
7782
|
const oldPayload = await loadJsonDocument(oldPath);
|
|
7525
7783
|
const newPayload = await loadJsonDocument(newPath);
|
|
@@ -8606,6 +8864,24 @@ function renderOperationTable(operations) {
|
|
|
8606
8864
|
...rows.map((row) => row.map((cell, index) => cell.padEnd(widths[index] ?? cell.length)).join(" "))
|
|
8607
8865
|
];
|
|
8608
8866
|
}
|
|
8867
|
+
function renderCompanyTable(companies) {
|
|
8868
|
+
const rows = companies.map((item) => [
|
|
8869
|
+
String(item.company_id ?? item.id ?? ""),
|
|
8870
|
+
String(item.name ?? ""),
|
|
8871
|
+
String(item.membership_role ?? (item.is_founder ? "founder" : "")),
|
|
8872
|
+
String(item.settlement_wallet_ready === true ? "ready" : "not_ready"),
|
|
8873
|
+
String(item.pending_approval_count ?? 0)
|
|
8874
|
+
]);
|
|
8875
|
+
const headers = ["company_id", "name", "role", "settlement", "pending"];
|
|
8876
|
+
const widths = headers.map(
|
|
8877
|
+
(header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0))
|
|
8878
|
+
);
|
|
8879
|
+
return [
|
|
8880
|
+
headers.map((header, index) => header.padEnd(widths[index] ?? header.length)).join(" "),
|
|
8881
|
+
widths.map((width) => "-".repeat(width)).join(" "),
|
|
8882
|
+
...rows.map((row) => row.map((cell, index) => cell.padEnd(widths[index] ?? cell.length)).join(" "))
|
|
8883
|
+
];
|
|
8884
|
+
}
|
|
8609
8885
|
async function runCli(argv, deps = {}) {
|
|
8610
8886
|
const stdout = deps.stdout;
|
|
8611
8887
|
const stderr = deps.stderr ?? console.error;
|
|
@@ -8762,7 +9038,21 @@ async function runCli(argv, deps = {}) {
|
|
|
8762
9038
|
if (report.runtime_validation_path) emit(stdout, `runtime_validation_path: ${String(report.runtime_validation_path)}`);
|
|
8763
9039
|
if (report.oauth_credentials_path) emit(stdout, `oauth_credentials_path: ${String(report.oauth_credentials_path)}`);
|
|
8764
9040
|
});
|
|
8765
|
-
program.command("
|
|
9041
|
+
program.command("companies").description("List Siglume companies available for company-name publishing.").option("--json", "emit machine-readable JSON", false).action(async (options) => {
|
|
9042
|
+
const report = await listCompanyPublishersReport(deps);
|
|
9043
|
+
if (options.json) {
|
|
9044
|
+
emit(stdout, renderJson(report));
|
|
9045
|
+
return;
|
|
9046
|
+
}
|
|
9047
|
+
const companies = Array.isArray(report.companies) ? report.companies.filter((item) => Boolean(item && typeof item === "object")) : [];
|
|
9048
|
+
if (companies.length === 0) {
|
|
9049
|
+
emit(stdout, "No company publishers available for this API key.");
|
|
9050
|
+
return;
|
|
9051
|
+
}
|
|
9052
|
+
emit(stdout, "Company publishers");
|
|
9053
|
+
renderCompanyTable(companies).forEach((line) => emit(stdout, line));
|
|
9054
|
+
});
|
|
9055
|
+
program.command("register").option("--confirm", "explicitly confirm the registration; this is the default unless --draft-only is set", false).option("--draft-only", "create or refresh the draft without confirming publication", false).option("--submit-review", "legacy alias: publish immediately if your environment still routes through submit-review", false).option("--company <companyId>", "publish under a Siglume company name; revenue is split equally among active members", "").option("--company-slug <slug>", "publish under a Siglume company by matching the slugified company name", "").option("--json", "emit machine-readable JSON", false).argument("[path]", ".", "project path").action(async (path, options) => {
|
|
8766
9056
|
const draftOnly = Boolean(options.draftOnly);
|
|
8767
9057
|
if (draftOnly && options.confirm) {
|
|
8768
9058
|
throw new SiglumeProjectError("--draft-only cannot be combined with --confirm.");
|
|
@@ -8771,7 +9061,13 @@ async function runCli(argv, deps = {}) {
|
|
|
8771
9061
|
throw new SiglumeProjectError("--draft-only cannot be combined with --submit-review.");
|
|
8772
9062
|
}
|
|
8773
9063
|
const shouldConfirm = Boolean(options.confirm) || !draftOnly && !options.submitReview;
|
|
8774
|
-
const report = await runRegistration(path, {
|
|
9064
|
+
const report = await runRegistration(path, {
|
|
9065
|
+
confirm: shouldConfirm,
|
|
9066
|
+
draft_only: draftOnly,
|
|
9067
|
+
submit_review: options.submitReview,
|
|
9068
|
+
company_id: options.company,
|
|
9069
|
+
company_slug: options.companySlug
|
|
9070
|
+
}, deps);
|
|
8775
9071
|
if (options.json) {
|
|
8776
9072
|
emit(stdout, renderJson(report));
|
|
8777
9073
|
} else {
|