@lotics/cli 0.101.0 → 0.101.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/render_page.js +94 -20
- package/dist/src/cli.js +58 -42
- package/dist/src/client.d.ts +9 -4
- package/dist/src/client.js +1 -0
- package/package.json +1 -1
package/dist/render_page.js
CHANGED
|
@@ -28695,6 +28695,73 @@ ${e.toString()}`);
|
|
|
28695
28695
|
offsetYEmu
|
|
28696
28696
|
};
|
|
28697
28697
|
}
|
|
28698
|
+
var EMU_PER_PT = 12700;
|
|
28699
|
+
var VML_UNIT_TO_EMU = {
|
|
28700
|
+
pt: EMU_PER_PT,
|
|
28701
|
+
in: EMU_PER_PT * 72,
|
|
28702
|
+
cm: EMU_PER_PT * 72 / 2.54,
|
|
28703
|
+
mm: EMU_PER_PT * 72 / 25.4,
|
|
28704
|
+
pc: EMU_PER_PT * 12,
|
|
28705
|
+
px: EMU_PER_PT * 72 / 96
|
|
28706
|
+
};
|
|
28707
|
+
function readVmlLength(style, property) {
|
|
28708
|
+
const match = new RegExp(`(?:^|;)\\s*${property}\\s*:\\s*([0-9.]+)([a-z]*)`, "i").exec(style);
|
|
28709
|
+
if (!match) return null;
|
|
28710
|
+
const value = Number.parseFloat(match[1]);
|
|
28711
|
+
if (!Number.isFinite(value)) return null;
|
|
28712
|
+
const unit = match[2].toLowerCase();
|
|
28713
|
+
const perUnit = unit === "" ? EMU_PER_PT : VML_UNIT_TO_EMU[unit];
|
|
28714
|
+
if (perUnit === void 0) return null;
|
|
28715
|
+
return Math.round(value * perUnit);
|
|
28716
|
+
}
|
|
28717
|
+
function parsePict(pictXml) {
|
|
28718
|
+
if (getTagName(pictXml) !== "w:pict") return null;
|
|
28719
|
+
const imagedata = findFirstByTag(pictXml, "v:imagedata");
|
|
28720
|
+
if (!imagedata) return null;
|
|
28721
|
+
const relationshipId = getAttr(imagedata, "r:id") ?? getAttr(imagedata, "r:embed") ?? null;
|
|
28722
|
+
if (relationshipId === null) return null;
|
|
28723
|
+
const shape = findFirstByTag(pictXml, "v:shape") ?? findFirstByTag(pictXml, "v:rect");
|
|
28724
|
+
const style = shape ? getAttr(shape, "style") ?? "" : "";
|
|
28725
|
+
return {
|
|
28726
|
+
relationshipId,
|
|
28727
|
+
widthEmu: readVmlLength(style, "width"),
|
|
28728
|
+
heightEmu: readVmlLength(style, "height"),
|
|
28729
|
+
alt: (shape ? getAttr(shape, "alt") : void 0) ?? "",
|
|
28730
|
+
// VML positioning is a CSS-ish `style`, not the wp: anchor vocabulary the
|
|
28731
|
+
// anchor fields describe. Reporting it as inline keeps the renderer from
|
|
28732
|
+
// acting on offsets that were never read.
|
|
28733
|
+
inline: true,
|
|
28734
|
+
wrap: null,
|
|
28735
|
+
floatSide: null,
|
|
28736
|
+
behindDoc: false,
|
|
28737
|
+
offsetXEmu: null,
|
|
28738
|
+
offsetYEmu: null
|
|
28739
|
+
};
|
|
28740
|
+
}
|
|
28741
|
+
function parseAlternateContent(el) {
|
|
28742
|
+
if (getTagName(el) !== "mc:AlternateContent") return null;
|
|
28743
|
+
const branches = getChildren(el).filter((child) => {
|
|
28744
|
+
const tag = getTagName(child);
|
|
28745
|
+
return tag === "mc:Choice" || tag === "mc:Fallback";
|
|
28746
|
+
});
|
|
28747
|
+
const ordered = [
|
|
28748
|
+
...branches.filter((b) => getTagName(b) === "mc:Choice"),
|
|
28749
|
+
...branches.filter((b) => getTagName(b) === "mc:Fallback")
|
|
28750
|
+
];
|
|
28751
|
+
for (const branch of ordered) {
|
|
28752
|
+
const drawing = findFirstByTag(branch, "w:drawing");
|
|
28753
|
+
if (drawing) {
|
|
28754
|
+
const info = parseDrawing(drawing);
|
|
28755
|
+
if (info && info.relationshipId !== null) return info;
|
|
28756
|
+
}
|
|
28757
|
+
const pict = findFirstByTag(branch, "w:pict");
|
|
28758
|
+
if (pict) {
|
|
28759
|
+
const info = parsePict(pict);
|
|
28760
|
+
if (info) return info;
|
|
28761
|
+
}
|
|
28762
|
+
}
|
|
28763
|
+
return null;
|
|
28764
|
+
}
|
|
28698
28765
|
function readPosOffset(containerEl, positionTag) {
|
|
28699
28766
|
const position = findFirstByTag(containerEl, positionTag);
|
|
28700
28767
|
if (!position) return null;
|
|
@@ -42936,6 +43003,24 @@ ${e.toString()}`);
|
|
|
42936
43003
|
}
|
|
42937
43004
|
};
|
|
42938
43005
|
}
|
|
43006
|
+
function imageNode(info, originalXml, marks) {
|
|
43007
|
+
return docxSchema.nodes.image_inline.create(
|
|
43008
|
+
{
|
|
43009
|
+
relationshipId: info.relationshipId,
|
|
43010
|
+
widthEmu: info.widthEmu,
|
|
43011
|
+
heightEmu: info.heightEmu,
|
|
43012
|
+
alt: info.alt,
|
|
43013
|
+
originalXml,
|
|
43014
|
+
wrap: info.wrap,
|
|
43015
|
+
floatSide: info.floatSide,
|
|
43016
|
+
behindDoc: info.behindDoc,
|
|
43017
|
+
offsetXEmu: info.offsetXEmu,
|
|
43018
|
+
offsetYEmu: info.offsetYEmu
|
|
43019
|
+
},
|
|
43020
|
+
void 0,
|
|
43021
|
+
marks
|
|
43022
|
+
);
|
|
43023
|
+
}
|
|
42939
43024
|
function convertRunChild(child, marks, state) {
|
|
42940
43025
|
if (child.kind === "text") {
|
|
42941
43026
|
if (child.value.length === 0) return [];
|
|
@@ -42963,26 +43048,15 @@ ${e.toString()}`);
|
|
|
42963
43048
|
}
|
|
42964
43049
|
if (tag === "w:drawing") {
|
|
42965
43050
|
const info = parseDrawing(child.xml);
|
|
42966
|
-
if (info)
|
|
42967
|
-
|
|
42968
|
-
|
|
42969
|
-
|
|
42970
|
-
|
|
42971
|
-
|
|
42972
|
-
|
|
42973
|
-
|
|
42974
|
-
|
|
42975
|
-
wrap: info.wrap,
|
|
42976
|
-
floatSide: info.floatSide,
|
|
42977
|
-
behindDoc: info.behindDoc,
|
|
42978
|
-
offsetXEmu: info.offsetXEmu,
|
|
42979
|
-
offsetYEmu: info.offsetYEmu
|
|
42980
|
-
},
|
|
42981
|
-
void 0,
|
|
42982
|
-
marks
|
|
42983
|
-
)
|
|
42984
|
-
];
|
|
42985
|
-
}
|
|
43051
|
+
if (info) return [imageNode(info, child.xml, marks)];
|
|
43052
|
+
}
|
|
43053
|
+
if (tag === "mc:AlternateContent") {
|
|
43054
|
+
const info = parseAlternateContent(child.xml);
|
|
43055
|
+
if (info) return [imageNode(info, child.xml, marks)];
|
|
43056
|
+
}
|
|
43057
|
+
if (tag === "w:pict") {
|
|
43058
|
+
const info = parsePict(child.xml);
|
|
43059
|
+
if (info) return [imageNode(info, child.xml, marks)];
|
|
42986
43060
|
}
|
|
42987
43061
|
return [
|
|
42988
43062
|
docxSchema.nodes.opaque_inline.create({ xml: child.xml }, void 0, marks)
|
package/dist/src/cli.js
CHANGED
|
@@ -44955,6 +44955,7 @@ var LoticsClient = class {
|
|
|
44955
44955
|
formData.append("capabilities", JSON.stringify(args.capabilities));
|
|
44956
44956
|
}
|
|
44957
44957
|
formData.append("workflow_aliases", JSON.stringify(args.workflow_aliases ?? []));
|
|
44958
|
+
formData.append("query_aliases", JSON.stringify(args.query_aliases ?? []));
|
|
44958
44959
|
const url2 = `${this.baseUrl}/v1/apps/${encodeURIComponent(args.app_id)}/versions`;
|
|
44959
44960
|
const response = await fetch(url2, {
|
|
44960
44961
|
method: "POST",
|
|
@@ -64951,12 +64952,16 @@ var appWorkflowContractSchema = zod_default.object({
|
|
|
64951
64952
|
inputs: zod_default.record(zod_default.string(), appWorkflowInputSchema).optional(),
|
|
64952
64953
|
outputs: zod_default.record(zod_default.string(), appWorkflowOutputSchema).optional()
|
|
64953
64954
|
});
|
|
64955
|
+
var MAX_APP_CAPABILITY_DESCRIPTION = 300;
|
|
64954
64956
|
var appQueryDeclarationSchema = zod_default.object({
|
|
64955
64957
|
ast: zod_default.unknown().describe(
|
|
64956
64958
|
"Query AST template (a QueryNode). Validated server-side via parseQueryNode at deploy. May embed {{params.<name>}} tokens in filter value positions."
|
|
64957
64959
|
),
|
|
64958
64960
|
params: zod_default.record(zod_default.string(), appWorkflowInputSchema).optional().describe(
|
|
64959
64961
|
"Typed param schema. Keys are param names referenced as {{params.<name>}} in the ast; values declare type + constraints. The server validates the caller's params payload against this before interpolating. Omit for queries that take no params."
|
|
64962
|
+
),
|
|
64963
|
+
description: zod_default.string().optional().describe(
|
|
64964
|
+
`What this query returns, in one line \u2014 read by an agent choosing between the app's aliases. An alias is a JS identifier, which names a query without saying what it covers. Capped at ${MAX_APP_CAPABILITY_DESCRIPTION} characters.`
|
|
64960
64965
|
)
|
|
64961
64966
|
});
|
|
64962
64967
|
var appAgentDeclarationSchema = zod_default.object({
|
|
@@ -70822,7 +70827,8 @@ async function appDeploy(client, args) {
|
|
|
70822
70827
|
// typing artifact maintained by habit, so its keys answered this question
|
|
70823
70828
|
// with whatever the author last remembered to write. Stop calling an
|
|
70824
70829
|
// alias + redeploy to lift the guard before removing its binding.
|
|
70825
|
-
workflow_aliases: called.workflows
|
|
70830
|
+
workflow_aliases: called.workflows,
|
|
70831
|
+
query_aliases: called.queries
|
|
70826
70832
|
});
|
|
70827
70833
|
writeAppMeta(projectDir, {
|
|
70828
70834
|
...meta3,
|
|
@@ -89648,37 +89654,47 @@ function extractParagraphText(el) {
|
|
|
89648
89654
|
}
|
|
89649
89655
|
return parts.join("");
|
|
89650
89656
|
}
|
|
89651
|
-
function
|
|
89652
|
-
const
|
|
89657
|
+
function getParagraphTextSegments(el) {
|
|
89658
|
+
const segments = [];
|
|
89653
89659
|
for (const child of getChildren(el)) {
|
|
89654
89660
|
if (getTagName(child) !== "w:r") continue;
|
|
89655
|
-
let
|
|
89656
|
-
|
|
89661
|
+
let pending = [];
|
|
89662
|
+
const flush = () => {
|
|
89663
|
+
if (pending.length === 0) return;
|
|
89664
|
+
const text = pending.map(
|
|
89665
|
+
(node) => getChildren(node).reduce(
|
|
89666
|
+
(acc, tn) => typeof tn["#text"] === "string" ? acc + tn["#text"] : acc,
|
|
89667
|
+
""
|
|
89668
|
+
)
|
|
89669
|
+
).join("");
|
|
89670
|
+
segments.push({ element: child, textNodes: pending, text });
|
|
89671
|
+
pending = [];
|
|
89672
|
+
};
|
|
89657
89673
|
for (const grandchild of getChildren(child)) {
|
|
89658
|
-
if (getTagName(grandchild)
|
|
89659
|
-
|
|
89660
|
-
|
|
89661
|
-
if (typeof tn["#text"] === "string") text += tn["#text"];
|
|
89674
|
+
if (getTagName(grandchild) === "w:t") {
|
|
89675
|
+
pending.push(grandchild);
|
|
89676
|
+
continue;
|
|
89662
89677
|
}
|
|
89678
|
+
flush();
|
|
89663
89679
|
}
|
|
89664
|
-
|
|
89680
|
+
flush();
|
|
89665
89681
|
}
|
|
89666
|
-
return
|
|
89682
|
+
return segments;
|
|
89667
89683
|
}
|
|
89668
|
-
function
|
|
89669
|
-
const children = getChildren(
|
|
89670
|
-
const textNode = {
|
|
89671
|
-
|
|
89672
|
-
|
|
89673
|
-
|
|
89674
|
-
|
|
89684
|
+
function setSegmentText(segment, newText) {
|
|
89685
|
+
const children = getChildren(segment.element);
|
|
89686
|
+
const textNode = {
|
|
89687
|
+
"w:t": [{ "#text": newText }],
|
|
89688
|
+
":@": { "@_xml:space": "preserve" }
|
|
89689
|
+
};
|
|
89690
|
+
const head = children.indexOf(segment.textNodes[0]);
|
|
89691
|
+
children[head] = textNode;
|
|
89692
|
+
for (let i2 = segment.textNodes.length - 1; i2 >= 1; i2--) {
|
|
89693
|
+
const at2 = children.indexOf(segment.textNodes[i2]);
|
|
89694
|
+
if (at2 >= 0) children.splice(at2, 1);
|
|
89675
89695
|
}
|
|
89676
|
-
|
|
89677
|
-
|
|
89678
|
-
}
|
|
89679
|
-
function setRunText(run, newText) {
|
|
89680
|
-
writeRunText(run.element, newText);
|
|
89681
|
-
run.text = newText;
|
|
89696
|
+
segment.textNodes = [textNode];
|
|
89697
|
+
segment.text = newText;
|
|
89682
89698
|
}
|
|
89683
89699
|
function computeReplacementRanges(text, query, replacement, matchType, maxReplacements, startCount) {
|
|
89684
89700
|
const ranges = [];
|
|
@@ -89713,39 +89729,39 @@ function computeReplacementRanges(text, query, replacement, matchType, maxReplac
|
|
|
89713
89729
|
}
|
|
89714
89730
|
return { ranges, count };
|
|
89715
89731
|
}
|
|
89716
|
-
function applyRangeReplacements(
|
|
89732
|
+
function applyRangeReplacements(segments, ranges) {
|
|
89717
89733
|
if (ranges.length === 0) return;
|
|
89718
89734
|
const bounds = [];
|
|
89719
89735
|
let offset = 0;
|
|
89720
|
-
for (const
|
|
89721
|
-
bounds.push({
|
|
89722
|
-
offset +=
|
|
89736
|
+
for (const segment of segments) {
|
|
89737
|
+
bounds.push({ segment, start: offset, end: offset + segment.text.length });
|
|
89738
|
+
offset += segment.text.length;
|
|
89723
89739
|
}
|
|
89724
|
-
const joined =
|
|
89740
|
+
const joined = segments.map((s) => s.text).join("");
|
|
89725
89741
|
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
89726
|
-
for (const {
|
|
89742
|
+
for (const { segment, start: segStart, end: segEnd } of bounds) {
|
|
89727
89743
|
let next = "";
|
|
89728
|
-
let cursor =
|
|
89744
|
+
let cursor = segStart;
|
|
89729
89745
|
for (const range2 of sorted) {
|
|
89730
|
-
if (range2.end <=
|
|
89731
|
-
const keepUntil = Math.min(range2.start,
|
|
89732
|
-
const from = Math.max(cursor,
|
|
89746
|
+
if (range2.end <= segStart || range2.start >= segEnd) continue;
|
|
89747
|
+
const keepUntil = Math.min(range2.start, segEnd);
|
|
89748
|
+
const from = Math.max(cursor, segStart);
|
|
89733
89749
|
if (keepUntil > from) next += joined.slice(from, keepUntil);
|
|
89734
|
-
if (
|
|
89750
|
+
if (segStart <= range2.start && range2.start < segEnd) next += range2.replacement;
|
|
89735
89751
|
cursor = Math.max(cursor, range2.end);
|
|
89736
89752
|
}
|
|
89737
|
-
const tail = Math.max(cursor,
|
|
89738
|
-
if (
|
|
89739
|
-
if (next !==
|
|
89753
|
+
const tail = Math.max(cursor, segStart);
|
|
89754
|
+
if (segEnd > tail) next += joined.slice(tail, segEnd);
|
|
89755
|
+
if (next !== segment.text) setSegmentText(segment, next);
|
|
89740
89756
|
}
|
|
89741
89757
|
}
|
|
89742
89758
|
function replaceInParagraph(el, query, replacement, matchType, maxReplacements, replacementsMade) {
|
|
89743
89759
|
if (!extractParagraphText(el)) return replacementsMade;
|
|
89744
|
-
const
|
|
89745
|
-
if (
|
|
89746
|
-
const text =
|
|
89760
|
+
const segments = getParagraphTextSegments(el);
|
|
89761
|
+
if (segments.length === 0) return replacementsMade;
|
|
89762
|
+
const text = segments.length === 1 ? segments[0].text : segments.map((s) => s.text).join("");
|
|
89747
89763
|
const { ranges, count } = computeReplacementRanges(text, query, replacement, matchType, maxReplacements, replacementsMade);
|
|
89748
|
-
applyRangeReplacements(
|
|
89764
|
+
applyRangeReplacements(segments, ranges);
|
|
89749
89765
|
return count;
|
|
89750
89766
|
}
|
|
89751
89767
|
function replaceText(bodyElements, query, replacement, matchType = "contains", maxReplacements = Infinity) {
|
package/dist/src/client.d.ts
CHANGED
|
@@ -222,6 +222,7 @@ export declare class LoticsClient {
|
|
|
222
222
|
queries?: Record<string, {
|
|
223
223
|
ast: unknown;
|
|
224
224
|
params?: Record<string, unknown>;
|
|
225
|
+
description?: string;
|
|
225
226
|
}> | null;
|
|
226
227
|
/**
|
|
227
228
|
* Live alias → agent declaration map from `apps.agents`. Source of truth for
|
|
@@ -866,6 +867,7 @@ export declare class LoticsClient {
|
|
|
866
867
|
setAppQuery(app_id: string, alias: string, declaration: {
|
|
867
868
|
ast: unknown;
|
|
868
869
|
params?: Record<string, unknown>;
|
|
870
|
+
description?: string;
|
|
869
871
|
}): Promise<ToolExecuteResult>;
|
|
870
872
|
/**
|
|
871
873
|
* Bind (create or replace) an app agent by alias via the `set_app_agent` tool
|
|
@@ -1006,14 +1008,16 @@ export declare class LoticsClient {
|
|
|
1006
1008
|
prev_version_id?: string | null;
|
|
1007
1009
|
message?: string | null;
|
|
1008
1010
|
/**
|
|
1009
|
-
* Alias → query declaration map from
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1011
|
+
* Alias → query declaration map ECHOED BACK from the live row (see
|
|
1012
|
+
* `readLiveQueries`), not read from the manifest. Every key the row holds
|
|
1013
|
+
* must survive the round trip — `description` included — because a server
|
|
1014
|
+
* that treats a present map as authoritative writes exactly what it is
|
|
1015
|
+
* sent, so a lossy echo silently strips whatever it forgot.
|
|
1013
1016
|
*/
|
|
1014
1017
|
queries?: Record<string, {
|
|
1015
1018
|
ast: unknown;
|
|
1016
1019
|
params?: Record<string, unknown>;
|
|
1020
|
+
description?: string;
|
|
1017
1021
|
}>;
|
|
1018
1022
|
/**
|
|
1019
1023
|
* Opt-in app capabilities from `package.json#lotics.capabilities`. The CLI
|
|
@@ -1032,6 +1036,7 @@ export declare class LoticsClient {
|
|
|
1032
1036
|
* (empty array when none declared).
|
|
1033
1037
|
*/
|
|
1034
1038
|
workflow_aliases?: string[];
|
|
1039
|
+
query_aliases?: string[];
|
|
1035
1040
|
}): Promise<{
|
|
1036
1041
|
version_id: string;
|
|
1037
1042
|
version_number: number;
|
package/dist/src/client.js
CHANGED
|
@@ -723,6 +723,7 @@ export class LoticsClient {
|
|
|
723
723
|
// server records what the served version calls — the remove_app_workflow
|
|
724
724
|
// guard reads this back. These are the manifest KEYS only, never bindings.
|
|
725
725
|
formData.append("workflow_aliases", JSON.stringify(args.workflow_aliases ?? []));
|
|
726
|
+
formData.append("query_aliases", JSON.stringify(args.query_aliases ?? []));
|
|
726
727
|
const url = `${this.baseUrl}/v1/apps/${encodeURIComponent(args.app_id)}/versions`;
|
|
727
728
|
const response = await fetch(url, {
|
|
728
729
|
method: "POST",
|