@aglyn/plugins-ai 1.0.0-beta.260 → 1.0.0-beta.262
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/package.json +17 -17
- package/src/lib/components/ai-brief-dialog.component.d.ts +21 -58
- package/src/lib/components/ai-brief-dialog.component.js +8 -132
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
- package/src/lib/components/ai-job-follow.component.js +2 -35
- package/src/lib/components/ai-job-follow.component.js.map +1 -1
- package/src/lib/components/ai-job-plan.component.d.ts +2 -8
- package/src/lib/components/ai-job-plan.component.js +13 -74
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-site-start-card.component.js +43 -34
- package/src/lib/components/ai-site-start-card.component.js.map +1 -1
- package/src/lib/components/ai-template-collection-field.component.d.ts +2 -12
- package/src/lib/components/ai-template-collection-field.component.js +13 -10
- package/src/lib/components/ai-template-collection-field.component.js.map +1 -1
- package/src/lib/components/ai-upsell-dialog.component.d.ts +3 -25
- package/src/lib/components/ai-upsell-dialog.component.js +9 -66
- package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
- package/src/lib/components/use-ai-job-run.d.ts +3 -8
- package/src/lib/components/use-ai-job-run.js +4 -15
- package/src/lib/components/use-ai-job-run.js.map +1 -1
- package/src/lib/insights/ai-figure-readers.js +15 -5
- package/src/lib/insights/ai-figure-readers.js.map +1 -1
- package/src/lib/insights/ai-figure-summaries.d.ts +27 -0
- package/src/lib/insights/ai-figure-summaries.js +79 -0
- package/src/lib/insights/ai-figure-summaries.js.map +1 -0
- package/src/lib/insights/ai-insight-readers.d.ts +2 -1
- package/src/lib/insights/ai-insight-readers.js +11 -26
- package/src/lib/insights/ai-insight-readers.js.map +1 -1
- package/src/lib/jobs/ai-job-admission.d.ts +6 -0
- package/src/lib/jobs/ai-job-admission.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.js +10 -6
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +43 -11
- package/src/lib/jobs/ai-layout-stock-photos.js +329 -32
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-stock-photo-picker.js +13 -7
- package/src/lib/jobs/ai-stock-photo-picker.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-recordings.d.ts +35 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-recordings.js +404 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-agl3856-recordings.js.map +1 -0
- package/src/lib/layout-language/ai-layout-motion.d.ts +9 -3
- package/src/lib/layout-language/ai-layout-motion.js +9 -3
- package/src/lib/layout-language/ai-layout-motion.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.d.ts +10 -1
- package/src/lib/layout-language/ai-layout-pictures.js +12 -6
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-brief-copy.d.ts +85 -0
- package/src/lib/model/ai-brief-copy.js +152 -0
- package/src/lib/model/ai-brief-copy.js.map +1 -0
- package/src/lib/model/ai-create-view.d.ts +200 -0
- package/src/lib/model/ai-create-view.js +263 -0
- package/src/lib/model/ai-create-view.js.map +1 -0
- package/src/lib/model/ai-insight.d.ts +1 -1
- package/src/lib/model/ai-insight.js +4 -39
- package/src/lib/model/ai-insight.js.map +1 -1
- package/src/lib/model/ai-job-activity.d.ts +24 -0
- package/src/lib/model/ai-job-activity.js +52 -1
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-job-plan-lines.d.ts +46 -0
- package/src/lib/model/ai-job-plan-lines.js +70 -0
- package/src/lib/model/ai-job-plan-lines.js.map +1 -0
- package/src/lib/model/ai-template-collections.d.ts +28 -0
- package/src/lib/model/ai-template-collections.js +28 -0
- package/src/lib/model/ai-template-collections.js.map +1 -0
- package/src/lib/model/ai-upsell-copy.d.ts +41 -0
- package/src/lib/model/ai-upsell-copy.js +85 -0
- package/src/lib/model/ai-upsell-copy.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +40 -0
- package/src/lib/runtime/ai-doctrine-validators.js +148 -3
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +6 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-memory-firestore.js +2 -0
- package/src/lib/runtime/ai-eval-memory-firestore.js.map +1 -1
- package/src/lib/server/ai-create-route.d.ts +32 -0
- package/src/lib/server/ai-create-route.js +295 -0
- package/src/lib/server/ai-create-route.js.map +1 -0
- package/src/lib/server/ai-jobs-route.js +19 -0
- package/src/lib/server/ai-jobs-route.js.map +1 -1
- package/src/lib/server.js +14 -0
- package/src/lib/server.js.map +1 -1
|
@@ -642,6 +642,15 @@ const COLOR_KEYWORDS = new Set([
|
|
|
642
642
|
const LITERAL_COLOR = /#[0-9a-f]{3,8}\b|\b(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\s*\(|\b(?:black|white|red|green|blue|yellow|orange|purple|pink|gray|grey|brown|cyan|magenta|navy|teal|maroon|olive|lime|aqua|silver|gold|indigo|violet|beige|coral|crimson|salmon|tomato|turquoise|khaki|lavender|ivory|azure)\b/i;
|
|
643
643
|
const LENGTH_WITH_UNIT = /-?\d*\.?\d+\s*(?:px|rem|em|pt|vh|vw|ch)\b/i;
|
|
644
644
|
const paletteTokens = new Set(AI_SX_TOKENS.palette);
|
|
645
|
+
/**
|
|
646
|
+
* A color written as a value — a hex code or a color function — and never a
|
|
647
|
+
* color WORD. Plan prose names things in words: a photographer's "Blue Ridge
|
|
648
|
+
* elopements" or "Black and white portraits" is a place and a style, not a
|
|
649
|
+
* color, and the live 2026-10-16 guided start was refused for it (AGL-3864).
|
|
650
|
+
*/ const LITERAL_COLOR_VALUE = /#[0-9a-f]{3,8}\b|\b(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\s*\(/i;
|
|
651
|
+
/** Whether plan prose writes a color by value: a hex code or a color function. */ function proseHasLiteralColor(value) {
|
|
652
|
+
return typeof value === 'string' && LITERAL_COLOR_VALUE.test(value);
|
|
653
|
+
}
|
|
645
654
|
/** Whether a value names a color by value rather than by theme token. */ function hasLiteralColor(value) {
|
|
646
655
|
if (typeof value !== 'string') return false;
|
|
647
656
|
const parts = value.trim().split(/\s+/).filter((part)=>!paletteTokens.has(part) && !COLOR_KEYWORDS.has(part.toLowerCase()));
|
|
@@ -3892,6 +3901,53 @@ const FORM_SECTION_NAME = /\bform\b|\bsign[- ]?up\b|\bsubscribe\b|\bnewsletter\b
|
|
|
3892
3901
|
screens
|
|
3893
3902
|
}) : plan;
|
|
3894
3903
|
}
|
|
3904
|
+
/**
|
|
3905
|
+
* References to nothing at all are taken out before the rules read the plan
|
|
3906
|
+
* (AGL-3845), where each has one reading. The live Free candle-shop start of
|
|
3907
|
+
* 2026-10-16, on an empty site, reused a layout `laySite` and duplicated a
|
|
3908
|
+
* page `scrStarter` the site does not have, and wrote what each section
|
|
3909
|
+
* shows into its uses ("hero", "product grid", "help text"). It was refused
|
|
3910
|
+
* for the unknown records, and the Free wall's trim, which never takes a
|
|
3911
|
+
* section that places something, could take none of them.
|
|
3912
|
+
*
|
|
3913
|
+
* - A reuse of a record the site does not have is dropped, and a page laid
|
|
3914
|
+
* out in it names no layout, for the layouts settle to place.
|
|
3915
|
+
* - A page duplicated from a page the site does not have starts fresh.
|
|
3916
|
+
* - A section's use that names no record the site has and no creation of the
|
|
3917
|
+
* plan is a description, not a reference, and comes out.
|
|
3918
|
+
*
|
|
3919
|
+
* Runs after `aiSettlePlanRefs`, so a creation spelled another way is
|
|
3920
|
+
* already pointed at, never dropped.
|
|
3921
|
+
*/ export function aiSettlePlanUnknownIds(plan, inventory) {
|
|
3922
|
+
const kinds = inventoryKinds(inventory);
|
|
3923
|
+
const reuse = plan.reuse.filter((entry)=>entry.kind === 'theme' || kinds.get(entry.id) === entry.kind);
|
|
3924
|
+
const dropped = new Set(plan.reuse.filter((entry)=>!reuse.includes(entry)).map((entry)=>entry.id));
|
|
3925
|
+
const names = (ref)=>!!ref && (kinds.has(ref) || !!aiPlanCreateFor(plan, ref) || !!aiPlanItemFor(plan, ref) || isAiPlanNewRef(ref) && !dropped.has(ref));
|
|
3926
|
+
let changed = reuse.length !== plan.reuse.length;
|
|
3927
|
+
const screens = plan.screens.map((screen)=>{
|
|
3928
|
+
const layout = screen.layout && dropped.has(screen.layout) ? null : screen.layout;
|
|
3929
|
+
const duplicateOf = screen.duplicateOf && !kinds.has(screen.duplicateOf) ? null : screen.duplicateOf;
|
|
3930
|
+
const sections = screen.sections.map((section)=>{
|
|
3931
|
+
const uses = section.uses.filter(names);
|
|
3932
|
+
return uses.length === section.uses.length ? section : _extends({}, section, {
|
|
3933
|
+
uses
|
|
3934
|
+
});
|
|
3935
|
+
});
|
|
3936
|
+
if (layout === screen.layout && duplicateOf === screen.duplicateOf && sections.every((one, index)=>one === screen.sections[index])) {
|
|
3937
|
+
return screen;
|
|
3938
|
+
}
|
|
3939
|
+
changed = true;
|
|
3940
|
+
return _extends({}, screen, {
|
|
3941
|
+
layout,
|
|
3942
|
+
duplicateOf,
|
|
3943
|
+
sections
|
|
3944
|
+
});
|
|
3945
|
+
});
|
|
3946
|
+
return changed ? _extends({}, plan, {
|
|
3947
|
+
reuse,
|
|
3948
|
+
screens
|
|
3949
|
+
}) : plan;
|
|
3950
|
+
}
|
|
3895
3951
|
/**
|
|
3896
3952
|
* What customers say, which no dataset of the site's holds: a review, a
|
|
3897
3953
|
* testimonial, a rating, a quote (AGL-3616). A job never writes them for the
|
|
@@ -4466,12 +4522,12 @@ const FORM_SECTION_NAME = /\bform\b|\bsign[- ]?up\b|\bsubscribe\b|\bnewsletter\b
|
|
|
4466
4522
|
const paths = [];
|
|
4467
4523
|
plan.create.forEach((entry, index)=>{
|
|
4468
4524
|
if (entry.kind === 'theme-change') return;
|
|
4469
|
-
if (
|
|
4525
|
+
if (proseHasLiteralColor(entry.why) || entry.fields.some(proseHasLiteralColor)) {
|
|
4470
4526
|
paths.push(`create[${index}]`);
|
|
4471
4527
|
}
|
|
4472
4528
|
});
|
|
4473
4529
|
for (const { section, path } of sectionPaths(plan)){
|
|
4474
|
-
if (
|
|
4530
|
+
if (proseHasLiteralColor(section.name)) paths.push(path);
|
|
4475
4531
|
}
|
|
4476
4532
|
return paths.length ? [
|
|
4477
4533
|
{
|
|
@@ -4560,10 +4616,94 @@ const REUSE_BEFORE_CREATE_KINDS = new Set([
|
|
|
4560
4616
|
* a component. Only the message reads it; the reference is refused whatever
|
|
4561
4617
|
* it was meant to be.
|
|
4562
4618
|
*/ function undeclaredPlacementKind(name, section, plan, kinds) {
|
|
4563
|
-
if (
|
|
4619
|
+
if (readsAsForm(name)) return 'form';
|
|
4564
4620
|
const placesForm = section.uses.some((ref)=>refKind(ref, plan, kinds) === 'form');
|
|
4565
4621
|
return FORM_SECTION_NAME.test(section.name) && !placesForm ? 'form' : 'component';
|
|
4566
4622
|
}
|
|
4623
|
+
/** A creation's name in words: `contactForm` → "contact Form", so `\\bform\\b` can read it. */ function nameInWords(name) {
|
|
4624
|
+
return name.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[-_]+/g, ' ').trim();
|
|
4625
|
+
}
|
|
4626
|
+
/** Whether a creation's name, camelCase or not, names a form. */ function readsAsForm(name) {
|
|
4627
|
+
return FORM_SECTION_NAME.test(nameInWords(name));
|
|
4628
|
+
}
|
|
4629
|
+
const NEWSLETTER_NAME = /\bnewsletter\b|\bsubscribe\b|\bsign[- ]?up\b/i;
|
|
4630
|
+
/**
|
|
4631
|
+
* A section that places a creation the plan never declares is settled
|
|
4632
|
+
* before the rules read the plan, where it has one answer (AGL-3845). The
|
|
4633
|
+
* live candle-shop start of 2026-10-16 placed `new:contactForm` in its
|
|
4634
|
+
* "Care, shipping and contact" section on both answers and stopped needing
|
|
4635
|
+
* input: the camelCase name read as a component, which a site start may not
|
|
4636
|
+
* make, and the refusal itself said to take it out.
|
|
4637
|
+
*
|
|
4638
|
+
* - A name that reads as a form, where this job may make one more form, is
|
|
4639
|
+
* declared as one: a newsletter's takes an email, any other the contact
|
|
4640
|
+
* form's fields, named in words ("Contact form") with the reference
|
|
4641
|
+
* pointed at it.
|
|
4642
|
+
* - Anything else this job could not make one more of is taken out of the
|
|
4643
|
+
* section's uses, and the section is drawn on the page — unless the
|
|
4644
|
+
* section itself is the form ("consultation request form"): without it
|
|
4645
|
+
* the section has no purpose, and what to put there instead is the
|
|
4646
|
+
* rule's to ask.
|
|
4647
|
+
* - A component the job could declare is left for the rule to ask about:
|
|
4648
|
+
* what it should be has more than one answer.
|
|
4649
|
+
*/ export function aiSettlePlanUndeclaredUses(plan, inventory, capabilities = null) {
|
|
4650
|
+
if (!capabilities) return plan;
|
|
4651
|
+
const kinds = inventoryKinds(inventory);
|
|
4652
|
+
let next = plan;
|
|
4653
|
+
const repoint = new Map();
|
|
4654
|
+
const drop = new Set();
|
|
4655
|
+
for (const ref of aiPlanUndeclaredRefs(plan)){
|
|
4656
|
+
if (ref.field !== 'uses') continue;
|
|
4657
|
+
const key = ref.name.toLowerCase();
|
|
4658
|
+
if (repoint.has(key) || drop.has(ref.path)) continue;
|
|
4659
|
+
const section = plan.screens[ref.screenIndex].sections[ref.sectionIndex];
|
|
4660
|
+
const kind = undeclaredPlacementKind(ref.name, section, next, kinds);
|
|
4661
|
+
if (kind === 'form' && readsAsForm(ref.name) && !aiPlanUncreatableKind(next, 'form', capabilities)) {
|
|
4662
|
+
const words = nameInWords(ref.name).toLowerCase();
|
|
4663
|
+
const name = `${words.charAt(0).toUpperCase()}${words.slice(1)}`;
|
|
4664
|
+
repoint.set(key, `new:${name}`);
|
|
4665
|
+
if (!aiPlanCreateFor(next, `new:${name}`)) {
|
|
4666
|
+
next = _extends({}, next, {
|
|
4667
|
+
create: [
|
|
4668
|
+
...next.create,
|
|
4669
|
+
{
|
|
4670
|
+
kind: 'form',
|
|
4671
|
+
name,
|
|
4672
|
+
why: AI_PLAN_SETTLED_FORM.why,
|
|
4673
|
+
duplicateOf: null,
|
|
4674
|
+
fields: NEWSLETTER_NAME.test(words) ? [
|
|
4675
|
+
'email'
|
|
4676
|
+
] : [
|
|
4677
|
+
...AI_PLAN_SETTLED_FORM.fields
|
|
4678
|
+
]
|
|
4679
|
+
}
|
|
4680
|
+
]
|
|
4681
|
+
});
|
|
4682
|
+
}
|
|
4683
|
+
} else if (!FORM_SECTION_NAME.test(section.name) && aiPlanUncreatableKind(next, kind, capabilities)) {
|
|
4684
|
+
drop.add(ref.path);
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
if (!repoint.size && !drop.size) return plan;
|
|
4688
|
+
const undeclaredName = (ref)=>isAiPlanNewRef(ref) && !aiPlanCreateFor(plan, ref) && !aiPlanItemFor(plan, ref) ? ref.slice('new:'.length).trim().toLowerCase() : null;
|
|
4689
|
+
return _extends({}, next, {
|
|
4690
|
+
screens: next.screens.map((screen, screenIndex)=>_extends({}, screen, {
|
|
4691
|
+
sections: screen.sections.map((section, sectionIndex)=>{
|
|
4692
|
+
const uses = section.uses.flatMap((ref, useIndex)=>{
|
|
4693
|
+
var _repoint_get;
|
|
4694
|
+
if (drop.has(`screens[${screenIndex}].sections[${sectionIndex}].uses[${useIndex}]`)) return [];
|
|
4695
|
+
const name = undeclaredName(ref);
|
|
4696
|
+
return [
|
|
4697
|
+
name !== null ? (_repoint_get = repoint.get(name)) != null ? _repoint_get : ref : ref
|
|
4698
|
+
];
|
|
4699
|
+
});
|
|
4700
|
+
return uses.length === section.uses.length && uses.every((ref, index)=>ref === section.uses[index]) ? section : _extends({}, section, {
|
|
4701
|
+
uses
|
|
4702
|
+
});
|
|
4703
|
+
})
|
|
4704
|
+
}))
|
|
4705
|
+
});
|
|
4706
|
+
}
|
|
4567
4707
|
/**
|
|
4568
4708
|
* Rule 7 (plan): what a plan places, it reuses or it creates (AGL-3040). The
|
|
4569
4709
|
* doctrine has a plan refer to what it creates as new:<name>, so a reference
|
|
@@ -4635,6 +4775,11 @@ const REUSE_BEFORE_CREATE_KINDS = new Set([
|
|
|
4635
4775
|
].includes(String(refKind(ref, plan, kinds))));
|
|
4636
4776
|
if (bindsData) continue;
|
|
4637
4777
|
if (section.items >= AI_TYPED_LIST_MIN_ITEMS) typed.push(path);
|
|
4778
|
+
// A form section COLLECTS what its dataset holds; it never copies it
|
|
4779
|
+
// (AGL-3864). A workspace whose other site made a "Consultation
|
|
4780
|
+
// requests" dataset refused a new law firm's "Consultation requests" form.
|
|
4781
|
+
const collects = FORM_SECTION_NAME.test(section.name) || section.uses.some((ref)=>refKind(ref, plan, kinds) === 'form');
|
|
4782
|
+
if (collects) continue;
|
|
4638
4783
|
const match = data.find((row)=>aiNamesMatch(row.name, section.name));
|
|
4639
4784
|
if (match) unbound.push({
|
|
4640
4785
|
path,
|