@floomhq/skills 1.0.3 → 1.1.1
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 +34 -40
- package/dist/index.js +1429 -268
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -2352,12 +2352,170 @@ var init_skill_package = __esm({
|
|
|
2352
2352
|
}
|
|
2353
2353
|
});
|
|
2354
2354
|
|
|
2355
|
-
// ../shared/src/contract/
|
|
2355
|
+
// ../shared/src/contract/catalog-install.ts
|
|
2356
2356
|
import { z as z2 } from "zod";
|
|
2357
|
-
var
|
|
2357
|
+
var UuidSchema, Sha256Schema, IsoDateTimeSchema, HexTokenSchema, Ed25519PublicKeySchema, Ed25519SignatureSchema, CATALOG_UPGRADE_FREEZES_AT, CatalogInstallAgentSchema, CatalogInstallMethodSchema, CatalogInstallOsSchema, CatalogInstallScopeSchema, CatalogInstallEnvironmentSchema, CatalogInstallerIdentitySchema, CatalogInstallerSupportCellSchema, CatalogInstallDurationBaselineSchema, CatalogUpgradeQualificationRuleSchema, CatalogInstallChallengeRequestSchema, CatalogInstallChallengeResponseSchema, CatalogInstallNonceRequestSchema, CatalogInstallNonceResponseSchema, CatalogInstallReceiptRequestSchema, CatalogUpgradeDispositionSchema, CatalogInstallReceiptResponseSchema;
|
|
2358
|
+
var init_catalog_install = __esm({
|
|
2359
|
+
"../shared/src/contract/catalog-install.ts"() {
|
|
2360
|
+
"use strict";
|
|
2361
|
+
UuidSchema = z2.string().uuid();
|
|
2362
|
+
Sha256Schema = z2.string().regex(/^[a-f0-9]{64}$/);
|
|
2363
|
+
IsoDateTimeSchema = z2.string().datetime({ offset: true });
|
|
2364
|
+
HexTokenSchema = z2.string().regex(/^[a-f0-9]{64}$/);
|
|
2365
|
+
Ed25519PublicKeySchema = z2.string().regex(/^[A-Za-z0-9+/]{43}=$/);
|
|
2366
|
+
Ed25519SignatureSchema = z2.string().regex(/^[A-Za-z0-9+/]{86}==$/);
|
|
2367
|
+
CATALOG_UPGRADE_FREEZES_AT = "2026-09-30T23:59:59.999999Z";
|
|
2368
|
+
CatalogInstallAgentSchema = z2.enum([
|
|
2369
|
+
"claude",
|
|
2370
|
+
"codex",
|
|
2371
|
+
"cursor",
|
|
2372
|
+
"gemini",
|
|
2373
|
+
"opencode"
|
|
2374
|
+
]);
|
|
2375
|
+
CatalogInstallMethodSchema = z2.enum(["cli", "npx", "mcp"]);
|
|
2376
|
+
CatalogInstallOsSchema = z2.enum(["darwin", "linux", "windows"]);
|
|
2377
|
+
CatalogInstallScopeSchema = z2.enum(["global", "project"]);
|
|
2378
|
+
CatalogInstallEnvironmentSchema = z2.enum([
|
|
2379
|
+
"production",
|
|
2380
|
+
"preview",
|
|
2381
|
+
"staging",
|
|
2382
|
+
"ci",
|
|
2383
|
+
"platform_test",
|
|
2384
|
+
"floom_owned"
|
|
2385
|
+
]);
|
|
2386
|
+
CatalogInstallerIdentitySchema = z2.object({
|
|
2387
|
+
name: z2.string().regex(/^[a-z0-9][a-z0-9._-]{0,63}$/),
|
|
2388
|
+
version: z2.string().regex(/^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/),
|
|
2389
|
+
artifact_sha256: Sha256Schema
|
|
2390
|
+
}).strict();
|
|
2391
|
+
CatalogInstallerSupportCellSchema = z2.object({
|
|
2392
|
+
installer: CatalogInstallerIdentitySchema,
|
|
2393
|
+
agent: CatalogInstallAgentSchema,
|
|
2394
|
+
target_os: CatalogInstallOsSchema,
|
|
2395
|
+
install_scope: CatalogInstallScopeSchema,
|
|
2396
|
+
install_method: CatalogInstallMethodSchema,
|
|
2397
|
+
support_status: z2.enum(["U", "S"]),
|
|
2398
|
+
valid_from: IsoDateTimeSchema,
|
|
2399
|
+
valid_until: IsoDateTimeSchema,
|
|
2400
|
+
evidence_manifest_sha256: Sha256Schema
|
|
2401
|
+
}).strict();
|
|
2402
|
+
CatalogInstallDurationBaselineSchema = z2.object({
|
|
2403
|
+
baseline_version: z2.string().regex(/^[a-z0-9][a-z0-9._-]{0,63}$/),
|
|
2404
|
+
cell: CatalogInstallerSupportCellSchema,
|
|
2405
|
+
sample_count: z2.number().int().min(100),
|
|
2406
|
+
p01_duration_ms: z2.number().int().positive(),
|
|
2407
|
+
corpus_sha256: Sha256Schema,
|
|
2408
|
+
evidence_manifest_sha256: Sha256Schema,
|
|
2409
|
+
excludes_warm_cache: z2.literal(true)
|
|
2410
|
+
}).strict();
|
|
2411
|
+
CatalogUpgradeQualificationRuleSchema = z2.object({
|
|
2412
|
+
version: z2.string().regex(/^[a-z0-9][a-z0-9._-]{0,63}$/),
|
|
2413
|
+
rule_hash: Sha256Schema,
|
|
2414
|
+
source_sha256: Sha256Schema,
|
|
2415
|
+
configuration_sha256: Sha256Schema,
|
|
2416
|
+
reconciliation_query_sha256: Sha256Schema,
|
|
2417
|
+
installer_registry_version: z2.string().min(1).max(64),
|
|
2418
|
+
goal_count: z2.literal(1e5),
|
|
2419
|
+
freezes_at: z2.literal(CATALOG_UPGRADE_FREEZES_AT)
|
|
2420
|
+
}).strict();
|
|
2421
|
+
CatalogInstallChallengeRequestSchema = z2.object({
|
|
2422
|
+
release_id: UuidSchema,
|
|
2423
|
+
agent: CatalogInstallAgentSchema,
|
|
2424
|
+
install_method: CatalogInstallMethodSchema,
|
|
2425
|
+
installer: CatalogInstallerIdentitySchema,
|
|
2426
|
+
target_os: CatalogInstallOsSchema,
|
|
2427
|
+
install_scope: CatalogInstallScopeSchema,
|
|
2428
|
+
environment: CatalogInstallEnvironmentSchema,
|
|
2429
|
+
installation_public_key: Ed25519PublicKeySchema,
|
|
2430
|
+
attribution_token: z2.string().min(32).max(256).nullable()
|
|
2431
|
+
}).strict();
|
|
2432
|
+
CatalogInstallChallengeResponseSchema = z2.object({
|
|
2433
|
+
challenge_id: UuidSchema,
|
|
2434
|
+
challenge_token: HexTokenSchema,
|
|
2435
|
+
proof_payload: z2.string().startsWith("floom-install-challenge-v2|"),
|
|
2436
|
+
server_manifest_sha256: Sha256Schema,
|
|
2437
|
+
expires_at: IsoDateTimeSchema
|
|
2438
|
+
}).strict();
|
|
2439
|
+
CatalogInstallNonceRequestSchema = z2.object({
|
|
2440
|
+
challenge_id: UuidSchema,
|
|
2441
|
+
challenge_token: HexTokenSchema,
|
|
2442
|
+
installer_attestation_signature: Ed25519SignatureSchema,
|
|
2443
|
+
installation_proof_signature: Ed25519SignatureSchema
|
|
2444
|
+
}).strict();
|
|
2445
|
+
CatalogInstallNonceResponseSchema = z2.object({
|
|
2446
|
+
nonce_id: UuidSchema,
|
|
2447
|
+
nonce_token: HexTokenSchema,
|
|
2448
|
+
installer_session_id: UuidSchema,
|
|
2449
|
+
installer_session_token: HexTokenSchema,
|
|
2450
|
+
release_id: UuidSchema,
|
|
2451
|
+
content_sha256: Sha256Schema,
|
|
2452
|
+
server_manifest_sha256: Sha256Schema,
|
|
2453
|
+
agent: CatalogInstallAgentSchema,
|
|
2454
|
+
install_method: CatalogInstallMethodSchema,
|
|
2455
|
+
installer: CatalogInstallerIdentitySchema,
|
|
2456
|
+
target_os: CatalogInstallOsSchema,
|
|
2457
|
+
install_scope: CatalogInstallScopeSchema,
|
|
2458
|
+
environment: CatalogInstallEnvironmentSchema,
|
|
2459
|
+
qualification_rule_id: UuidSchema,
|
|
2460
|
+
registry_version_id: UuidSchema,
|
|
2461
|
+
expires_at: IsoDateTimeSchema
|
|
2462
|
+
}).strict();
|
|
2463
|
+
CatalogInstallReceiptRequestSchema = z2.object({
|
|
2464
|
+
receipt_id: UuidSchema,
|
|
2465
|
+
nonce_id: UuidSchema,
|
|
2466
|
+
nonce_token: HexTokenSchema,
|
|
2467
|
+
installer_session_id: UuidSchema,
|
|
2468
|
+
installer_session_token: HexTokenSchema,
|
|
2469
|
+
release_id: UuidSchema,
|
|
2470
|
+
content_sha256: Sha256Schema,
|
|
2471
|
+
manifest_sha256: Sha256Schema,
|
|
2472
|
+
agent: CatalogInstallAgentSchema,
|
|
2473
|
+
install_method: CatalogInstallMethodSchema,
|
|
2474
|
+
installer: CatalogInstallerIdentitySchema,
|
|
2475
|
+
target_os: CatalogInstallOsSchema,
|
|
2476
|
+
install_scope: CatalogInstallScopeSchema,
|
|
2477
|
+
environment: CatalogInstallEnvironmentSchema,
|
|
2478
|
+
started_at: IsoDateTimeSchema,
|
|
2479
|
+
completed_at: IsoDateTimeSchema,
|
|
2480
|
+
result: z2.enum(["success", "failure"]),
|
|
2481
|
+
qualification_rule_id: UuidSchema,
|
|
2482
|
+
registry_version_id: UuidSchema,
|
|
2483
|
+
installation_public_key: Ed25519PublicKeySchema,
|
|
2484
|
+
installation_signature: Ed25519SignatureSchema
|
|
2485
|
+
}).strict().superRefine((receipt, context) => {
|
|
2486
|
+
if (Date.parse(receipt.completed_at) < Date.parse(receipt.started_at)) {
|
|
2487
|
+
context.addIssue({
|
|
2488
|
+
code: z2.ZodIssueCode.custom,
|
|
2489
|
+
path: ["completed_at"],
|
|
2490
|
+
message: "completed_at must not precede started_at"
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2493
|
+
});
|
|
2494
|
+
CatalogUpgradeDispositionSchema = z2.enum([
|
|
2495
|
+
"qualified",
|
|
2496
|
+
"duplicate",
|
|
2497
|
+
"excluded",
|
|
2498
|
+
"quarantined",
|
|
2499
|
+
"released",
|
|
2500
|
+
"exclude_abuse",
|
|
2501
|
+
"continue_quarantine"
|
|
2502
|
+
]);
|
|
2503
|
+
CatalogInstallReceiptResponseSchema = z2.object({
|
|
2504
|
+
receipt_id: UuidSchema,
|
|
2505
|
+
disposition: CatalogUpgradeDispositionSchema,
|
|
2506
|
+
reason_code: z2.string().min(1).max(120),
|
|
2507
|
+
rule_version: z2.string().min(1).max(64)
|
|
2508
|
+
}).strict();
|
|
2509
|
+
}
|
|
2510
|
+
});
|
|
2511
|
+
|
|
2512
|
+
// ../shared/src/contract/index.ts
|
|
2513
|
+
import { z as z3 } from "zod";
|
|
2514
|
+
var CONTRACT_ERROR_CODES, ContractErrorCodeSchema, RequestIdSchema, IsoDateTimeSchema2, IdSchema, SlugSchema, EmailSchema, Sha256Schema2, VersionSeqSchema, UrlSchema, ErrorDetailSchema, ErrorEnvelopeSchema, UserSchema, WorkspaceSchema, MeResponseSchema, WorkspaceCreateRequestSchema, WorkspaceCreateResponseSchema, MemberSchema, MembersListResponseSchema, InviteStatusSchema, InviteCreateRequestSchema, InviteSchema, InviteCreateResponseSchema, InviteLinkRotateResponseSchema, InvitesListResponseSchema, InviteAcceptResponseSchema, TargetSchema, VersionRefSchema, PersonNameSchema, PersonNameEmailSchema, FileMetadataSchema, FileTreeEntrySchema, FileDownloadSchema, FileCopySchema, FileActionSchema, TextFileContentSchema, SafeExtractionSchema, BinaryMetadataSchema, NonTextFileContentSchema, FileContentSchema, SkillsListItemSchema, SkillsListResponseSchema, VersionHistoryItemSchema, SkillDetailResponseSchema, SkillVersionReadResponseSchema, ShareCreateRequestSchema, ShareCreateResponseSchema, PublicShareGetResponseSchema, DeviceSessionStateSchema, DeviceSessionResponseSchema, DeviceSessionActionResponseSchema, CliLibraryStateSchema, CliLibraryTargetQuerySchema, CliLibrarySkillSchema, CliLibraryResponseSchema, LocalManifestSkillSchema, LocalManifestSchema, ContractDecisionChecklistItemSchema, AGENT_TARGETS, AgentTargetSyncSchema, AgentMachineSchema, AgentsListResponseSchema, ActivityEventSchema, ActivityFeedResponseSchema, SkillSyncTargetEntrySchema, SkillSyncMachineSchema, SkillSyncStateResponseSchema;
|
|
2358
2515
|
var init_contract = __esm({
|
|
2359
2516
|
"../shared/src/contract/index.ts"() {
|
|
2360
2517
|
"use strict";
|
|
2518
|
+
init_catalog_install();
|
|
2361
2519
|
CONTRACT_ERROR_CODES = [
|
|
2362
2520
|
"UNAUTHENTICATED",
|
|
2363
2521
|
"FORBIDDEN",
|
|
@@ -2365,6 +2523,7 @@ var init_contract = __esm({
|
|
|
2365
2523
|
"VALIDATION_FAILED",
|
|
2366
2524
|
"CONFLICT",
|
|
2367
2525
|
"RATE_LIMITED",
|
|
2526
|
+
"SERVICE_UNAVAILABLE",
|
|
2368
2527
|
"INTERNAL",
|
|
2369
2528
|
"WORKSPACE_REQUIRED",
|
|
2370
2529
|
"WORKSPACE_ALREADY_EXISTS",
|
|
@@ -2382,270 +2541,270 @@ var init_contract = __esm({
|
|
|
2382
2541
|
"UNSAFE_FILE_PATH",
|
|
2383
2542
|
"SKILL_MARKDOWN_REQUIRED"
|
|
2384
2543
|
];
|
|
2385
|
-
ContractErrorCodeSchema =
|
|
2386
|
-
RequestIdSchema =
|
|
2387
|
-
|
|
2388
|
-
IdSchema =
|
|
2389
|
-
SlugSchema =
|
|
2390
|
-
EmailSchema =
|
|
2391
|
-
|
|
2392
|
-
VersionSeqSchema =
|
|
2393
|
-
UrlSchema =
|
|
2394
|
-
ErrorDetailSchema =
|
|
2544
|
+
ContractErrorCodeSchema = z3.enum(CONTRACT_ERROR_CODES);
|
|
2545
|
+
RequestIdSchema = z3.string().min(1);
|
|
2546
|
+
IsoDateTimeSchema2 = z3.string().datetime({ offset: true });
|
|
2547
|
+
IdSchema = z3.string().uuid();
|
|
2548
|
+
SlugSchema = z3.string().min(1).max(80).regex(/^(?=.{1,80}$)[a-z0-9]+(?:-[a-z0-9]+)*$/);
|
|
2549
|
+
EmailSchema = z3.string().email().max(320);
|
|
2550
|
+
Sha256Schema2 = z3.string().regex(/^[a-f0-9]{64}$/);
|
|
2551
|
+
VersionSeqSchema = z3.number().int().positive();
|
|
2552
|
+
UrlSchema = z3.string().url();
|
|
2553
|
+
ErrorDetailSchema = z3.object({
|
|
2395
2554
|
code: ContractErrorCodeSchema,
|
|
2396
|
-
message:
|
|
2555
|
+
message: z3.string().min(1),
|
|
2397
2556
|
request_id: RequestIdSchema
|
|
2398
|
-
}).catchall(
|
|
2399
|
-
ErrorEnvelopeSchema =
|
|
2557
|
+
}).catchall(z3.unknown());
|
|
2558
|
+
ErrorEnvelopeSchema = z3.object({
|
|
2400
2559
|
error: ErrorDetailSchema
|
|
2401
2560
|
}).strict();
|
|
2402
|
-
UserSchema =
|
|
2561
|
+
UserSchema = z3.object({
|
|
2403
2562
|
id: IdSchema,
|
|
2404
2563
|
email: EmailSchema,
|
|
2405
|
-
name:
|
|
2564
|
+
name: z3.string().min(1),
|
|
2406
2565
|
avatar_url: UrlSchema.nullable()
|
|
2407
2566
|
}).strict();
|
|
2408
|
-
WorkspaceSchema =
|
|
2567
|
+
WorkspaceSchema = z3.object({
|
|
2409
2568
|
id: IdSchema,
|
|
2410
2569
|
slug: SlugSchema,
|
|
2411
|
-
name:
|
|
2570
|
+
name: z3.string().min(1).max(120)
|
|
2412
2571
|
}).strict();
|
|
2413
|
-
MeResponseSchema =
|
|
2572
|
+
MeResponseSchema = z3.object({
|
|
2414
2573
|
user: UserSchema,
|
|
2415
2574
|
workspace: WorkspaceSchema.nullable()
|
|
2416
2575
|
}).strict();
|
|
2417
|
-
WorkspaceCreateRequestSchema =
|
|
2418
|
-
name:
|
|
2576
|
+
WorkspaceCreateRequestSchema = z3.object({
|
|
2577
|
+
name: z3.string().trim().min(1).max(120)
|
|
2419
2578
|
}).strict();
|
|
2420
|
-
WorkspaceCreateResponseSchema =
|
|
2579
|
+
WorkspaceCreateResponseSchema = z3.object({
|
|
2421
2580
|
workspace: WorkspaceSchema
|
|
2422
2581
|
}).strict();
|
|
2423
|
-
MemberSchema =
|
|
2424
|
-
name:
|
|
2582
|
+
MemberSchema = z3.object({
|
|
2583
|
+
name: z3.string().min(1),
|
|
2425
2584
|
email: EmailSchema,
|
|
2426
|
-
joined_at:
|
|
2585
|
+
joined_at: IsoDateTimeSchema2
|
|
2427
2586
|
}).strict();
|
|
2428
|
-
MembersListResponseSchema =
|
|
2587
|
+
MembersListResponseSchema = z3.object({
|
|
2429
2588
|
workspace: WorkspaceSchema,
|
|
2430
|
-
members:
|
|
2431
|
-
total:
|
|
2589
|
+
members: z3.array(MemberSchema),
|
|
2590
|
+
total: z3.number().int().nonnegative()
|
|
2432
2591
|
}).strict();
|
|
2433
|
-
InviteStatusSchema =
|
|
2592
|
+
InviteStatusSchema = z3.enum([
|
|
2434
2593
|
"pending",
|
|
2435
2594
|
"accepted",
|
|
2436
2595
|
"revoked",
|
|
2437
2596
|
"expired"
|
|
2438
2597
|
]);
|
|
2439
|
-
InviteCreateRequestSchema =
|
|
2598
|
+
InviteCreateRequestSchema = z3.object({
|
|
2440
2599
|
email: EmailSchema
|
|
2441
2600
|
}).strict();
|
|
2442
|
-
InviteSchema =
|
|
2601
|
+
InviteSchema = z3.object({
|
|
2443
2602
|
email: EmailSchema,
|
|
2444
2603
|
status: InviteStatusSchema,
|
|
2445
|
-
expires_at:
|
|
2446
|
-
created_at:
|
|
2604
|
+
expires_at: IsoDateTimeSchema2,
|
|
2605
|
+
created_at: IsoDateTimeSchema2
|
|
2447
2606
|
}).strict();
|
|
2448
|
-
InviteCreateResponseSchema =
|
|
2607
|
+
InviteCreateResponseSchema = z3.object({
|
|
2449
2608
|
invite: InviteSchema,
|
|
2450
2609
|
accept_url: UrlSchema
|
|
2451
2610
|
}).strict();
|
|
2452
|
-
InviteLinkRotateResponseSchema =
|
|
2611
|
+
InviteLinkRotateResponseSchema = z3.object({
|
|
2453
2612
|
invite: InviteSchema,
|
|
2454
2613
|
accept_url: UrlSchema
|
|
2455
2614
|
}).strict();
|
|
2456
|
-
InvitesListResponseSchema =
|
|
2457
|
-
invites:
|
|
2458
|
-
total:
|
|
2615
|
+
InvitesListResponseSchema = z3.object({
|
|
2616
|
+
invites: z3.array(InviteSchema),
|
|
2617
|
+
total: z3.number().int().nonnegative()
|
|
2459
2618
|
}).strict();
|
|
2460
|
-
InviteAcceptResponseSchema =
|
|
2619
|
+
InviteAcceptResponseSchema = z3.object({
|
|
2461
2620
|
invite: InviteSchema.extend({
|
|
2462
|
-
status:
|
|
2463
|
-
accepted_at:
|
|
2621
|
+
status: z3.literal("accepted"),
|
|
2622
|
+
accepted_at: IsoDateTimeSchema2
|
|
2464
2623
|
}),
|
|
2465
2624
|
workspace: WorkspaceSchema
|
|
2466
2625
|
}).strict();
|
|
2467
|
-
TargetSchema =
|
|
2626
|
+
TargetSchema = z3.enum([
|
|
2468
2627
|
"claude",
|
|
2469
2628
|
"codex",
|
|
2470
2629
|
"cursor",
|
|
2471
2630
|
"gemini",
|
|
2472
2631
|
"opencode"
|
|
2473
2632
|
]);
|
|
2474
|
-
VersionRefSchema =
|
|
2633
|
+
VersionRefSchema = z3.object({
|
|
2475
2634
|
version_seq: VersionSeqSchema,
|
|
2476
|
-
display:
|
|
2635
|
+
display: z3.string().regex(/^v[1-9][0-9]*$/)
|
|
2477
2636
|
}).strict().superRefine((value, context) => {
|
|
2478
2637
|
if (value.display !== `v${value.version_seq}`) {
|
|
2479
2638
|
context.addIssue({
|
|
2480
|
-
code:
|
|
2639
|
+
code: z3.ZodIssueCode.custom,
|
|
2481
2640
|
message: "display must equal v${version_seq}",
|
|
2482
2641
|
path: ["display"]
|
|
2483
2642
|
});
|
|
2484
2643
|
}
|
|
2485
2644
|
});
|
|
2486
|
-
PersonNameSchema =
|
|
2487
|
-
name:
|
|
2645
|
+
PersonNameSchema = z3.object({
|
|
2646
|
+
name: z3.string().min(1)
|
|
2488
2647
|
}).strict();
|
|
2489
2648
|
PersonNameEmailSchema = PersonNameSchema.extend({
|
|
2490
2649
|
email: EmailSchema
|
|
2491
2650
|
}).strict();
|
|
2492
|
-
FileMetadataSchema =
|
|
2493
|
-
path:
|
|
2494
|
-
size_bytes:
|
|
2495
|
-
size:
|
|
2496
|
-
sha256:
|
|
2497
|
-
mime:
|
|
2651
|
+
FileMetadataSchema = z3.object({
|
|
2652
|
+
path: z3.string().min(1).max(512),
|
|
2653
|
+
size_bytes: z3.number().int().nonnegative(),
|
|
2654
|
+
size: z3.number().int().nonnegative(),
|
|
2655
|
+
sha256: Sha256Schema2,
|
|
2656
|
+
mime: z3.string().min(1)
|
|
2498
2657
|
}).strict();
|
|
2499
|
-
FileTreeEntrySchema =
|
|
2500
|
-
path:
|
|
2501
|
-
kind:
|
|
2502
|
-
parent_path:
|
|
2503
|
-
depth:
|
|
2504
|
-
size_bytes:
|
|
2658
|
+
FileTreeEntrySchema = z3.object({
|
|
2659
|
+
path: z3.string().min(1).max(512),
|
|
2660
|
+
kind: z3.enum(["directory", "file"]),
|
|
2661
|
+
parent_path: z3.string().max(512).nullable(),
|
|
2662
|
+
depth: z3.number().int().nonnegative(),
|
|
2663
|
+
size_bytes: z3.number().int().nonnegative().nullable()
|
|
2505
2664
|
}).strict();
|
|
2506
|
-
FileDownloadSchema =
|
|
2507
|
-
available:
|
|
2665
|
+
FileDownloadSchema = z3.object({
|
|
2666
|
+
available: z3.boolean(),
|
|
2508
2667
|
url: UrlSchema.nullable(),
|
|
2509
|
-
filename:
|
|
2510
|
-
expires_at:
|
|
2668
|
+
filename: z3.string().min(1).nullable(),
|
|
2669
|
+
expires_at: IsoDateTimeSchema2.nullable()
|
|
2511
2670
|
}).strict();
|
|
2512
|
-
FileCopySchema =
|
|
2513
|
-
available:
|
|
2514
|
-
source:
|
|
2671
|
+
FileCopySchema = z3.object({
|
|
2672
|
+
available: z3.boolean(),
|
|
2673
|
+
source: z3.enum(["content_text", "safe_extraction", "none"])
|
|
2515
2674
|
}).strict();
|
|
2516
|
-
FileActionSchema =
|
|
2675
|
+
FileActionSchema = z3.object({
|
|
2517
2676
|
copy: FileCopySchema,
|
|
2518
2677
|
download: FileDownloadSchema
|
|
2519
2678
|
}).strict();
|
|
2520
2679
|
TextFileContentSchema = FileMetadataSchema.extend({
|
|
2521
|
-
mode:
|
|
2522
|
-
content_text:
|
|
2523
|
-
safe_extraction:
|
|
2524
|
-
binary:
|
|
2680
|
+
mode: z3.literal("text"),
|
|
2681
|
+
content_text: z3.string(),
|
|
2682
|
+
safe_extraction: z3.null(),
|
|
2683
|
+
binary: z3.null(),
|
|
2525
2684
|
actions: FileActionSchema
|
|
2526
2685
|
}).strict();
|
|
2527
|
-
SafeExtractionSchema =
|
|
2528
|
-
status:
|
|
2529
|
-
text_preview:
|
|
2530
|
-
reason:
|
|
2686
|
+
SafeExtractionSchema = z3.object({
|
|
2687
|
+
status: z3.enum(["available", "truncated", "unsupported"]),
|
|
2688
|
+
text_preview: z3.string().nullable(),
|
|
2689
|
+
reason: z3.string().min(1).nullable()
|
|
2531
2690
|
}).strict();
|
|
2532
|
-
BinaryMetadataSchema =
|
|
2533
|
-
filename:
|
|
2534
|
-
size_bytes:
|
|
2535
|
-
sha256:
|
|
2536
|
-
mime:
|
|
2691
|
+
BinaryMetadataSchema = z3.object({
|
|
2692
|
+
filename: z3.string().min(1),
|
|
2693
|
+
size_bytes: z3.number().int().nonnegative(),
|
|
2694
|
+
sha256: Sha256Schema2,
|
|
2695
|
+
mime: z3.string().min(1),
|
|
2537
2696
|
download_url: UrlSchema.nullable()
|
|
2538
2697
|
}).strict();
|
|
2539
2698
|
NonTextFileContentSchema = FileMetadataSchema.extend({
|
|
2540
|
-
mode:
|
|
2541
|
-
content_text:
|
|
2699
|
+
mode: z3.literal("non_text"),
|
|
2700
|
+
content_text: z3.null(),
|
|
2542
2701
|
safe_extraction: SafeExtractionSchema,
|
|
2543
2702
|
binary: BinaryMetadataSchema,
|
|
2544
2703
|
actions: FileActionSchema
|
|
2545
2704
|
}).strict();
|
|
2546
|
-
FileContentSchema =
|
|
2705
|
+
FileContentSchema = z3.discriminatedUnion("mode", [
|
|
2547
2706
|
TextFileContentSchema,
|
|
2548
2707
|
NonTextFileContentSchema
|
|
2549
2708
|
]);
|
|
2550
|
-
SkillsListItemSchema =
|
|
2709
|
+
SkillsListItemSchema = z3.object({
|
|
2551
2710
|
slug: SlugSchema,
|
|
2552
|
-
title:
|
|
2553
|
-
description:
|
|
2554
|
-
icon:
|
|
2711
|
+
title: z3.string().min(1),
|
|
2712
|
+
description: z3.string(),
|
|
2713
|
+
icon: z3.string().min(1).nullable().optional(),
|
|
2555
2714
|
latest_version: VersionRefSchema,
|
|
2556
|
-
updated_at:
|
|
2715
|
+
updated_at: IsoDateTimeSchema2,
|
|
2557
2716
|
updated_by: PersonNameSchema
|
|
2558
2717
|
}).strict();
|
|
2559
|
-
SkillsListResponseSchema =
|
|
2560
|
-
skills:
|
|
2561
|
-
total:
|
|
2562
|
-
order:
|
|
2563
|
-
search:
|
|
2564
|
-
mode:
|
|
2565
|
-
server_search:
|
|
2566
|
-
query_param:
|
|
2718
|
+
SkillsListResponseSchema = z3.object({
|
|
2719
|
+
skills: z3.array(SkillsListItemSchema),
|
|
2720
|
+
total: z3.number().int().nonnegative(),
|
|
2721
|
+
order: z3.literal("updated_desc"),
|
|
2722
|
+
search: z3.object({
|
|
2723
|
+
mode: z3.literal("client_side_only"),
|
|
2724
|
+
server_search: z3.literal(false),
|
|
2725
|
+
query_param: z3.null()
|
|
2567
2726
|
}).strict(),
|
|
2568
|
-
pagination:
|
|
2727
|
+
pagination: z3.null()
|
|
2569
2728
|
}).strict();
|
|
2570
|
-
VersionHistoryItemSchema =
|
|
2729
|
+
VersionHistoryItemSchema = z3.object({
|
|
2571
2730
|
version_seq: VersionSeqSchema,
|
|
2572
|
-
display:
|
|
2573
|
-
created_at:
|
|
2731
|
+
display: z3.string().regex(/^v[1-9][0-9]*$/),
|
|
2732
|
+
created_at: IsoDateTimeSchema2,
|
|
2574
2733
|
created_by: PersonNameSchema,
|
|
2575
|
-
changelog:
|
|
2734
|
+
changelog: z3.string().nullable().optional()
|
|
2576
2735
|
}).strict().superRefine((value, context) => {
|
|
2577
2736
|
if (value.display !== `v${value.version_seq}`) {
|
|
2578
2737
|
context.addIssue({
|
|
2579
|
-
code:
|
|
2738
|
+
code: z3.ZodIssueCode.custom,
|
|
2580
2739
|
message: "display must equal v${version_seq}",
|
|
2581
2740
|
path: ["display"]
|
|
2582
2741
|
});
|
|
2583
2742
|
}
|
|
2584
2743
|
});
|
|
2585
|
-
SkillDetailResponseSchema =
|
|
2586
|
-
skill:
|
|
2744
|
+
SkillDetailResponseSchema = z3.object({
|
|
2745
|
+
skill: z3.object({
|
|
2587
2746
|
slug: SlugSchema,
|
|
2588
|
-
title:
|
|
2589
|
-
description:
|
|
2747
|
+
title: z3.string().min(1),
|
|
2748
|
+
description: z3.string(),
|
|
2590
2749
|
owner: PersonNameEmailSchema,
|
|
2591
|
-
created_at:
|
|
2592
|
-
license:
|
|
2593
|
-
min_floom:
|
|
2750
|
+
created_at: IsoDateTimeSchema2,
|
|
2751
|
+
license: z3.string().nullable().optional(),
|
|
2752
|
+
min_floom: z3.string().nullable().optional(),
|
|
2594
2753
|
latest: VersionRefSchema,
|
|
2595
|
-
works_with:
|
|
2596
|
-
files:
|
|
2597
|
-
versions:
|
|
2754
|
+
works_with: z3.array(TargetSchema),
|
|
2755
|
+
files: z3.array(FileMetadataSchema),
|
|
2756
|
+
versions: z3.array(VersionHistoryItemSchema)
|
|
2598
2757
|
}).strict()
|
|
2599
2758
|
}).strict();
|
|
2600
|
-
SkillVersionReadResponseSchema =
|
|
2601
|
-
skill:
|
|
2759
|
+
SkillVersionReadResponseSchema = z3.object({
|
|
2760
|
+
skill: z3.object({
|
|
2602
2761
|
slug: SlugSchema,
|
|
2603
|
-
title:
|
|
2604
|
-
description:
|
|
2762
|
+
title: z3.string().min(1),
|
|
2763
|
+
description: z3.string()
|
|
2605
2764
|
}).strict(),
|
|
2606
2765
|
version: VersionHistoryItemSchema,
|
|
2607
|
-
files:
|
|
2608
|
-
tree:
|
|
2766
|
+
files: z3.array(FileMetadataSchema),
|
|
2767
|
+
tree: z3.array(FileTreeEntrySchema),
|
|
2609
2768
|
selected_file: FileContentSchema.nullable(),
|
|
2610
|
-
file_contents:
|
|
2769
|
+
file_contents: z3.array(FileContentSchema)
|
|
2611
2770
|
}).strict();
|
|
2612
|
-
ShareCreateRequestSchema =
|
|
2613
|
-
ShareCreateResponseSchema =
|
|
2771
|
+
ShareCreateRequestSchema = z3.object({}).strict();
|
|
2772
|
+
ShareCreateResponseSchema = z3.object({
|
|
2614
2773
|
url: UrlSchema,
|
|
2615
|
-
token:
|
|
2774
|
+
token: z3.string().min(32)
|
|
2616
2775
|
}).strict();
|
|
2617
|
-
PublicShareGetResponseSchema =
|
|
2618
|
-
skill:
|
|
2619
|
-
title:
|
|
2620
|
-
description:
|
|
2776
|
+
PublicShareGetResponseSchema = z3.object({
|
|
2777
|
+
skill: z3.object({
|
|
2778
|
+
title: z3.string().min(1),
|
|
2779
|
+
description: z3.string(),
|
|
2621
2780
|
owner: PersonNameSchema,
|
|
2622
2781
|
version: VersionRefSchema
|
|
2623
2782
|
}).strict(),
|
|
2624
|
-
files:
|
|
2625
|
-
tree:
|
|
2783
|
+
files: z3.array(FileMetadataSchema),
|
|
2784
|
+
tree: z3.array(FileTreeEntrySchema),
|
|
2626
2785
|
selected_file: FileContentSchema.nullable(),
|
|
2627
|
-
file_contents:
|
|
2628
|
-
license:
|
|
2786
|
+
file_contents: z3.array(FileContentSchema),
|
|
2787
|
+
license: z3.string().nullable().optional()
|
|
2629
2788
|
}).strict();
|
|
2630
|
-
DeviceSessionStateSchema =
|
|
2789
|
+
DeviceSessionStateSchema = z3.enum([
|
|
2631
2790
|
"pending",
|
|
2632
2791
|
"approved",
|
|
2633
2792
|
"denied",
|
|
2634
2793
|
"expired"
|
|
2635
2794
|
]);
|
|
2636
|
-
DeviceSessionResponseSchema =
|
|
2795
|
+
DeviceSessionResponseSchema = z3.object({
|
|
2637
2796
|
state: DeviceSessionStateSchema,
|
|
2638
|
-
device:
|
|
2639
|
-
label:
|
|
2640
|
-
location:
|
|
2641
|
-
client:
|
|
2642
|
-
first_seen:
|
|
2797
|
+
device: z3.object({
|
|
2798
|
+
label: z3.string().min(1),
|
|
2799
|
+
location: z3.string().min(1).nullable().optional(),
|
|
2800
|
+
client: z3.string().min(1),
|
|
2801
|
+
first_seen: IsoDateTimeSchema2
|
|
2643
2802
|
}).strict()
|
|
2644
2803
|
}).strict();
|
|
2645
|
-
DeviceSessionActionResponseSchema =
|
|
2804
|
+
DeviceSessionActionResponseSchema = z3.object({
|
|
2646
2805
|
state: DeviceSessionStateSchema
|
|
2647
2806
|
}).strict();
|
|
2648
|
-
CliLibraryStateSchema =
|
|
2807
|
+
CliLibraryStateSchema = z3.enum([
|
|
2649
2808
|
"active",
|
|
2650
2809
|
"stale",
|
|
2651
2810
|
"missing",
|
|
@@ -2653,90 +2812,1015 @@ var init_contract = __esm({
|
|
|
2653
2812
|
"conflict",
|
|
2654
2813
|
"unsupported_target"
|
|
2655
2814
|
]);
|
|
2656
|
-
CliLibraryTargetQuerySchema =
|
|
2815
|
+
CliLibraryTargetQuerySchema = z3.object({
|
|
2657
2816
|
target: TargetSchema
|
|
2658
2817
|
}).strict();
|
|
2659
|
-
CliLibrarySkillSchema =
|
|
2818
|
+
CliLibrarySkillSchema = z3.object({
|
|
2660
2819
|
slug: SlugSchema,
|
|
2661
|
-
title:
|
|
2662
|
-
description:
|
|
2820
|
+
title: z3.string().min(1),
|
|
2821
|
+
description: z3.string(),
|
|
2663
2822
|
version: VersionRefSchema,
|
|
2664
|
-
hash:
|
|
2823
|
+
hash: Sha256Schema2,
|
|
2665
2824
|
state: CliLibraryStateSchema,
|
|
2666
|
-
files:
|
|
2825
|
+
files: z3.array(FileContentSchema)
|
|
2667
2826
|
}).strict();
|
|
2668
|
-
CliLibraryResponseSchema =
|
|
2827
|
+
CliLibraryResponseSchema = z3.object({
|
|
2669
2828
|
workspace: WorkspaceSchema,
|
|
2670
2829
|
target: TargetSchema,
|
|
2671
|
-
generated_at:
|
|
2672
|
-
manifest_schema_version:
|
|
2673
|
-
hash_basis:
|
|
2674
|
-
full_hash:
|
|
2675
|
-
states:
|
|
2676
|
-
skills:
|
|
2830
|
+
generated_at: IsoDateTimeSchema2,
|
|
2831
|
+
manifest_schema_version: z3.literal(1),
|
|
2832
|
+
hash_basis: z3.literal("workspace_slug:skill_slug:version_seq:file_sha256"),
|
|
2833
|
+
full_hash: Sha256Schema2,
|
|
2834
|
+
states: z3.array(CliLibraryStateSchema),
|
|
2835
|
+
skills: z3.array(CliLibrarySkillSchema)
|
|
2677
2836
|
}).strict();
|
|
2678
|
-
LocalManifestSkillSchema =
|
|
2837
|
+
LocalManifestSkillSchema = z3.object({
|
|
2679
2838
|
slug: SlugSchema,
|
|
2680
2839
|
version_seq: VersionSeqSchema,
|
|
2681
|
-
hash:
|
|
2840
|
+
hash: Sha256Schema2,
|
|
2682
2841
|
state: CliLibraryStateSchema,
|
|
2683
|
-
installed_paths:
|
|
2842
|
+
installed_paths: z3.array(z3.string().min(1))
|
|
2684
2843
|
}).strict();
|
|
2685
|
-
LocalManifestSchema =
|
|
2686
|
-
manifest_schema_version:
|
|
2844
|
+
LocalManifestSchema = z3.object({
|
|
2845
|
+
manifest_schema_version: z3.literal(1),
|
|
2687
2846
|
target: TargetSchema,
|
|
2688
2847
|
workspace_slug: SlugSchema,
|
|
2689
|
-
full_hash:
|
|
2690
|
-
hash_basis:
|
|
2691
|
-
installed_at:
|
|
2692
|
-
backup_path:
|
|
2693
|
-
skills:
|
|
2848
|
+
full_hash: Sha256Schema2,
|
|
2849
|
+
hash_basis: z3.literal("workspace_slug:skill_slug:version_seq:file_sha256"),
|
|
2850
|
+
installed_at: IsoDateTimeSchema2,
|
|
2851
|
+
backup_path: z3.string().min(1).nullable(),
|
|
2852
|
+
skills: z3.array(LocalManifestSkillSchema)
|
|
2694
2853
|
}).strict();
|
|
2695
|
-
ContractDecisionChecklistItemSchema =
|
|
2696
|
-
id:
|
|
2697
|
-
title:
|
|
2698
|
-
locked:
|
|
2854
|
+
ContractDecisionChecklistItemSchema = z3.object({
|
|
2855
|
+
id: z3.string().min(1),
|
|
2856
|
+
title: z3.string().min(1),
|
|
2857
|
+
locked: z3.literal(true)
|
|
2699
2858
|
}).strict();
|
|
2700
2859
|
AGENT_TARGETS = ["claude", "codex", "cursor", "gemini", "opencode"];
|
|
2701
|
-
AgentTargetSyncSchema =
|
|
2702
|
-
last_pulled_at:
|
|
2860
|
+
AgentTargetSyncSchema = z3.object({
|
|
2861
|
+
last_pulled_at: IsoDateTimeSchema2.nullable()
|
|
2703
2862
|
}).strict();
|
|
2704
|
-
AgentMachineSchema =
|
|
2705
|
-
machine_id:
|
|
2706
|
-
machine_label:
|
|
2707
|
-
last_seen_at:
|
|
2708
|
-
target_sync:
|
|
2863
|
+
AgentMachineSchema = z3.object({
|
|
2864
|
+
machine_id: z3.string().uuid(),
|
|
2865
|
+
machine_label: z3.string().min(1),
|
|
2866
|
+
last_seen_at: IsoDateTimeSchema2,
|
|
2867
|
+
target_sync: z3.record(z3.enum(AGENT_TARGETS), AgentTargetSyncSchema)
|
|
2709
2868
|
}).strict();
|
|
2710
|
-
AgentsListResponseSchema =
|
|
2711
|
-
machines:
|
|
2712
|
-
total:
|
|
2869
|
+
AgentsListResponseSchema = z3.object({
|
|
2870
|
+
machines: z3.array(AgentMachineSchema),
|
|
2871
|
+
total: z3.number().int().nonnegative()
|
|
2713
2872
|
}).strict();
|
|
2714
|
-
ActivityEventSchema =
|
|
2873
|
+
ActivityEventSchema = z3.object({
|
|
2715
2874
|
id: IdSchema,
|
|
2716
|
-
event_name:
|
|
2717
|
-
source:
|
|
2718
|
-
target:
|
|
2719
|
-
skill_slug:
|
|
2720
|
-
created_at:
|
|
2875
|
+
event_name: z3.enum(["signup", "workspace_create", "push", "pull", "share_create", "skill_delete"]),
|
|
2876
|
+
source: z3.enum(["web", "cli", "api"]),
|
|
2877
|
+
target: z3.enum(AGENT_TARGETS).nullable(),
|
|
2878
|
+
skill_slug: z3.string().nullable(),
|
|
2879
|
+
created_at: IsoDateTimeSchema2
|
|
2721
2880
|
}).strict();
|
|
2722
|
-
ActivityFeedResponseSchema =
|
|
2723
|
-
events:
|
|
2724
|
-
total:
|
|
2881
|
+
ActivityFeedResponseSchema = z3.object({
|
|
2882
|
+
events: z3.array(ActivityEventSchema),
|
|
2883
|
+
total: z3.number().int().nonnegative()
|
|
2725
2884
|
}).strict();
|
|
2726
|
-
SkillSyncTargetEntrySchema =
|
|
2885
|
+
SkillSyncTargetEntrySchema = z3.object({
|
|
2727
2886
|
target: TargetSchema,
|
|
2728
|
-
last_pulled_at:
|
|
2887
|
+
last_pulled_at: IsoDateTimeSchema2
|
|
2729
2888
|
}).strict();
|
|
2730
|
-
SkillSyncMachineSchema =
|
|
2889
|
+
SkillSyncMachineSchema = z3.object({
|
|
2731
2890
|
machine_id: IdSchema,
|
|
2732
|
-
machine_label:
|
|
2733
|
-
targets:
|
|
2891
|
+
machine_label: z3.string().min(1),
|
|
2892
|
+
targets: z3.array(SkillSyncTargetEntrySchema)
|
|
2893
|
+
}).strict();
|
|
2894
|
+
SkillSyncStateResponseSchema = z3.object({
|
|
2895
|
+
machines: z3.array(SkillSyncMachineSchema),
|
|
2896
|
+
total_machines: z3.number().int().nonnegative(),
|
|
2897
|
+
total_targets_synced: z3.number().int().nonnegative()
|
|
2898
|
+
}).strict();
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
|
|
2902
|
+
// ../shared/src/catalog.ts
|
|
2903
|
+
import { z as z4 } from "zod";
|
|
2904
|
+
var CatalogSlugSchema, CatalogPublicationStateSchema, CatalogProfileTypeSchema, CatalogSourceSchema, CatalogSourceRevisionSchema, CatalogProfileSchema, CatalogPersonSchema, CatalogCompanySchema, CatalogSkillSchema, CatalogReleaseSchema, CatalogStackSchema, CatalogStackVersionSchema, CatalogTaxonomyAxisSchema, CatalogAssignmentSourceSchema, CatalogEvidenceClassSchema, CatalogSkillLabelSchema, CatalogCompatibilitySchema, CatalogPermissionSchema, CatalogEvidenceEventSchema, CatalogRightsEventSchema, CatalogTrustAssertionSchema, CatalogTrustAssertionEventSchema;
|
|
2905
|
+
var init_catalog = __esm({
|
|
2906
|
+
"../shared/src/catalog.ts"() {
|
|
2907
|
+
"use strict";
|
|
2908
|
+
init_contract();
|
|
2909
|
+
CatalogSlugSchema = SlugSchema.refine((slug) => slug.length >= 3, {
|
|
2910
|
+
message: "catalog slugs must contain at least three characters"
|
|
2911
|
+
});
|
|
2912
|
+
CatalogPublicationStateSchema = z4.enum([
|
|
2913
|
+
"draft",
|
|
2914
|
+
"review",
|
|
2915
|
+
"published",
|
|
2916
|
+
"withdrawn"
|
|
2917
|
+
]);
|
|
2918
|
+
CatalogProfileTypeSchema = z4.enum(["person", "company"]);
|
|
2919
|
+
CatalogSourceSchema = z4.object({
|
|
2920
|
+
id: IdSchema,
|
|
2921
|
+
source_type: z4.enum(["repository", "registry", "url", "manual"]),
|
|
2922
|
+
canonical_url: UrlSchema.nullable(),
|
|
2923
|
+
external_key: z4.string().trim().min(1).max(500).nullable(),
|
|
2924
|
+
display_name: z4.string().trim().min(1).max(200),
|
|
2925
|
+
license_expression: z4.string().trim().min(1).max(500).nullable(),
|
|
2926
|
+
source_state: z4.enum(["active", "withdrawn", "unavailable"]),
|
|
2927
|
+
observed_at: IsoDateTimeSchema2
|
|
2928
|
+
}).strict().superRefine((source, context) => {
|
|
2929
|
+
if (source.canonical_url === null && source.external_key === null) {
|
|
2930
|
+
context.addIssue({
|
|
2931
|
+
code: z4.ZodIssueCode.custom,
|
|
2932
|
+
path: ["canonical_url"],
|
|
2933
|
+
message: "a canonical URL or external key is required"
|
|
2934
|
+
});
|
|
2935
|
+
}
|
|
2936
|
+
});
|
|
2937
|
+
CatalogSourceRevisionSchema = z4.object({
|
|
2938
|
+
id: IdSchema,
|
|
2939
|
+
source_id: IdSchema,
|
|
2940
|
+
revision_key: z4.string().trim().min(1).max(500),
|
|
2941
|
+
content_sha256: Sha256Schema2.nullable(),
|
|
2942
|
+
source_updated_at: IsoDateTimeSchema2.nullable(),
|
|
2943
|
+
observed_at: IsoDateTimeSchema2,
|
|
2944
|
+
metadata: z4.record(z4.unknown())
|
|
2945
|
+
}).strict();
|
|
2946
|
+
CatalogProfileSchema = z4.object({
|
|
2947
|
+
id: IdSchema,
|
|
2948
|
+
profile_type: CatalogProfileTypeSchema,
|
|
2949
|
+
handle: CatalogSlugSchema,
|
|
2950
|
+
display_name: z4.string().trim().min(1).max(200),
|
|
2951
|
+
summary: z4.string().max(2e3).nullable(),
|
|
2952
|
+
avatar_url: UrlSchema.nullable(),
|
|
2953
|
+
canonical_source_revision_id: IdSchema,
|
|
2954
|
+
publication_state: CatalogPublicationStateSchema,
|
|
2955
|
+
published_at: IsoDateTimeSchema2.nullable(),
|
|
2956
|
+
withdrawn_at: IsoDateTimeSchema2.nullable()
|
|
2957
|
+
}).strict().superRefine((profile, context) => {
|
|
2958
|
+
if (profile.publication_state === "published" && profile.published_at === null) {
|
|
2959
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["published_at"], message: "published Profiles require published_at" });
|
|
2960
|
+
}
|
|
2961
|
+
if (profile.publication_state === "withdrawn" && profile.withdrawn_at === null) {
|
|
2962
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["withdrawn_at"], message: "withdrawn Profiles require withdrawn_at" });
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
CatalogPersonSchema = z4.object({
|
|
2966
|
+
profile_id: IdSchema,
|
|
2967
|
+
public_name: z4.string().trim().min(1).max(200),
|
|
2968
|
+
headline: z4.string().max(500).nullable()
|
|
2969
|
+
}).strict();
|
|
2970
|
+
CatalogCompanySchema = z4.object({
|
|
2971
|
+
profile_id: IdSchema,
|
|
2972
|
+
legal_name: z4.string().trim().min(1).max(300).nullable(),
|
|
2973
|
+
website_url: UrlSchema.nullable(),
|
|
2974
|
+
is_publisher: z4.boolean()
|
|
2975
|
+
}).strict();
|
|
2976
|
+
CatalogSkillSchema = z4.object({
|
|
2977
|
+
id: IdSchema,
|
|
2978
|
+
slug: CatalogSlugSchema,
|
|
2979
|
+
title: z4.string().trim().min(1).max(200),
|
|
2980
|
+
summary: z4.string().max(2e3).nullable(),
|
|
2981
|
+
outcome: z4.string().max(2e3).nullable(),
|
|
2982
|
+
canonical_source_id: IdSchema,
|
|
2983
|
+
primary_creator_profile_id: IdSchema.nullable(),
|
|
2984
|
+
publisher_profile_id: IdSchema.nullable(),
|
|
2985
|
+
distribution_skill_id: IdSchema.nullable(),
|
|
2986
|
+
distribution_workspace_id: IdSchema.nullable(),
|
|
2987
|
+
canonical_release_id: IdSchema.nullable(),
|
|
2988
|
+
publication_state: CatalogPublicationStateSchema,
|
|
2989
|
+
published_at: IsoDateTimeSchema2.nullable(),
|
|
2990
|
+
withdrawn_at: IsoDateTimeSchema2.nullable()
|
|
2991
|
+
}).strict().superRefine((skill, context) => {
|
|
2992
|
+
if (skill.publication_state === "published") {
|
|
2993
|
+
for (const key of ["publisher_profile_id", "distribution_skill_id", "distribution_workspace_id", "canonical_release_id", "published_at"]) {
|
|
2994
|
+
if (skill[key] === null) context.addIssue({ code: z4.ZodIssueCode.custom, path: [key], message: `published Skills require ${key}` });
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
if (skill.publication_state === "withdrawn" && skill.withdrawn_at === null) {
|
|
2998
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["withdrawn_at"], message: "withdrawn Skills require withdrawn_at" });
|
|
2999
|
+
}
|
|
3000
|
+
});
|
|
3001
|
+
CatalogReleaseSchema = z4.object({
|
|
3002
|
+
id: IdSchema,
|
|
3003
|
+
skill_id: IdSchema,
|
|
3004
|
+
source_revision_id: IdSchema,
|
|
3005
|
+
private_skill_version_id: IdSchema.nullable(),
|
|
3006
|
+
version: z4.string().trim().min(1).max(120),
|
|
3007
|
+
content_sha256: Sha256Schema2,
|
|
3008
|
+
publication_state: CatalogPublicationStateSchema,
|
|
3009
|
+
published_at: IsoDateTimeSchema2.nullable(),
|
|
3010
|
+
withdrawn_at: IsoDateTimeSchema2.nullable()
|
|
3011
|
+
}).strict().superRefine((release2, context) => {
|
|
3012
|
+
if (release2.publication_state === "published" && (release2.published_at === null || release2.private_skill_version_id === null)) {
|
|
3013
|
+
context.addIssue({
|
|
3014
|
+
code: z4.ZodIssueCode.custom,
|
|
3015
|
+
path: ["published_at"],
|
|
3016
|
+
message: "published releases require published_at and an immutable private Skill version"
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
3019
|
+
if (release2.publication_state === "withdrawn" && release2.withdrawn_at === null) {
|
|
3020
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["withdrawn_at"], message: "withdrawn Releases require withdrawn_at" });
|
|
3021
|
+
}
|
|
3022
|
+
});
|
|
3023
|
+
CatalogStackSchema = z4.object({
|
|
3024
|
+
id: IdSchema,
|
|
3025
|
+
slug: CatalogSlugSchema,
|
|
3026
|
+
title: z4.string().trim().min(1).max(200),
|
|
3027
|
+
summary: z4.string().max(2e3).nullable(),
|
|
3028
|
+
curator_profile_id: IdSchema,
|
|
3029
|
+
canonical_stack_version_id: IdSchema.nullable(),
|
|
3030
|
+
publication_state: CatalogPublicationStateSchema,
|
|
3031
|
+
published_at: IsoDateTimeSchema2.nullable(),
|
|
3032
|
+
withdrawn_at: IsoDateTimeSchema2.nullable()
|
|
3033
|
+
}).strict().superRefine((stack, context) => {
|
|
3034
|
+
if (stack.publication_state === "published" && (stack.canonical_stack_version_id === null || stack.published_at === null)) {
|
|
3035
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["canonical_stack_version_id"], message: "published Stacks require a canonical version and published_at" });
|
|
3036
|
+
}
|
|
3037
|
+
if (stack.publication_state === "withdrawn" && stack.withdrawn_at === null) {
|
|
3038
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["withdrawn_at"], message: "withdrawn Stacks require withdrawn_at" });
|
|
3039
|
+
}
|
|
3040
|
+
});
|
|
3041
|
+
CatalogStackVersionSchema = z4.object({
|
|
3042
|
+
id: IdSchema,
|
|
3043
|
+
stack_id: IdSchema,
|
|
3044
|
+
version_seq: z4.number().int().positive(),
|
|
3045
|
+
rationale: z4.string().trim().min(1).max(4e3),
|
|
3046
|
+
source_revision_id: IdSchema.nullable(),
|
|
3047
|
+
publication_state: CatalogPublicationStateSchema,
|
|
3048
|
+
published_at: IsoDateTimeSchema2.nullable(),
|
|
3049
|
+
withdrawn_at: IsoDateTimeSchema2.nullable()
|
|
3050
|
+
}).strict().superRefine((version, context) => {
|
|
3051
|
+
if (version.publication_state === "published" && version.published_at === null) {
|
|
3052
|
+
context.addIssue({
|
|
3053
|
+
code: z4.ZodIssueCode.custom,
|
|
3054
|
+
path: ["published_at"],
|
|
3055
|
+
message: "published Stack versions require published_at"
|
|
3056
|
+
});
|
|
3057
|
+
}
|
|
3058
|
+
if (version.publication_state === "published" && version.source_revision_id === null) {
|
|
3059
|
+
context.addIssue({
|
|
3060
|
+
code: z4.ZodIssueCode.custom,
|
|
3061
|
+
path: ["source_revision_id"],
|
|
3062
|
+
message: "published Stack versions require a source revision"
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
if (version.publication_state === "withdrawn" && version.withdrawn_at === null) {
|
|
3066
|
+
context.addIssue({
|
|
3067
|
+
code: z4.ZodIssueCode.custom,
|
|
3068
|
+
path: ["withdrawn_at"],
|
|
3069
|
+
message: "withdrawn Stack versions require withdrawn_at"
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
});
|
|
3073
|
+
CatalogTaxonomyAxisSchema = z4.enum([
|
|
3074
|
+
"capability",
|
|
3075
|
+
"task",
|
|
3076
|
+
"domain",
|
|
3077
|
+
"workflow_stage",
|
|
3078
|
+
"input",
|
|
3079
|
+
"output",
|
|
3080
|
+
"audience",
|
|
3081
|
+
"modality",
|
|
3082
|
+
"runtime",
|
|
3083
|
+
"integration"
|
|
3084
|
+
]);
|
|
3085
|
+
CatalogAssignmentSourceSchema = z4.enum([
|
|
3086
|
+
"imported",
|
|
3087
|
+
"publisher",
|
|
3088
|
+
"model_assisted",
|
|
3089
|
+
"reviewer",
|
|
3090
|
+
"floom"
|
|
3091
|
+
]);
|
|
3092
|
+
CatalogEvidenceClassSchema = z4.enum([
|
|
3093
|
+
"declared_fact",
|
|
3094
|
+
"inferred_assertion",
|
|
3095
|
+
"observed_evidence"
|
|
3096
|
+
]);
|
|
3097
|
+
CatalogSkillLabelSchema = z4.object({
|
|
3098
|
+
skill_id: IdSchema,
|
|
3099
|
+
release_id: IdSchema.nullable(),
|
|
3100
|
+
source_revision_id: IdSchema.nullable(),
|
|
3101
|
+
label_id: IdSchema,
|
|
3102
|
+
axis: CatalogTaxonomyAxisSchema,
|
|
3103
|
+
taxonomy_version_id: IdSchema,
|
|
3104
|
+
label_role: z4.enum(["primary", "secondary"]),
|
|
3105
|
+
assignment_source: CatalogAssignmentSourceSchema,
|
|
3106
|
+
evidence_class: CatalogEvidenceClassSchema,
|
|
3107
|
+
confidence: z4.number().min(0).max(1).nullable(),
|
|
3108
|
+
classifier_version: z4.string().min(1).nullable(),
|
|
3109
|
+
prompt_version: z4.string().min(1).nullable(),
|
|
3110
|
+
input_content_sha256: Sha256Schema2.nullable(),
|
|
3111
|
+
reviewer_id: IdSchema.nullable(),
|
|
3112
|
+
reviewed_at: IsoDateTimeSchema2.nullable()
|
|
3113
|
+
}).strict().superRefine((assignment, context) => {
|
|
3114
|
+
if (assignment.release_id === null === (assignment.source_revision_id === null)) {
|
|
3115
|
+
context.addIssue({
|
|
3116
|
+
code: z4.ZodIssueCode.custom,
|
|
3117
|
+
path: ["release_id"],
|
|
3118
|
+
message: "exactly one release_id or source_revision_id is required"
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
if (assignment.label_role === "primary" && !["capability", "task"].includes(assignment.axis)) {
|
|
3122
|
+
context.addIssue({
|
|
3123
|
+
code: z4.ZodIssueCode.custom,
|
|
3124
|
+
path: ["label_role"],
|
|
3125
|
+
message: "only capability and task labels can be primary"
|
|
3126
|
+
});
|
|
3127
|
+
}
|
|
3128
|
+
if (assignment.assignment_source === "model_assisted") {
|
|
3129
|
+
const hasModelProvenance = assignment.evidence_class === "inferred_assertion" && assignment.confidence !== null && assignment.classifier_version !== null && assignment.prompt_version !== null && assignment.input_content_sha256 !== null;
|
|
3130
|
+
if (!hasModelProvenance) {
|
|
3131
|
+
context.addIssue({
|
|
3132
|
+
code: z4.ZodIssueCode.custom,
|
|
3133
|
+
path: ["assignment_source"],
|
|
3134
|
+
message: "model-assisted labels require complete inference provenance"
|
|
3135
|
+
});
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
if (assignment.reviewer_id !== null && assignment.reviewed_at === null) {
|
|
3139
|
+
context.addIssue({
|
|
3140
|
+
code: z4.ZodIssueCode.custom,
|
|
3141
|
+
path: ["reviewed_at"],
|
|
3142
|
+
message: "reviewed labels require reviewed_at"
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
3145
|
+
});
|
|
3146
|
+
CatalogCompatibilitySchema = z4.object({
|
|
3147
|
+
release_id: IdSchema,
|
|
3148
|
+
target_type: z4.enum(["runtime", "integration", "operating_system", "tool"]),
|
|
3149
|
+
target_slug: z4.string().regex(/^[a-z0-9][a-z0-9._-]{0,79}$/),
|
|
3150
|
+
compatibility_state: z4.enum(["unknown", "supported", "unsupported", "verified"]),
|
|
3151
|
+
install_method: z4.string().min(1).max(120).nullable(),
|
|
3152
|
+
evidence_id: IdSchema.nullable(),
|
|
3153
|
+
verified_at: IsoDateTimeSchema2.nullable()
|
|
3154
|
+
}).strict().superRefine((compatibility, context) => {
|
|
3155
|
+
if (compatibility.compatibility_state === "verified" && (compatibility.evidence_id === null || compatibility.verified_at === null)) {
|
|
3156
|
+
context.addIssue({
|
|
3157
|
+
code: z4.ZodIssueCode.custom,
|
|
3158
|
+
path: ["compatibility_state"],
|
|
3159
|
+
message: "verified compatibility requires evidence and verified_at"
|
|
3160
|
+
});
|
|
3161
|
+
}
|
|
3162
|
+
});
|
|
3163
|
+
CatalogPermissionSchema = z4.object({
|
|
3164
|
+
release_id: IdSchema,
|
|
3165
|
+
permission_key: z4.string().regex(/^[a-z][a-z0-9._-]{1,79}$/),
|
|
3166
|
+
access_mode: z4.enum(["read", "write", "execute", "send"]),
|
|
3167
|
+
required: z4.boolean(),
|
|
3168
|
+
approval_mode: z4.enum(["none", "per_action", "session", "external"]),
|
|
3169
|
+
data_sensitivity: z4.enum(["public", "internal", "confidential", "restricted"]),
|
|
3170
|
+
description: z4.string().max(2e3).nullable(),
|
|
3171
|
+
evidence_id: IdSchema.nullable()
|
|
3172
|
+
}).strict();
|
|
3173
|
+
CatalogEvidenceEventSchema = z4.object({
|
|
3174
|
+
id: IdSchema,
|
|
3175
|
+
evidence_id: IdSchema,
|
|
3176
|
+
event_type: z4.enum(["recorded", "published", "withdrawn"]),
|
|
3177
|
+
prior_event_id: IdSchema.nullable(),
|
|
3178
|
+
actor_id: IdSchema.nullable(),
|
|
3179
|
+
reason: z4.string().trim().min(1).max(2e3).nullable(),
|
|
3180
|
+
occurred_at: IsoDateTimeSchema2
|
|
3181
|
+
}).strict().superRefine((event, context) => {
|
|
3182
|
+
if (event.event_type === "recorded" && event.prior_event_id !== null) {
|
|
3183
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["prior_event_id"], message: "recorded is the root event" });
|
|
3184
|
+
}
|
|
3185
|
+
if (event.event_type !== "recorded" && event.prior_event_id === null) {
|
|
3186
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["prior_event_id"], message: "non-root evidence events require prior_event_id" });
|
|
3187
|
+
}
|
|
3188
|
+
if (event.event_type === "withdrawn" && event.reason === null) {
|
|
3189
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["reason"], message: "withdrawal requires a reason" });
|
|
3190
|
+
}
|
|
3191
|
+
});
|
|
3192
|
+
CatalogRightsEventSchema = z4.object({
|
|
3193
|
+
id: IdSchema,
|
|
3194
|
+
release_id: IdSchema,
|
|
3195
|
+
event_type: z4.enum(["grant", "supersession", "withdrawal", "expiry"]),
|
|
3196
|
+
rights_state: z4.enum(["allowed", "restricted", "prohibited", "withdrawn", "expired"]),
|
|
3197
|
+
rights_basis: z4.enum(["license", "direct_permission", "public_domain", "ownership"]).nullable(),
|
|
3198
|
+
scopes: z4.array(z4.enum(["distribution", "redistribution", "display", "evaluation"])).min(0),
|
|
3199
|
+
evidence_id: IdSchema,
|
|
3200
|
+
prior_event_id: IdSchema.nullable(),
|
|
3201
|
+
effective_at: IsoDateTimeSchema2,
|
|
3202
|
+
expires_at: IsoDateTimeSchema2.nullable()
|
|
3203
|
+
}).strict().superRefine((rights, context) => {
|
|
3204
|
+
const grantsRights = ["grant", "supersession"].includes(rights.event_type);
|
|
3205
|
+
if (grantsRights && (rights.rights_basis === null || rights.scopes.length === 0)) {
|
|
3206
|
+
context.addIssue({
|
|
3207
|
+
code: z4.ZodIssueCode.custom,
|
|
3208
|
+
path: ["rights_basis"],
|
|
3209
|
+
message: "grant and supersession require a basis and explicit scopes"
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
if (!grantsRights && (rights.rights_basis !== null || rights.scopes.length !== 0)) {
|
|
3213
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["scopes"], message: "withdrawal and expiry do not grant scopes" });
|
|
3214
|
+
}
|
|
3215
|
+
if (rights.event_type === "grant" && rights.prior_event_id !== null) {
|
|
3216
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["prior_event_id"], message: "grant is the root rights event" });
|
|
3217
|
+
}
|
|
3218
|
+
if (rights.event_type !== "grant" && rights.prior_event_id === null) {
|
|
3219
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["prior_event_id"], message: "non-root rights events require prior_event_id" });
|
|
3220
|
+
}
|
|
3221
|
+
const expectedState = rights.event_type === "withdrawal" ? "withdrawn" : rights.event_type === "expiry" ? "expired" : null;
|
|
3222
|
+
if (expectedState !== null && rights.rights_state !== expectedState) {
|
|
3223
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["rights_state"], message: `${rights.event_type} requires ${expectedState}` });
|
|
3224
|
+
}
|
|
3225
|
+
if (grantsRights && !["allowed", "restricted", "prohibited"].includes(rights.rights_state)) {
|
|
3226
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["rights_state"], message: "granting events require an asserted rights state" });
|
|
3227
|
+
}
|
|
3228
|
+
if (rights.expires_at !== null && Date.parse(rights.expires_at) <= Date.parse(rights.effective_at)) {
|
|
3229
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["expires_at"], message: "rights expiry must follow its effective time" });
|
|
3230
|
+
}
|
|
3231
|
+
});
|
|
3232
|
+
CatalogTrustAssertionSchema = z4.object({
|
|
3233
|
+
id: IdSchema,
|
|
3234
|
+
assertion_type: z4.enum(["signed_by", "tested", "evaluated", "recommended"]),
|
|
3235
|
+
profile_id: IdSchema.nullable(),
|
|
3236
|
+
skill_id: IdSchema.nullable(),
|
|
3237
|
+
release_id: IdSchema.nullable(),
|
|
3238
|
+
release_content_sha256: Sha256Schema2.nullable(),
|
|
3239
|
+
issuer_profile_id: IdSchema,
|
|
3240
|
+
issuer_verification_evidence_id: IdSchema.nullable(),
|
|
3241
|
+
issuer_identity_verification_record_id: IdSchema.nullable(),
|
|
3242
|
+
evidence_id: IdSchema,
|
|
3243
|
+
install_evidence_id: IdSchema.nullable(),
|
|
3244
|
+
agent: z4.string().trim().min(1).max(120).nullable(),
|
|
3245
|
+
runtime: z4.string().trim().min(1).max(120).nullable(),
|
|
3246
|
+
test_name: z4.string().trim().min(1).max(200).nullable(),
|
|
3247
|
+
eval_suite: z4.string().trim().min(1).max(200).nullable(),
|
|
3248
|
+
eval_suite_version: z4.string().trim().min(1).max(120).nullable(),
|
|
3249
|
+
result: z4.string().trim().min(1).max(500).nullable(),
|
|
3250
|
+
score: z4.number().finite().nullable(),
|
|
3251
|
+
recommendation_statement: z4.string().trim().min(1).max(2e3).nullable(),
|
|
3252
|
+
asserted_at: IsoDateTimeSchema2,
|
|
3253
|
+
proposed_by: IdSchema,
|
|
3254
|
+
public_explanation: z4.string().trim().min(1).max(2e3)
|
|
3255
|
+
}).strict().superRefine((assertion, context) => {
|
|
3256
|
+
if ([assertion.profile_id, assertion.skill_id, assertion.release_id].filter((value) => value !== null).length !== 1) {
|
|
3257
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["release_id"], message: "exactly one Trust subject is required" });
|
|
3258
|
+
}
|
|
3259
|
+
const releaseBound = ["signed_by", "tested", "evaluated"].includes(assertion.assertion_type);
|
|
3260
|
+
if (releaseBound && (assertion.release_id === null || assertion.release_content_sha256 === null)) {
|
|
3261
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["release_id"], message: "release-bound Trust requires exact Release and hash" });
|
|
3262
|
+
}
|
|
3263
|
+
if (assertion.assertion_type === "signed_by" && (assertion.issuer_verification_evidence_id === null || assertion.issuer_identity_verification_record_id === null)) {
|
|
3264
|
+
context.addIssue({
|
|
3265
|
+
code: z4.ZodIssueCode.custom,
|
|
3266
|
+
path: ["issuer_identity_verification_record_id"],
|
|
3267
|
+
message: "Signed by requires verified issuer evidence and an active Identity Verification Record"
|
|
3268
|
+
});
|
|
3269
|
+
}
|
|
3270
|
+
if (assertion.assertion_type === "tested" && (assertion.install_evidence_id === null || assertion.agent === null || assertion.runtime === null || assertion.test_name === null || assertion.result !== "passed")) {
|
|
3271
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["result"], message: "Tested requires agent, runtime, named smoke test, and passed result" });
|
|
3272
|
+
}
|
|
3273
|
+
if (assertion.assertion_type === "evaluated" && (assertion.eval_suite === null || assertion.eval_suite_version === null || assertion.result === null)) {
|
|
3274
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["eval_suite"], message: "Evaluated requires named versioned suite and result" });
|
|
3275
|
+
}
|
|
3276
|
+
if (assertion.assertion_type === "recommended" && assertion.recommendation_statement === null) {
|
|
3277
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["recommendation_statement"], message: "Recommended requires an explicit statement" });
|
|
3278
|
+
}
|
|
3279
|
+
});
|
|
3280
|
+
CatalogTrustAssertionEventSchema = z4.object({
|
|
3281
|
+
id: IdSchema,
|
|
3282
|
+
assertion_id: IdSchema,
|
|
3283
|
+
status: z4.enum(["draft", "active", "disputed", "suspended", "withdrawn", "expired"]),
|
|
3284
|
+
prior_event_id: IdSchema.nullable(),
|
|
3285
|
+
reviewer_id: IdSchema.nullable(),
|
|
3286
|
+
review_method: z4.string().trim().min(1).max(500).nullable(),
|
|
3287
|
+
reason: z4.string().trim().min(1).max(2e3).nullable(),
|
|
3288
|
+
occurred_at: IsoDateTimeSchema2
|
|
3289
|
+
}).strict().superRefine((event, context) => {
|
|
3290
|
+
if (event.status === "draft" && event.prior_event_id !== null) {
|
|
3291
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["prior_event_id"], message: "draft is the root Trust event" });
|
|
3292
|
+
}
|
|
3293
|
+
if (event.status !== "draft" && event.prior_event_id === null) {
|
|
3294
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["prior_event_id"], message: "non-draft Trust events require prior_event_id" });
|
|
3295
|
+
}
|
|
3296
|
+
if (event.status === "active" && (event.reviewer_id === null || event.review_method === null)) {
|
|
3297
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["reviewer_id"], message: "active Trust requires review evidence" });
|
|
3298
|
+
}
|
|
3299
|
+
if (["disputed", "suspended", "withdrawn", "expired"].includes(event.status) && event.reason === null) {
|
|
3300
|
+
context.addIssue({ code: z4.ZodIssueCode.custom, path: ["reason"], message: `${event.status} requires a reason` });
|
|
3301
|
+
}
|
|
3302
|
+
});
|
|
3303
|
+
}
|
|
3304
|
+
});
|
|
3305
|
+
|
|
3306
|
+
// ../shared/src/catalog-trust.ts
|
|
3307
|
+
import { z as z5 } from "zod";
|
|
3308
|
+
function addUtcMonthsClamped(value, months) {
|
|
3309
|
+
const source = new Date(value);
|
|
3310
|
+
const result = new Date(source);
|
|
3311
|
+
const day = result.getUTCDate();
|
|
3312
|
+
result.setUTCDate(1);
|
|
3313
|
+
result.setUTCMonth(result.getUTCMonth() + months);
|
|
3314
|
+
const finalDay = new Date(Date.UTC(result.getUTCFullYear(), result.getUTCMonth() + 1, 0)).getUTCDate();
|
|
3315
|
+
result.setUTCDate(Math.min(day, finalDay));
|
|
3316
|
+
return result.getTime();
|
|
3317
|
+
}
|
|
3318
|
+
var CatalogContractAuthoritySchema, CatalogProfileClaimIntentSchema, CatalogProfileClaimRequestStateSchema, CatalogProfileControlStateSchema, CatalogIdentityVerificationRequestStateSchema, CatalogIdentityVerificationRecordStateSchema, CatalogGovernanceScopeSchema, CatalogMethodVersionStateSchema, Ed25519PublicKeySchema2, Ed25519SignatureSchema2, CatalogTrustAuthorityRootSchema, CatalogTrustReviewerAssignmentSchema, CatalogTrustReviewerAssignmentEventSchema, CatalogMethodVersionBaseSchema, CatalogProfileClaimMethodVersionSchema, CatalogIdentityVerificationMethodVersionSchema, CatalogMethodVersionEventSchema, CatalogProfileClaimChallengeSchema, CatalogProfileClaimRequestSchema, CatalogProfileClaimEvidenceReferenceSchema, CatalogWorkflowEventBaseSchema, CatalogProfileClaimRequestEventSchema, CatalogProfileControlEventSchema, CatalogProfileControlSchema, CatalogIdentityVerificationRequestSchema, CatalogIdentityVerificationRequestEventSchema, CatalogIdentityEvidenceReferenceSchema, CatalogIdentityVerificationChallengeSchema, CatalogIdentityVerificationResultSchema, CatalogPrivateEvidenceRetentionEventSchema, CatalogPrivateEvidenceLegalHoldEventSchema, CatalogPrivateEvidenceDeletionReceiptSchema, CatalogIdentityVerificationRecordSchema, CatalogIdentityVerificationRecordEventSchema;
|
|
3319
|
+
var init_catalog_trust = __esm({
|
|
3320
|
+
"../shared/src/catalog-trust.ts"() {
|
|
3321
|
+
"use strict";
|
|
3322
|
+
init_contract();
|
|
3323
|
+
CatalogContractAuthoritySchema = z5.literal(
|
|
3324
|
+
"agent_proposed_reviewer_verified"
|
|
3325
|
+
);
|
|
3326
|
+
CatalogProfileClaimIntentSchema = z5.enum([
|
|
3327
|
+
"initial",
|
|
3328
|
+
"reclaim",
|
|
3329
|
+
"transfer"
|
|
3330
|
+
]);
|
|
3331
|
+
CatalogProfileClaimRequestStateSchema = z5.enum([
|
|
3332
|
+
"claim_requested",
|
|
3333
|
+
"challenge_issued",
|
|
3334
|
+
"proof_submitted",
|
|
3335
|
+
"under_review",
|
|
3336
|
+
"approved",
|
|
3337
|
+
"rejected",
|
|
3338
|
+
"expired",
|
|
3339
|
+
"withdrawn",
|
|
3340
|
+
"superseded"
|
|
3341
|
+
]);
|
|
3342
|
+
CatalogProfileControlStateSchema = z5.enum([
|
|
3343
|
+
"active",
|
|
3344
|
+
"disputed",
|
|
3345
|
+
"transferred",
|
|
3346
|
+
"withdrawn",
|
|
3347
|
+
"expired"
|
|
3348
|
+
]);
|
|
3349
|
+
CatalogIdentityVerificationRequestStateSchema = z5.enum([
|
|
3350
|
+
"verification_requested",
|
|
3351
|
+
"challenge_issued",
|
|
3352
|
+
"proof_submitted",
|
|
3353
|
+
"under_review",
|
|
3354
|
+
"approved",
|
|
3355
|
+
"rejected",
|
|
3356
|
+
"expired",
|
|
3357
|
+
"withdrawn",
|
|
3358
|
+
"superseded"
|
|
3359
|
+
]);
|
|
3360
|
+
CatalogIdentityVerificationRecordStateSchema = z5.enum([
|
|
3361
|
+
"active",
|
|
3362
|
+
"suspended",
|
|
3363
|
+
"revoked",
|
|
3364
|
+
"expired"
|
|
3365
|
+
]);
|
|
3366
|
+
CatalogGovernanceScopeSchema = z5.literal("catalog_trust_governance");
|
|
3367
|
+
CatalogMethodVersionStateSchema = z5.enum(["proposed", "active", "retired"]);
|
|
3368
|
+
Ed25519PublicKeySchema2 = z5.string().regex(/^[A-Za-z0-9+/]{43}=$/);
|
|
3369
|
+
Ed25519SignatureSchema2 = z5.string().regex(/^[A-Za-z0-9+/]{86}==$/);
|
|
3370
|
+
CatalogTrustAuthorityRootSchema = z5.object({
|
|
3371
|
+
id: IdSchema,
|
|
3372
|
+
authority_scope: CatalogGovernanceScopeSchema,
|
|
3373
|
+
authority_reference: z5.string().trim().min(1).max(2e3),
|
|
3374
|
+
authority_sha256: Sha256Schema2,
|
|
3375
|
+
anchor_key_id: z5.string().regex(/^[a-z0-9][a-z0-9._:-]{0,119}$/),
|
|
3376
|
+
authority_public_key: Ed25519PublicKeySchema2,
|
|
3377
|
+
anchor_signature: Ed25519SignatureSchema2,
|
|
3378
|
+
active_from: IsoDateTimeSchema2,
|
|
3379
|
+
created_at: IsoDateTimeSchema2
|
|
2734
3380
|
}).strict();
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
3381
|
+
CatalogTrustReviewerAssignmentSchema = z5.object({
|
|
3382
|
+
id: IdSchema,
|
|
3383
|
+
authority_root_id: IdSchema,
|
|
3384
|
+
authority_scope: CatalogGovernanceScopeSchema,
|
|
3385
|
+
reviewer_id: IdSchema,
|
|
3386
|
+
assignment_role: z5.enum(["trust_reviewer", "backup_trust_reviewer"]),
|
|
3387
|
+
appointed_by: IdSchema,
|
|
3388
|
+
authority_reference: z5.string().trim().min(1).max(2e3),
|
|
3389
|
+
authority_sha256: Sha256Schema2,
|
|
3390
|
+
valid_from: IsoDateTimeSchema2,
|
|
3391
|
+
valid_until: IsoDateTimeSchema2,
|
|
3392
|
+
current_state: z5.enum(["active", "revoked", "expired"]),
|
|
3393
|
+
terminal_at: IsoDateTimeSchema2.nullable(),
|
|
3394
|
+
created_at: IsoDateTimeSchema2
|
|
3395
|
+
}).strict().superRefine((assignment, context) => {
|
|
3396
|
+
if (assignment.reviewer_id === assignment.appointed_by) {
|
|
3397
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["appointed_by"], message: "reviewers cannot appoint themselves" });
|
|
3398
|
+
}
|
|
3399
|
+
if (Date.parse(assignment.valid_until) <= Date.parse(assignment.valid_from)) {
|
|
3400
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["valid_until"], message: "valid_until must follow valid_from" });
|
|
3401
|
+
}
|
|
3402
|
+
if (Date.parse(assignment.valid_until) > Date.parse(assignment.valid_from) + 365 * 24 * 60 * 60 * 1e3) {
|
|
3403
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["valid_until"], message: "assignment exceeds its one-year bound" });
|
|
3404
|
+
}
|
|
3405
|
+
const terminal = assignment.current_state !== "active";
|
|
3406
|
+
if (terminal !== (assignment.terminal_at !== null)) {
|
|
3407
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["terminal_at"], message: "terminal_at must match assignment state" });
|
|
3408
|
+
}
|
|
3409
|
+
});
|
|
3410
|
+
CatalogTrustReviewerAssignmentEventSchema = z5.object({
|
|
3411
|
+
id: IdSchema,
|
|
3412
|
+
assignment_id: IdSchema,
|
|
3413
|
+
state: z5.enum(["active", "revoked", "expired"]),
|
|
3414
|
+
prior_event_id: IdSchema.nullable(),
|
|
3415
|
+
actor_id: IdSchema,
|
|
3416
|
+
authority_root_id: IdSchema,
|
|
3417
|
+
reason: z5.string().trim().min(1).max(2e3),
|
|
3418
|
+
occurred_at: IsoDateTimeSchema2,
|
|
3419
|
+
created_at: IsoDateTimeSchema2
|
|
3420
|
+
}).strict().superRefine((event, context) => {
|
|
3421
|
+
if (event.state === "active" !== (event.prior_event_id === null)) {
|
|
3422
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["prior_event_id"], message: "assignment history begins once with active" });
|
|
3423
|
+
}
|
|
3424
|
+
});
|
|
3425
|
+
CatalogMethodVersionBaseSchema = z5.object({
|
|
3426
|
+
id: IdSchema,
|
|
3427
|
+
version: z5.string().trim().min(1).max(120),
|
|
3428
|
+
contract_authority: CatalogContractAuthoritySchema,
|
|
3429
|
+
configuration_sha256: Sha256Schema2,
|
|
3430
|
+
activated_at: IsoDateTimeSchema2.nullable(),
|
|
3431
|
+
retired_at: IsoDateTimeSchema2.nullable(),
|
|
3432
|
+
proposed_by: IdSchema,
|
|
3433
|
+
reviewed_by: IdSchema.nullable(),
|
|
3434
|
+
current_state: CatalogMethodVersionStateSchema,
|
|
3435
|
+
created_at: IsoDateTimeSchema2
|
|
2739
3436
|
}).strict();
|
|
3437
|
+
CatalogProfileClaimMethodVersionSchema = CatalogMethodVersionBaseSchema.extend({
|
|
3438
|
+
method: z5.enum(["corporate_domain_email", "operator_direct_relationship"])
|
|
3439
|
+
}).superRefine((method, context) => {
|
|
3440
|
+
if (method.reviewed_by !== null && method.proposed_by === method.reviewed_by) {
|
|
3441
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reviewed_by"], message: "method review must be independent" });
|
|
3442
|
+
}
|
|
3443
|
+
if (method.retired_at !== null && method.activated_at !== null && Date.parse(method.retired_at) <= Date.parse(method.activated_at)) {
|
|
3444
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["retired_at"], message: "retired_at must follow activated_at" });
|
|
3445
|
+
}
|
|
3446
|
+
const validState = method.current_state === "proposed" && method.activated_at === null && method.retired_at === null && method.reviewed_by === null || method.current_state === "active" && method.activated_at !== null && method.retired_at === null && method.reviewed_by !== null || method.current_state === "retired" && method.activated_at !== null && method.retired_at !== null && method.reviewed_by !== null;
|
|
3447
|
+
if (!validState) context.addIssue({ code: z5.ZodIssueCode.custom, path: ["current_state"], message: "method lifecycle fields are inconsistent" });
|
|
3448
|
+
});
|
|
3449
|
+
CatalogIdentityVerificationMethodVersionSchema = CatalogMethodVersionBaseSchema.extend({
|
|
3450
|
+
subject_kind: z5.enum(["person", "publisher"])
|
|
3451
|
+
}).superRefine((method, context) => {
|
|
3452
|
+
if (method.reviewed_by !== null && method.proposed_by === method.reviewed_by) {
|
|
3453
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reviewed_by"], message: "method review must be independent" });
|
|
3454
|
+
}
|
|
3455
|
+
if (method.retired_at !== null && method.activated_at !== null && Date.parse(method.retired_at) <= Date.parse(method.activated_at)) {
|
|
3456
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["retired_at"], message: "retired_at must follow activated_at" });
|
|
3457
|
+
}
|
|
3458
|
+
const validState = method.current_state === "proposed" && method.activated_at === null && method.retired_at === null && method.reviewed_by === null || method.current_state === "active" && method.activated_at !== null && method.retired_at === null && method.reviewed_by !== null || method.current_state === "retired" && method.activated_at !== null && method.retired_at !== null && method.reviewed_by !== null;
|
|
3459
|
+
if (!validState) context.addIssue({ code: z5.ZodIssueCode.custom, path: ["current_state"], message: "method lifecycle fields are inconsistent" });
|
|
3460
|
+
});
|
|
3461
|
+
CatalogMethodVersionEventSchema = z5.object({
|
|
3462
|
+
id: IdSchema,
|
|
3463
|
+
method_version_id: IdSchema,
|
|
3464
|
+
state: CatalogMethodVersionStateSchema,
|
|
3465
|
+
prior_event_id: IdSchema.nullable(),
|
|
3466
|
+
actor_id: IdSchema,
|
|
3467
|
+
reviewer_id: IdSchema.nullable(),
|
|
3468
|
+
reason: z5.string().trim().min(1).max(2e3),
|
|
3469
|
+
occurred_at: IsoDateTimeSchema2,
|
|
3470
|
+
created_at: IsoDateTimeSchema2
|
|
3471
|
+
}).strict().superRefine((event, context) => {
|
|
3472
|
+
if (event.state === "proposed" !== (event.prior_event_id === null)) {
|
|
3473
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["prior_event_id"], message: "method history begins once with proposed" });
|
|
3474
|
+
}
|
|
3475
|
+
if (event.state !== "proposed" && (event.reviewer_id === null || event.actor_id !== event.reviewer_id)) {
|
|
3476
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reviewer_id"], message: "method decisions require the acting reviewer" });
|
|
3477
|
+
}
|
|
3478
|
+
});
|
|
3479
|
+
CatalogProfileClaimChallengeSchema = z5.object({
|
|
3480
|
+
id: IdSchema,
|
|
3481
|
+
claim_request_id: IdSchema,
|
|
3482
|
+
challenge_secret_hash: Sha256Schema2,
|
|
3483
|
+
binding_sha256: Sha256Schema2,
|
|
3484
|
+
issued_at: IsoDateTimeSchema2,
|
|
3485
|
+
expires_at: IsoDateTimeSchema2,
|
|
3486
|
+
consumed_at: IsoDateTimeSchema2.nullable(),
|
|
3487
|
+
purge_after: IsoDateTimeSchema2,
|
|
3488
|
+
created_at: IsoDateTimeSchema2
|
|
3489
|
+
}).strict().superRefine((challenge, context) => {
|
|
3490
|
+
const issued = Date.parse(challenge.issued_at);
|
|
3491
|
+
if (Date.parse(challenge.expires_at) !== issued + 30 * 60 * 1e3) {
|
|
3492
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["expires_at"], message: "challenge expires exactly 30 minutes after issuance" });
|
|
3493
|
+
}
|
|
3494
|
+
if (Date.parse(challenge.purge_after) !== issued + 30 * 24 * 60 * 60 * 1e3) {
|
|
3495
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_after"], message: "challenge purges exactly 30 days after issuance" });
|
|
3496
|
+
}
|
|
3497
|
+
if (challenge.consumed_at !== null) {
|
|
3498
|
+
const consumed = Date.parse(challenge.consumed_at);
|
|
3499
|
+
if (consumed < issued || consumed > Date.parse(challenge.expires_at)) {
|
|
3500
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["consumed_at"], message: "consumption must occur during challenge validity" });
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
});
|
|
3504
|
+
CatalogProfileClaimRequestSchema = z5.object({
|
|
3505
|
+
id: IdSchema,
|
|
3506
|
+
profile_id: IdSchema,
|
|
3507
|
+
claimant_user_id: IdSchema,
|
|
3508
|
+
proposed_controller_user_id: IdSchema,
|
|
3509
|
+
intent: CatalogProfileClaimIntentSchema,
|
|
3510
|
+
actor_capacity: z5.enum([
|
|
3511
|
+
"person",
|
|
3512
|
+
"company_representative",
|
|
3513
|
+
"publisher_representative"
|
|
3514
|
+
]),
|
|
3515
|
+
method_version_id: IdSchema,
|
|
3516
|
+
prior_profile_control_id: IdSchema.nullable(),
|
|
3517
|
+
transfer_authorization_type: z5.enum(["controller_consent", "dispute_resolution"]).nullable(),
|
|
3518
|
+
transfer_authorization_sha256: Sha256Schema2.nullable(),
|
|
3519
|
+
transfer_consent_event_id: IdSchema.nullable(),
|
|
3520
|
+
transfer_dispute_record_id: IdSchema.nullable(),
|
|
3521
|
+
current_state: CatalogProfileClaimRequestStateSchema,
|
|
3522
|
+
created_at: IsoDateTimeSchema2,
|
|
3523
|
+
terminal_at: IsoDateTimeSchema2.nullable()
|
|
3524
|
+
}).strict().superRefine((request, context) => {
|
|
3525
|
+
const terminal = ["approved", "rejected", "expired", "withdrawn", "superseded"].includes(
|
|
3526
|
+
request.current_state
|
|
3527
|
+
);
|
|
3528
|
+
if (terminal !== (request.terminal_at !== null)) {
|
|
3529
|
+
context.addIssue({
|
|
3530
|
+
code: z5.ZodIssueCode.custom,
|
|
3531
|
+
path: ["terminal_at"],
|
|
3532
|
+
message: "terminal_at must match terminal Claim Request state"
|
|
3533
|
+
});
|
|
3534
|
+
}
|
|
3535
|
+
const transferFields = [
|
|
3536
|
+
request.prior_profile_control_id,
|
|
3537
|
+
request.transfer_authorization_type,
|
|
3538
|
+
request.transfer_authorization_sha256
|
|
3539
|
+
];
|
|
3540
|
+
if (request.intent === "transfer" && transferFields.some((value) => value === null) || request.intent !== "transfer" && transferFields.some((value) => value !== null)) {
|
|
3541
|
+
context.addIssue({
|
|
3542
|
+
code: z5.ZodIssueCode.custom,
|
|
3543
|
+
path: ["intent"],
|
|
3544
|
+
message: "transfer bindings are required only for transfer requests"
|
|
3545
|
+
});
|
|
3546
|
+
}
|
|
3547
|
+
const recordBindings = [request.transfer_consent_event_id, request.transfer_dispute_record_id];
|
|
3548
|
+
if (request.intent !== "transfer" && recordBindings.some((value) => value !== null)) {
|
|
3549
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["intent"], message: "authorization records belong only to transfers" });
|
|
3550
|
+
}
|
|
3551
|
+
if (request.intent === "transfer") {
|
|
3552
|
+
const consent = request.transfer_authorization_type === "controller_consent";
|
|
3553
|
+
if (consent && (request.transfer_consent_event_id === null || request.transfer_dispute_record_id !== null) || !consent && (request.transfer_consent_event_id !== null || request.transfer_dispute_record_id === null)) {
|
|
3554
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["transfer_authorization_type"], message: "transfer authorization must bind exactly one matching record" });
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
});
|
|
3558
|
+
CatalogProfileClaimEvidenceReferenceSchema = z5.object({
|
|
3559
|
+
id: IdSchema,
|
|
3560
|
+
claim_request_id: IdSchema,
|
|
3561
|
+
evidence_class: z5.enum([
|
|
3562
|
+
"corporate_domain_control",
|
|
3563
|
+
"authenticated_channel",
|
|
3564
|
+
"corroborating_relationship",
|
|
3565
|
+
"reviewer_evidence",
|
|
3566
|
+
"malformed_proof"
|
|
3567
|
+
]),
|
|
3568
|
+
private_reference: z5.string().regex(/^private:\/\/[^\s]+$/).max(2e3),
|
|
3569
|
+
reference_sha256: Sha256Schema2,
|
|
3570
|
+
submitted_by: IdSchema,
|
|
3571
|
+
created_at: IsoDateTimeSchema2,
|
|
3572
|
+
purge_after: IsoDateTimeSchema2,
|
|
3573
|
+
purge_claimed_at: IsoDateTimeSchema2.nullable(),
|
|
3574
|
+
purge_claim_token: IdSchema.nullable(),
|
|
3575
|
+
purge_attempt_count: z5.number().int().nonnegative()
|
|
3576
|
+
}).strict().superRefine((evidence, context) => {
|
|
3577
|
+
const created = new Date(evidence.created_at);
|
|
3578
|
+
const maximum = new Date(created);
|
|
3579
|
+
if (evidence.evidence_class === "malformed_proof") maximum.setUTCDate(maximum.getUTCDate() + 7);
|
|
3580
|
+
else maximum.setTime(addUtcMonthsClamped(evidence.created_at, 24));
|
|
3581
|
+
if (Date.parse(evidence.purge_after) < created.getTime() + 24 * 60 * 60 * 1e3) {
|
|
3582
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_after"], message: "retention is below its one-day floor" });
|
|
3583
|
+
}
|
|
3584
|
+
if (Date.parse(evidence.purge_after) > maximum.getTime()) {
|
|
3585
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_after"], message: "retention exceeds its evidence-class bound" });
|
|
3586
|
+
}
|
|
3587
|
+
if (evidence.purge_claimed_at === null !== (evidence.purge_claim_token === null)) {
|
|
3588
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_claim_token"], message: "purge claim time and token must be paired" });
|
|
3589
|
+
}
|
|
3590
|
+
});
|
|
3591
|
+
CatalogWorkflowEventBaseSchema = z5.object({
|
|
3592
|
+
id: IdSchema,
|
|
3593
|
+
prior_event_id: IdSchema.nullable(),
|
|
3594
|
+
actor_id: IdSchema,
|
|
3595
|
+
reviewer_id: IdSchema.nullable(),
|
|
3596
|
+
evidence_manifest_sha256: Sha256Schema2.nullable(),
|
|
3597
|
+
reason: z5.string().trim().min(1).max(2e3).nullable(),
|
|
3598
|
+
occurred_at: IsoDateTimeSchema2,
|
|
3599
|
+
created_at: IsoDateTimeSchema2
|
|
3600
|
+
}).strict();
|
|
3601
|
+
CatalogProfileClaimRequestEventSchema = CatalogWorkflowEventBaseSchema.extend({
|
|
3602
|
+
claim_request_id: IdSchema,
|
|
3603
|
+
state: CatalogProfileClaimRequestStateSchema
|
|
3604
|
+
}).superRefine((event, context) => {
|
|
3605
|
+
if (event.state === "claim_requested" !== (event.prior_event_id === null)) {
|
|
3606
|
+
context.addIssue({
|
|
3607
|
+
code: z5.ZodIssueCode.custom,
|
|
3608
|
+
path: ["prior_event_id"],
|
|
3609
|
+
message: "only claim_requested is a root event"
|
|
3610
|
+
});
|
|
3611
|
+
}
|
|
3612
|
+
if (["rejected", "expired", "withdrawn", "superseded"].includes(event.state) && event.reason === null) {
|
|
3613
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reason"], message: `${event.state} requires a reason` });
|
|
3614
|
+
}
|
|
3615
|
+
});
|
|
3616
|
+
CatalogProfileControlEventSchema = CatalogWorkflowEventBaseSchema.extend({
|
|
3617
|
+
profile_control_id: IdSchema,
|
|
3618
|
+
state: CatalogProfileControlStateSchema
|
|
3619
|
+
}).superRefine((event, context) => {
|
|
3620
|
+
if (event.prior_event_id === null && event.state !== "active") {
|
|
3621
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["prior_event_id"], message: "Profile Control history must begin with active" });
|
|
3622
|
+
}
|
|
3623
|
+
if (event.state !== "active" && event.reason === null) {
|
|
3624
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reason"], message: `${event.state} requires a reason` });
|
|
3625
|
+
}
|
|
3626
|
+
});
|
|
3627
|
+
CatalogProfileControlSchema = z5.object({
|
|
3628
|
+
id: IdSchema,
|
|
3629
|
+
profile_id: IdSchema,
|
|
3630
|
+
controller_user_id: IdSchema,
|
|
3631
|
+
claim_request_id: IdSchema,
|
|
3632
|
+
current_state: CatalogProfileControlStateSchema,
|
|
3633
|
+
next_recheck_at: IsoDateTimeSchema2,
|
|
3634
|
+
created_at: IsoDateTimeSchema2,
|
|
3635
|
+
terminal_at: IsoDateTimeSchema2.nullable()
|
|
3636
|
+
}).strict().superRefine((control, context) => {
|
|
3637
|
+
const terminal = ["transferred", "withdrawn", "expired"].includes(control.current_state);
|
|
3638
|
+
if (terminal !== (control.terminal_at !== null)) {
|
|
3639
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["terminal_at"], message: "terminal_at must match terminal Profile Control state" });
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3642
|
+
CatalogIdentityVerificationRequestSchema = z5.object({
|
|
3643
|
+
id: IdSchema,
|
|
3644
|
+
profile_id: IdSchema,
|
|
3645
|
+
profile_control_id: IdSchema,
|
|
3646
|
+
claimant_user_id: IdSchema,
|
|
3647
|
+
evidence_proposer_id: IdSchema,
|
|
3648
|
+
subject_kind: z5.enum(["person", "publisher"]),
|
|
3649
|
+
method_version_id: IdSchema,
|
|
3650
|
+
current_state: CatalogIdentityVerificationRequestStateSchema,
|
|
3651
|
+
created_at: IsoDateTimeSchema2,
|
|
3652
|
+
terminal_at: IsoDateTimeSchema2.nullable()
|
|
3653
|
+
}).strict().superRefine((request, context) => {
|
|
3654
|
+
const terminal = ["approved", "rejected", "expired", "withdrawn", "superseded"].includes(request.current_state);
|
|
3655
|
+
if (terminal !== (request.terminal_at !== null)) {
|
|
3656
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["terminal_at"], message: "terminal_at must match terminal Identity Request state" });
|
|
3657
|
+
}
|
|
3658
|
+
});
|
|
3659
|
+
CatalogIdentityVerificationRequestEventSchema = CatalogWorkflowEventBaseSchema.extend({
|
|
3660
|
+
identity_verification_request_id: IdSchema,
|
|
3661
|
+
state: CatalogIdentityVerificationRequestStateSchema
|
|
3662
|
+
}).superRefine((event, context) => {
|
|
3663
|
+
if (event.state === "verification_requested" !== (event.prior_event_id === null)) {
|
|
3664
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["prior_event_id"], message: "only verification_requested is a root event" });
|
|
3665
|
+
}
|
|
3666
|
+
if (["rejected", "expired", "withdrawn", "superseded"].includes(event.state) && event.reason === null) {
|
|
3667
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reason"], message: `${event.state} requires a reason` });
|
|
3668
|
+
}
|
|
3669
|
+
});
|
|
3670
|
+
CatalogIdentityEvidenceReferenceSchema = z5.object({
|
|
3671
|
+
id: IdSchema,
|
|
3672
|
+
identity_verification_request_id: IdSchema,
|
|
3673
|
+
evidence_kind: z5.enum([
|
|
3674
|
+
"government_photo_id",
|
|
3675
|
+
"live_face_match",
|
|
3676
|
+
"controlled_domain",
|
|
3677
|
+
"publishing_account",
|
|
3678
|
+
"derived_match",
|
|
3679
|
+
"reviewer_evidence"
|
|
3680
|
+
]),
|
|
3681
|
+
private_reference: z5.string().regex(/^private:\/\/[^\s]+$/).max(2e3),
|
|
3682
|
+
reference_sha256: Sha256Schema2,
|
|
3683
|
+
derived_result: z5.string().trim().min(1).max(2e3).nullable(),
|
|
3684
|
+
submitted_by: IdSchema,
|
|
3685
|
+
created_at: IsoDateTimeSchema2,
|
|
3686
|
+
purge_after: IsoDateTimeSchema2,
|
|
3687
|
+
purge_claimed_at: IsoDateTimeSchema2.nullable(),
|
|
3688
|
+
purge_claim_token: IdSchema.nullable(),
|
|
3689
|
+
purge_attempt_count: z5.number().int().nonnegative()
|
|
3690
|
+
}).strict().superRefine((evidence, context) => {
|
|
3691
|
+
const created = new Date(evidence.created_at);
|
|
3692
|
+
const maximum = new Date(created);
|
|
3693
|
+
if (["government_photo_id", "live_face_match"].includes(evidence.evidence_kind)) {
|
|
3694
|
+
maximum.setUTCDate(maximum.getUTCDate() + 30);
|
|
3695
|
+
} else {
|
|
3696
|
+
maximum.setTime(addUtcMonthsClamped(evidence.created_at, 24));
|
|
3697
|
+
}
|
|
3698
|
+
if (Date.parse(evidence.purge_after) < created.getTime() + 24 * 60 * 60 * 1e3) {
|
|
3699
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_after"], message: "retention is below its one-day floor" });
|
|
3700
|
+
}
|
|
3701
|
+
if (Date.parse(evidence.purge_after) > maximum.getTime()) {
|
|
3702
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_after"], message: "retention exceeds its evidence-kind bound" });
|
|
3703
|
+
}
|
|
3704
|
+
if (evidence.purge_claimed_at === null !== (evidence.purge_claim_token === null)) {
|
|
3705
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_claim_token"], message: "purge claim time and token must be paired" });
|
|
3706
|
+
}
|
|
3707
|
+
});
|
|
3708
|
+
CatalogIdentityVerificationChallengeSchema = z5.object({
|
|
3709
|
+
id: IdSchema,
|
|
3710
|
+
identity_verification_request_id: IdSchema,
|
|
3711
|
+
subject_kind: z5.enum(["person", "publisher"]),
|
|
3712
|
+
challenge_secret_hash: Sha256Schema2,
|
|
3713
|
+
binding_sha256: Sha256Schema2,
|
|
3714
|
+
issued_by: IdSchema,
|
|
3715
|
+
issued_at: IsoDateTimeSchema2,
|
|
3716
|
+
expires_at: IsoDateTimeSchema2,
|
|
3717
|
+
consumed_at: IsoDateTimeSchema2.nullable(),
|
|
3718
|
+
purge_after: IsoDateTimeSchema2,
|
|
3719
|
+
created_at: IsoDateTimeSchema2
|
|
3720
|
+
}).strict().superRefine((challenge, context) => {
|
|
3721
|
+
const issued = Date.parse(challenge.issued_at);
|
|
3722
|
+
if (Date.parse(challenge.expires_at) !== issued + 30 * 60 * 1e3) {
|
|
3723
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["expires_at"], message: "identity challenge expires after exactly 30 minutes" });
|
|
3724
|
+
}
|
|
3725
|
+
if (Date.parse(challenge.purge_after) !== issued + 30 * 24 * 60 * 60 * 1e3) {
|
|
3726
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["purge_after"], message: "identity challenge retention is exactly 30 days" });
|
|
3727
|
+
}
|
|
3728
|
+
if (challenge.consumed_at !== null) {
|
|
3729
|
+
const consumed = Date.parse(challenge.consumed_at);
|
|
3730
|
+
if (consumed < issued || consumed > Date.parse(challenge.expires_at)) {
|
|
3731
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["consumed_at"], message: "challenge consumption must occur before expiry" });
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
});
|
|
3735
|
+
CatalogIdentityVerificationResultSchema = z5.object({
|
|
3736
|
+
id: IdSchema,
|
|
3737
|
+
identity_verification_request_id: IdSchema,
|
|
3738
|
+
challenge_id: IdSchema,
|
|
3739
|
+
result_kind: z5.enum(["identity_match", "liveness", "domain_control", "publishing_account_control"]),
|
|
3740
|
+
outcome: z5.enum(["match", "mismatch", "inconclusive"]),
|
|
3741
|
+
private_attestation_reference: z5.string().regex(/^private:\/\/[^\s]+$/).max(2e3),
|
|
3742
|
+
attestation_sha256: Sha256Schema2,
|
|
3743
|
+
recorded_by: IdSchema,
|
|
3744
|
+
recorded_at: IsoDateTimeSchema2
|
|
3745
|
+
}).strict();
|
|
3746
|
+
CatalogPrivateEvidenceRetentionEventSchema = z5.object({
|
|
3747
|
+
id: IdSchema,
|
|
3748
|
+
evidence_table: z5.enum(["catalog_profile_claim_evidence_references", "catalog_identity_evidence_references"]),
|
|
3749
|
+
evidence_id: IdSchema,
|
|
3750
|
+
lifecycle_table: z5.enum(["catalog_profile_claim_request_events", "catalog_identity_verification_request_events", "catalog_profile_control_events", "catalog_identity_verification_record_events"]),
|
|
3751
|
+
lifecycle_event_id: IdSchema,
|
|
3752
|
+
retention_policy: z5.enum(["malformed_7d", "sensitive_30d", "workflow_24m"]),
|
|
3753
|
+
purge_after: IsoDateTimeSchema2,
|
|
3754
|
+
prior_event_id: IdSchema.nullable(),
|
|
3755
|
+
occurred_at: IsoDateTimeSchema2,
|
|
3756
|
+
created_at: IsoDateTimeSchema2
|
|
3757
|
+
}).strict();
|
|
3758
|
+
CatalogPrivateEvidenceLegalHoldEventSchema = z5.object({
|
|
3759
|
+
id: IdSchema,
|
|
3760
|
+
evidence_table: z5.enum(["catalog_profile_claim_evidence_references", "catalog_identity_evidence_references"]),
|
|
3761
|
+
evidence_id: IdSchema,
|
|
3762
|
+
action: z5.enum(["placed", "released"]),
|
|
3763
|
+
prior_event_id: IdSchema.nullable(),
|
|
3764
|
+
actor_id: IdSchema,
|
|
3765
|
+
reviewer_id: IdSchema,
|
|
3766
|
+
reason: z5.string().trim().min(1).max(2e3),
|
|
3767
|
+
occurred_at: IsoDateTimeSchema2,
|
|
3768
|
+
created_at: IsoDateTimeSchema2
|
|
3769
|
+
}).strict().superRefine((event, context) => {
|
|
3770
|
+
if (event.actor_id === event.reviewer_id) {
|
|
3771
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reviewer_id"], message: "legal hold review must be independent" });
|
|
3772
|
+
}
|
|
3773
|
+
if (event.action === "placed" !== (event.prior_event_id === null)) {
|
|
3774
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["prior_event_id"], message: "hold placement is the root and release is its successor" });
|
|
3775
|
+
}
|
|
3776
|
+
});
|
|
3777
|
+
CatalogPrivateEvidenceDeletionReceiptSchema = z5.object({
|
|
3778
|
+
id: IdSchema,
|
|
3779
|
+
evidence_table: z5.enum(["catalog_profile_claim_evidence_references", "catalog_identity_evidence_references"]),
|
|
3780
|
+
evidence_id: IdSchema,
|
|
3781
|
+
claim_token: IdSchema,
|
|
3782
|
+
private_reference_sha256: Sha256Schema2,
|
|
3783
|
+
storage_receipt_reference: z5.string().regex(/^storage:\/\/[^\s]+$/).max(2e3),
|
|
3784
|
+
storage_receipt_sha256: Sha256Schema2,
|
|
3785
|
+
acknowledged_by: IdSchema,
|
|
3786
|
+
storage_deleted_at: IsoDateTimeSchema2,
|
|
3787
|
+
created_at: IsoDateTimeSchema2
|
|
3788
|
+
}).strict();
|
|
3789
|
+
CatalogIdentityVerificationRecordSchema = z5.object({
|
|
3790
|
+
id: IdSchema,
|
|
3791
|
+
identity_verification_request_id: IdSchema,
|
|
3792
|
+
profile_id: IdSchema,
|
|
3793
|
+
profile_control_id: IdSchema,
|
|
3794
|
+
subject_kind: z5.enum(["person", "publisher"]),
|
|
3795
|
+
method_version_id: IdSchema,
|
|
3796
|
+
derived_evidence_sha256: Sha256Schema2,
|
|
3797
|
+
current_state: CatalogIdentityVerificationRecordStateSchema,
|
|
3798
|
+
created_at: IsoDateTimeSchema2,
|
|
3799
|
+
terminal_at: IsoDateTimeSchema2.nullable()
|
|
3800
|
+
}).strict().superRefine((record, context) => {
|
|
3801
|
+
const terminal = ["revoked", "expired"].includes(record.current_state);
|
|
3802
|
+
if (terminal !== (record.terminal_at !== null)) {
|
|
3803
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["terminal_at"], message: "terminal_at must match terminal Identity Record state" });
|
|
3804
|
+
}
|
|
3805
|
+
});
|
|
3806
|
+
CatalogIdentityVerificationRecordEventSchema = z5.object({
|
|
3807
|
+
id: IdSchema,
|
|
3808
|
+
identity_verification_record_id: IdSchema,
|
|
3809
|
+
state: CatalogIdentityVerificationRecordStateSchema,
|
|
3810
|
+
prior_event_id: IdSchema.nullable(),
|
|
3811
|
+
actor_id: IdSchema,
|
|
3812
|
+
reviewer_id: IdSchema.nullable(),
|
|
3813
|
+
reason: z5.string().trim().min(1).max(2e3).nullable(),
|
|
3814
|
+
occurred_at: IsoDateTimeSchema2,
|
|
3815
|
+
created_at: IsoDateTimeSchema2
|
|
3816
|
+
}).strict().superRefine((event, context) => {
|
|
3817
|
+
if (event.state === "active" !== (event.prior_event_id === null)) {
|
|
3818
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["prior_event_id"], message: "only the initial active state is a root event" });
|
|
3819
|
+
}
|
|
3820
|
+
if (event.state !== "active" && event.reason === null) {
|
|
3821
|
+
context.addIssue({ code: z5.ZodIssueCode.custom, path: ["reason"], message: `${event.state} requires a reason` });
|
|
3822
|
+
}
|
|
3823
|
+
});
|
|
2740
3824
|
}
|
|
2741
3825
|
});
|
|
2742
3826
|
|
|
@@ -2751,6 +3835,8 @@ var init_src = __esm({
|
|
|
2751
3835
|
init_install_targets();
|
|
2752
3836
|
init_security_scan();
|
|
2753
3837
|
init_skill_package();
|
|
3838
|
+
init_catalog();
|
|
3839
|
+
init_catalog_trust();
|
|
2754
3840
|
init_contract();
|
|
2755
3841
|
}
|
|
2756
3842
|
});
|
|
@@ -3070,8 +4156,8 @@ import { mkdir as mkdir2, readFile as readFile3, writeFile, chmod } from "node:f
|
|
|
3070
4156
|
|
|
3071
4157
|
// src/lib/invocation.ts
|
|
3072
4158
|
var NPX_HINTS = ["_npx", "npm-cache/_npx", "npm-cache\\_npx", ".npm/_npx"];
|
|
3073
|
-
var NPX_INVOCATION = "npx -y @floomhq/
|
|
3074
|
-
var GLOBAL_INVOCATION = "floom";
|
|
4159
|
+
var NPX_INVOCATION = "npx -y @floomhq/skills";
|
|
4160
|
+
var GLOBAL_INVOCATION = "floom-skills";
|
|
3075
4161
|
var cached = null;
|
|
3076
4162
|
function detect() {
|
|
3077
4163
|
const override = process.env.FLOOM_INVOKED_AS;
|
|
@@ -3089,7 +4175,7 @@ function cliInvocation() {
|
|
|
3089
4175
|
return cached;
|
|
3090
4176
|
}
|
|
3091
4177
|
function cliCmd(cmd) {
|
|
3092
|
-
const stripped = cmd.startsWith("floom ") ? cmd.slice("floom ".length) : cmd;
|
|
4178
|
+
const stripped = cmd.startsWith("floom-skills ") ? cmd.slice("floom-skills ".length) : cmd.startsWith("floom ") ? cmd.slice("floom ".length) : cmd;
|
|
3093
4179
|
return `${cliInvocation()} ${stripped}`;
|
|
3094
4180
|
}
|
|
3095
4181
|
|
|
@@ -3112,7 +4198,7 @@ function isTrustedApiUrl(apiUrl) {
|
|
|
3112
4198
|
return url.protocol === "https:";
|
|
3113
4199
|
}
|
|
3114
4200
|
if (LOOPBACK_HOSTS.has(url.hostname) && devModeEnabled()) {
|
|
3115
|
-
return
|
|
4201
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
3116
4202
|
}
|
|
3117
4203
|
return false;
|
|
3118
4204
|
} catch {
|
|
@@ -3149,13 +4235,13 @@ async function readRawAuth() {
|
|
|
3149
4235
|
`Cannot read your Floom auth file (permission denied).
|
|
3150
4236
|
Fix: chmod 600 ~/.floom/auth.json
|
|
3151
4237
|
Or re-authenticate: ${cliCmd("login")}
|
|
3152
|
-
More help: https://floom.dev/docs#troubleshooting`
|
|
4238
|
+
More help: https://skills.floom.dev/docs#troubleshooting`
|
|
3153
4239
|
);
|
|
3154
4240
|
}
|
|
3155
4241
|
throw new Error(
|
|
3156
4242
|
`Cannot read your Floom auth file.
|
|
3157
4243
|
Run: ${cliCmd("login")}
|
|
3158
|
-
More help: https://floom.dev/docs#troubleshooting`
|
|
4244
|
+
More help: https://skills.floom.dev/docs#troubleshooting`
|
|
3159
4245
|
);
|
|
3160
4246
|
}
|
|
3161
4247
|
try {
|
|
@@ -3164,7 +4250,7 @@ async function readRawAuth() {
|
|
|
3164
4250
|
throw new Error(
|
|
3165
4251
|
`Your Floom auth file is corrupted.
|
|
3166
4252
|
Run: ${cliCmd("login")} to generate a fresh one.
|
|
3167
|
-
More help: https://floom.dev/docs#troubleshooting`
|
|
4253
|
+
More help: https://skills.floom.dev/docs#troubleshooting`
|
|
3168
4254
|
);
|
|
3169
4255
|
}
|
|
3170
4256
|
}
|
|
@@ -3193,7 +4279,11 @@ function getApiUrl() {
|
|
|
3193
4279
|
return DEFAULT_API_URL;
|
|
3194
4280
|
}
|
|
3195
4281
|
function getAppUrl() {
|
|
3196
|
-
|
|
4282
|
+
const configured = process.env.FLOOM_APP_URL?.trim();
|
|
4283
|
+
if (!configured) return DEFAULT_APP_URL;
|
|
4284
|
+
const normalized = trustedApiUrlOrDefault(`${configured.replace(/\/$/, "")}/api/v1`);
|
|
4285
|
+
if (normalized === DEFAULT_API_URL) return DEFAULT_APP_URL;
|
|
4286
|
+
return normalized.replace(/\/api\/v1$/, "");
|
|
3197
4287
|
}
|
|
3198
4288
|
function getApiBaseUrls(preferred) {
|
|
3199
4289
|
const explicitApiUrl = process.env.FLOOM_API_URL?.trim();
|
|
@@ -3287,7 +4377,7 @@ async function getMachineIdentity() {
|
|
|
3287
4377
|
}
|
|
3288
4378
|
|
|
3289
4379
|
// src/version.ts
|
|
3290
|
-
var VERSION = "1.
|
|
4380
|
+
var VERSION = "1.1.1";
|
|
3291
4381
|
|
|
3292
4382
|
// src/api-client.ts
|
|
3293
4383
|
var DEFAULT_TIMEOUT_MS = 2e4;
|
|
@@ -3334,7 +4424,7 @@ async function readLimitedText(res, limitBytes = MAX_ERROR_BODY_BYTES) {
|
|
|
3334
4424
|
return truncated ? `${text}
|
|
3335
4425
|
[truncated]` : text;
|
|
3336
4426
|
}
|
|
3337
|
-
var HELP = "https://floom.dev/docs#troubleshooting";
|
|
4427
|
+
var HELP = "https://skills.floom.dev/docs#troubleshooting";
|
|
3338
4428
|
function friendlyApiErrorMessage(code, raw, status) {
|
|
3339
4429
|
if (code === "AUTH_REQUIRED" || code === "TOKEN_INVALID" || status === 401) {
|
|
3340
4430
|
return `Not signed in.
|
|
@@ -3361,7 +4451,7 @@ function friendlyApiErrorMessage(code, raw, status) {
|
|
|
3361
4451
|
}
|
|
3362
4452
|
if (code === "CLI_VERSION_TOO_OLD") {
|
|
3363
4453
|
return `Your CLI is out of date.
|
|
3364
|
-
Run: npm i -g @floomhq/
|
|
4454
|
+
Run: npm i -g @floomhq/skills@latest
|
|
3365
4455
|
More help: ${HELP}`;
|
|
3366
4456
|
}
|
|
3367
4457
|
if (code === "FILE_TOO_LARGE" || code === "BUNDLE_TOO_LARGE") {
|
|
@@ -3382,7 +4472,7 @@ async function api(path, opts = {}) {
|
|
|
3382
4472
|
"AUTH_REQUIRED",
|
|
3383
4473
|
`Not signed in.
|
|
3384
4474
|
Run: ${cliCmd("login")}
|
|
3385
|
-
More help: https://floom.dev/docs#troubleshooting`
|
|
4475
|
+
More help: https://skills.floom.dev/docs#troubleshooting`
|
|
3386
4476
|
);
|
|
3387
4477
|
}
|
|
3388
4478
|
let lastError = null;
|
|
@@ -3416,9 +4506,9 @@ async function api(path, opts = {}) {
|
|
|
3416
4506
|
} catch (e) {
|
|
3417
4507
|
lastError = new FloomError(
|
|
3418
4508
|
"INTERNAL_ERROR",
|
|
3419
|
-
`Cannot reach Floom (${base}): ${e.message}
|
|
4509
|
+
`Cannot reach Floom Skills (${base}): ${e.message}
|
|
3420
4510
|
Check your internet connection or firewall. If on a corporate network, you may need to set a proxy: npm config set proxy http://...
|
|
3421
|
-
More help: https://floom.dev/docs#troubleshooting`,
|
|
4511
|
+
More help: https://skills.floom.dev/docs#troubleshooting`,
|
|
3422
4512
|
{ apiUrl: base }
|
|
3423
4513
|
);
|
|
3424
4514
|
continue;
|
|
@@ -3606,7 +4696,7 @@ Fix: replace the link with the real file contents:
|
|
|
3606
4696
|
|
|
3607
4697
|
(or move the target file under the skill folder if it lives elsewhere)
|
|
3608
4698
|
|
|
3609
|
-
More help: https://floom.dev/docs#skill-folder-rules`
|
|
4699
|
+
More help: https://skills.floom.dev/docs#skill-folder-rules`
|
|
3610
4700
|
);
|
|
3611
4701
|
}
|
|
3612
4702
|
if (entry.isDirectory()) {
|
|
@@ -3772,7 +4862,7 @@ async function loginCommand() {
|
|
|
3772
4862
|
]);
|
|
3773
4863
|
if (cliCmd("login").startsWith("npx ")) {
|
|
3774
4864
|
log.blank();
|
|
3775
|
-
log.info(" Tip: install once with npm i -g @floomhq/
|
|
4865
|
+
log.info(" Tip: install once with npm i -g @floomhq/skills and just type `floom-skills` after that.");
|
|
3776
4866
|
}
|
|
3777
4867
|
return;
|
|
3778
4868
|
}
|
|
@@ -3793,7 +4883,7 @@ async function loginCommand() {
|
|
|
3793
4883
|
log.err("Login timed out \u2014 the browser window expired.");
|
|
3794
4884
|
printNext([
|
|
3795
4885
|
{ command: cliCmd("login"), description: "try again" },
|
|
3796
|
-
{ command: "More help: https://floom.dev/docs#troubleshooting" }
|
|
4886
|
+
{ command: "More help: https://skills.floom.dev/docs#troubleshooting" }
|
|
3797
4887
|
]);
|
|
3798
4888
|
process.exitCode = 1;
|
|
3799
4889
|
}
|
|
@@ -3817,7 +4907,7 @@ async function logoutCommand(opts = {}, deps = {}) {
|
|
|
3817
4907
|
remoteRevokeFailed = true;
|
|
3818
4908
|
process.exitCode = 1;
|
|
3819
4909
|
log.err(
|
|
3820
|
-
"Local session cleared. Other devices are still authenticated.\nSign in at https://floom.dev/settings to revoke other sessions from the web."
|
|
4910
|
+
"Local session cleared. Other devices are still authenticated.\nSign in at https://skills.floom.dev/settings to revoke other sessions from the web."
|
|
3821
4911
|
);
|
|
3822
4912
|
} else {
|
|
3823
4913
|
log.warn(`Remote session revoke failed: ${error.message}`);
|
|
@@ -3940,7 +5030,7 @@ async function accountCommand(opts = {}) {
|
|
|
3940
5030
|
init_src();
|
|
3941
5031
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3942
5032
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3943
|
-
import { z as
|
|
5033
|
+
import { z as z6 } from "zod";
|
|
3944
5034
|
|
|
3945
5035
|
// src/commands/sync-engine.ts
|
|
3946
5036
|
init_src();
|
|
@@ -4011,9 +5101,9 @@ async function readManifest(root) {
|
|
|
4011
5101
|
if (err.code === "ENOENT") return null;
|
|
4012
5102
|
if (error instanceof SyntaxError || error instanceof ZodError) {
|
|
4013
5103
|
throw new Error(
|
|
4014
|
-
`Corrupted manifest at ${manifestPath(root)}. Remove that file or run floom pull after backing up local edits.
|
|
4015
|
-
Run: rm ${manifestPath(root)} && npx -y @floomhq/
|
|
4016
|
-
More help: https://floom.dev/docs#troubleshooting`
|
|
5104
|
+
`Corrupted manifest at ${manifestPath(root)}. Remove that file or run floom-skills pull after backing up local edits.
|
|
5105
|
+
Run: rm ${manifestPath(root)} && npx -y @floomhq/skills pull
|
|
5106
|
+
More help: https://skills.floom.dev/docs#troubleshooting`
|
|
4017
5107
|
);
|
|
4018
5108
|
}
|
|
4019
5109
|
throw error;
|
|
@@ -4476,7 +5566,7 @@ function createMcpServer(deps = {}) {
|
|
|
4476
5566
|
{
|
|
4477
5567
|
title: "Floom Search Skills",
|
|
4478
5568
|
description: "Search the authenticated workspace skill library by keyword. Returns matching skills with title and description.",
|
|
4479
|
-
inputSchema: { query:
|
|
5569
|
+
inputSchema: { query: z6.string().describe("Search query string") },
|
|
4480
5570
|
annotations: {
|
|
4481
5571
|
readOnlyHint: true,
|
|
4482
5572
|
destructiveHint: false,
|
|
@@ -4502,7 +5592,7 @@ function createMcpServer(deps = {}) {
|
|
|
4502
5592
|
query,
|
|
4503
5593
|
status: "error",
|
|
4504
5594
|
message: err.message,
|
|
4505
|
-
hint: "Run: npx -y @floomhq/
|
|
5595
|
+
hint: "Run: npx -y @floomhq/skills login"
|
|
4506
5596
|
});
|
|
4507
5597
|
}
|
|
4508
5598
|
}
|
|
@@ -4512,7 +5602,7 @@ function createMcpServer(deps = {}) {
|
|
|
4512
5602
|
{
|
|
4513
5603
|
title: "Floom Get Skill",
|
|
4514
5604
|
description: "Fetch full skill detail (body, files, version history) for a given skill slug from the workspace.",
|
|
4515
|
-
inputSchema: { slug:
|
|
5605
|
+
inputSchema: { slug: z6.string().describe("Skill slug, e.g. 'brand-voice'") },
|
|
4516
5606
|
annotations: {
|
|
4517
5607
|
readOnlyHint: true,
|
|
4518
5608
|
destructiveHint: false,
|
|
@@ -4538,7 +5628,7 @@ function createMcpServer(deps = {}) {
|
|
|
4538
5628
|
slug,
|
|
4539
5629
|
status: "error",
|
|
4540
5630
|
message: err.message,
|
|
4541
|
-
hint: "Run: npx -y @floomhq/
|
|
5631
|
+
hint: "Run: npx -y @floomhq/skills login"
|
|
4542
5632
|
});
|
|
4543
5633
|
}
|
|
4544
5634
|
}
|
|
@@ -4549,8 +5639,8 @@ function createMcpServer(deps = {}) {
|
|
|
4549
5639
|
title: "Floom Send Feedback",
|
|
4550
5640
|
description: "Send feedback, a feature request, or a bug report to the Floom team.",
|
|
4551
5641
|
inputSchema: {
|
|
4552
|
-
message:
|
|
4553
|
-
type:
|
|
5642
|
+
message: z6.string().describe("Feedback message"),
|
|
5643
|
+
type: z6.enum(["feedback", "bug", "feature"]).default("feedback").describe("Type of feedback")
|
|
4554
5644
|
},
|
|
4555
5645
|
annotations: {
|
|
4556
5646
|
readOnlyHint: false,
|
|
@@ -4590,10 +5680,10 @@ async function mcpCommand() {
|
|
|
4590
5680
|
This command is launched by your AI agent, not run directly.
|
|
4591
5681
|
|
|
4592
5682
|
Add this to your agent's MCP configuration:
|
|
4593
|
-
{"command":"npx","args":["-y","@floomhq/
|
|
5683
|
+
{"command":"npx","args":["-y","@floomhq/skills","mcp"]}
|
|
4594
5684
|
|
|
4595
5685
|
Claude Code users can instead run:
|
|
4596
|
-
claude mcp add floom -- npx -y @floomhq/
|
|
5686
|
+
claude mcp add floom -- npx -y @floomhq/skills mcp
|
|
4597
5687
|
|
|
4598
5688
|
Press Ctrl+C to stop.
|
|
4599
5689
|
`
|
|
@@ -5004,7 +6094,7 @@ async function pushExplicitPath(pathArg, options, pushApi, authed) {
|
|
|
5004
6094
|
if (!await hasSkillMd(folder)) {
|
|
5005
6095
|
if (!json) {
|
|
5006
6096
|
log.err(`No SKILL.md at the root of ${pathArg}.`);
|
|
5007
|
-
log.info(" Every skill folder needs a SKILL.md at its root. See: https://floom.dev/docs#concept");
|
|
6097
|
+
log.info(" Every skill folder needs a SKILL.md at its root. See: https://skills.floom.dev/docs#concept");
|
|
5008
6098
|
}
|
|
5009
6099
|
process.exitCode = 2;
|
|
5010
6100
|
return;
|
|
@@ -5486,7 +6576,7 @@ async function pullCommand(skillArg, rawOpts = {}) {
|
|
|
5486
6576
|
log.blank();
|
|
5487
6577
|
log.info(`Or use: ${cliCmd("pull --agent claude")}`);
|
|
5488
6578
|
log.blank();
|
|
5489
|
-
log.info("More help: https://floom.dev/docs#agents");
|
|
6579
|
+
log.info("More help: https://skills.floom.dev/docs#agents");
|
|
5490
6580
|
}
|
|
5491
6581
|
process.exitCode = 1;
|
|
5492
6582
|
return;
|
|
@@ -5817,7 +6907,7 @@ function printPreview(plan) {
|
|
|
5817
6907
|
log.err(` Keep your local version: ${cliCmd(`push <${skill.slug}-dir>`)}`);
|
|
5818
6908
|
}
|
|
5819
6909
|
log.err("Your local copy is always backed up to .floom/backups/ first.");
|
|
5820
|
-
log.err("More: https://floom.dev/docs#conflicts");
|
|
6910
|
+
log.err("More: https://skills.floom.dev/docs#conflicts");
|
|
5821
6911
|
}
|
|
5822
6912
|
}
|
|
5823
6913
|
async function defaultConfirmProceed() {
|
|
@@ -6042,7 +7132,7 @@ async function syncCommand(rawOpts = {}, deps = {}) {
|
|
|
6042
7132
|
} else {
|
|
6043
7133
|
log.err("No agents detected \u2014 install Claude, Codex, Cursor, Gemini, or OpenCode, then re-run.");
|
|
6044
7134
|
log.info("Floom syncs into one of: Claude, Codex, Cursor, Gemini, OpenCode.");
|
|
6045
|
-
log.info("More: https://floom.dev/docs#agents");
|
|
7135
|
+
log.info("More: https://skills.floom.dev/docs#agents");
|
|
6046
7136
|
}
|
|
6047
7137
|
process.exitCode = 1;
|
|
6048
7138
|
return;
|
|
@@ -6329,7 +7419,7 @@ async function statusCommand(rawOpts = {}) {
|
|
|
6329
7419
|
log.info("If someone sent you a shared skill:");
|
|
6330
7420
|
log.command(cliCmd("install <link>"));
|
|
6331
7421
|
log.blank();
|
|
6332
|
-
log.info("More help: https://floom.dev/docs#agents");
|
|
7422
|
+
log.info("More help: https://skills.floom.dev/docs#agents");
|
|
6333
7423
|
}
|
|
6334
7424
|
process.exitCode = 1;
|
|
6335
7425
|
return;
|
|
@@ -6612,29 +7702,71 @@ async function renameDeviceCommand(newLabel) {
|
|
|
6612
7702
|
|
|
6613
7703
|
// src/commands/install.ts
|
|
6614
7704
|
init_src();
|
|
6615
|
-
import { mkdir as mkdir6, rm as rm3, writeFile as writeFile5, stat as stat7, readFile as readFile11 } from "node:fs/promises";
|
|
7705
|
+
import { mkdir as mkdir6, rm as rm3, writeFile as writeFile5, stat as stat7, lstat as lstat4, readFile as readFile11 } from "node:fs/promises";
|
|
6616
7706
|
import { dirname as dirname2, join as join12, resolve as resolve8 } from "node:path";
|
|
7707
|
+
import { z as z7 } from "zod";
|
|
6617
7708
|
init_runtime();
|
|
6618
7709
|
init_prompt();
|
|
6619
7710
|
var TOKEN_RE = /^fls_[A-Za-z0-9_-]{32,}$/;
|
|
6620
7711
|
var SAFE_SLUG_RE2 = /^(?=.{1,80}$)[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
6621
7712
|
var MAX_DECODED_FILE_BYTES2 = 2 * 1024 * 1024;
|
|
6622
|
-
|
|
7713
|
+
var TRUSTED_CATALOG_HOSTS = /* @__PURE__ */ new Set(["skills.floom.dev", "cyborg.floom.dev"]);
|
|
7714
|
+
var CATALOG_LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost"]);
|
|
7715
|
+
function trustedCatalogOrigin(url) {
|
|
7716
|
+
if (TRUSTED_CATALOG_HOSTS.has(url.hostname)) return url.protocol === "https:";
|
|
7717
|
+
const dev = process.env.FLOOM_DEV;
|
|
7718
|
+
const devMode = dev === "1" || dev === "true";
|
|
7719
|
+
if (!devMode || !CATALOG_LOOPBACK_HOSTS.has(url.hostname)) return false;
|
|
7720
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
7721
|
+
}
|
|
7722
|
+
var trustedCatalogHosts = () => [...TRUSTED_CATALOG_HOSTS];
|
|
7723
|
+
function parseInstallSource(input) {
|
|
6623
7724
|
const trimmed = input.trim();
|
|
6624
|
-
if (TOKEN_RE.test(trimmed)) return trimmed;
|
|
7725
|
+
if (TOKEN_RE.test(trimmed)) return { kind: "share", token: trimmed };
|
|
7726
|
+
let url;
|
|
6625
7727
|
try {
|
|
6626
|
-
|
|
6627
|
-
const parts = url.pathname.split("/").filter(Boolean);
|
|
6628
|
-
if (parts.length >= 2 && parts[parts.length - 2] === "s") {
|
|
6629
|
-
const candidate = parts[parts.length - 1];
|
|
6630
|
-
if (candidate && TOKEN_RE.test(candidate)) return candidate;
|
|
6631
|
-
}
|
|
6632
|
-
const last = parts[parts.length - 1];
|
|
6633
|
-
if (last && TOKEN_RE.test(last)) return last;
|
|
7728
|
+
url = new URL(trimmed);
|
|
6634
7729
|
} catch {
|
|
7730
|
+
return null;
|
|
7731
|
+
}
|
|
7732
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
7733
|
+
const last = parts[parts.length - 1];
|
|
7734
|
+
const parent = parts.length >= 2 ? parts[parts.length - 2] : null;
|
|
7735
|
+
if (parent === "s" && last && TOKEN_RE.test(last)) return { kind: "share", token: last };
|
|
7736
|
+
if (last && TOKEN_RE.test(last)) return { kind: "share", token: last };
|
|
7737
|
+
if (parent === "skills" && last && SAFE_SLUG_RE2.test(last) && trustedCatalogOrigin(url)) {
|
|
7738
|
+
return { kind: "catalog", origin: url.origin, slug: last };
|
|
6635
7739
|
}
|
|
6636
7740
|
return null;
|
|
6637
7741
|
}
|
|
7742
|
+
function untrustedCatalogHost(input) {
|
|
7743
|
+
let url;
|
|
7744
|
+
try {
|
|
7745
|
+
url = new URL(input.trim());
|
|
7746
|
+
} catch {
|
|
7747
|
+
return null;
|
|
7748
|
+
}
|
|
7749
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
7750
|
+
const last = parts[parts.length - 1];
|
|
7751
|
+
const parent = parts.length >= 2 ? parts[parts.length - 2] : null;
|
|
7752
|
+
if (parent !== "skills" || !last || !SAFE_SLUG_RE2.test(last)) return null;
|
|
7753
|
+
return trustedCatalogOrigin(url) ? null : url.host;
|
|
7754
|
+
}
|
|
7755
|
+
var ShareFileSchema = z7.object({
|
|
7756
|
+
path: z7.string().min(1).max(1024),
|
|
7757
|
+
mode: z7.enum(["text", "non_text"]),
|
|
7758
|
+
content_text: z7.string().nullable().optional().default(null),
|
|
7759
|
+
binary: z7.object({ download_url: z7.string().nullable().optional().default(null) }).passthrough().nullable().optional().default(null)
|
|
7760
|
+
}).passthrough();
|
|
7761
|
+
var PublicShareResponseSchema = z7.object({
|
|
7762
|
+
skill: z7.object({
|
|
7763
|
+
title: z7.string().min(1).max(500),
|
|
7764
|
+
description: z7.string().max(2e4).optional().default(""),
|
|
7765
|
+
owner: z7.object({ name: z7.string().min(1).max(500) }).passthrough(),
|
|
7766
|
+
version: z7.object({ version_seq: z7.number().int().nonnegative(), display: z7.string().min(1).max(100) }).passthrough()
|
|
7767
|
+
}).passthrough(),
|
|
7768
|
+
file_contents: z7.array(ShareFileSchema).max(5e3)
|
|
7769
|
+
}).passthrough();
|
|
6638
7770
|
function safeSkillSlug2(slug) {
|
|
6639
7771
|
if (!slug || !SAFE_SLUG_RE2.test(slug)) throw new Error(`Unsafe shared skill name: ${slug}`);
|
|
6640
7772
|
return slug;
|
|
@@ -6666,9 +7798,9 @@ function bytesForShareFile(file) {
|
|
|
6666
7798
|
function derivedSlug(title) {
|
|
6667
7799
|
return title.toLowerCase().replace(/[^a-z0-9 -]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").slice(0, 80).replace(/^-+|-+$/g, "") || "shared-skill";
|
|
6668
7800
|
}
|
|
6669
|
-
async function
|
|
6670
|
-
const
|
|
6671
|
-
const
|
|
7801
|
+
async function fetchInstallSource(source) {
|
|
7802
|
+
const url = source.kind === "share" ? `${getAppUrl().replace(/\/$/, "")}/api/v1/share/${encodeURIComponent(source.token)}` : `${source.origin}/api/v1/catalog/install/skills/${encodeURIComponent(source.slug)}`;
|
|
7803
|
+
const notFoundMessage = source.kind === "share" ? "Share link not found or has been revoked." : "Install link not found or has been withdrawn.";
|
|
6672
7804
|
const controller = new AbortController();
|
|
6673
7805
|
const timer = setTimeout(() => controller.abort(), 3e4);
|
|
6674
7806
|
let res;
|
|
@@ -6681,7 +7813,7 @@ async function fetchPublicShare(token) {
|
|
|
6681
7813
|
clearTimeout(timer);
|
|
6682
7814
|
}
|
|
6683
7815
|
if (res.status === 404) {
|
|
6684
|
-
throw new FloomError("SKILL_NOT_FOUND",
|
|
7816
|
+
throw new FloomError("SKILL_NOT_FOUND", notFoundMessage);
|
|
6685
7817
|
}
|
|
6686
7818
|
if (!res.ok) throw new Error(`Floom API returned HTTP ${res.status}. Try again in a moment.`);
|
|
6687
7819
|
let json;
|
|
@@ -6690,21 +7822,43 @@ async function fetchPublicShare(token) {
|
|
|
6690
7822
|
} catch {
|
|
6691
7823
|
throw new Error("Unexpected response from Floom API. Try again in a moment.");
|
|
6692
7824
|
}
|
|
6693
|
-
const
|
|
6694
|
-
if (!
|
|
7825
|
+
const parsed = PublicShareResponseSchema.safeParse(json);
|
|
7826
|
+
if (!parsed.success) {
|
|
6695
7827
|
throw new Error("Unexpected response shape from Floom API.");
|
|
6696
7828
|
}
|
|
6697
|
-
return
|
|
7829
|
+
return parsed.data;
|
|
6698
7830
|
}
|
|
6699
7831
|
var nativePathOperations = { dirname: dirname2 };
|
|
6700
7832
|
function installParentDirectory(destination, pathOperations = nativePathOperations) {
|
|
6701
7833
|
return pathOperations.dirname(destination);
|
|
6702
7834
|
}
|
|
7835
|
+
async function stagingRoot(skillsDir) {
|
|
7836
|
+
let current = skillsDir;
|
|
7837
|
+
for (const segment of [".floom", "tmp"]) {
|
|
7838
|
+
current = join12(current, segment);
|
|
7839
|
+
let entry;
|
|
7840
|
+
try {
|
|
7841
|
+
entry = await lstat4(current);
|
|
7842
|
+
} catch (error) {
|
|
7843
|
+
if (error.code !== "ENOENT") throw error;
|
|
7844
|
+
await mkdir6(current, { recursive: true });
|
|
7845
|
+
continue;
|
|
7846
|
+
}
|
|
7847
|
+
if (entry.isSymbolicLink()) {
|
|
7848
|
+
throw new Error(`Refusing to stage an install through a symlinked ${tildePath(current)}.`);
|
|
7849
|
+
}
|
|
7850
|
+
if (!entry.isDirectory()) {
|
|
7851
|
+
throw new Error(`Refusing to stage an install: ${tildePath(current)} is not a directory.`);
|
|
7852
|
+
}
|
|
7853
|
+
}
|
|
7854
|
+
return current;
|
|
7855
|
+
}
|
|
6703
7856
|
async function installToDir(target, slug, files) {
|
|
6704
7857
|
const finalDir = join12(target.skillsDir, slug);
|
|
6705
|
-
const
|
|
6706
|
-
const
|
|
6707
|
-
|
|
7858
|
+
const staging = await stagingRoot(target.skillsDir);
|
|
7859
|
+
const tempDir = join12(staging, `${slug}-install-${Date.now()}`);
|
|
7860
|
+
const replacedDir = join12(staging, `${slug}-previous-${Date.now()}`);
|
|
7861
|
+
await mkdir6(tempDir);
|
|
6708
7862
|
try {
|
|
6709
7863
|
for (const file of files) {
|
|
6710
7864
|
const safePath = safeRemotePath2(file.path);
|
|
@@ -6763,17 +7917,24 @@ async function installCommand(input, rawOpts = {}) {
|
|
|
6763
7917
|
throw error;
|
|
6764
7918
|
}
|
|
6765
7919
|
const json = flags.json;
|
|
6766
|
-
const
|
|
6767
|
-
if (!
|
|
7920
|
+
const source = parseInstallSource(input);
|
|
7921
|
+
if (!source) {
|
|
7922
|
+
const untrustedHost = untrustedCatalogHost(input);
|
|
6768
7923
|
if (!json) {
|
|
6769
|
-
|
|
7924
|
+
if (untrustedHost) {
|
|
7925
|
+
log.err(`Refusing to install from ${untrustedHost}: it is not a Floom catalog host.`);
|
|
7926
|
+
log.info(`Catalog installs are accepted only from: ${trustedCatalogHosts().join(", ")}`);
|
|
7927
|
+
} else {
|
|
7928
|
+
log.err("That doesn't look like a Floom share link. It must look like: https://skills.floom.dev/s/fls_xxx");
|
|
7929
|
+
log.info(`A public catalog Skill page also works: https://${trustedCatalogHosts()[0]}/skills/<slug>`);
|
|
7930
|
+
}
|
|
6770
7931
|
}
|
|
6771
7932
|
process.exitCode = 2;
|
|
6772
7933
|
return;
|
|
6773
7934
|
}
|
|
6774
7935
|
let shareData;
|
|
6775
7936
|
try {
|
|
6776
|
-
shareData = await
|
|
7937
|
+
shareData = await fetchInstallSource(source);
|
|
6777
7938
|
} catch (e) {
|
|
6778
7939
|
if (!json) {
|
|
6779
7940
|
log.err(e instanceof FloomError ? e.message : e.message);
|
|
@@ -6798,7 +7959,7 @@ async function installCommand(input, rawOpts = {}) {
|
|
|
6798
7959
|
log.info("Floom can install shared skills into Claude, Codex, Cursor, Gemini, or OpenCode.");
|
|
6799
7960
|
log.info("Install one of those agents, then run this command again.");
|
|
6800
7961
|
log.blank();
|
|
6801
|
-
log.info("More help: https://floom.dev/docs#agents");
|
|
7962
|
+
log.info("More help: https://skills.floom.dev/docs#agents");
|
|
6802
7963
|
}
|
|
6803
7964
|
process.exitCode = 1;
|
|
6804
7965
|
return;
|
|
@@ -7005,7 +8166,7 @@ description: TODO: Use when the user needs help with [specific task, workflow, o
|
|
|
7005
8166
|
<!--
|
|
7006
8167
|
This file teaches your AI agent when and how to use the skill.
|
|
7007
8168
|
Keep it practical: triggers, rules, examples, and done criteria.
|
|
7008
|
-
See: https://floom.dev/docs/skills
|
|
8169
|
+
See: https://skills.floom.dev/docs/skills
|
|
7009
8170
|
-->
|
|
7010
8171
|
|
|
7011
8172
|
Use this skill when:
|
|
@@ -7250,7 +8411,7 @@ function npmLatest() {
|
|
|
7250
8411
|
return new Promise((resolveP) => {
|
|
7251
8412
|
let child;
|
|
7252
8413
|
try {
|
|
7253
|
-
child = spawn3("npm", ["view", "@floomhq/
|
|
8414
|
+
child = spawn3("npm", ["view", "@floomhq/skills", "version"], { stdio: ["ignore", "pipe", "ignore"] });
|
|
7254
8415
|
} catch {
|
|
7255
8416
|
resolveP(null);
|
|
7256
8417
|
return;
|
|
@@ -7303,7 +8464,7 @@ async function doctorCommand(opts = {}) {
|
|
|
7303
8464
|
}
|
|
7304
8465
|
}
|
|
7305
8466
|
if (authOk) {
|
|
7306
|
-
checks.push({ name: "api", status: "pass", message: "https://floom.dev reachable", fix: null });
|
|
8467
|
+
checks.push({ name: "api", status: "pass", message: "https://skills.floom.dev reachable", fix: null });
|
|
7307
8468
|
} else {
|
|
7308
8469
|
checks.push({ name: "api", status: "warn", message: "skipped \u2014 sign in first", fix: cliCmd("login") });
|
|
7309
8470
|
}
|
|
@@ -7370,11 +8531,11 @@ async function doctorCommand(opts = {}) {
|
|
|
7370
8531
|
}
|
|
7371
8532
|
const latest = await npmLatest();
|
|
7372
8533
|
if (!latest) {
|
|
7373
|
-
checks.push({ name: "version", status: "warn", message: `@floomhq/
|
|
8534
|
+
checks.push({ name: "version", status: "warn", message: `@floomhq/skills ${VERSION}; latest version unreachable`, fix: null });
|
|
7374
8535
|
} else if (significantlyOutdated(VERSION, latest)) {
|
|
7375
|
-
checks.push({ name: "version", status: "warn", message: `@floomhq/
|
|
8536
|
+
checks.push({ name: "version", status: "warn", message: `@floomhq/skills ${VERSION} installed, latest is ${latest}`, fix: "npx -y @floomhq/skills@latest" });
|
|
7376
8537
|
} else {
|
|
7377
|
-
checks.push({ name: "version", status: "pass", message: `@floomhq/
|
|
8538
|
+
checks.push({ name: "version", status: "pass", message: `@floomhq/skills ${VERSION} is current`, fix: null });
|
|
7378
8539
|
}
|
|
7379
8540
|
const failures = checks.filter((c) => c.status === "fail");
|
|
7380
8541
|
const warnings = checks.filter((c) => c.status === "warn");
|
|
@@ -8119,8 +9280,8 @@ var COMMON_FLAGS = `Common flags
|
|
|
8119
9280
|
--no-secret-check with push, skip the pre-publish secret scan`;
|
|
8120
9281
|
function printGroupedHelp() {
|
|
8121
9282
|
const out2 = process.stdout;
|
|
8122
|
-
out2.write("\n" + chalk7.bold("Usage: floom [command]") + "\n\n");
|
|
8123
|
-
out2.write(` ${chalk7.cyan.bold("floom")}
|
|
9283
|
+
out2.write("\n" + chalk7.bold("Usage: floom-skills [command]") + "\n\n");
|
|
9284
|
+
out2.write(` ${chalk7.cyan.bold("floom-skills")} your dashboard \u2014 Library and agent status at a glance
|
|
8124
9285
|
`);
|
|
8125
9286
|
const allNames = GROUPS.flatMap((g) => g.rows.map((r) => r.name));
|
|
8126
9287
|
const width = Math.max(...allNames.map((n) => n.length), 14);
|
|
@@ -8133,7 +9294,7 @@ function printGroupedHelp() {
|
|
|
8133
9294
|
}
|
|
8134
9295
|
}
|
|
8135
9296
|
out2.write("\n" + COMMON_FLAGS + "\n");
|
|
8136
|
-
out2.write("\n" + chalk7.dim("More help: https://floom.dev/docs") + "\n");
|
|
9297
|
+
out2.write("\n" + chalk7.dim("More help: https://skills.floom.dev/docs") + "\n");
|
|
8137
9298
|
}
|
|
8138
9299
|
|
|
8139
9300
|
// src/index.ts
|
|
@@ -8144,7 +9305,7 @@ function aliasNotice(oldName, newName) {
|
|
|
8144
9305
|
log.notice(`"${oldName}" is now "${newName}" \u2014 both work for now.`);
|
|
8145
9306
|
}
|
|
8146
9307
|
var program = new Command();
|
|
8147
|
-
program.name("floom").description("Floom:
|
|
9308
|
+
program.name("floom-skills").description("Floom Skills: publish, install, sync, and share AI agent skills.").version(VERSION).addHelpCommand(false).helpOption("-h, --help", "show grouped help").allowExcessArguments(true).showSuggestionAfterError(true).showHelpAfterError(false);
|
|
8148
9309
|
program.helpInformation = function helpInformation() {
|
|
8149
9310
|
printGroupedHelp();
|
|
8150
9311
|
return "";
|
|
@@ -8159,8 +9320,8 @@ program.action(async (_opts, cmd) => {
|
|
|
8159
9320
|
log.err(`unknown command: ${unknown}`);
|
|
8160
9321
|
const knownNames = program.commands.map((c) => c.name());
|
|
8161
9322
|
const suggestion = closestCommand(unknown, knownNames);
|
|
8162
|
-
if (suggestion) log.info(`Did you mean: floom ${suggestion}?`);
|
|
8163
|
-
log.info("Run: floom --help");
|
|
9323
|
+
if (suggestion) log.info(`Did you mean: floom-skills ${suggestion}?`);
|
|
9324
|
+
log.info("Run: floom-skills --help");
|
|
8164
9325
|
process.exitCode = 2;
|
|
8165
9326
|
return;
|
|
8166
9327
|
}
|