@avocadostudio-ai/orchestrator-core 0.1.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.
Files changed (196) hide show
  1. package/LICENSE +201 -0
  2. package/dist/agent/agent-context.d.ts +19 -0
  3. package/dist/agent/agent-context.js +67 -0
  4. package/dist/agent/agent-logger.d.ts +5 -0
  5. package/dist/agent/agent-logger.js +22 -0
  6. package/dist/agent/agent-loop-openai.d.ts +8 -0
  7. package/dist/agent/agent-loop-openai.js +172 -0
  8. package/dist/agent/agent-loop.d.ts +56 -0
  9. package/dist/agent/agent-loop.js +167 -0
  10. package/dist/agent/agent-provider.d.ts +28 -0
  11. package/dist/agent/agent-provider.js +63 -0
  12. package/dist/agent/agent-tools.d.ts +28 -0
  13. package/dist/agent/agent-tools.js +899 -0
  14. package/dist/agent/context/editing-guidelines.md +46 -0
  15. package/dist/agent/context/role.md +39 -0
  16. package/dist/agent/integration-prompt.d.ts +9 -0
  17. package/dist/agent/integration-prompt.js +154 -0
  18. package/dist/agent/sites-agent-context.d.ts +12 -0
  19. package/dist/agent/sites-agent-context.js +316 -0
  20. package/dist/agent/sites-agent-shared.d.ts +161 -0
  21. package/dist/agent/sites-agent-shared.js +1101 -0
  22. package/dist/agent/sites-agent-tools.d.ts +18 -0
  23. package/dist/agent/sites-agent-tools.js +1227 -0
  24. package/dist/chat/anthropic-cache.d.ts +20 -0
  25. package/dist/chat/anthropic-cache.js +54 -0
  26. package/dist/chat/anthropic-planner.d.ts +98 -0
  27. package/dist/chat/anthropic-planner.js +1012 -0
  28. package/dist/chat/changelog-coverage-validator.d.ts +37 -0
  29. package/dist/chat/changelog-coverage-validator.js +215 -0
  30. package/dist/chat/chat-pipeline-context.d.ts +211 -0
  31. package/dist/chat/chat-pipeline-context.js +249 -0
  32. package/dist/chat/chat-pipeline-deterministic.d.ts +61 -0
  33. package/dist/chat/chat-pipeline-deterministic.js +407 -0
  34. package/dist/chat/chat-pipeline-image.d.ts +86 -0
  35. package/dist/chat/chat-pipeline-image.js +897 -0
  36. package/dist/chat/chat-pipeline-shared.d.ts +69 -0
  37. package/dist/chat/chat-pipeline-shared.js +212 -0
  38. package/dist/chat/chat-pipeline-translation.d.ts +27 -0
  39. package/dist/chat/chat-pipeline-translation.js +417 -0
  40. package/dist/chat/chat-pipeline-ui.d.ts +14 -0
  41. package/dist/chat/chat-pipeline-ui.js +244 -0
  42. package/dist/chat/chat-pipeline.d.ts +99 -0
  43. package/dist/chat/chat-pipeline.js +3999 -0
  44. package/dist/chat/decomposer.d.ts +21 -0
  45. package/dist/chat/decomposer.js +65 -0
  46. package/dist/chat/gemini-planner.d.ts +70 -0
  47. package/dist/chat/gemini-planner.js +541 -0
  48. package/dist/chat/hallucination-validator.d.ts +36 -0
  49. package/dist/chat/hallucination-validator.js +110 -0
  50. package/dist/chat/locale-strings.d.ts +47 -0
  51. package/dist/chat/locale-strings.js +100 -0
  52. package/dist/chat/plan-json-schema.d.ts +133 -0
  53. package/dist/chat/plan-json-schema.js +112 -0
  54. package/dist/chat/planner-types.d.ts +120 -0
  55. package/dist/chat/planner-types.js +66 -0
  56. package/dist/chat/planner.d.ts +148 -0
  57. package/dist/chat/planner.js +1361 -0
  58. package/dist/chat/prompts.d.ts +67 -0
  59. package/dist/chat/prompts.js +356 -0
  60. package/dist/chat/provider-routing.d.ts +14 -0
  61. package/dist/chat/provider-routing.js +27 -0
  62. package/dist/chat/variation-pipeline.d.ts +135 -0
  63. package/dist/chat/variation-pipeline.js +837 -0
  64. package/dist/chat/vision-alt-generator.d.ts +35 -0
  65. package/dist/chat/vision-alt-generator.js +152 -0
  66. package/dist/cms/adapter.d.ts +62 -0
  67. package/dist/cms/adapter.js +1 -0
  68. package/dist/cms/bootstrap.d.ts +17 -0
  69. package/dist/cms/bootstrap.js +85 -0
  70. package/dist/cms/editor-api-adapter.d.ts +23 -0
  71. package/dist/cms/editor-api-adapter.js +71 -0
  72. package/dist/cms/index.d.ts +4 -0
  73. package/dist/cms/index.js +3 -0
  74. package/dist/cms/json-file-adapter.d.ts +11 -0
  75. package/dist/cms/json-file-adapter.js +62 -0
  76. package/dist/demo-mode.d.ts +59 -0
  77. package/dist/demo-mode.js +201 -0
  78. package/dist/errors.d.ts +67 -0
  79. package/dist/errors.js +129 -0
  80. package/dist/http/chat-stream-resumable.d.ts +108 -0
  81. package/dist/http/chat-stream-resumable.js +290 -0
  82. package/dist/http/chat-stream.d.ts +99 -0
  83. package/dist/http/chat-stream.js +92 -0
  84. package/dist/image/gdrive-client.d.ts +22 -0
  85. package/dist/image/gdrive-client.js +215 -0
  86. package/dist/image/image-helpers.d.ts +95 -0
  87. package/dist/image/image-helpers.js +488 -0
  88. package/dist/index.d.ts +1 -0
  89. package/dist/index.js +1 -0
  90. package/dist/jira/jira-approval.d.ts +22 -0
  91. package/dist/jira/jira-approval.js +51 -0
  92. package/dist/jira/jira-client.d.ts +44 -0
  93. package/dist/jira/jira-client.js +313 -0
  94. package/dist/jira/jira-poller.d.ts +46 -0
  95. package/dist/jira/jira-poller.js +184 -0
  96. package/dist/jira/jira-processor.d.ts +103 -0
  97. package/dist/jira/jira-processor.js +1085 -0
  98. package/dist/jira/jira-types.d.ts +117 -0
  99. package/dist/jira/jira-types.js +38 -0
  100. package/dist/logger.d.ts +12 -0
  101. package/dist/logger.js +28 -0
  102. package/dist/migration/mcp-server-stdio.d.ts +8 -0
  103. package/dist/migration/mcp-server-stdio.js +672 -0
  104. package/dist/migration/migration-prompt.d.ts +7 -0
  105. package/dist/migration/migration-prompt.js +197 -0
  106. package/dist/migration/migration-tools.d.ts +17 -0
  107. package/dist/migration/migration-tools.js +159 -0
  108. package/dist/migration/scrape-cache.d.ts +9 -0
  109. package/dist/migration/scrape-cache.js +19 -0
  110. package/dist/nlp/deterministic-planner-context.d.ts +141 -0
  111. package/dist/nlp/deterministic-planner-context.js +362 -0
  112. package/dist/nlp/deterministic-planner-pages.d.ts +26 -0
  113. package/dist/nlp/deterministic-planner-pages.js +170 -0
  114. package/dist/nlp/deterministic-planner-patches.d.ts +80 -0
  115. package/dist/nlp/deterministic-planner-patches.js +508 -0
  116. package/dist/nlp/deterministic-planner-refs.d.ts +33 -0
  117. package/dist/nlp/deterministic-planner-refs.js +164 -0
  118. package/dist/nlp/deterministic-planner-suggestions.d.ts +49 -0
  119. package/dist/nlp/deterministic-planner-suggestions.js +579 -0
  120. package/dist/nlp/deterministic-planner.d.ts +85 -0
  121. package/dist/nlp/deterministic-planner.js +1631 -0
  122. package/dist/nlp/intent-detection.d.ts +309 -0
  123. package/dist/nlp/intent-detection.js +730 -0
  124. package/dist/nlp/intent-helpers.d.ts +15 -0
  125. package/dist/nlp/intent-helpers.js +243 -0
  126. package/dist/nlp/intent-patterns.d.ts +40 -0
  127. package/dist/nlp/intent-patterns.js +223 -0
  128. package/dist/nlp/plan-normalizer.d.ts +41 -0
  129. package/dist/nlp/plan-normalizer.js +1537 -0
  130. package/dist/ops/destructive-action-gate.d.ts +44 -0
  131. package/dist/ops/destructive-action-gate.js +90 -0
  132. package/dist/ops/ops-engine.d.ts +151 -0
  133. package/dist/ops/ops-engine.js +1394 -0
  134. package/dist/publish/diff-engine.d.ts +18 -0
  135. package/dist/publish/diff-engine.js +305 -0
  136. package/dist/publish/publish-helpers.d.ts +87 -0
  137. package/dist/publish/publish-helpers.js +521 -0
  138. package/dist/publish/publish-target-registry.d.ts +7 -0
  139. package/dist/publish/publish-target-registry.js +61 -0
  140. package/dist/publish/publish-target.d.ts +81 -0
  141. package/dist/publish/publish-target.js +1 -0
  142. package/dist/publish/targets/deploy-hook.d.ts +13 -0
  143. package/dist/publish/targets/deploy-hook.js +123 -0
  144. package/dist/publish/targets/git.d.ts +13 -0
  145. package/dist/publish/targets/git.js +55 -0
  146. package/dist/publish/targets/site-contract.d.ts +19 -0
  147. package/dist/publish/targets/site-contract.js +124 -0
  148. package/dist/state/content-source.d.ts +17 -0
  149. package/dist/state/content-source.js +1 -0
  150. package/dist/state/in-memory-content-source.d.ts +27 -0
  151. package/dist/state/in-memory-content-source.js +51 -0
  152. package/dist/state/session-lock.d.ts +13 -0
  153. package/dist/state/session-lock.js +29 -0
  154. package/dist/state/session-state.d.ts +310 -0
  155. package/dist/state/session-state.js +1083 -0
  156. package/dist/state/sqlite-store-singleton.d.ts +31 -0
  157. package/dist/state/sqlite-store-singleton.js +170 -0
  158. package/dist/state/sqlite-store.d.ts +135 -0
  159. package/dist/state/sqlite-store.js +421 -0
  160. package/dist/telemetry/chat-telemetry.d.ts +105 -0
  161. package/dist/telemetry/chat-telemetry.js +247 -0
  162. package/dist/telemetry/eval-candidate-store.d.ts +50 -0
  163. package/dist/telemetry/eval-candidate-store.js +120 -0
  164. package/dist/telemetry/feedback-store.d.ts +34 -0
  165. package/dist/telemetry/feedback-store.js +76 -0
  166. package/dist/telemetry/jira-telemetry.d.ts +57 -0
  167. package/dist/telemetry/jira-telemetry.js +68 -0
  168. package/dist/telemetry/migration-telemetry.d.ts +35 -0
  169. package/dist/telemetry/migration-telemetry.js +40 -0
  170. package/dist/telemetry/usage.d.ts +24 -0
  171. package/dist/telemetry/usage.js +80 -0
  172. package/dist/tools/builtin-registrations.d.ts +12 -0
  173. package/dist/tools/builtin-registrations.js +33 -0
  174. package/dist/tools/builtins/gdrive-browse.d.ts +3 -0
  175. package/dist/tools/builtins/gdrive-browse.js +68 -0
  176. package/dist/tools/builtins/image-generate.d.ts +3 -0
  177. package/dist/tools/builtins/image-generate.js +211 -0
  178. package/dist/tools/builtins/unsplash-get-by-id.d.ts +23 -0
  179. package/dist/tools/builtins/unsplash-get-by-id.js +119 -0
  180. package/dist/tools/builtins/unsplash-search.d.ts +3 -0
  181. package/dist/tools/builtins/unsplash-search.js +74 -0
  182. package/dist/tools/executor.d.ts +23 -0
  183. package/dist/tools/executor.js +169 -0
  184. package/dist/tools/index.d.ts +5 -0
  185. package/dist/tools/index.js +5 -0
  186. package/dist/tools/registry.d.ts +21 -0
  187. package/dist/tools/registry.js +75 -0
  188. package/dist/tools/runtime.d.ts +27 -0
  189. package/dist/tools/runtime.js +48 -0
  190. package/dist/tools/schema-validator.d.ts +24 -0
  191. package/dist/tools/schema-validator.js +88 -0
  192. package/dist/tools/types.d.ts +86 -0
  193. package/dist/tools/types.js +1 -0
  194. package/dist/variation-images.d.ts +19 -0
  195. package/dist/variation-images.js +12 -0
  196. package/package.json +78 -0
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Computes a structured diff between the session's draft pages and the
3
+ * currently-published pages. Pure function — no I/O. Shared with the editor
4
+ * via the PublishDiff type in @avocadostudio-ai/shared.
5
+ */
6
+ import type { PageDoc, SiteConfig } from "@avocadostudio-ai/shared";
7
+ import type { PublishDiff } from "@avocadostudio-ai/shared";
8
+ /**
9
+ * Compare drafts to published and produce a structured diff. Pages are
10
+ * matched by slug. Within a page, blocks are matched by id.
11
+ *
12
+ * The resulting `pages` list is ordered: changed pages first (added →
13
+ * modified → removed), unchanged last. This lets the UI collapse noise.
14
+ */
15
+ export declare function computePublishDiff(draft: PageDoc[], published: PageDoc[], options?: {
16
+ draftSiteConfig?: SiteConfig | null;
17
+ publishedSiteConfig?: SiteConfig | null;
18
+ }): PublishDiff;
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Computes a structured diff between the session's draft pages and the
3
+ * currently-published pages. Pure function — no I/O. Shared with the editor
4
+ * via the PublishDiff type in @avocadostudio-ai/shared.
5
+ */
6
+ const IMAGE_PATH_HINT = /(^|\.)(imageUrl|image|src|poster|logo|avatar|thumbnail)$/i;
7
+ function inferKind(path, before, after) {
8
+ if (IMAGE_PATH_HINT.test(path))
9
+ return "image";
10
+ if (typeof before === "string" || typeof after === "string")
11
+ return "text";
12
+ return "other";
13
+ }
14
+ function isPlainObject(v) {
15
+ return v !== null && typeof v === "object" && !Array.isArray(v);
16
+ }
17
+ function arraysShallowEqual(a, b) {
18
+ if (a.length !== b.length)
19
+ return false;
20
+ for (let i = 0; i < a.length; i++)
21
+ if (!deepEqual(a[i], b[i]))
22
+ return false;
23
+ return true;
24
+ }
25
+ function deepEqual(a, b) {
26
+ if (Object.is(a, b))
27
+ return true;
28
+ if (Array.isArray(a) && Array.isArray(b))
29
+ return arraysShallowEqual(a, b);
30
+ if (isPlainObject(a) && isPlainObject(b)) {
31
+ const ka = Object.keys(a);
32
+ const kb = Object.keys(b);
33
+ if (ka.length !== kb.length)
34
+ return false;
35
+ for (const key of ka)
36
+ if (!deepEqual(a[key], b[key]))
37
+ return false;
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+ /**
43
+ * Walks two prop trees and emits one FieldDiff per leaf that changed.
44
+ * - Plain objects: recurse key-by-key (union of keys).
45
+ * - Arrays of plain objects: recurse element-by-element by index.
46
+ * - Arrays of primitives or mixed: treated as single leaves.
47
+ */
48
+ function diffProps(before, after, path, out) {
49
+ if (deepEqual(before, after))
50
+ return;
51
+ const bothObjects = isPlainObject(before) && isPlainObject(after);
52
+ if (bothObjects) {
53
+ const keys = new Set([...Object.keys(before), ...Object.keys(after)]);
54
+ for (const key of keys) {
55
+ // `id` on a list item is internal addressing metadata, not user content —
56
+ // never surface it as a published change (it would otherwise show up as
57
+ // noise the first time a pre-item-id baseline is diffed against a draft
58
+ // whose items have since been backfilled with ids).
59
+ if (key === "id")
60
+ continue;
61
+ const childPath = path ? `${path}.${key}` : key;
62
+ diffProps(before[key], after[key], childPath, out);
63
+ }
64
+ return;
65
+ }
66
+ const bothArrays = Array.isArray(before) && Array.isArray(after);
67
+ if (bothArrays) {
68
+ const allObjects = before.every((x) => isPlainObject(x)) &&
69
+ after.every((x) => isPlainObject(x));
70
+ if (allObjects) {
71
+ const maxLen = Math.max(before.length, after.length);
72
+ for (let i = 0; i < maxLen; i++) {
73
+ const childPath = `${path}[${i}]`;
74
+ diffProps(before[i], after[i], childPath, out);
75
+ }
76
+ return;
77
+ }
78
+ // Arrays of primitives / mixed: emit as a single leaf.
79
+ out.push({ path, before, after, kind: inferKind(path, before, after) });
80
+ return;
81
+ }
82
+ // Leaf — before !== after by deep equality check above.
83
+ out.push({ path, before, after, kind: inferKind(path, before, after) });
84
+ }
85
+ function diffBlocks(beforeBlocks, afterBlocks) {
86
+ const beforeById = new Map();
87
+ beforeBlocks.forEach((b, i) => beforeById.set(b.id, { block: b, index: i }));
88
+ const afterById = new Map();
89
+ afterBlocks.forEach((b, i) => afterById.set(b.id, { block: b, index: i }));
90
+ const out = [];
91
+ const seen = new Set();
92
+ // Iterate in draft (after) order so the diff reads top-to-bottom like the page.
93
+ for (const [id, { block, index }] of afterById) {
94
+ seen.add(id);
95
+ const prev = beforeById.get(id);
96
+ if (!prev) {
97
+ out.push({ blockId: id, type: block.type, status: "added", positionAfter: index });
98
+ continue;
99
+ }
100
+ const fieldDiffs = [];
101
+ // Type change: treat as modified with a synthetic "type" diff so the UI can show it.
102
+ if (prev.block.type !== block.type) {
103
+ fieldDiffs.push({ path: "type", before: prev.block.type, after: block.type, kind: "other" });
104
+ }
105
+ diffProps(prev.block.props, block.props, "", fieldDiffs);
106
+ const moved = prev.index !== index;
107
+ const changed = fieldDiffs.length > 0;
108
+ if (!moved && !changed) {
109
+ out.push({ blockId: id, type: block.type, status: "unchanged", positionBefore: prev.index, positionAfter: index });
110
+ continue;
111
+ }
112
+ out.push({
113
+ blockId: id,
114
+ type: block.type,
115
+ status: changed ? "modified" : "moved",
116
+ fieldDiffs: changed ? fieldDiffs : undefined,
117
+ positionBefore: prev.index,
118
+ positionAfter: index,
119
+ });
120
+ }
121
+ // Removed blocks — in published but not in draft.
122
+ for (const [id, { block, index }] of beforeById) {
123
+ if (seen.has(id))
124
+ continue;
125
+ out.push({ blockId: id, type: block.type, status: "removed", positionBefore: index });
126
+ }
127
+ return out;
128
+ }
129
+ function diffPage(before, after) {
130
+ if (!before && !after)
131
+ return null;
132
+ if (!before && after) {
133
+ return {
134
+ slug: after.slug,
135
+ status: "added",
136
+ titleAfter: after.title,
137
+ blockDiffs: after.blocks.map((b, i) => ({
138
+ blockId: b.id,
139
+ type: b.type,
140
+ status: "added",
141
+ positionAfter: i,
142
+ })),
143
+ };
144
+ }
145
+ if (before && !after) {
146
+ return {
147
+ slug: before.slug,
148
+ status: "removed",
149
+ titleBefore: before.title,
150
+ blockDiffs: before.blocks.map((b, i) => ({
151
+ blockId: b.id,
152
+ type: b.type,
153
+ status: "removed",
154
+ positionBefore: i,
155
+ })),
156
+ };
157
+ }
158
+ const b = before;
159
+ const a = after;
160
+ const blockDiffs = diffBlocks(b.blocks, a.blocks);
161
+ const titleChanged = b.title !== a.title;
162
+ const hasStructuralChange = blockDiffs.some((bd) => bd.status !== "unchanged");
163
+ return {
164
+ slug: a.slug,
165
+ status: titleChanged || hasStructuralChange ? "modified" : "unchanged",
166
+ titleBefore: titleChanged ? b.title : undefined,
167
+ titleAfter: titleChanged ? a.title : undefined,
168
+ blockDiffs,
169
+ };
170
+ }
171
+ // Keys of SiteConfig that drive the rendered SiteHeader chrome. We diff
172
+ // only these to keep the publish UI focused on user-visible header changes;
173
+ // `purpose`, `tone`, `constraints`, `themeOverrides` are AI/style context
174
+ // that lives outside the published chrome (and shouldn't trigger a publish CTA).
175
+ const SITE_HEADER_KEYS = ["name", "logo", "navLabels", "navGroups"];
176
+ function pickHeaderFields(config) {
177
+ const out = {};
178
+ if (!config)
179
+ return out;
180
+ for (const key of SITE_HEADER_KEYS) {
181
+ const value = config[key];
182
+ if (value === undefined)
183
+ continue;
184
+ out[key] = value;
185
+ }
186
+ return out;
187
+ }
188
+ function emitMapDiff(rootKey, before, after, out) {
189
+ if (deepEqual(before, after))
190
+ return;
191
+ const keys = new Set([...Object.keys(before ?? {}), ...Object.keys(after ?? {})]);
192
+ for (const key of keys) {
193
+ const b = before?.[key];
194
+ const a = after?.[key];
195
+ if (deepEqual(b, a))
196
+ continue;
197
+ out.push({
198
+ path: `${rootKey}["${key}"]`,
199
+ before: b,
200
+ after: a,
201
+ kind: "other",
202
+ });
203
+ }
204
+ }
205
+ function diffSiteConfig(before, after) {
206
+ const beforeHeader = pickHeaderFields(before);
207
+ const afterHeader = pickHeaderFields(after);
208
+ const beforeEmpty = Object.keys(beforeHeader).length === 0;
209
+ const afterEmpty = Object.keys(afterHeader).length === 0;
210
+ if (beforeEmpty && afterEmpty) {
211
+ return { status: "unchanged", fieldDiffs: [] };
212
+ }
213
+ const fieldDiffs = [];
214
+ // Scalars: name, logo
215
+ if (!deepEqual(beforeHeader.name, afterHeader.name)) {
216
+ fieldDiffs.push({ path: "name", before: beforeHeader.name, after: afterHeader.name, kind: "text" });
217
+ }
218
+ if (!deepEqual(beforeHeader.logo, afterHeader.logo)) {
219
+ fieldDiffs.push({ path: "logo", before: beforeHeader.logo, after: afterHeader.logo, kind: "image" });
220
+ }
221
+ // Maps: navLabels (slug→label), navGroups (label→slug[])
222
+ emitMapDiff("navLabels", beforeHeader.navLabels, afterHeader.navLabels, fieldDiffs);
223
+ emitMapDiff("navGroups", beforeHeader.navGroups, afterHeader.navGroups, fieldDiffs);
224
+ if (fieldDiffs.length === 0)
225
+ return { status: "unchanged", fieldDiffs: [] };
226
+ // "added" / "removed" are useful signals when the entire chrome appears or
227
+ // disappears at once (e.g. first publish, or a site reset). Otherwise it's
228
+ // a `modified`.
229
+ if (beforeEmpty)
230
+ return { status: "added", fieldDiffs };
231
+ if (afterEmpty)
232
+ return { status: "removed", fieldDiffs };
233
+ return { status: "modified", fieldDiffs };
234
+ }
235
+ /**
236
+ * Compare drafts to published and produce a structured diff. Pages are
237
+ * matched by slug. Within a page, blocks are matched by id.
238
+ *
239
+ * The resulting `pages` list is ordered: changed pages first (added →
240
+ * modified → removed), unchanged last. This lets the UI collapse noise.
241
+ */
242
+ export function computePublishDiff(draft, published, options) {
243
+ const draftBySlug = new Map();
244
+ for (const p of draft)
245
+ draftBySlug.set(p.slug, p);
246
+ const publishedBySlug = new Map();
247
+ for (const p of published)
248
+ publishedBySlug.set(p.slug, p);
249
+ const allSlugs = new Set([...draftBySlug.keys(), ...publishedBySlug.keys()]);
250
+ const pageDiffs = [];
251
+ let pagesAdded = 0;
252
+ let pagesRemoved = 0;
253
+ let pagesModified = 0;
254
+ let pagesUnchanged = 0;
255
+ let totalChangedFields = 0;
256
+ for (const slug of allSlugs) {
257
+ const diff = diffPage(publishedBySlug.get(slug), draftBySlug.get(slug));
258
+ if (!diff)
259
+ continue;
260
+ pageDiffs.push(diff);
261
+ switch (diff.status) {
262
+ case "added":
263
+ pagesAdded++;
264
+ break;
265
+ case "removed":
266
+ pagesRemoved++;
267
+ break;
268
+ case "modified":
269
+ pagesModified++;
270
+ break;
271
+ case "unchanged":
272
+ pagesUnchanged++;
273
+ break;
274
+ }
275
+ for (const bd of diff.blockDiffs) {
276
+ if (bd.fieldDiffs)
277
+ totalChangedFields += bd.fieldDiffs.length;
278
+ }
279
+ }
280
+ const statusOrder = {
281
+ added: 0,
282
+ modified: 1,
283
+ removed: 2,
284
+ unchanged: 3,
285
+ };
286
+ pageDiffs.sort((x, y) => {
287
+ const s = statusOrder[x.status] - statusOrder[y.status];
288
+ if (s !== 0)
289
+ return s;
290
+ return x.slug.localeCompare(y.slug);
291
+ });
292
+ const siteConfig = diffSiteConfig(options?.publishedSiteConfig, options?.draftSiteConfig);
293
+ return {
294
+ summary: {
295
+ pagesAdded,
296
+ pagesRemoved,
297
+ pagesModified,
298
+ pagesUnchanged,
299
+ totalChangedFields,
300
+ siteConfigChangedFields: siteConfig.fieldDiffs.length,
301
+ },
302
+ pages: pageDiffs,
303
+ siteConfig,
304
+ };
305
+ }
@@ -0,0 +1,87 @@
1
+ import type { Logger } from "../logger.ts";
2
+ import { type PageDoc } from "@avocadostudio-ai/shared";
3
+ import { type PublishTracker } from "../state/session-state.ts";
4
+ export declare function deploymentIdFromAny(input: string): string | undefined;
5
+ export declare function refreshPublishStatusFromVercel(current: PublishTracker): Promise<PublishTracker>;
6
+ export declare function requirePublishToken(request: {
7
+ headers: Record<string, unknown>;
8
+ }): boolean;
9
+ export type SnapshotDescriptor = {
10
+ commit: string;
11
+ committedAt: string;
12
+ message: string;
13
+ pageCount: number;
14
+ homeHeading: string;
15
+ };
16
+ export declare function loadPublishedSnapshotFromCommit(commit: string): Promise<PageDoc[]>;
17
+ export declare function listRestoreSnapshots(limit?: number, siteId?: string): Promise<SnapshotDescriptor[]>;
18
+ /**
19
+ * Delete a publish snapshot by reverting its git commit.
20
+ * Uses `git revert --no-commit` + `git commit` to keep history linear.
21
+ * Returns true if the revert succeeded, false otherwise.
22
+ */
23
+ export declare function deletePublishSnapshot(commit: string): Promise<boolean>;
24
+ export declare function isTemplateFallbackSession(sessionDraft: Map<string, PageDoc>): boolean;
25
+ export declare function ensurePresetRestoreSessions(log: Logger): Promise<void>;
26
+ export declare function findLocalhostImageUrls(pages: PageDoc[]): Map<string, string>;
27
+ export type InlineAsset = {
28
+ /** base64-encoded image bytes */
29
+ data: string;
30
+ /** MIME type, e.g. "image/png" */
31
+ mimeType: string;
32
+ /** Original filename */
33
+ fileName: string;
34
+ };
35
+ /**
36
+ * Collect generated/gdrive images referenced by localhost URLs in pages,
37
+ * read them from disk, and return a map of originalUrl → base64 InlineAsset.
38
+ * Missing files are silently skipped.
39
+ */
40
+ export declare function collectInlineAssets(pages: PageDoc[], generatedImageDir: string): Promise<Record<string, InlineAsset>>;
41
+ /**
42
+ * Record a publish snapshot in git history (commit only, no push).
43
+ * Used after site-contract publishes so version history can find them.
44
+ * Best-effort: failures are silently ignored.
45
+ */
46
+ export declare function recordPublishSnapshot(session: string, pages: PageDoc[], log?: Logger, siteConfig?: Record<string, unknown>): Promise<string | undefined>;
47
+ export declare function publishViaGit(session: string): Promise<{
48
+ status: "failed";
49
+ session: string;
50
+ slugs: string[];
51
+ reason: string;
52
+ details: string[];
53
+ branch?: undefined;
54
+ message?: undefined;
55
+ commitSha?: undefined;
56
+ vercelState?: undefined;
57
+ } | {
58
+ status: "ready";
59
+ session: string;
60
+ slugs: string[];
61
+ branch: string;
62
+ message: string;
63
+ reason?: undefined;
64
+ details?: undefined;
65
+ commitSha?: undefined;
66
+ vercelState?: undefined;
67
+ } | {
68
+ status: "triggered";
69
+ session: string;
70
+ slugs: string[];
71
+ branch: string;
72
+ commitSha: string | undefined;
73
+ vercelState: string;
74
+ reason?: undefined;
75
+ details?: undefined;
76
+ message?: undefined;
77
+ } | {
78
+ status: "failed";
79
+ session: string;
80
+ slugs: string[];
81
+ branch: string;
82
+ commitSha: string | undefined;
83
+ reason: string;
84
+ details: string[];
85
+ message?: undefined;
86
+ vercelState?: undefined;
87
+ }>;