@koda-sl/baker-cli 0.101.0 → 0.103.0
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 +5 -1
- package/dist/cli.js +371 -132
- package/dist/cli.js.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -632,11 +632,11 @@ registerSchema({
|
|
|
632
632
|
async function recommendSkills(actionId) {
|
|
633
633
|
const skills = readSkillCatalog(process.cwd());
|
|
634
634
|
if (skills.length === 0) return [];
|
|
635
|
-
const response = await apiPost(
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
);
|
|
639
|
-
return response.data
|
|
635
|
+
const response = await apiPost("/api/actions/recommend-skills", {
|
|
636
|
+
actionId,
|
|
637
|
+
skills
|
|
638
|
+
});
|
|
639
|
+
return response.data.recommendations;
|
|
640
640
|
}
|
|
641
641
|
function buildHints(recommendations) {
|
|
642
642
|
if (recommendations.length === 0) {
|
|
@@ -684,9 +684,251 @@ var claimCommand = defineCommand({
|
|
|
684
684
|
}
|
|
685
685
|
});
|
|
686
686
|
|
|
687
|
+
// ../api/src/actions.ts
|
|
688
|
+
import { z as z2 } from "zod";
|
|
689
|
+
var actionStatusSchema = z2.enum(["pending", "in_progress", "completed", "discarded"]);
|
|
690
|
+
var actionPrioritySchema = z2.enum(["urgent", "high", "medium", "low"]);
|
|
691
|
+
var actionRefResolutionStatusSchema = z2.union([actionStatusSchema, z2.enum(["draft", "not_found"])]);
|
|
692
|
+
var actionDocSchema = z2.object({
|
|
693
|
+
_id: z2.string(),
|
|
694
|
+
_creationTime: z2.number(),
|
|
695
|
+
companyId: z2.string(),
|
|
696
|
+
name: z2.string(),
|
|
697
|
+
description: z2.string(),
|
|
698
|
+
status: actionStatusSchema,
|
|
699
|
+
priority: actionPrioritySchema.optional(),
|
|
700
|
+
requiresHuman: z2.boolean().optional(),
|
|
701
|
+
tags: z2.array(z2.string()).optional(),
|
|
702
|
+
createdByType: z2.enum(["user", "chat", "schedule"]),
|
|
703
|
+
createdByUserId: z2.string().optional(),
|
|
704
|
+
createdByChatId: z2.string().optional(),
|
|
705
|
+
createdByScheduleId: z2.string().optional(),
|
|
706
|
+
createdFromTempId: z2.string().optional(),
|
|
707
|
+
scheduledActionTrigger: z2.enum(["scheduled", "manual"]).optional(),
|
|
708
|
+
scheduledActionTriggerChatId: z2.string().optional(),
|
|
709
|
+
scheduledActionTriggerActorType: z2.enum(["user", "api", "system"]).optional(),
|
|
710
|
+
scheduledActionTriggerActorUserId: z2.string().optional(),
|
|
711
|
+
assigneeUserId: z2.string().optional(),
|
|
712
|
+
activeChatId: z2.string().optional(),
|
|
713
|
+
activeClaimedAt: z2.number().optional(),
|
|
714
|
+
completedAt: z2.number().optional(),
|
|
715
|
+
completedByType: z2.enum(["user", "chat"]).optional(),
|
|
716
|
+
completedByChatId: z2.string().optional(),
|
|
717
|
+
completedNote: z2.string().optional(),
|
|
718
|
+
discardedAt: z2.number().optional(),
|
|
719
|
+
discardedReason: z2.string().optional(),
|
|
720
|
+
createdAt: z2.number(),
|
|
721
|
+
updatedAt: z2.number(),
|
|
722
|
+
searchText: z2.string().optional()
|
|
723
|
+
});
|
|
724
|
+
var actionAssigneeSchema = z2.object({
|
|
725
|
+
userId: z2.string(),
|
|
726
|
+
name: z2.string(),
|
|
727
|
+
image: z2.string().optional()
|
|
728
|
+
});
|
|
729
|
+
var actionDepRefSchema = z2.object({
|
|
730
|
+
id: z2.string(),
|
|
731
|
+
name: z2.string(),
|
|
732
|
+
status: actionStatusSchema
|
|
733
|
+
});
|
|
734
|
+
var actionWithMetaSchema = z2.object({
|
|
735
|
+
action: actionDocSchema,
|
|
736
|
+
blockerCount: z2.number(),
|
|
737
|
+
openBlockerCount: z2.number(),
|
|
738
|
+
isBlocked: z2.boolean(),
|
|
739
|
+
openBlockingCount: z2.number(),
|
|
740
|
+
blockers: z2.array(actionDepRefSchema),
|
|
741
|
+
blocking: z2.array(actionDepRefSchema),
|
|
742
|
+
assignee: actionAssigneeSchema.nullable()
|
|
743
|
+
});
|
|
744
|
+
var actionBucketEntrySchema = z2.object({
|
|
745
|
+
id: z2.string(),
|
|
746
|
+
name: z2.string(),
|
|
747
|
+
description: z2.string(),
|
|
748
|
+
status: actionStatusSchema,
|
|
749
|
+
hint: z2.string(),
|
|
750
|
+
blockedBy: z2.array(z2.object({ id: z2.string(), name: z2.string() })).optional(),
|
|
751
|
+
claimedByChat: z2.object({ id: z2.string(), title: z2.string() }).optional(),
|
|
752
|
+
draftStatus: z2.enum(["in-progress", "completing", "discarding", "updating"]).optional()
|
|
753
|
+
});
|
|
754
|
+
var draftActionEntrySchema = z2.object({
|
|
755
|
+
tempId: z2.string(),
|
|
756
|
+
name: z2.string(),
|
|
757
|
+
description: z2.string(),
|
|
758
|
+
tags: z2.array(z2.string()),
|
|
759
|
+
hint: z2.string(),
|
|
760
|
+
draftStatus: z2.literal("creating")
|
|
761
|
+
});
|
|
762
|
+
var actionBucketsSchema = z2.object({
|
|
763
|
+
claimable: z2.array(actionBucketEntrySchema),
|
|
764
|
+
myClaims: z2.array(actionBucketEntrySchema),
|
|
765
|
+
blocked: z2.array(actionBucketEntrySchema),
|
|
766
|
+
claimedByOthers: z2.array(actionBucketEntrySchema),
|
|
767
|
+
completed: z2.array(actionBucketEntrySchema),
|
|
768
|
+
discarded: z2.array(actionBucketEntrySchema),
|
|
769
|
+
draftCreates: z2.array(draftActionEntrySchema)
|
|
770
|
+
});
|
|
771
|
+
var actionRefStatusResultSchema = z2.object({
|
|
772
|
+
ref: z2.string(),
|
|
773
|
+
status: actionRefResolutionStatusSchema,
|
|
774
|
+
actionId: z2.string().optional(),
|
|
775
|
+
name: z2.string().optional(),
|
|
776
|
+
hint: z2.string().optional()
|
|
777
|
+
});
|
|
778
|
+
var actionDetailSchema = z2.object({
|
|
779
|
+
action: actionDocSchema,
|
|
780
|
+
blockers: z2.array(actionDocSchema),
|
|
781
|
+
blocked: z2.array(actionDocSchema),
|
|
782
|
+
activeChat: z2.object({ _id: z2.string(), title: z2.string() }).nullable()
|
|
783
|
+
});
|
|
784
|
+
var actionDraftOpKindSchema = z2.enum(["create", "update", "complete", "discard", "link", "unlink"]);
|
|
785
|
+
var chatActionDraftOpViewSchema = z2.object({
|
|
786
|
+
kind: actionDraftOpKindSchema,
|
|
787
|
+
targetName: z2.string(),
|
|
788
|
+
targetActionId: z2.string().optional(),
|
|
789
|
+
tempId: z2.string().optional(),
|
|
790
|
+
tags: z2.array(z2.string()).optional(),
|
|
791
|
+
reason: z2.string().optional(),
|
|
792
|
+
note: z2.string().optional(),
|
|
793
|
+
name: z2.string().optional(),
|
|
794
|
+
description: z2.string().optional(),
|
|
795
|
+
blockerName: z2.string().optional(),
|
|
796
|
+
blockerActionId: z2.string().optional(),
|
|
797
|
+
blockerTempId: z2.string().optional()
|
|
798
|
+
});
|
|
799
|
+
var chatDraftViewSchema = z2.object({
|
|
800
|
+
status: z2.enum(["active", "publishing", "discarded", "applied", "none"]),
|
|
801
|
+
count: z2.number(),
|
|
802
|
+
ops: z2.array(chatActionDraftOpViewSchema),
|
|
803
|
+
warnings: z2.array(z2.object({ tempId: z2.string(), name: z2.string() }))
|
|
804
|
+
});
|
|
805
|
+
var actionsClaimDataSchema = z2.object({
|
|
806
|
+
id: z2.string(),
|
|
807
|
+
name: z2.string(),
|
|
808
|
+
description: z2.string(),
|
|
809
|
+
tags: z2.array(z2.string())
|
|
810
|
+
});
|
|
811
|
+
var skillRecommendationSchema = z2.object({
|
|
812
|
+
name: z2.string(),
|
|
813
|
+
reason: z2.string()
|
|
814
|
+
});
|
|
815
|
+
var removeDraftOpTargetSchema = z2.discriminatedUnion("kind", [
|
|
816
|
+
z2.object({ kind: z2.literal("tempId"), tempId: z2.string() }),
|
|
817
|
+
z2.object({
|
|
818
|
+
kind: z2.literal("actionId"),
|
|
819
|
+
actionId: z2.string(),
|
|
820
|
+
opKind: z2.enum(["update", "complete", "discard"])
|
|
821
|
+
})
|
|
822
|
+
]);
|
|
823
|
+
function okResponse(data) {
|
|
824
|
+
return z2.object({ ok: z2.literal(true), data });
|
|
825
|
+
}
|
|
826
|
+
function okOnlySchema() {
|
|
827
|
+
return z2.object({ ok: z2.literal(true) });
|
|
828
|
+
}
|
|
829
|
+
var actionsCreateRequestSchema = z2.object({
|
|
830
|
+
chatId: z2.string(),
|
|
831
|
+
tempId: z2.string(),
|
|
832
|
+
name: z2.string().min(1),
|
|
833
|
+
description: z2.string(),
|
|
834
|
+
tags: z2.array(z2.string()).optional(),
|
|
835
|
+
priority: actionPrioritySchema.optional()
|
|
836
|
+
});
|
|
837
|
+
var actionsCreateResponseSchema = okResponse(z2.object({ tempId: z2.string() }));
|
|
838
|
+
var actionsGetRequestSchema = z2.object({ actionId: z2.string().min(1) });
|
|
839
|
+
var actionsGetResponseSchema = okResponse(actionDetailSchema.nullable());
|
|
840
|
+
var actionsListRequestSchema = z2.object({
|
|
841
|
+
chatId: z2.string().optional(),
|
|
842
|
+
status: actionStatusSchema.optional(),
|
|
843
|
+
bucketed: z2.boolean().optional(),
|
|
844
|
+
q: z2.string().optional(),
|
|
845
|
+
sort: z2.enum(["recent", "priority"]).optional()
|
|
846
|
+
});
|
|
847
|
+
var actionsListResponseSchema = okResponse(z2.union([actionBucketsSchema, z2.array(actionWithMetaSchema)]));
|
|
848
|
+
var actionsStatusRequestSchema = z2.object({
|
|
849
|
+
refs: z2.array(z2.string().min(1)).max(50),
|
|
850
|
+
chatId: z2.string().min(1).optional()
|
|
851
|
+
});
|
|
852
|
+
var actionsStatusResponseSchema = okResponse(z2.array(actionRefStatusResultSchema));
|
|
853
|
+
var actionsUpdateRequestSchema = z2.object({
|
|
854
|
+
chatId: z2.string(),
|
|
855
|
+
actionId: z2.string(),
|
|
856
|
+
name: z2.string().optional(),
|
|
857
|
+
description: z2.string().optional(),
|
|
858
|
+
tags: z2.array(z2.string()).optional(),
|
|
859
|
+
priority: actionPrioritySchema.nullable().optional()
|
|
860
|
+
});
|
|
861
|
+
var actionsUpdateResponseSchema = okOnlySchema();
|
|
862
|
+
var ACTION_COMPLETE_NOTE_MIN = 20;
|
|
863
|
+
var actionsCompleteNoteMessage = `A completion note (\u2265${ACTION_COMPLETE_NOTE_MIN} chars) describing what was done is required: what changed, where, and the outcome.`;
|
|
864
|
+
var actionsCompleteRequestSchema = z2.object({
|
|
865
|
+
chatId: z2.string(),
|
|
866
|
+
actionRef: z2.string().min(1, "actionRef is required"),
|
|
867
|
+
note: z2.string().optional()
|
|
868
|
+
}).transform((body) => ({ ...body, note: (body.note ?? "").trim() })).refine((body) => body.note.length >= ACTION_COMPLETE_NOTE_MIN, {
|
|
869
|
+
message: actionsCompleteNoteMessage,
|
|
870
|
+
path: ["note"]
|
|
871
|
+
});
|
|
872
|
+
var actionsCompleteResponseSchema = okOnlySchema();
|
|
873
|
+
var actionsDiscardRequestSchema = z2.object({
|
|
874
|
+
chatId: z2.string(),
|
|
875
|
+
actionId: z2.string(),
|
|
876
|
+
reason: z2.string().optional()
|
|
877
|
+
});
|
|
878
|
+
var actionsDiscardResponseSchema = okOnlySchema();
|
|
879
|
+
var actionsLinkRequestSchema = z2.object({
|
|
880
|
+
chatId: z2.string(),
|
|
881
|
+
blockerRef: z2.string(),
|
|
882
|
+
blockedRef: z2.string()
|
|
883
|
+
});
|
|
884
|
+
var actionsLinkResponseSchema = okOnlySchema();
|
|
885
|
+
var actionsUnlinkRequestSchema = z2.object({
|
|
886
|
+
chatId: z2.string(),
|
|
887
|
+
blockerId: z2.string(),
|
|
888
|
+
blockedId: z2.string()
|
|
889
|
+
});
|
|
890
|
+
var actionsUnlinkResponseSchema = okOnlySchema();
|
|
891
|
+
var actionsClaimRequestSchema = z2.object({
|
|
892
|
+
actionId: z2.string(),
|
|
893
|
+
chatId: z2.string()
|
|
894
|
+
});
|
|
895
|
+
var actionsClaimResponseSchema = okResponse(actionsClaimDataSchema.nullable());
|
|
896
|
+
var actionsReleaseRequestSchema = z2.object({
|
|
897
|
+
actionId: z2.string(),
|
|
898
|
+
chatId: z2.string()
|
|
899
|
+
});
|
|
900
|
+
var actionsReleaseResponseSchema = okOnlySchema();
|
|
901
|
+
var actionsRecommendSkillsRequestSchema = z2.object({
|
|
902
|
+
actionId: z2.string().min(1),
|
|
903
|
+
// Bounds track what the CLI actually sends (descriptions truncated to ~600 chars); they
|
|
904
|
+
// cap the prompt size a direct API-key caller can push into the billed LLM call.
|
|
905
|
+
skills: z2.array(
|
|
906
|
+
z2.object({
|
|
907
|
+
name: z2.string().min(1).max(120),
|
|
908
|
+
description: z2.string().max(800)
|
|
909
|
+
})
|
|
910
|
+
).max(80)
|
|
911
|
+
});
|
|
912
|
+
var actionsRecommendSkillsResponseSchema = okResponse(
|
|
913
|
+
z2.object({ recommendations: z2.array(skillRecommendationSchema) })
|
|
914
|
+
);
|
|
915
|
+
var actionsLogRequestSchema = z2.object({
|
|
916
|
+
fromMs: z2.number(),
|
|
917
|
+
toMs: z2.number()
|
|
918
|
+
});
|
|
919
|
+
var actionsLogResponseSchema = okResponse(z2.array(actionWithMetaSchema));
|
|
920
|
+
var actionsDraftRequestSchema = z2.object({ chatId: z2.string() });
|
|
921
|
+
var actionsDraftResponseSchema = okResponse(chatDraftViewSchema);
|
|
922
|
+
var actionsDraftClearRequestSchema = z2.object({ chatId: z2.string() });
|
|
923
|
+
var actionsDraftClearResponseSchema = okOnlySchema();
|
|
924
|
+
var actionsRemoveDraftOpRequestSchema = z2.object({
|
|
925
|
+
chatId: z2.string(),
|
|
926
|
+
target: removeDraftOpTargetSchema
|
|
927
|
+
});
|
|
928
|
+
var actionsRemoveDraftOpResponseSchema = okOnlySchema();
|
|
929
|
+
|
|
687
930
|
// src/commands/actions/complete.ts
|
|
688
931
|
import { defineCommand as defineCommand2 } from "citty";
|
|
689
|
-
var COMPLETE_NOTE_MIN = 20;
|
|
690
932
|
registerSchema({
|
|
691
933
|
command: "actions.complete",
|
|
692
934
|
description: "Stage completion of an action (it was DONE). Accepts a real action ID (must be claimed) or a temp ID from the same draft. The action becomes completed when the chat is published. --note is REQUIRED and must describe what you actually did to resolve it (what changed, where, and the outcome) \u2014 it is the client-facing record surfaced by `baker actions log`. Do NOT use this to drop an action you no longer want \u2014 to remove a staged op use `actions draft remove`, to close an unwanted published action use `actions discard`.",
|
|
@@ -723,9 +965,9 @@ var completeCommand = defineCommand2({
|
|
|
723
965
|
validateConvexId(id);
|
|
724
966
|
}
|
|
725
967
|
const note = args.note?.trim() ?? "";
|
|
726
|
-
if (note.length <
|
|
968
|
+
if (note.length < ACTION_COMPLETE_NOTE_MIN) {
|
|
727
969
|
failValidation(
|
|
728
|
-
`--note is required and must describe what you did (\u2265${
|
|
970
|
+
`--note is required and must describe what you did (\u2265${ACTION_COMPLETE_NOTE_MIN} chars): what changed, where, and the outcome. This becomes the client-facing record surfaced by \`baker actions log\`.`
|
|
729
971
|
);
|
|
730
972
|
}
|
|
731
973
|
const chatId = requireChatId();
|
|
@@ -861,7 +1103,7 @@ var discardCommand = defineCommand4({
|
|
|
861
1103
|
|
|
862
1104
|
// src/commands/actions/draft.ts
|
|
863
1105
|
import { defineCommand as defineCommand5 } from "citty";
|
|
864
|
-
var REMOVE_OP_KINDS = ["update", "complete", "discard"
|
|
1106
|
+
var REMOVE_OP_KINDS = ["update", "complete", "discard"];
|
|
865
1107
|
registerSchema({
|
|
866
1108
|
command: "actions.draft.list",
|
|
867
1109
|
description: "Review the action ops staged in THIS chat's draft before publish (creates/updates/completes/discards/links). Staged ops are invisible to `actions list`/`status` until the chat publishes \u2014 use this to verify what will apply and catch duplicates.",
|
|
@@ -869,15 +1111,14 @@ registerSchema({
|
|
|
869
1111
|
});
|
|
870
1112
|
registerSchema({
|
|
871
1113
|
command: "actions.draft.remove",
|
|
872
|
-
description: "Drop a single staged action op from this chat's draft before publish. For a tempId, removing the create cascades into its complete/link
|
|
1114
|
+
description: "Drop a single staged action op from this chat's draft before publish. For a tempId, removing the create cascades into its complete/link ops. For a real action ID, pass --op to say which op to drop. Use this to UNDO a staged op \u2014 never stage `complete` to delete an action.",
|
|
873
1115
|
args: {
|
|
874
1116
|
ref: { type: "string", description: "tempId (temp_*) or real action ID to drop from the draft", required: true },
|
|
875
1117
|
op: {
|
|
876
1118
|
type: "string",
|
|
877
|
-
description: "Required for real action IDs: which op to drop (update|complete|discard
|
|
1119
|
+
description: "Required for real action IDs: which op to drop (update|complete|discard)",
|
|
878
1120
|
required: false
|
|
879
|
-
}
|
|
880
|
-
"tag-slug": { type: "string", description: "Tag slug (only for --op tagAdd|tagRemove)", required: false }
|
|
1121
|
+
}
|
|
881
1122
|
}
|
|
882
1123
|
});
|
|
883
1124
|
registerSchema({
|
|
@@ -909,10 +1150,9 @@ var removeCommand = defineCommand5({
|
|
|
909
1150
|
ref: { type: "positional", description: "tempId or real action ID", required: false },
|
|
910
1151
|
op: {
|
|
911
1152
|
type: "string",
|
|
912
|
-
description: "Op kind for real IDs: update|complete|discard
|
|
1153
|
+
description: "Op kind for real IDs: update|complete|discard",
|
|
913
1154
|
required: false
|
|
914
|
-
}
|
|
915
|
-
"tag-slug": { type: "string", description: "Tag slug (for tagAdd|tagRemove)", required: false }
|
|
1155
|
+
}
|
|
916
1156
|
},
|
|
917
1157
|
run: async ({ args }) => {
|
|
918
1158
|
try {
|
|
@@ -936,10 +1176,9 @@ var removeCommand = defineCommand5({
|
|
|
936
1176
|
`Removing a staged op for a real action ID requires --op (one of: ${REMOVE_OP_KINDS.join("|")}).`
|
|
937
1177
|
);
|
|
938
1178
|
}
|
|
939
|
-
const tagSlug = args["tag-slug"];
|
|
940
1179
|
await apiPost("/api/actions/draft-op/remove", {
|
|
941
1180
|
chatId,
|
|
942
|
-
target: { kind: "actionId", actionId: ref, opKind: op
|
|
1181
|
+
target: { kind: "actionId", actionId: ref, opKind: op }
|
|
943
1182
|
});
|
|
944
1183
|
writeJson({ ok: true, data: { removed: ref, kind: "actionId", op } });
|
|
945
1184
|
} catch (err) {
|
|
@@ -8562,27 +8801,27 @@ import path5 from "path";
|
|
|
8562
8801
|
import { defineCommand as defineCommand82 } from "citty";
|
|
8563
8802
|
|
|
8564
8803
|
// src/engine/scaffold/staticAd.ts
|
|
8565
|
-
import { z as
|
|
8804
|
+
import { z as z3 } from "zod";
|
|
8566
8805
|
var GEN_ASPECT_RATIOS = /* @__PURE__ */ new Set(["1:1", "4:5", "9:16", "16:9", "4:3", "3:4", "2:3", "3:2", "21:9"]);
|
|
8567
8806
|
var DEFAULT_ASPECT_RATIO = "9:16";
|
|
8568
|
-
var Blueprint =
|
|
8569
|
-
meta:
|
|
8570
|
-
text_content:
|
|
8807
|
+
var Blueprint = z3.object({
|
|
8808
|
+
meta: z3.object({ estimated_aspect_ratio: z3.string().optional() }).loose().optional(),
|
|
8809
|
+
text_content: z3.array(z3.object({ text: z3.string().optional() }).loose()).optional()
|
|
8571
8810
|
}).loose();
|
|
8572
|
-
var ElementLocator =
|
|
8573
|
-
collection:
|
|
8574
|
-
index:
|
|
8811
|
+
var ElementLocator = z3.object({
|
|
8812
|
+
collection: z3.enum(["subjects", "people", "brands_logos"]),
|
|
8813
|
+
index: z3.number().int().nonnegative()
|
|
8575
8814
|
}).loose();
|
|
8576
|
-
var MainElement =
|
|
8815
|
+
var MainElement = z3.object({
|
|
8577
8816
|
// logo | product | person | animal | badge | other
|
|
8578
|
-
type:
|
|
8579
|
-
label:
|
|
8580
|
-
description:
|
|
8581
|
-
expression:
|
|
8582
|
-
reason:
|
|
8817
|
+
type: z3.string(),
|
|
8818
|
+
label: z3.string().optional(),
|
|
8819
|
+
description: z3.string().optional(),
|
|
8820
|
+
expression: z3.string().nullable().optional(),
|
|
8821
|
+
reason: z3.string().optional(),
|
|
8583
8822
|
locator: ElementLocator.optional()
|
|
8584
8823
|
}).loose();
|
|
8585
|
-
var MainElements =
|
|
8824
|
+
var MainElements = z3.array(MainElement);
|
|
8586
8825
|
function sanitizeId(raw, fallback) {
|
|
8587
8826
|
const id = raw.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
8588
8827
|
return /^[a-z]/.test(id) ? id : `${fallback}_${id}`.replace(/_+$/g, "") || fallback;
|
|
@@ -9077,7 +9316,7 @@ import { toCardinal as nwKo } from "n2words/ko-KR";
|
|
|
9077
9316
|
import { toCardinal as nwNl } from "n2words/nl-NL";
|
|
9078
9317
|
import { toCardinal as nwPl } from "n2words/pl-PL";
|
|
9079
9318
|
import { toCardinal as nwPt } from "n2words/pt-PT";
|
|
9080
|
-
import { z as
|
|
9319
|
+
import { z as z4 } from "zod";
|
|
9081
9320
|
|
|
9082
9321
|
// src/engine/scaffold/lib/shoot-modes.ts
|
|
9083
9322
|
var SHOOT_MODES = [
|
|
@@ -9334,49 +9573,49 @@ function trimArgs(durationS, offsetS = 0) {
|
|
|
9334
9573
|
"{{out.video}}"
|
|
9335
9574
|
];
|
|
9336
9575
|
}
|
|
9337
|
-
var FrameAsset =
|
|
9338
|
-
var DialogueLine =
|
|
9339
|
-
speaker:
|
|
9340
|
-
line:
|
|
9576
|
+
var FrameAsset = z4.object({ url: z4.string().optional() }).loose().optional();
|
|
9577
|
+
var DialogueLine = z4.object({
|
|
9578
|
+
speaker: z4.string().optional(),
|
|
9579
|
+
line: z4.string().optional(),
|
|
9341
9580
|
// Absolute seconds on the source timeline (the deconstruct emits both).
|
|
9342
|
-
start_s:
|
|
9343
|
-
end_s:
|
|
9344
|
-
delivery:
|
|
9345
|
-
voice_description:
|
|
9581
|
+
start_s: z4.number().optional(),
|
|
9582
|
+
end_s: z4.number().optional(),
|
|
9583
|
+
delivery: z4.string().optional(),
|
|
9584
|
+
voice_description: z4.string().optional()
|
|
9346
9585
|
}).loose();
|
|
9347
|
-
var Sfx =
|
|
9348
|
-
at_s:
|
|
9349
|
-
duration_s:
|
|
9350
|
-
sound_effect_prompt:
|
|
9351
|
-
description:
|
|
9586
|
+
var Sfx = z4.object({
|
|
9587
|
+
at_s: z4.number().optional(),
|
|
9588
|
+
duration_s: z4.number().optional(),
|
|
9589
|
+
sound_effect_prompt: z4.string().optional(),
|
|
9590
|
+
description: z4.string().optional()
|
|
9352
9591
|
}).loose();
|
|
9353
|
-
var CompositionRegion =
|
|
9592
|
+
var CompositionRegion = z4.object({
|
|
9354
9593
|
// full | top | bottom | left | right | inset
|
|
9355
|
-
panel:
|
|
9594
|
+
panel: z4.string().optional(),
|
|
9356
9595
|
// 9-grid anchor for an `inset` presenter box.
|
|
9357
|
-
position:
|
|
9358
|
-
is_presenter:
|
|
9596
|
+
position: z4.string().optional(),
|
|
9597
|
+
is_presenter: z4.boolean().optional(),
|
|
9359
9598
|
// The cast id shown/speaking in this region (routes lip-sync + element refs).
|
|
9360
|
-
cast_ref:
|
|
9361
|
-
summary:
|
|
9362
|
-
frame_prompt:
|
|
9363
|
-
motion_prompt:
|
|
9599
|
+
cast_ref: z4.string().optional(),
|
|
9600
|
+
summary: z4.string().optional(),
|
|
9601
|
+
frame_prompt: z4.string().optional(),
|
|
9602
|
+
motion_prompt: z4.string().optional()
|
|
9364
9603
|
}).loose();
|
|
9365
|
-
var SceneComposition =
|
|
9604
|
+
var SceneComposition = z4.object({
|
|
9366
9605
|
// full_frame (default) | split_screen | pip | keyed_overlay
|
|
9367
|
-
layout:
|
|
9606
|
+
layout: z4.string().optional(),
|
|
9368
9607
|
// split_screen only: vertical (top/bottom) | horizontal (left/right).
|
|
9369
|
-
split_axis:
|
|
9370
|
-
regions:
|
|
9608
|
+
split_axis: z4.string().optional(),
|
|
9609
|
+
regions: z4.array(CompositionRegion).optional()
|
|
9371
9610
|
}).loose();
|
|
9372
|
-
var CameraMotion =
|
|
9373
|
-
var TranscriptWord =
|
|
9374
|
-
var Scene =
|
|
9375
|
-
start_s:
|
|
9376
|
-
end_s:
|
|
9377
|
-
duration_s:
|
|
9378
|
-
summary:
|
|
9379
|
-
action_detail:
|
|
9611
|
+
var CameraMotion = z4.object({ movement: z4.string().optional(), detail: z4.string().optional() }).loose();
|
|
9612
|
+
var TranscriptWord = z4.object({ text: z4.string().optional() }).loose();
|
|
9613
|
+
var Scene = z4.object({
|
|
9614
|
+
start_s: z4.number().optional(),
|
|
9615
|
+
end_s: z4.number().optional(),
|
|
9616
|
+
duration_s: z4.number().optional(),
|
|
9617
|
+
summary: z4.string().optional(),
|
|
9618
|
+
action_detail: z4.string().optional(),
|
|
9380
9619
|
// The scene's spatial layout. Absent/full_frame ⇒ one uncut shot (default path).
|
|
9381
9620
|
// A layered layout (split_screen/pip/keyed_overlay) with regions ⇒ the scaffold
|
|
9382
9621
|
// builds one clip per region and stacks/overlays them into the scene picture.
|
|
@@ -9384,77 +9623,77 @@ var Scene = z3.object({
|
|
|
9384
9623
|
// The capture "look" for this scene — selected from the ad-native shoot-mode
|
|
9385
9624
|
// grammar (see lib/shoot-modes.ts). When absent the scaffold auto-derives a
|
|
9386
9625
|
// UGC/product mode; a human can override per scene by setting this.
|
|
9387
|
-
shoot_mode:
|
|
9626
|
+
shoot_mode: z4.string().optional(),
|
|
9388
9627
|
// Diegetic ambient the clip's native audio should carry (no music). When
|
|
9389
9628
|
// absent the scene falls back to its shoot mode's default ambience.
|
|
9390
|
-
ambient:
|
|
9629
|
+
ambient: z4.string().optional(),
|
|
9391
9630
|
camera_motion: CameraMotion.optional(),
|
|
9392
|
-
start_frame_prompt:
|
|
9393
|
-
end_frame_prompt:
|
|
9394
|
-
motion_prompt:
|
|
9631
|
+
start_frame_prompt: z4.string().optional(),
|
|
9632
|
+
end_frame_prompt: z4.string().optional(),
|
|
9633
|
+
motion_prompt: z4.string().optional(),
|
|
9395
9634
|
// The scene's role in the ad's persuasion arc (DECON-supplied); drives the
|
|
9396
9635
|
// script re-craft checklist. Inferred from position when absent.
|
|
9397
|
-
narrative_role:
|
|
9636
|
+
narrative_role: z4.string().optional(),
|
|
9398
9637
|
// DECON-supplied on the HOOK scene: the engineered physical/emotional state that
|
|
9399
9638
|
// makes the first frame stop the scroll (sweaty/breathless/urgent …). Injected
|
|
9400
9639
|
// into the hook's start-frame description so the generator renders that state,
|
|
9401
9640
|
// not a calm influencer (CCA-11).
|
|
9402
|
-
hook_mechanic:
|
|
9641
|
+
hook_mechanic: z4.object({ mechanic: z4.string().optional(), why_it_stops_scroll: z4.string().optional() }).loose().optional(),
|
|
9403
9642
|
// DECON-supplied per-scene location (so a gym hook isn't flattened to "home").
|
|
9404
|
-
scene_setting:
|
|
9643
|
+
scene_setting: z4.string().optional(),
|
|
9405
9644
|
// How this scene cuts to the next (DECON-supplied). A recognized non-cut type
|
|
9406
9645
|
// (fade/whip/zoom/dissolve/swipe) is reproduced as an ffmpeg xfade at the
|
|
9407
9646
|
// boundary; cut/match_cut/none/other stay hard cuts. The last scene's value is
|
|
9408
9647
|
// ignored (nothing follows it).
|
|
9409
|
-
transition_out:
|
|
9410
|
-
dialogue:
|
|
9411
|
-
sfx:
|
|
9412
|
-
overlays:
|
|
9413
|
-
floating_elements:
|
|
9414
|
-
transcript_slice:
|
|
9648
|
+
transition_out: z4.object({ type: z4.string().optional(), description: z4.string().optional() }).loose().optional(),
|
|
9649
|
+
dialogue: z4.array(DialogueLine).optional(),
|
|
9650
|
+
sfx: z4.array(Sfx).optional(),
|
|
9651
|
+
overlays: z4.array(z4.unknown()).optional(),
|
|
9652
|
+
floating_elements: z4.array(z4.unknown()).optional(),
|
|
9653
|
+
transcript_slice: z4.array(TranscriptWord).optional(),
|
|
9415
9654
|
start_frame_asset: FrameAsset,
|
|
9416
9655
|
end_frame_asset: FrameAsset,
|
|
9417
9656
|
// DECON-supplied: true when this scene is a length-split CONTINUATION of the
|
|
9418
9657
|
// previous one (the SAME physical shot, broken up only because it exceeded the
|
|
9419
9658
|
// clip ceiling). The scaffold then shares the splice keyframe — this scene's
|
|
9420
9659
|
// start frame IS the previous scene's end frame — so the join is seamless.
|
|
9421
|
-
continues_previous:
|
|
9660
|
+
continues_previous: z4.boolean().optional()
|
|
9422
9661
|
}).loose();
|
|
9423
|
-
var VideoBlueprint =
|
|
9424
|
-
source:
|
|
9425
|
-
global:
|
|
9426
|
-
music:
|
|
9427
|
-
present:
|
|
9428
|
-
music_prompt:
|
|
9662
|
+
var VideoBlueprint = z4.object({
|
|
9663
|
+
source: z4.object({ aspect_ratio: z4.string().optional(), duration_s: z4.number().optional() }).loose().optional(),
|
|
9664
|
+
global: z4.object({
|
|
9665
|
+
music: z4.object({
|
|
9666
|
+
present: z4.boolean().optional(),
|
|
9667
|
+
music_prompt: z4.string().optional(),
|
|
9429
9668
|
// Absolute second the music enters in the reference (the bed often
|
|
9430
9669
|
// kicks in mid-ad, after the hook). We start the regenerated track here
|
|
9431
9670
|
// instead of at 0 so the timing matches.
|
|
9432
|
-
starts_at_s:
|
|
9671
|
+
starts_at_s: z4.number().optional(),
|
|
9433
9672
|
// Populated by the deconstruct when AudD (Shazam-style) recognizes the
|
|
9434
9673
|
// reference track. We never reuse it — only style the regenerated bed.
|
|
9435
|
-
identified_track:
|
|
9674
|
+
identified_track: z4.object({ title: z4.string().optional(), artist: z4.string().optional() }).loose().nullish()
|
|
9436
9675
|
}).loose().optional(),
|
|
9437
|
-
cast:
|
|
9438
|
-
|
|
9439
|
-
id:
|
|
9440
|
-
description:
|
|
9676
|
+
cast: z4.array(
|
|
9677
|
+
z4.object({
|
|
9678
|
+
id: z4.string().optional(),
|
|
9679
|
+
description: z4.string().optional(),
|
|
9441
9680
|
// The deconstruct's note on the target-market localization (e.g. "native
|
|
9442
9681
|
// French speaker") — read to derive the spoken-track language code.
|
|
9443
|
-
market_localization_note:
|
|
9682
|
+
market_localization_note: z4.string().optional()
|
|
9444
9683
|
}).loose()
|
|
9445
9684
|
).optional(),
|
|
9446
|
-
voiceover:
|
|
9685
|
+
voiceover: z4.object({
|
|
9447
9686
|
// on_camera | mixed → mouths are on screen (lip-sync candidates);
|
|
9448
9687
|
// voiceover | none → narration over the picture (no lip-sync).
|
|
9449
|
-
mode:
|
|
9450
|
-
voice_description:
|
|
9451
|
-
persona:
|
|
9688
|
+
mode: z4.string().optional(),
|
|
9689
|
+
voice_description: z4.string().optional(),
|
|
9690
|
+
persona: z4.string().optional()
|
|
9452
9691
|
}).loose().optional(),
|
|
9453
9692
|
// Visual palette — read only to colour a clean brand-card/CTA plate (the
|
|
9454
9693
|
// first hex is the dominant brand colour); never to drive frame generation.
|
|
9455
|
-
style:
|
|
9694
|
+
style: z4.object({ palette: z4.array(z4.object({ hex: z4.string().optional() }).loose()).optional() }).loose().optional()
|
|
9456
9695
|
}).loose().optional(),
|
|
9457
|
-
scenes:
|
|
9696
|
+
scenes: z4.array(Scene).min(1)
|
|
9458
9697
|
}).loose();
|
|
9459
9698
|
function injectHookPhysicality(blueprint) {
|
|
9460
9699
|
for (const scene of blueprint.scenes) {
|
|
@@ -9464,26 +9703,26 @@ function injectHookPhysicality(blueprint) {
|
|
|
9464
9703
|
scene.start_frame_prompt = `${prompt} The subject's physical state IS the scroll-stopper \u2014 render it explicitly, not a calm pose: ${why}.`;
|
|
9465
9704
|
}
|
|
9466
9705
|
}
|
|
9467
|
-
var AppearsItem =
|
|
9468
|
-
var RecurringElement =
|
|
9706
|
+
var AppearsItem = z4.union([z4.number(), z4.object({ scene: z4.number(), edge: z4.string().optional() }).loose()]);
|
|
9707
|
+
var RecurringElement = z4.object({
|
|
9469
9708
|
// person | animal | product | logo | badge | other
|
|
9470
|
-
type:
|
|
9471
|
-
label:
|
|
9472
|
-
description:
|
|
9473
|
-
expression:
|
|
9709
|
+
type: z4.string(),
|
|
9710
|
+
label: z4.string().optional(),
|
|
9711
|
+
description: z4.string().optional(),
|
|
9712
|
+
expression: z4.string().nullable().optional(),
|
|
9474
9713
|
// When the element maps to a global cast entry, its stable id (for annotation).
|
|
9475
|
-
cast_id:
|
|
9714
|
+
cast_id: z4.string().nullable().optional(),
|
|
9476
9715
|
// The label of another element that is the SAME individual as this one, shown
|
|
9477
9716
|
// in a DIFFERENT wardrobe/persona/state (e.g. one creator playing skeptic in a
|
|
9478
9717
|
// pink shirt and believer in a white shirt). Each look gets its own reference
|
|
9479
9718
|
// slot, but the face/identity must stay identical across them.
|
|
9480
|
-
same_as:
|
|
9719
|
+
same_as: z4.string().nullable().optional(),
|
|
9481
9720
|
// Scenes the element appears in. Either a bare list of scene indices (both
|
|
9482
9721
|
// edges) or per-{scene,edge} entries. Both forms are accepted and merged.
|
|
9483
|
-
scenes:
|
|
9484
|
-
appears_in:
|
|
9722
|
+
scenes: z4.array(z4.number()).optional(),
|
|
9723
|
+
appears_in: z4.array(AppearsItem).optional()
|
|
9485
9724
|
}).loose();
|
|
9486
|
-
var RecurringElements =
|
|
9725
|
+
var RecurringElements = z4.array(RecurringElement);
|
|
9487
9726
|
function sanitizeId2(raw, fallback) {
|
|
9488
9727
|
const id = raw.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
9489
9728
|
return /^[a-z]/.test(id) ? id : `${fallback}_${id}`.replace(/_+$/g, "") || fallback;
|
|
@@ -10946,25 +11185,25 @@ function buildSfxMusic(blueprint, nodes) {
|
|
|
10946
11185
|
}
|
|
10947
11186
|
return tracks;
|
|
10948
11187
|
}
|
|
10949
|
-
var OverlayStyle =
|
|
10950
|
-
var Overlay =
|
|
10951
|
-
text:
|
|
10952
|
-
appears_at_s:
|
|
10953
|
-
duration_s:
|
|
10954
|
-
position:
|
|
10955
|
-
role:
|
|
10956
|
-
animation:
|
|
10957
|
-
animation_detail:
|
|
11188
|
+
var OverlayStyle = z4.object({ color_hex: z4.string().optional(), background: z4.string().optional(), size: z4.string().optional() }).loose();
|
|
11189
|
+
var Overlay = z4.object({
|
|
11190
|
+
text: z4.string().optional(),
|
|
11191
|
+
appears_at_s: z4.number().optional(),
|
|
11192
|
+
duration_s: z4.number().optional(),
|
|
11193
|
+
position: z4.string().optional(),
|
|
11194
|
+
role: z4.string().optional(),
|
|
11195
|
+
animation: z4.string().optional(),
|
|
11196
|
+
animation_detail: z4.string().optional(),
|
|
10958
11197
|
style: OverlayStyle.optional()
|
|
10959
11198
|
}).loose();
|
|
10960
|
-
var FloatingElement =
|
|
10961
|
-
kind:
|
|
10962
|
-
description:
|
|
10963
|
-
brand_name:
|
|
10964
|
-
what_it_represents:
|
|
10965
|
-
appears_at_s:
|
|
10966
|
-
duration_s:
|
|
10967
|
-
position:
|
|
11199
|
+
var FloatingElement = z4.object({
|
|
11200
|
+
kind: z4.string().optional(),
|
|
11201
|
+
description: z4.string().optional(),
|
|
11202
|
+
brand_name: z4.string().nullish(),
|
|
11203
|
+
what_it_represents: z4.string().optional(),
|
|
11204
|
+
appears_at_s: z4.number().optional(),
|
|
11205
|
+
duration_s: z4.number().optional(),
|
|
11206
|
+
position: z4.string().optional()
|
|
10968
11207
|
}).loose();
|
|
10969
11208
|
function escapeHtml(s) {
|
|
10970
11209
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -10996,7 +11235,7 @@ function positionClass(position) {
|
|
|
10996
11235
|
function collectCaptions(blueprint) {
|
|
10997
11236
|
return blueprint.scenes.flatMap((scene) => {
|
|
10998
11237
|
const sceneStart = scene.start_s ?? 0;
|
|
10999
|
-
const overlays =
|
|
11238
|
+
const overlays = z4.array(Overlay).safeParse(scene.overlays ?? []);
|
|
11000
11239
|
return overlays.success ? overlays.data.filter((ov) => Boolean(ov.text?.trim())).map((ov) => {
|
|
11001
11240
|
const at = ov.appears_at_s ?? sceneStart;
|
|
11002
11241
|
return { text: ov.text.trim(), at, end: at + (ov.duration_s ?? 2.5), ov };
|
|
@@ -11105,7 +11344,7 @@ function buildOverlayHtml(input) {
|
|
|
11105
11344
|
if (ovParts.length > 0) blocks.push(ovParts.join("\n"));
|
|
11106
11345
|
for (const scene of blueprint.scenes) {
|
|
11107
11346
|
const sceneStart = scene.start_s ?? 0;
|
|
11108
|
-
const floats =
|
|
11347
|
+
const floats = z4.array(FloatingElement).safeParse(scene.floating_elements ?? []);
|
|
11109
11348
|
const parts = (floats.success ? floats.data.map((fe) => floatingStub(fe, sceneStart)) : []).filter(Boolean);
|
|
11110
11349
|
const pip = uiPipStub(scene);
|
|
11111
11350
|
if (pip) parts.push(pip);
|
|
@@ -11362,8 +11601,8 @@ function buildMotionBoard(blueprint) {
|
|
|
11362
11601
|
const end_s = scene.end_s ?? start_s + sceneDurationS(scene);
|
|
11363
11602
|
cursor = end_s;
|
|
11364
11603
|
const spoken = sceneSpokenText(scene);
|
|
11365
|
-
const overlays =
|
|
11366
|
-
const floats =
|
|
11604
|
+
const overlays = z4.array(Overlay).safeParse(scene.overlays ?? []);
|
|
11605
|
+
const floats = z4.array(FloatingElement).safeParse(scene.floating_elements ?? []);
|
|
11367
11606
|
const graphics = [
|
|
11368
11607
|
...(overlays.success ? overlays.data : []).filter((ov) => ov.text?.trim()).map((ov) => ({
|
|
11369
11608
|
kind: "text",
|