@sitecoreai-labs/sitecoreai-cli 0.1.2 → 0.2.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/dist/agents/tasks/agent.js +2 -2
- package/dist/agents/tasks/resources.js +2 -2
- package/dist/agents/tasks/space.js +1 -1
- package/dist/brand/api/auth.d.ts +16 -9
- package/dist/brand/api/auth.js +29 -19
- package/dist/brand/credential.d.ts +71 -1
- package/dist/brand/credential.js +119 -2
- package/dist/brand/recipe/diff.js +7 -2
- package/dist/brand/recipe/kind.js +0 -0
- package/dist/brand/recipe/schema.d.ts +113 -7
- package/dist/brand/recipe/schema.js +137 -8
- package/dist/brand/seed.d.ts +9 -5
- package/dist/brand/seed.js +30 -5
- package/dist/brief/api/briefs.d.ts +8 -0
- package/dist/brief/api/briefs.js +49 -11
- package/dist/brief/index.d.ts +1 -1
- package/dist/brief/index.js +2 -1
- package/dist/brief/recipe/index.d.ts +11 -2
- package/dist/brief/recipe/index.js +17 -3
- package/dist/brief/recipe/instance-diff.d.ts +4 -0
- package/dist/brief/recipe/instance-diff.js +77 -0
- package/dist/brief/recipe/instance-kind.d.ts +4 -0
- package/dist/brief/recipe/instance-kind.js +190 -0
- package/dist/brief/recipe/instance-schema.d.ts +61 -0
- package/dist/brief/recipe/instance-schema.js +68 -0
- package/dist/brief/recipe/schema.js +4 -1
- package/dist/brief/tasks/index.d.ts +35 -0
- package/dist/brief/tasks/index.js +62 -1
- package/dist/campaigns/recipe/schema.d.ts +39 -8
- package/dist/campaigns/recipe/schema.js +40 -10
- package/dist/commands/agents/sync.js +2 -2
- package/dist/commands/brand/seed.js +1 -1
- package/dist/commands/brand/sync.js +2 -2
- package/dist/commands/brief/create.d.ts +2 -0
- package/dist/commands/brief/create.js +56 -0
- package/dist/commands/brief/index.d.ts +3 -1
- package/dist/commands/brief/index.js +11 -1
- package/dist/commands/brief/sync.d.ts +9 -6
- package/dist/commands/brief/sync.js +54 -22
- package/dist/commands/brief/update.d.ts +2 -0
- package/dist/commands/brief/update.js +84 -0
- package/dist/commands/campaign/sync.js +2 -2
- package/dist/mcp/descriptions.js +3 -3
- package/dist/mcp/tools/brief-recipe.js +67 -23
- package/dist/mcp/tools/brief.js +83 -6
- package/dist/recipe/compile/design-parameters-template.js +5 -3
- package/dist/recipe/compile/enumeration.js +6 -11
- package/dist/recipe/compile/shared.js +12 -12
- package/dist/recipe/compile.js +4 -4
- package/dist/recipe/io.d.ts +8 -3
- package/dist/recipe/io.js +11 -81
- package/dist/recipe/items/read-current.js +31 -24
- package/dist/recipe/schema/recipe.d.ts +167 -84
- package/dist/recipe/schema/recipe.js +130 -46
- package/dist/recipe/schema/source-fields.d.ts +20 -0
- package/dist/recipe/schema/source-fields.js +25 -1
- package/dist/recipe/validate.d.ts +3 -3
- package/dist/recipe/validate.js +20 -10
- package/dist/sync/aggregate-kinds.js +1 -0
- package/dist/sync/aggregate.js +2 -2
- package/dist/sync/io.d.ts +13 -3
- package/dist/sync/io.js +43 -17
- package/dist/sync/typescript-recipe.d.ts +30 -0
- package/dist/sync/typescript-recipe.js +112 -0
- package/package.json +1 -1
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.briefInstanceKind = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The `brief` recipe kind — wires the Sitecore Content Operations
|
|
6
|
+
* Brief instance API into the `sync` engine.
|
|
7
|
+
*
|
|
8
|
+
* `ref.id` is the brief's display NAME — recipes identify a brief by
|
|
9
|
+
* name, not UUID, mirroring how `campaign` identifies a project. The
|
|
10
|
+
* brief type is referenced by its stable codename (`briefTypeName`)
|
|
11
|
+
* and resolved to a server id at push-time via `listBriefTypes`.
|
|
12
|
+
*
|
|
13
|
+
* `apply` is straight CRUD: `createBrief` when the brief is absent,
|
|
14
|
+
* `updateBrief` (partial PUT) to converge an existing one. Repointing
|
|
15
|
+
* an existing brief at a different brief type is refused — the Brief
|
|
16
|
+
* API has no verified path for that.
|
|
17
|
+
*
|
|
18
|
+
* See docs/recipe-sync-architecture.md.
|
|
19
|
+
*/
|
|
20
|
+
const brief_1 = require("../../brief");
|
|
21
|
+
const errors_1 = require("../../shared/errors");
|
|
22
|
+
const client_1 = require("./client");
|
|
23
|
+
const instance_diff_1 = require("./instance-diff");
|
|
24
|
+
const instance_schema_1 = require("./instance-schema");
|
|
25
|
+
/**
|
|
26
|
+
* Find a brief by its display name, paging the list endpoint until a
|
|
27
|
+
* match is found or the cursor is exhausted. The Brief list endpoint
|
|
28
|
+
* supports no server-side name filter (see `ListBriefsQuery`), so the
|
|
29
|
+
* walk is unavoidable.
|
|
30
|
+
*/
|
|
31
|
+
const findBriefByName = async (client, name) => {
|
|
32
|
+
let cursor;
|
|
33
|
+
for (;;) {
|
|
34
|
+
const page = await (0, brief_1.listBriefs)(client, cursor ? { next: cursor } : undefined);
|
|
35
|
+
const match = page.data.find((brief) => brief.name === name);
|
|
36
|
+
if (match)
|
|
37
|
+
return match;
|
|
38
|
+
if (!page.next || page.data.length === 0)
|
|
39
|
+
return null;
|
|
40
|
+
cursor = page.next;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
/** Find a brief type by its codename (mirrors `briefTypeKind`'s helper). */
|
|
44
|
+
const findTypeByName = async (client, name) => {
|
|
45
|
+
const page = await (0, brief_1.listBriefTypes)(client);
|
|
46
|
+
return page.data.find((type) => type.name === name) ?? null;
|
|
47
|
+
};
|
|
48
|
+
/** Enumerate every brief on the remote — fans out into the aggregate sync. */
|
|
49
|
+
const list = async (ctx) => {
|
|
50
|
+
const client = await (0, client_1.resolveBriefClient)(ctx);
|
|
51
|
+
const refs = [];
|
|
52
|
+
let cursor;
|
|
53
|
+
for (;;) {
|
|
54
|
+
const page = await (0, brief_1.listBriefs)(client, cursor ? { next: cursor } : undefined);
|
|
55
|
+
for (const brief of page.data) {
|
|
56
|
+
refs.push({ kind: "brief", id: brief.name });
|
|
57
|
+
}
|
|
58
|
+
if (!page.next || page.data.length === 0)
|
|
59
|
+
return refs;
|
|
60
|
+
cursor = page.next;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/** Project a live brief into the recipe shape, dropping server ids/metadata. */
|
|
64
|
+
const toRecipe = (brief, briefTypeName) => ({
|
|
65
|
+
name: brief.name,
|
|
66
|
+
briefTypeName,
|
|
67
|
+
locale: brief.locale || undefined,
|
|
68
|
+
status: brief.status,
|
|
69
|
+
isTemplate: brief.isTemplate,
|
|
70
|
+
fields: brief.fields ?? {},
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* Capture a live brief as a recipe. `null` when no brief has the name.
|
|
74
|
+
*
|
|
75
|
+
* The list endpoint omits the full nested `fields` map on some
|
|
76
|
+
* envelopes, so the matched id is re-read via `getBrief` for fidelity.
|
|
77
|
+
*/
|
|
78
|
+
const readCurrent = async (ref, ctx) => {
|
|
79
|
+
const client = await (0, client_1.resolveBriefClient)(ctx);
|
|
80
|
+
const found = await findBriefByName(client, ref.id);
|
|
81
|
+
if (!found)
|
|
82
|
+
return null;
|
|
83
|
+
const brief = await (0, brief_1.getBrief)(client, found.id);
|
|
84
|
+
// Resolve the brief-type codename. The brief carries a `Link` to its
|
|
85
|
+
// type with the id but not the codename, so a follow-up listTypes
|
|
86
|
+
// resolves it. If the type has been deleted (orphan brief), surface
|
|
87
|
+
// the id verbatim so the pulled recipe still round-trips.
|
|
88
|
+
const types = await (0, brief_1.listBriefTypes)(client);
|
|
89
|
+
const briefTypeName = types.data.find((type) => type.id === brief.briefType.id)?.name ?? brief.briefType.id;
|
|
90
|
+
return toRecipe(brief, briefTypeName);
|
|
91
|
+
};
|
|
92
|
+
/** Resolve a recipe's `briefTypeName` to its server id, or fail with a hint. */
|
|
93
|
+
const resolveBriefTypeId = async (client, briefTypeName) => {
|
|
94
|
+
const type = await findTypeByName(client, briefTypeName);
|
|
95
|
+
if (!type) {
|
|
96
|
+
throw (0, errors_1.createScaiError)(`Brief type "${briefTypeName}" not found.`, "INPUT_INVALID", {
|
|
97
|
+
hint: "Push the brief-type recipe first, or check the `briefTypeName` codename with `scai ops brief types list`.",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return type.id;
|
|
101
|
+
};
|
|
102
|
+
/** Apply a plan — create the brief, or PUT-patch it onto the desired state. */
|
|
103
|
+
const apply = async (plan, ref, ctx) => {
|
|
104
|
+
const client = await (0, client_1.resolveBriefClient)(ctx);
|
|
105
|
+
const applied = [];
|
|
106
|
+
const skipped = [];
|
|
107
|
+
// The single `stage: "instance"` change carries the full desired
|
|
108
|
+
// recipe; per-element `stage: "field"` changes are descriptive only.
|
|
109
|
+
const instanceChange = plan.changes.find((change) => change.meta?.stage === "instance");
|
|
110
|
+
if (!instanceChange) {
|
|
111
|
+
// Nothing to write — an all-noop plan.
|
|
112
|
+
for (const change of plan.changes)
|
|
113
|
+
skipped.push(change);
|
|
114
|
+
return { applied, skipped };
|
|
115
|
+
}
|
|
116
|
+
const recipe = instanceChange.meta?.recipe;
|
|
117
|
+
if (!recipe) {
|
|
118
|
+
throw (0, errors_1.createScaiError)("Brief plan change is missing its recipe payload.", "INPUT_INVALID", {
|
|
119
|
+
hint: "This is an internal diff error — change.meta.recipe was not set.",
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
if (instanceChange.kind === "create") {
|
|
123
|
+
const briefTypeId = await resolveBriefTypeId(client, recipe.briefTypeName);
|
|
124
|
+
const input = {
|
|
125
|
+
name: recipe.name,
|
|
126
|
+
briefTypeId,
|
|
127
|
+
...(recipe.locale !== undefined && { locale: recipe.locale }),
|
|
128
|
+
...(Object.keys(recipe.fields ?? {}).length > 0 && { fields: recipe.fields }),
|
|
129
|
+
...(recipe.isTemplate !== undefined && { isTemplate: recipe.isTemplate }),
|
|
130
|
+
};
|
|
131
|
+
ctx.logger?.info(`Creating brief "${recipe.name}".`);
|
|
132
|
+
const created = await (0, brief_1.createBrief)(client, input);
|
|
133
|
+
// `createBrief` accepts no `status` field — POSTs land in the
|
|
134
|
+
// server default ("Draft"). If the recipe pins a different status,
|
|
135
|
+
// converge with a follow-up PUT so the post-apply state matches.
|
|
136
|
+
if (recipe.status && recipe.status !== created.status) {
|
|
137
|
+
ctx.logger?.info(`Setting brief "${recipe.name}" status to "${recipe.status}".`);
|
|
138
|
+
await (0, brief_1.updateBrief)(client, created.id, { status: recipe.status });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const existing = await findBriefByName(client, ref.id);
|
|
143
|
+
if (!existing) {
|
|
144
|
+
throw (0, errors_1.createScaiError)(`Brief "${ref.id}" not found.`, "INPUT_INVALID", {
|
|
145
|
+
hint: "The brief was expected to exist for an update — check the name or push a create.",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// The Brief API has no verified path to repoint a brief at a
|
|
149
|
+
// different type. Surface that loudly instead of silently dropping
|
|
150
|
+
// the change.
|
|
151
|
+
const types = await (0, brief_1.listBriefTypes)(client);
|
|
152
|
+
const existingTypeName = types.data.find((type) => type.id === existing.briefType.id)?.name ?? existing.briefType.id;
|
|
153
|
+
if (existingTypeName !== recipe.briefTypeName) {
|
|
154
|
+
throw (0, errors_1.createScaiError)(`Cannot repoint brief "${recipe.name}" from type "${existingTypeName}" to "${recipe.briefTypeName}".`, "INPUT_INVALID", {
|
|
155
|
+
hint: "The Brief API has no verified path to change a brief's type. Delete and recreate the brief, or correct the recipe's briefTypeName.",
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const patch = {
|
|
159
|
+
name: recipe.name,
|
|
160
|
+
...(recipe.locale !== undefined && { locale: recipe.locale }),
|
|
161
|
+
...(recipe.isTemplate !== undefined && { isTemplate: recipe.isTemplate }),
|
|
162
|
+
...(recipe.status !== undefined && { status: recipe.status }),
|
|
163
|
+
fields: recipe.fields ?? {},
|
|
164
|
+
};
|
|
165
|
+
ctx.logger?.info(`Updating brief "${recipe.name}" (${existing.id}).`);
|
|
166
|
+
await (0, brief_1.updateBrief)(client, existing.id, patch);
|
|
167
|
+
}
|
|
168
|
+
applied.push(instanceChange);
|
|
169
|
+
// Per-element changes are converged by the single PUT (or POST).
|
|
170
|
+
for (const change of plan.changes) {
|
|
171
|
+
if (change === instanceChange)
|
|
172
|
+
continue;
|
|
173
|
+
if (change.kind === "noop")
|
|
174
|
+
skipped.push(change);
|
|
175
|
+
else
|
|
176
|
+
applied.push(change);
|
|
177
|
+
}
|
|
178
|
+
return { applied, skipped };
|
|
179
|
+
};
|
|
180
|
+
/** Compute the plan to converge a brief onto `desired`. */
|
|
181
|
+
const plan = async (desired, ref, ctx) => (0, instance_diff_1.diffBriefInstance)(desired, await readCurrent(ref, ctx));
|
|
182
|
+
/** The `brief` recipe kind. */
|
|
183
|
+
exports.briefInstanceKind = {
|
|
184
|
+
name: "brief",
|
|
185
|
+
schema: instance_schema_1.BriefInstanceRecipeSchema,
|
|
186
|
+
readCurrent,
|
|
187
|
+
plan,
|
|
188
|
+
apply,
|
|
189
|
+
list,
|
|
190
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `BriefInstanceRecipe` — the declarative definition of a Sitecore
|
|
3
|
+
* Content Operations *brief instance* (the unit of work — a populated
|
|
4
|
+
* brief built against a `BriefType` schema).
|
|
5
|
+
*
|
|
6
|
+
* Companion to `BriefTypeRecipeSchema` (this file's sibling `schema.ts`,
|
|
7
|
+
* which models the schema template). Brief instances reference their
|
|
8
|
+
* type by stable codename (`briefTypeName`) rather than UUID, exactly as
|
|
9
|
+
* a `campaign` recipe references nothing by id and identifies itself by
|
|
10
|
+
* `name`. See docs/recipe-sync-architecture.md.
|
|
11
|
+
*
|
|
12
|
+
* The schema captures the fields `createBrief` / `updateBrief` accept
|
|
13
|
+
* on the Brief API — `name`, `briefTypeName`, `locale`, `status`,
|
|
14
|
+
* `isTemplate`, and the per-field `fields` map. Sub-resources (tasks,
|
|
15
|
+
* comments, references, contributors, external mappings) are returned
|
|
16
|
+
* by the read endpoints but are not part of the brief write surface,
|
|
17
|
+
* so they stay out of the recipe.
|
|
18
|
+
*/
|
|
19
|
+
import { z } from "zod";
|
|
20
|
+
/**
|
|
21
|
+
* Brief workflow status — the values the Brief API accepts on a write.
|
|
22
|
+
* Mirrors the `BriefStatus` wire type in `../api/schema.ts`; surfacing
|
|
23
|
+
* the literal set here means the model reads the enum directly off the
|
|
24
|
+
* recipe schema (and bad values fail at parse-time, not push-time).
|
|
25
|
+
*
|
|
26
|
+
* `InReview` is the wire form for the "In Review" UI label.
|
|
27
|
+
*/
|
|
28
|
+
export declare const BriefInstanceStatusSchema: z.ZodEnum<{
|
|
29
|
+
Draft: "Draft";
|
|
30
|
+
InReview: "InReview";
|
|
31
|
+
Approved: "Approved";
|
|
32
|
+
Canceled: "Canceled";
|
|
33
|
+
Archived: "Archived";
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Field values on a brief instance, keyed by `BriefField.name`. The
|
|
37
|
+
* per-field shape varies by field `type` on the brief's type (RichText
|
|
38
|
+
* values are ProseMirror docs; DateTime is an ISO string; Timeline and
|
|
39
|
+
* Budget carry their own object shape). The shape is left as
|
|
40
|
+
* `z.unknown()` so any field type round-trips losslessly between
|
|
41
|
+
* `recipe pull` and `recipe push` without the recipe schema chasing
|
|
42
|
+
* the per-field encoding. Validation is deferred to the server.
|
|
43
|
+
*/
|
|
44
|
+
export declare const BriefInstanceFieldsSchema: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
45
|
+
/** The full brief-instance recipe. */
|
|
46
|
+
export declare const BriefInstanceRecipeSchema: z.ZodObject<{
|
|
47
|
+
name: z.ZodString;
|
|
48
|
+
briefTypeName: z.ZodString;
|
|
49
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
50
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
51
|
+
Draft: "Draft";
|
|
52
|
+
InReview: "InReview";
|
|
53
|
+
Approved: "Approved";
|
|
54
|
+
Canceled: "Canceled";
|
|
55
|
+
Archived: "Archived";
|
|
56
|
+
}>>;
|
|
57
|
+
isTemplate: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
fields: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
59
|
+
}, z.core.$strip>;
|
|
60
|
+
/** A validated brief-instance recipe. */
|
|
61
|
+
export type BriefInstanceRecipe = z.infer<typeof BriefInstanceRecipeSchema>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BriefInstanceRecipeSchema = exports.BriefInstanceFieldsSchema = exports.BriefInstanceStatusSchema = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `BriefInstanceRecipe` — the declarative definition of a Sitecore
|
|
6
|
+
* Content Operations *brief instance* (the unit of work — a populated
|
|
7
|
+
* brief built against a `BriefType` schema).
|
|
8
|
+
*
|
|
9
|
+
* Companion to `BriefTypeRecipeSchema` (this file's sibling `schema.ts`,
|
|
10
|
+
* which models the schema template). Brief instances reference their
|
|
11
|
+
* type by stable codename (`briefTypeName`) rather than UUID, exactly as
|
|
12
|
+
* a `campaign` recipe references nothing by id and identifies itself by
|
|
13
|
+
* `name`. See docs/recipe-sync-architecture.md.
|
|
14
|
+
*
|
|
15
|
+
* The schema captures the fields `createBrief` / `updateBrief` accept
|
|
16
|
+
* on the Brief API — `name`, `briefTypeName`, `locale`, `status`,
|
|
17
|
+
* `isTemplate`, and the per-field `fields` map. Sub-resources (tasks,
|
|
18
|
+
* comments, references, contributors, external mappings) are returned
|
|
19
|
+
* by the read endpoints but are not part of the brief write surface,
|
|
20
|
+
* so they stay out of the recipe.
|
|
21
|
+
*/
|
|
22
|
+
const zod_1 = require("zod");
|
|
23
|
+
/**
|
|
24
|
+
* Brief workflow status — the values the Brief API accepts on a write.
|
|
25
|
+
* Mirrors the `BriefStatus` wire type in `../api/schema.ts`; surfacing
|
|
26
|
+
* the literal set here means the model reads the enum directly off the
|
|
27
|
+
* recipe schema (and bad values fail at parse-time, not push-time).
|
|
28
|
+
*
|
|
29
|
+
* `InReview` is the wire form for the "In Review" UI label.
|
|
30
|
+
*/
|
|
31
|
+
exports.BriefInstanceStatusSchema = zod_1.z
|
|
32
|
+
.enum(["Draft", "InReview", "Approved", "Canceled", "Archived"])
|
|
33
|
+
.describe('Brief workflow status. Wire form — "InReview" is the "In Review" UI label. A brief must leave "Draft" before it can be linked to a campaign.');
|
|
34
|
+
/**
|
|
35
|
+
* Field values on a brief instance, keyed by `BriefField.name`. The
|
|
36
|
+
* per-field shape varies by field `type` on the brief's type (RichText
|
|
37
|
+
* values are ProseMirror docs; DateTime is an ISO string; Timeline and
|
|
38
|
+
* Budget carry their own object shape). The shape is left as
|
|
39
|
+
* `z.unknown()` so any field type round-trips losslessly between
|
|
40
|
+
* `recipe pull` and `recipe push` without the recipe schema chasing
|
|
41
|
+
* the per-field encoding. Validation is deferred to the server.
|
|
42
|
+
*/
|
|
43
|
+
exports.BriefInstanceFieldsSchema = zod_1.z
|
|
44
|
+
.record(zod_1.z.string(), zod_1.z.unknown())
|
|
45
|
+
.default({})
|
|
46
|
+
.describe("Field values keyed by BriefField.name. Per-field value shape follows the brief type's field definitions (e.g. RichText is a ProseMirror doc node).");
|
|
47
|
+
/** The full brief-instance recipe. */
|
|
48
|
+
exports.BriefInstanceRecipeSchema = zod_1.z.object({
|
|
49
|
+
name: zod_1.z
|
|
50
|
+
.string()
|
|
51
|
+
.min(1)
|
|
52
|
+
.describe("Display name of the brief. Identifies the brief when pushing. Briefs are matched by name; the recipe pushes through to `createBrief` / `updateBrief`."),
|
|
53
|
+
briefTypeName: zod_1.z
|
|
54
|
+
.string()
|
|
55
|
+
.min(1)
|
|
56
|
+
.regex(/^[A-Za-z][A-Za-z0-9_]*$/, "Must start with a letter and contain only letters, digits, or underscores.")
|
|
57
|
+
.describe("Codename of the brief type this brief is built against — looked up at push-time and resolved to its server id. The brief type must already exist (push the type's recipe first if it doesn't)."),
|
|
58
|
+
locale: zod_1.z
|
|
59
|
+
.string()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe('Brief locale — BCP-47-ish, e.g. "en-us". Omit to let the server default apply.'),
|
|
62
|
+
status: exports.BriefInstanceStatusSchema.optional().describe('Brief workflow status. Omit to leave at the server default ("Draft" on creation).'),
|
|
63
|
+
isTemplate: zod_1.z
|
|
64
|
+
.boolean()
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Whether the brief is a template (omit to leave at the server default)."),
|
|
67
|
+
fields: exports.BriefInstanceFieldsSchema,
|
|
68
|
+
});
|
|
@@ -69,7 +69,10 @@ exports.BudgetFieldSchema = zod_1.z
|
|
|
69
69
|
type: zod_1.z.literal("Budget").describe("Discriminator — a budget/currency field."),
|
|
70
70
|
...briefFieldBaseShape,
|
|
71
71
|
currencies: zod_1.z
|
|
72
|
-
.array(zod_1.z
|
|
72
|
+
.array(zod_1.z
|
|
73
|
+
.string()
|
|
74
|
+
.length(3)
|
|
75
|
+
.regex(/^[A-Z]{3}$/, "ISO-4217 currency code must be 3 uppercase letters (e.g. `USD`)."))
|
|
73
76
|
.describe('ISO-4217 currency codes the field accepts, e.g. ["USD", "EUR"].'),
|
|
74
77
|
})
|
|
75
78
|
.describe("A budget/currency field.");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CreateBriefInput } from "../api/briefs";
|
|
1
2
|
import { type CreateBriefTypeInput } from "../api/brief-types";
|
|
2
3
|
import type { Brief, BriefComment, BriefStatus, BriefTask, BriefType, PagedResult } from "../api/schema";
|
|
3
4
|
/**
|
|
@@ -100,6 +101,40 @@ export declare const runBriefCommentsList: (options: RunBriefBaseOptions & {
|
|
|
100
101
|
briefId?: string;
|
|
101
102
|
limit?: number;
|
|
102
103
|
}) => Promise<PagedResult<BriefComment>>;
|
|
104
|
+
/**
|
|
105
|
+
* Create a brief instance from a `CreateBriefInput`. Mirrors
|
|
106
|
+
* `runBriefTypeCreate` — honours `whatIf` for a plan-only dry run. The
|
|
107
|
+
* SDK `createBrief` is verified against the Agents tenant.
|
|
108
|
+
*/
|
|
109
|
+
export declare const runBriefCreate: (options: RunBriefBaseOptions & {
|
|
110
|
+
input: CreateBriefInput;
|
|
111
|
+
whatIf?: boolean;
|
|
112
|
+
}) => Promise<Brief | {
|
|
113
|
+
plan: CreateBriefInput;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Update a brief instance by id with a partial patch (`PUT`). Accepts
|
|
117
|
+
* any subset of `CreateBriefInput` plus an optional `status`. Mirrors
|
|
118
|
+
* `runBriefTypeUpdate` — honours `whatIf` for a plan-only dry run. The
|
|
119
|
+
* status-only PUT path is verified (2026-05-15); other partial fields
|
|
120
|
+
* are wired the same way but not smoke-tested.
|
|
121
|
+
*/
|
|
122
|
+
export declare const runBriefUpdate: (options: RunBriefBaseOptions & {
|
|
123
|
+
briefId: string;
|
|
124
|
+
patch: Partial<CreateBriefInput> & {
|
|
125
|
+
status?: BriefStatus;
|
|
126
|
+
};
|
|
127
|
+
whatIf?: boolean;
|
|
128
|
+
}) => Promise<{
|
|
129
|
+
id: string;
|
|
130
|
+
} | {
|
|
131
|
+
plan: {
|
|
132
|
+
id: string;
|
|
133
|
+
patch: Partial<CreateBriefInput> & {
|
|
134
|
+
status?: BriefStatus;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
}>;
|
|
103
138
|
/**
|
|
104
139
|
* Delete a brief instance. Mirrors `runBriefTypeDelete` — honours
|
|
105
140
|
* `whatIf` for a plan-only dry run. SDK `deleteBrief` is verified
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runBriefCommentAdd = exports.runBriefDelete = exports.runBriefCommentsList = exports.runBriefTodosList = exports.runBriefTypeDelete = exports.runBriefTypeUpdate = exports.runBriefTypeCreate = exports.runBriefTypeGet = exports.runBriefSetStatus = exports.runBriefTypes = exports.runBriefShow = exports.runBriefList = void 0;
|
|
3
|
+
exports.runBriefCommentAdd = exports.runBriefDelete = exports.runBriefUpdate = exports.runBriefCreate = exports.runBriefCommentsList = exports.runBriefTodosList = exports.runBriefTypeDelete = exports.runBriefTypeUpdate = exports.runBriefTypeCreate = exports.runBriefTypeGet = exports.runBriefSetStatus = exports.runBriefTypes = exports.runBriefShow = exports.runBriefList = void 0;
|
|
4
4
|
const logger_1 = require("../../shared/logger");
|
|
5
5
|
const client_1 = require("../client");
|
|
6
6
|
const briefs_1 = require("../api/briefs");
|
|
@@ -229,6 +229,67 @@ const runBriefCommentsList = async (options) => {
|
|
|
229
229
|
return result;
|
|
230
230
|
};
|
|
231
231
|
exports.runBriefCommentsList = runBriefCommentsList;
|
|
232
|
+
/**
|
|
233
|
+
* Create a brief instance from a `CreateBriefInput`. Mirrors
|
|
234
|
+
* `runBriefTypeCreate` — honours `whatIf` for a plan-only dry run. The
|
|
235
|
+
* SDK `createBrief` is verified against the Agents tenant.
|
|
236
|
+
*/
|
|
237
|
+
const runBriefCreate = async (options) => {
|
|
238
|
+
const { logger, client } = await prepareBriefClient(options);
|
|
239
|
+
if (options.whatIf) {
|
|
240
|
+
const plan = { plan: options.input };
|
|
241
|
+
if (logger.isJson()) {
|
|
242
|
+
writeJson(plan);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
logger.info(`Would create brief '${options.input.name}'.`, "yellow");
|
|
246
|
+
logger.info(` Brief type: ${options.input.briefTypeId}`);
|
|
247
|
+
if (options.input.locale)
|
|
248
|
+
logger.info(` Locale: ${options.input.locale}`);
|
|
249
|
+
const fieldCount = Object.keys(options.input.fields ?? {}).length;
|
|
250
|
+
logger.info(` Fields: ${fieldCount}`);
|
|
251
|
+
}
|
|
252
|
+
return plan;
|
|
253
|
+
}
|
|
254
|
+
const created = await (0, briefs_1.createBrief)(client, options.input);
|
|
255
|
+
if (logger.isJson()) {
|
|
256
|
+
writeJson(created);
|
|
257
|
+
return created;
|
|
258
|
+
}
|
|
259
|
+
logger.info(`Created brief ${created.id} (${created.name}).`, "green");
|
|
260
|
+
return created;
|
|
261
|
+
};
|
|
262
|
+
exports.runBriefCreate = runBriefCreate;
|
|
263
|
+
/**
|
|
264
|
+
* Update a brief instance by id with a partial patch (`PUT`). Accepts
|
|
265
|
+
* any subset of `CreateBriefInput` plus an optional `status`. Mirrors
|
|
266
|
+
* `runBriefTypeUpdate` — honours `whatIf` for a plan-only dry run. The
|
|
267
|
+
* status-only PUT path is verified (2026-05-15); other partial fields
|
|
268
|
+
* are wired the same way but not smoke-tested.
|
|
269
|
+
*/
|
|
270
|
+
const runBriefUpdate = async (options) => {
|
|
271
|
+
const { logger, client } = await prepareBriefClient(options);
|
|
272
|
+
if (options.whatIf) {
|
|
273
|
+
const plan = { plan: { id: options.briefId, patch: options.patch } };
|
|
274
|
+
if (logger.isJson()) {
|
|
275
|
+
writeJson(plan);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
logger.info(`Would PUT-update brief ${options.briefId}.`, "yellow");
|
|
279
|
+
const keys = Object.keys(options.patch);
|
|
280
|
+
logger.info(` Patch keys: ${keys.length === 0 ? "(none)" : keys.join(", ")}`);
|
|
281
|
+
}
|
|
282
|
+
return plan;
|
|
283
|
+
}
|
|
284
|
+
await (0, briefs_1.updateBrief)(client, options.briefId, options.patch);
|
|
285
|
+
if (logger.isJson()) {
|
|
286
|
+
writeJson({ id: options.briefId });
|
|
287
|
+
return { id: options.briefId };
|
|
288
|
+
}
|
|
289
|
+
logger.info(`Updated brief ${options.briefId}.`, "green");
|
|
290
|
+
return { id: options.briefId };
|
|
291
|
+
};
|
|
292
|
+
exports.runBriefUpdate = runBriefUpdate;
|
|
232
293
|
/**
|
|
233
294
|
* Delete a brief instance. Mirrors `runBriefTypeDelete` — honours
|
|
234
295
|
* `whatIf` for a plan-only dry run. SDK `deleteBrief` is verified
|
|
@@ -9,6 +9,21 @@
|
|
|
9
9
|
* model reads it. See docs/recipe-sync-architecture.md.
|
|
10
10
|
*/
|
|
11
11
|
import { z } from "zod";
|
|
12
|
+
/**
|
|
13
|
+
* Server enum values **confirmed by observation** in HAR captures of the
|
|
14
|
+
* Sitecore Content Operations UI driving the Orchestrate API. Other
|
|
15
|
+
* values likely exist in the server's enum — `recipe pull` from a tenant
|
|
16
|
+
* with a live `IN_PROGRESS` campaign must still round-trip cleanly — so
|
|
17
|
+
* the schema accepts the known set as a strong hint and falls back to
|
|
18
|
+
* `z.string()`. JSON Schema renders this as `anyOf: [{ enum: [...] }, { type:
|
|
19
|
+
* "string" }]`, which the model reads as "prefer one of these values; new
|
|
20
|
+
* uppercase enums are acceptable too".
|
|
21
|
+
*
|
|
22
|
+
* Update the lists when more values are observed; the trailing
|
|
23
|
+
* `z.string()` keeps the schema permissive in the meantime.
|
|
24
|
+
*/
|
|
25
|
+
export declare const KNOWN_CAMPAIGN_STATUSES: readonly ["NOT_STARTED"];
|
|
26
|
+
export declare const KNOWN_CAMPAIGN_FUNNEL_STAGES: readonly ["TOP"];
|
|
12
27
|
/**
|
|
13
28
|
* A task — the leaf work item of a campaign. Owned by a deliverable.
|
|
14
29
|
* Identified within its deliverable by `name`; server ids are dropped
|
|
@@ -16,7 +31,9 @@ import { z } from "zod";
|
|
|
16
31
|
*/
|
|
17
32
|
export declare const CampaignTaskSchema: z.ZodObject<{
|
|
18
33
|
name: z.ZodString;
|
|
19
|
-
status: z.ZodOptional<z.
|
|
34
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
35
|
+
NOT_STARTED: "NOT_STARTED";
|
|
36
|
+
}>, z.ZodString]>>;
|
|
20
37
|
dueDate: z.ZodOptional<z.ZodString>;
|
|
21
38
|
priority: z.ZodOptional<z.ZodString>;
|
|
22
39
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -29,14 +46,20 @@ export declare const CampaignTaskSchema: z.ZodObject<{
|
|
|
29
46
|
*/
|
|
30
47
|
export declare const CampaignDeliverableSchema: z.ZodObject<{
|
|
31
48
|
name: z.ZodString;
|
|
32
|
-
status: z.ZodOptional<z.
|
|
49
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
50
|
+
NOT_STARTED: "NOT_STARTED";
|
|
51
|
+
}>, z.ZodString]>>;
|
|
33
52
|
dueDate: z.ZodOptional<z.ZodString>;
|
|
34
|
-
funnelStage: z.ZodOptional<z.
|
|
53
|
+
funnelStage: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
54
|
+
TOP: "TOP";
|
|
55
|
+
}>, z.ZodString]>>;
|
|
35
56
|
funnelTactics: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
36
57
|
labels: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
37
58
|
tasks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
38
59
|
name: z.ZodString;
|
|
39
|
-
status: z.ZodOptional<z.
|
|
60
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
61
|
+
NOT_STARTED: "NOT_STARTED";
|
|
62
|
+
}>, z.ZodString]>>;
|
|
40
63
|
dueDate: z.ZodOptional<z.ZodString>;
|
|
41
64
|
priority: z.ZodOptional<z.ZodString>;
|
|
42
65
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -48,21 +71,29 @@ export declare const CampaignDeliverableSchema: z.ZodObject<{
|
|
|
48
71
|
export declare const CampaignRecipeSchema: z.ZodObject<{
|
|
49
72
|
name: z.ZodString;
|
|
50
73
|
description: z.ZodOptional<z.ZodString>;
|
|
51
|
-
status: z.ZodOptional<z.
|
|
74
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
75
|
+
NOT_STARTED: "NOT_STARTED";
|
|
76
|
+
}>, z.ZodString]>>;
|
|
52
77
|
startDate: z.ZodOptional<z.ZodString>;
|
|
53
78
|
dueDate: z.ZodOptional<z.ZodString>;
|
|
54
79
|
brandKitId: z.ZodOptional<z.ZodString>;
|
|
55
80
|
labels: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
56
81
|
deliverables: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
57
82
|
name: z.ZodString;
|
|
58
|
-
status: z.ZodOptional<z.
|
|
83
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
84
|
+
NOT_STARTED: "NOT_STARTED";
|
|
85
|
+
}>, z.ZodString]>>;
|
|
59
86
|
dueDate: z.ZodOptional<z.ZodString>;
|
|
60
|
-
funnelStage: z.ZodOptional<z.
|
|
87
|
+
funnelStage: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
88
|
+
TOP: "TOP";
|
|
89
|
+
}>, z.ZodString]>>;
|
|
61
90
|
funnelTactics: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
62
91
|
labels: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
63
92
|
tasks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
64
93
|
name: z.ZodString;
|
|
65
|
-
status: z.ZodOptional<z.
|
|
94
|
+
status: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
95
|
+
NOT_STARTED: "NOT_STARTED";
|
|
96
|
+
}>, z.ZodString]>>;
|
|
66
97
|
dueDate: z.ZodOptional<z.ZodString>;
|
|
67
98
|
priority: z.ZodOptional<z.ZodString>;
|
|
68
99
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CampaignRecipeSchema = exports.CampaignDeliverableSchema = exports.CampaignTaskSchema = void 0;
|
|
3
|
+
exports.CampaignRecipeSchema = exports.CampaignDeliverableSchema = exports.CampaignTaskSchema = exports.KNOWN_CAMPAIGN_FUNNEL_STAGES = exports.KNOWN_CAMPAIGN_STATUSES = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* `CampaignRecipe` — the declarative definition of a Sitecore
|
|
6
6
|
* Orchestrate campaign (a `project`, with its nested deliverables and
|
|
@@ -12,6 +12,33 @@ exports.CampaignRecipeSchema = exports.CampaignDeliverableSchema = exports.Campa
|
|
|
12
12
|
* model reads it. See docs/recipe-sync-architecture.md.
|
|
13
13
|
*/
|
|
14
14
|
const zod_1 = require("zod");
|
|
15
|
+
/**
|
|
16
|
+
* ISO-8601 date-or-datetime — accepts `2026-05-26`, `2026-05-26T15:00:00Z`,
|
|
17
|
+
* or `2026-05-26T15:00:00.123+02:00`. Less strict than `z.string().datetime()`
|
|
18
|
+
* because the campaign API returns date-only values for some fields.
|
|
19
|
+
*/
|
|
20
|
+
const Iso8601 = zod_1.z
|
|
21
|
+
.string()
|
|
22
|
+
.regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2}))?$/, {
|
|
23
|
+
message: "must be an ISO-8601 date or datetime (e.g. `2026-05-26` or `2026-05-26T15:00:00Z`)",
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Server enum values **confirmed by observation** in HAR captures of the
|
|
27
|
+
* Sitecore Content Operations UI driving the Orchestrate API. Other
|
|
28
|
+
* values likely exist in the server's enum — `recipe pull` from a tenant
|
|
29
|
+
* with a live `IN_PROGRESS` campaign must still round-trip cleanly — so
|
|
30
|
+
* the schema accepts the known set as a strong hint and falls back to
|
|
31
|
+
* `z.string()`. JSON Schema renders this as `anyOf: [{ enum: [...] }, { type:
|
|
32
|
+
* "string" }]`, which the model reads as "prefer one of these values; new
|
|
33
|
+
* uppercase enums are acceptable too".
|
|
34
|
+
*
|
|
35
|
+
* Update the lists when more values are observed; the trailing
|
|
36
|
+
* `z.string()` keeps the schema permissive in the meantime.
|
|
37
|
+
*/
|
|
38
|
+
exports.KNOWN_CAMPAIGN_STATUSES = ["NOT_STARTED"];
|
|
39
|
+
exports.KNOWN_CAMPAIGN_FUNNEL_STAGES = ["TOP"];
|
|
40
|
+
const CampaignStatusSchema = zod_1.z.union([zod_1.z.enum(exports.KNOWN_CAMPAIGN_STATUSES), zod_1.z.string()]);
|
|
41
|
+
const CampaignFunnelStageSchema = zod_1.z.union([zod_1.z.enum(exports.KNOWN_CAMPAIGN_FUNNEL_STAGES), zod_1.z.string()]);
|
|
15
42
|
/**
|
|
16
43
|
* A task — the leaf work item of a campaign. Owned by a deliverable.
|
|
17
44
|
* Identified within its deliverable by `name`; server ids are dropped
|
|
@@ -19,9 +46,12 @@ const zod_1 = require("zod");
|
|
|
19
46
|
*/
|
|
20
47
|
exports.CampaignTaskSchema = zod_1.z.object({
|
|
21
48
|
name: zod_1.z.string().min(1).describe("Task name. Identifies the task within its deliverable."),
|
|
22
|
-
status:
|
|
23
|
-
dueDate:
|
|
24
|
-
priority: zod_1.z
|
|
49
|
+
status: CampaignStatusSchema.optional().describe('Task status — a server enum. Confirmed values: "NOT_STARTED". Other UPPER_SNAKE values may exist on the server; the schema accepts them but agents should prefer the confirmed set.'),
|
|
50
|
+
dueDate: Iso8601.optional().describe("Task due date (ISO-8601 date or datetime)."),
|
|
51
|
+
priority: zod_1.z
|
|
52
|
+
.string()
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Task priority — a server enum. No values have been observed yet; convention follows project-management norms (e.g. UPPERCASE strings). Schema is `string` until the enum set is captured."),
|
|
25
55
|
description: zod_1.z.string().optional().describe("Task description. HTML."),
|
|
26
56
|
assignee: zod_1.z.string().optional().describe('Assignee — an Auth0 user subject (e.g. "auth0|...").'),
|
|
27
57
|
labels: zod_1.z.array(zod_1.z.string()).default([]).describe("Free-form labels on the task."),
|
|
@@ -35,9 +65,9 @@ exports.CampaignDeliverableSchema = zod_1.z.object({
|
|
|
35
65
|
.string()
|
|
36
66
|
.min(1)
|
|
37
67
|
.describe("Deliverable name. Identifies the deliverable within its campaign."),
|
|
38
|
-
status:
|
|
39
|
-
dueDate:
|
|
40
|
-
funnelStage:
|
|
68
|
+
status: CampaignStatusSchema.optional().describe('Deliverable status — a server enum. Confirmed values: "NOT_STARTED". Other UPPER_SNAKE values may exist on the server; the schema accepts them but agents should prefer the confirmed set.'),
|
|
69
|
+
dueDate: Iso8601.optional().describe("Deliverable due date (ISO-8601 date or datetime)."),
|
|
70
|
+
funnelStage: CampaignFunnelStageSchema.optional().describe('Funnel stage — a server enum. Confirmed values: "TOP". Other values likely exist (e.g. middle / bottom of funnel); the schema accepts them but agents should prefer the confirmed set.'),
|
|
41
71
|
funnelTactics: zod_1.z.array(zod_1.z.string()).default([]).describe("Funnel tactics for the deliverable."),
|
|
42
72
|
labels: zod_1.z.array(zod_1.z.string()).default([]).describe("Free-form labels on the deliverable."),
|
|
43
73
|
tasks: zod_1.z
|
|
@@ -52,9 +82,9 @@ exports.CampaignRecipeSchema = zod_1.z.object({
|
|
|
52
82
|
.min(1)
|
|
53
83
|
.describe("Display name of the campaign (project). Identifies the campaign when pushing."),
|
|
54
84
|
description: zod_1.z.string().optional().describe("Human description of the campaign."),
|
|
55
|
-
status:
|
|
56
|
-
startDate:
|
|
57
|
-
dueDate:
|
|
85
|
+
status: CampaignStatusSchema.optional().describe('Campaign status — a server enum. Confirmed values: "NOT_STARTED". Other UPPER_SNAKE values may exist on the server; the schema accepts them but agents should prefer the confirmed set.'),
|
|
86
|
+
startDate: Iso8601.optional().describe("Campaign start date (ISO-8601 date or datetime)."),
|
|
87
|
+
dueDate: Iso8601.optional().describe("Campaign due date (ISO-8601 date or datetime)."),
|
|
58
88
|
brandKitId: zod_1.z
|
|
59
89
|
.string()
|
|
60
90
|
.optional()
|
|
@@ -91,7 +91,7 @@ const createDiffCommand = () => {
|
|
|
91
91
|
const logger = (0, cli_tasks_1.toLogger)(options);
|
|
92
92
|
const kind = resolveKind(options.kind);
|
|
93
93
|
const ctx = buildContext(options, logger);
|
|
94
|
-
const recipe = (0, sync_1.loadRecipe)(options.file ?? "", kind.schema);
|
|
94
|
+
const recipe = await (0, sync_1.loadRecipe)(options.file ?? "", kind.schema);
|
|
95
95
|
const plan = await (0, sync_1.syncDiff)(kind, recipe, { kind: kind.name, id: recipeName(recipe) }, ctx);
|
|
96
96
|
printPlan(logger, plan);
|
|
97
97
|
});
|
|
@@ -110,7 +110,7 @@ const createPushCommand = () => {
|
|
|
110
110
|
const logger = (0, cli_tasks_1.toLogger)(options);
|
|
111
111
|
const kind = resolveKind(options.kind);
|
|
112
112
|
const ctx = buildContext(options, logger);
|
|
113
|
-
const recipe = (0, sync_1.loadRecipe)(options.file ?? "", kind.schema);
|
|
113
|
+
const recipe = await (0, sync_1.loadRecipe)(options.file ?? "", kind.schema);
|
|
114
114
|
const mode = options.allowWrite ? "apply" : "what-if";
|
|
115
115
|
const outcome = await (0, sync_1.syncPush)(kind, recipe, { kind: kind.name, id: recipeName(recipe) }, ctx, {
|
|
116
116
|
mode,
|
|
@@ -70,7 +70,7 @@ const seedFromFile = async (options, logger) => {
|
|
|
70
70
|
configPath,
|
|
71
71
|
logger,
|
|
72
72
|
};
|
|
73
|
-
const recipe = (0, sync_1.loadRecipe)(options.file ?? "", recipe_1.brandKitKind.schema);
|
|
73
|
+
const recipe = await (0, sync_1.loadRecipe)(options.file ?? "", recipe_1.brandKitKind.schema);
|
|
74
74
|
const outcome = await (0, sync_1.syncPush)(recipe_1.brandKitKind, recipe, { kind: recipe_1.brandKitKind.name, id: recipe.name }, ctx, { mode: "apply", prune: false });
|
|
75
75
|
if (options.format === "json") {
|
|
76
76
|
process.stdout.write(JSON.stringify({ recipe: recipe.name, plan: outcome.plan, result: outcome.result }, null, 2) +
|