@lotics/cli 0.96.6 → 0.98.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/render_page.js +10 -5
- package/dist/src/cli.js +175 -42
- package/dist/src/client.d.ts +7 -14
- package/dist/src/client.js +1 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,11 +92,14 @@ Every command names its target before it acts — `lotics → <org> / <workspace
|
|
|
92
92
|
|
|
93
93
|
```
|
|
94
94
|
--api-key flag > LOTICS_API_KEY env > LOTICS_ORG env (name|id)
|
|
95
|
-
> local .lotics/config.json >
|
|
95
|
+
> local .lotics/config.json > app manifest workspace → its saved profile
|
|
96
|
+
> global active profile
|
|
96
97
|
```
|
|
97
98
|
|
|
98
99
|
`LOTICS_WORKSPACE` (or `--workspace <id>` / `-w`) overrides the workspace at any level. For ephemeral or CI use, set `LOTICS_API_KEY` instead of saving anything.
|
|
99
100
|
|
|
101
|
+
In an app project, `lotics app *` commands derive the credential from the directory when nothing explicit chose one: the manifest names the app's workspace, and when exactly one saved profile owns that workspace, that profile is used — the machine-wide default (which another shell can move between two of your commands) is never consulted. An explicit flag, env var, or directory pin still wins, and an org whose profile remembers a different workspace simply falls through to the announced default, exactly as before.
|
|
102
|
+
|
|
100
103
|
## Workspaces
|
|
101
104
|
|
|
102
105
|
Workspaces live inside the active org. If the org has more than one, select before running tools:
|
package/dist/render_page.js
CHANGED
|
@@ -52872,8 +52872,9 @@ ${e.toString()}`);
|
|
|
52872
52872
|
const max2 = parseInt(col["@_max"] ?? "1", 10);
|
|
52873
52873
|
const width = col["@_width"] ? parseFloat(col["@_width"]) : defaultColWidth;
|
|
52874
52874
|
const hidden = col["@_hidden"] === "1" || col["@_hidden"] === "true";
|
|
52875
|
+
const customWidth = col["@_customWidth"] === "1" || col["@_customWidth"] === "true";
|
|
52875
52876
|
const outlineLevel = parseInt(col["@_outlineLevel"] ?? "0", 10);
|
|
52876
|
-
columns.push({ min, max: max2, width, hidden, outlineLevel });
|
|
52877
|
+
columns.push({ min, max: max2, width, hidden, customWidth, outlineLevel });
|
|
52877
52878
|
for (let c = min; c <= max2; c++) {
|
|
52878
52879
|
if (hidden) colHidden.add(c);
|
|
52879
52880
|
if (outlineLevel > 0) colOutlineLevels.set(c, outlineLevel);
|
|
@@ -52883,9 +52884,11 @@ ${e.toString()}`);
|
|
|
52883
52884
|
}
|
|
52884
52885
|
function buildColumns(colDefs, colHidden, maxContentWidth, colCount, _defaultColWidth) {
|
|
52885
52886
|
const explicitWidth = /* @__PURE__ */ new Map();
|
|
52887
|
+
const pinned = /* @__PURE__ */ new Set();
|
|
52886
52888
|
for (const def of colDefs) {
|
|
52887
52889
|
for (let c = def.min; c <= def.max; c++) {
|
|
52888
52890
|
explicitWidth.set(c, def.width);
|
|
52891
|
+
if (def.customWidth) pinned.add(c);
|
|
52889
52892
|
}
|
|
52890
52893
|
}
|
|
52891
52894
|
const columns = [];
|
|
@@ -52899,7 +52902,7 @@ ${e.toString()}`);
|
|
|
52899
52902
|
} else {
|
|
52900
52903
|
width = Math.max(8, Math.min(contentChars + 2, 40));
|
|
52901
52904
|
}
|
|
52902
|
-
columns.push({ index: c, width, hidden });
|
|
52905
|
+
columns.push({ index: c, width, hidden, ...pinned.has(c) ? { customWidth: true } : {} });
|
|
52903
52906
|
}
|
|
52904
52907
|
return columns;
|
|
52905
52908
|
}
|
|
@@ -52943,6 +52946,7 @@ ${e.toString()}`);
|
|
|
52943
52946
|
rowCount++;
|
|
52944
52947
|
if (rowCount > maxRows) continue;
|
|
52945
52948
|
const height = rowEl["@_ht"] ? parseFloat(rowEl["@_ht"]) : defaultRowHeight;
|
|
52949
|
+
const customHeight = rowEl["@_customHeight"] === "1" || rowEl["@_customHeight"] === "true";
|
|
52946
52950
|
const cellArr = rowEl["c"];
|
|
52947
52951
|
const cells = [];
|
|
52948
52952
|
if (cellArr) {
|
|
@@ -52964,7 +52968,8 @@ ${e.toString()}`);
|
|
|
52964
52968
|
index: rowIndex,
|
|
52965
52969
|
height,
|
|
52966
52970
|
cells,
|
|
52967
|
-
hidden: rowHidden
|
|
52971
|
+
hidden: rowHidden,
|
|
52972
|
+
...customHeight ? { customHeight: true } : {}
|
|
52968
52973
|
});
|
|
52969
52974
|
}
|
|
52970
52975
|
return {
|
|
@@ -54378,7 +54383,7 @@ ${e.toString()}`);
|
|
|
54378
54383
|
sheet.freeze = { row: ps.freezePane.frozenRows, col: ps.freezePane.frozenCols };
|
|
54379
54384
|
}
|
|
54380
54385
|
for (const col of ps.columns) {
|
|
54381
|
-
if (col.width !== ps.defaultColWidth) {
|
|
54386
|
+
if (col.customWidth || col.width !== ps.defaultColWidth) {
|
|
54382
54387
|
sheet.colWidths.set(col.index, col.width);
|
|
54383
54388
|
}
|
|
54384
54389
|
if (col.hidden) {
|
|
@@ -54391,7 +54396,7 @@ ${e.toString()}`);
|
|
|
54391
54396
|
return `${startRef}:${endRef}`;
|
|
54392
54397
|
});
|
|
54393
54398
|
for (const row of ps.rows) {
|
|
54394
|
-
if (row.height !== ps.defaultRowHeight) {
|
|
54399
|
+
if (row.customHeight || row.height !== ps.defaultRowHeight) {
|
|
54395
54400
|
sheet.rowHeights.set(row.index, row.height);
|
|
54396
54401
|
}
|
|
54397
54402
|
if (row.hidden) {
|
package/dist/src/cli.js
CHANGED
|
@@ -44165,9 +44165,7 @@ import os2 from "node:os";
|
|
|
44165
44165
|
import path7 from "node:path";
|
|
44166
44166
|
import readline from "node:readline";
|
|
44167
44167
|
|
|
44168
|
-
// src/
|
|
44169
|
-
import fs from "node:fs";
|
|
44170
|
-
import path from "node:path";
|
|
44168
|
+
// ../shared/src/transport_error.ts
|
|
44171
44169
|
function gatewayErrorMessage(status) {
|
|
44172
44170
|
if (status === 524) {
|
|
44173
44171
|
return "The request took too long to finish (gateway timeout). It may still be running \u2014 check back in a moment, or try again.";
|
|
@@ -44181,6 +44179,10 @@ function transportErrorMessage(status, parsed) {
|
|
|
44181
44179
|
const jsonMessage = parsed && typeof parsed.message === "string" ? parsed.message : null;
|
|
44182
44180
|
return parsed === null || status >= 500 || jsonMessage === null ? gatewayErrorMessage(status) : jsonMessage;
|
|
44183
44181
|
}
|
|
44182
|
+
|
|
44183
|
+
// src/client.ts
|
|
44184
|
+
import fs from "node:fs";
|
|
44185
|
+
import path from "node:path";
|
|
44184
44186
|
function findAvailableFilename(dir, filename, reserved) {
|
|
44185
44187
|
const isTaken = (name) => {
|
|
44186
44188
|
const full = path.join(dir, name);
|
|
@@ -45107,7 +45109,7 @@ function resolveProfileByNameOrId(profiles, nameOrId) {
|
|
|
45107
45109
|
}
|
|
45108
45110
|
return null;
|
|
45109
45111
|
}
|
|
45110
|
-
function resolveContext(flags) {
|
|
45112
|
+
function resolveContext(flags, appWorkspaceId) {
|
|
45111
45113
|
const envKey = process.env.LOTICS_API_KEY;
|
|
45112
45114
|
const envOrg = process.env.LOTICS_ORG;
|
|
45113
45115
|
const envWorkspace = process.env.LOTICS_WORKSPACE;
|
|
@@ -45157,6 +45159,19 @@ function resolveContext(flags) {
|
|
|
45157
45159
|
`This directory's .lotics/config.json uses the old self-contained format (inline key), which is no longer supported. Re-pin with "lotics auth api-key <key> --local" (or "lotics org use <name|id> --local").`
|
|
45158
45160
|
);
|
|
45159
45161
|
}
|
|
45162
|
+
if (appWorkspaceId && !wsOverride) {
|
|
45163
|
+
const matches = Object.entries(profiles).filter(([, p]) => p.workspace_id === appWorkspaceId);
|
|
45164
|
+
if (matches.length === 1) {
|
|
45165
|
+
const [orgId, profile] = matches[0];
|
|
45166
|
+
return {
|
|
45167
|
+
apiKey: profile.api_key,
|
|
45168
|
+
orgId,
|
|
45169
|
+
orgName: profile.org_name,
|
|
45170
|
+
workspaceId: appWorkspaceId,
|
|
45171
|
+
source: "app_manifest_profile"
|
|
45172
|
+
};
|
|
45173
|
+
}
|
|
45174
|
+
}
|
|
45160
45175
|
if (global2?.active_org) {
|
|
45161
45176
|
const profile = profiles[global2.active_org];
|
|
45162
45177
|
if (!profile) {
|
|
@@ -64402,7 +64417,8 @@ var aggregateOperationSchema = external_exports.enum([
|
|
|
64402
64417
|
"checked",
|
|
64403
64418
|
"unchecked",
|
|
64404
64419
|
"percent_checked",
|
|
64405
|
-
"percent_unchecked"
|
|
64420
|
+
"percent_unchecked",
|
|
64421
|
+
"string_agg"
|
|
64406
64422
|
]);
|
|
64407
64423
|
var OPERATION_FIELD_TYPES = {
|
|
64408
64424
|
empty: ["text", "number", "date", "select", "select_member", "select_record_link", "files", "formula", "rollup"],
|
|
@@ -64517,12 +64533,21 @@ var queryProjectionColumnSchema = zod_default.union([
|
|
|
64517
64533
|
zod_default.string().describe("Passthrough shorthand: a source field key. Output = the key, type = the field's type."),
|
|
64518
64534
|
queryProjectionColumnObjectSchema
|
|
64519
64535
|
]);
|
|
64536
|
+
var STRING_AGG_MAX_VALUES = 100;
|
|
64537
|
+
var STRING_AGG_DEFAULT_MAX_VALUES = 20;
|
|
64520
64538
|
var queryAggregateColumnSchema = zod_default.object({
|
|
64521
64539
|
output: zod_default.string().describe("Output column name"),
|
|
64522
64540
|
type: queryColumnTypeSchema.describe("Output column type"),
|
|
64523
64541
|
operation: aggregateOperationSchema,
|
|
64524
64542
|
input_column: zod_default.string().optional().describe(
|
|
64525
64543
|
"Input column to aggregate. Required for non-count operations; ignored for count."
|
|
64544
|
+
),
|
|
64545
|
+
separator: zod_default.string().max(8).optional().describe('string_agg only. Joins the values. Defaults to ", ".'),
|
|
64546
|
+
distinct: zod_default.boolean().optional().describe(
|
|
64547
|
+
"string_agg only. Collapses repeats \u2014 a group of containers sized 40HC/40HC/20DC aggregates to '20DC, 40HC'. Defaults to true, which is almost always what a summary column wants."
|
|
64548
|
+
),
|
|
64549
|
+
max_values: zod_default.number().int().min(1).max(STRING_AGG_MAX_VALUES).optional().describe(
|
|
64550
|
+
`string_agg only. Caps how many values are emitted so an unbounded child set cannot produce a giant cell. Defaults to ${STRING_AGG_DEFAULT_MAX_VALUES}. Pair with a \`unique\` aggregate to render an accurate '+N more'.`
|
|
64526
64551
|
)
|
|
64527
64552
|
});
|
|
64528
64553
|
var rankingWindowFunctionSchema = (fn) => zod_default.object({ output: zod_default.string().describe("Output column name"), fn: zod_default.literal(fn) }).strict();
|
|
@@ -64879,6 +64904,12 @@ var appAgentDeclarationSchema = zod_default.object({
|
|
|
64879
64904
|
knowledge_doc_ids: zod_default.array(zod_default.string().min(1)).optional().describe(
|
|
64880
64905
|
"Knowledge docs the agent may read, validated at declare time against the app owner's `use` access. Small docs are inlined into the agent's system prompt each run; a doc too large to inline requires the code tools (code_exec) in tool_names and is read by staging it into a code run. Omit for an agent that needs no knowledge."
|
|
64881
64906
|
),
|
|
64907
|
+
query_aliases: zod_default.array(zod_default.string().min(1)).optional().describe(
|
|
64908
|
+
"Named queries from this app's manifest the agent may run via `run_app_query`, validated at declare time against the app's own queries. This is the agent's ENTIRE read surface over workspace data \u2014 a template fixes the tables, filters, and projection, so it bounds rows and columns, not just tables. Omit for an agent that reads no records."
|
|
64909
|
+
),
|
|
64910
|
+
workflow_aliases: zod_default.array(zod_default.string().min(1)).optional().describe(
|
|
64911
|
+
"Workflows from this app's manifest the agent may invoke via `run_app_workflow`, validated at declare time against the app's own workflows. This is the agent's ENTIRE write surface \u2014 the same declared mutation path the app's UI uses, so table hooks and side-effect harvesting apply. Omit for a read-only agent."
|
|
64912
|
+
),
|
|
64882
64913
|
model_id: zod_default.string().min(1).optional().describe(
|
|
64883
64914
|
"Chat model id the agent runs on, validated against ACCEPTED_CHAT_MODEL_IDS. Omit to follow the platform default chat model, resolved at run time \u2014 the preferred choice: the agent tracks model generations with no per-app rewrite. Pin only a deliberate, tested choice."
|
|
64884
64915
|
),
|
|
@@ -79139,8 +79170,9 @@ function parseCols(worksheet, defaultColWidth) {
|
|
|
79139
79170
|
const max3 = parseInt(col["@_max"] ?? "1", 10);
|
|
79140
79171
|
const width = col["@_width"] ? parseFloat(col["@_width"]) : defaultColWidth;
|
|
79141
79172
|
const hidden = col["@_hidden"] === "1" || col["@_hidden"] === "true";
|
|
79173
|
+
const customWidth = col["@_customWidth"] === "1" || col["@_customWidth"] === "true";
|
|
79142
79174
|
const outlineLevel = parseInt(col["@_outlineLevel"] ?? "0", 10);
|
|
79143
|
-
columns.push({ min: min2, max: max3, width, hidden, outlineLevel });
|
|
79175
|
+
columns.push({ min: min2, max: max3, width, hidden, customWidth, outlineLevel });
|
|
79144
79176
|
for (let c = min2; c <= max3; c++) {
|
|
79145
79177
|
if (hidden) colHidden.add(c);
|
|
79146
79178
|
if (outlineLevel > 0) colOutlineLevels.set(c, outlineLevel);
|
|
@@ -79150,9 +79182,11 @@ function parseCols(worksheet, defaultColWidth) {
|
|
|
79150
79182
|
}
|
|
79151
79183
|
function buildColumns(colDefs, colHidden, maxContentWidth, colCount, _defaultColWidth) {
|
|
79152
79184
|
const explicitWidth = /* @__PURE__ */ new Map();
|
|
79185
|
+
const pinned = /* @__PURE__ */ new Set();
|
|
79153
79186
|
for (const def of colDefs) {
|
|
79154
79187
|
for (let c = def.min; c <= def.max; c++) {
|
|
79155
79188
|
explicitWidth.set(c, def.width);
|
|
79189
|
+
if (def.customWidth) pinned.add(c);
|
|
79156
79190
|
}
|
|
79157
79191
|
}
|
|
79158
79192
|
const columns = [];
|
|
@@ -79166,7 +79200,7 @@ function buildColumns(colDefs, colHidden, maxContentWidth, colCount, _defaultCol
|
|
|
79166
79200
|
} else {
|
|
79167
79201
|
width = Math.max(8, Math.min(contentChars + 2, 40));
|
|
79168
79202
|
}
|
|
79169
|
-
columns.push({ index: c, width, hidden });
|
|
79203
|
+
columns.push({ index: c, width, hidden, ...pinned.has(c) ? { customWidth: true } : {} });
|
|
79170
79204
|
}
|
|
79171
79205
|
return columns;
|
|
79172
79206
|
}
|
|
@@ -79210,6 +79244,7 @@ function parseSheetData(worksheet, styles, sharedStrings, hyperlinkMap, defaultR
|
|
|
79210
79244
|
rowCount++;
|
|
79211
79245
|
if (rowCount > maxRows) continue;
|
|
79212
79246
|
const height = rowEl["@_ht"] ? parseFloat(rowEl["@_ht"]) : defaultRowHeight;
|
|
79247
|
+
const customHeight = rowEl["@_customHeight"] === "1" || rowEl["@_customHeight"] === "true";
|
|
79213
79248
|
const cellArr = rowEl["c"];
|
|
79214
79249
|
const cells = [];
|
|
79215
79250
|
if (cellArr) {
|
|
@@ -79231,7 +79266,8 @@ function parseSheetData(worksheet, styles, sharedStrings, hyperlinkMap, defaultR
|
|
|
79231
79266
|
index: rowIndex,
|
|
79232
79267
|
height,
|
|
79233
79268
|
cells,
|
|
79234
|
-
hidden: rowHidden
|
|
79269
|
+
hidden: rowHidden,
|
|
79270
|
+
...customHeight ? { customHeight: true } : {}
|
|
79235
79271
|
});
|
|
79236
79272
|
}
|
|
79237
79273
|
return {
|
|
@@ -83767,7 +83803,7 @@ function loadSheetFromParsed(ps, styles) {
|
|
|
83767
83803
|
sheet.freeze = { row: ps.freezePane.frozenRows, col: ps.freezePane.frozenCols };
|
|
83768
83804
|
}
|
|
83769
83805
|
for (const col of ps.columns) {
|
|
83770
|
-
if (col.width !== ps.defaultColWidth) {
|
|
83806
|
+
if (col.customWidth || col.width !== ps.defaultColWidth) {
|
|
83771
83807
|
sheet.colWidths.set(col.index, col.width);
|
|
83772
83808
|
}
|
|
83773
83809
|
if (col.hidden) {
|
|
@@ -83780,7 +83816,7 @@ function loadSheetFromParsed(ps, styles) {
|
|
|
83780
83816
|
return `${startRef}:${endRef}`;
|
|
83781
83817
|
});
|
|
83782
83818
|
for (const row of ps.rows) {
|
|
83783
|
-
if (row.height !== ps.defaultRowHeight) {
|
|
83819
|
+
if (row.customHeight || row.height !== ps.defaultRowHeight) {
|
|
83784
83820
|
sheet.rowHeights.set(row.index, row.height);
|
|
83785
83821
|
}
|
|
83786
83822
|
if (row.hidden) {
|
|
@@ -84668,6 +84704,103 @@ function clampInertCells(sheet) {
|
|
|
84668
84704
|
for (const ref of pruned.keys()) sheet.cells.delete(ref);
|
|
84669
84705
|
return pruned;
|
|
84670
84706
|
}
|
|
84707
|
+
function axisStores(sheet, axis) {
|
|
84708
|
+
return axis === "row" ? {
|
|
84709
|
+
sizes: sheet.rowHeights,
|
|
84710
|
+
outline: sheet.rowOutlineLevels,
|
|
84711
|
+
hidden: sheet.hiddenRows,
|
|
84712
|
+
breaks: sheet.rowPageBreaks,
|
|
84713
|
+
setBreaks: (next) => {
|
|
84714
|
+
sheet.rowPageBreaks = next;
|
|
84715
|
+
}
|
|
84716
|
+
} : {
|
|
84717
|
+
sizes: sheet.colWidths,
|
|
84718
|
+
outline: sheet.colOutlineLevels,
|
|
84719
|
+
hidden: sheet.hiddenCols,
|
|
84720
|
+
breaks: sheet.colPageBreaks,
|
|
84721
|
+
setBreaks: (next) => {
|
|
84722
|
+
sheet.colPageBreaks = next;
|
|
84723
|
+
}
|
|
84724
|
+
};
|
|
84725
|
+
}
|
|
84726
|
+
function shiftedIndex(i2, at2, delta) {
|
|
84727
|
+
if (i2 < at2) return i2;
|
|
84728
|
+
if (delta < 0 && i2 < at2 - delta) return null;
|
|
84729
|
+
return i2 + delta;
|
|
84730
|
+
}
|
|
84731
|
+
function shiftKeys(map3, at2, delta) {
|
|
84732
|
+
const affected = [...map3.entries()].filter(([i2]) => i2 >= at2);
|
|
84733
|
+
for (const [i2] of affected) map3.delete(i2);
|
|
84734
|
+
for (const [i2, value] of affected) {
|
|
84735
|
+
const next = shiftedIndex(i2, at2, delta);
|
|
84736
|
+
if (next !== null) map3.set(next, value);
|
|
84737
|
+
}
|
|
84738
|
+
}
|
|
84739
|
+
function shiftMembers(set2, at2, delta) {
|
|
84740
|
+
const affected = [...set2].filter((i2) => i2 >= at2);
|
|
84741
|
+
for (const i2 of affected) set2.delete(i2);
|
|
84742
|
+
for (const i2 of affected) {
|
|
84743
|
+
const next = shiftedIndex(i2, at2, delta);
|
|
84744
|
+
if (next !== null) set2.add(next);
|
|
84745
|
+
}
|
|
84746
|
+
}
|
|
84747
|
+
function shiftBreaks(breaks, at2, delta) {
|
|
84748
|
+
const moved = breaks.map((i2) => shiftedIndex(i2, at2, delta)).filter((i2) => i2 !== null);
|
|
84749
|
+
return [...new Set(moved)].sort((a, b) => a - b);
|
|
84750
|
+
}
|
|
84751
|
+
function remapHyperlinks(sheet, landing) {
|
|
84752
|
+
const next = /* @__PURE__ */ new Map();
|
|
84753
|
+
for (const [ref, url2] of sheet.hyperlinks) {
|
|
84754
|
+
const rc = refToRowColSafe(ref);
|
|
84755
|
+
if (!rc) {
|
|
84756
|
+
next.set(ref, url2);
|
|
84757
|
+
continue;
|
|
84758
|
+
}
|
|
84759
|
+
const to = landing(rc.row, rc.col);
|
|
84760
|
+
if (to) next.set(rowColToRef(to.row, to.col), url2);
|
|
84761
|
+
}
|
|
84762
|
+
sheet.hyperlinks = next;
|
|
84763
|
+
}
|
|
84764
|
+
function axisLanding(axis, at2, delta) {
|
|
84765
|
+
return (row, col) => {
|
|
84766
|
+
const next = shiftedIndex(axis === "row" ? row : col, at2, delta);
|
|
84767
|
+
if (next === null) return null;
|
|
84768
|
+
return axis === "row" ? { row: next, col } : { row, col: next };
|
|
84769
|
+
};
|
|
84770
|
+
}
|
|
84771
|
+
function shiftAxisMetadata(sheet, axis, at2, delta) {
|
|
84772
|
+
const stores = axisStores(sheet, axis);
|
|
84773
|
+
shiftKeys(stores.sizes, at2, delta);
|
|
84774
|
+
shiftKeys(stores.outline, at2, delta);
|
|
84775
|
+
shiftMembers(stores.hidden, at2, delta);
|
|
84776
|
+
stores.setBreaks(shiftBreaks(stores.breaks, at2, delta));
|
|
84777
|
+
remapHyperlinks(sheet, axisLanding(axis, at2, delta));
|
|
84778
|
+
}
|
|
84779
|
+
var EMPTY_BAND = { sizes: [], outline: [], hidden: [], breaks: [], hyperlinks: [] };
|
|
84780
|
+
function snapshotAxisBand(sheet, axis, at2, count) {
|
|
84781
|
+
const stores = axisStores(sheet, axis);
|
|
84782
|
+
const inBand = (i2) => i2 >= at2 && i2 < at2 + count;
|
|
84783
|
+
const links = [];
|
|
84784
|
+
for (const [ref, url2] of sheet.hyperlinks) {
|
|
84785
|
+
const rc = refToRowColSafe(ref);
|
|
84786
|
+
if (rc && inBand(axis === "row" ? rc.row : rc.col)) links.push([ref, url2]);
|
|
84787
|
+
}
|
|
84788
|
+
return {
|
|
84789
|
+
sizes: [...stores.sizes.entries()].filter(([i2]) => inBand(i2)),
|
|
84790
|
+
outline: [...stores.outline.entries()].filter(([i2]) => inBand(i2)),
|
|
84791
|
+
hidden: [...stores.hidden].filter(inBand),
|
|
84792
|
+
breaks: stores.breaks.filter(inBand),
|
|
84793
|
+
hyperlinks: links
|
|
84794
|
+
};
|
|
84795
|
+
}
|
|
84796
|
+
function restoreAxisBand(sheet, axis, band) {
|
|
84797
|
+
const stores = axisStores(sheet, axis);
|
|
84798
|
+
for (const [i2, value] of band.sizes) stores.sizes.set(i2, value);
|
|
84799
|
+
for (const [i2, value] of band.outline) stores.outline.set(i2, value);
|
|
84800
|
+
for (const i2 of band.hidden) stores.hidden.add(i2);
|
|
84801
|
+
stores.setBreaks([.../* @__PURE__ */ new Set([...stores.breaks, ...band.breaks])].sort((a, b) => a - b));
|
|
84802
|
+
for (const [ref, url2] of band.hyperlinks) sheet.hyperlinks.set(ref, url2);
|
|
84803
|
+
}
|
|
84671
84804
|
function insertRowsCommand(workbook, sheetIndex, at2, count) {
|
|
84672
84805
|
const sheet = workbook.sheets[sheetIndex];
|
|
84673
84806
|
let mergeSnapshot = [];
|
|
@@ -84688,11 +84821,7 @@ function insertRowsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84688
84821
|
sheet.cells.delete(ref);
|
|
84689
84822
|
sheet.cells.set(rowColToRef(row + count, col), cell);
|
|
84690
84823
|
}
|
|
84691
|
-
|
|
84692
|
-
for (const [r, h] of heightsToShift) {
|
|
84693
|
-
sheet.rowHeights.delete(r);
|
|
84694
|
-
sheet.rowHeights.set(r + count, h);
|
|
84695
|
-
}
|
|
84824
|
+
shiftAxisMetadata(sheet, "row", at2, count);
|
|
84696
84825
|
adjustAllFormulasForRowShift(sheet, at2, count);
|
|
84697
84826
|
adjustMergedCellsForRowInsert(sheet, at2, count);
|
|
84698
84827
|
workbook.emit({ type: "rows_inserted", sheet: sheetIndex, at: at2, count });
|
|
@@ -84714,12 +84843,7 @@ function insertRowsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84714
84843
|
sheet.cells.delete(ref);
|
|
84715
84844
|
sheet.cells.set(rowColToRef(row - count, col), cell);
|
|
84716
84845
|
}
|
|
84717
|
-
|
|
84718
|
-
for (const [r, h] of heightsToShift) {
|
|
84719
|
-
sheet.rowHeights.delete(r);
|
|
84720
|
-
sheet.rowHeights.set(r - count, h);
|
|
84721
|
-
}
|
|
84722
|
-
for (let r = at2; r < at2 + count; r++) sheet.rowHeights.delete(r);
|
|
84846
|
+
shiftAxisMetadata(sheet, "row", at2, -count);
|
|
84723
84847
|
for (const [ref, cell] of inertSnapshot) sheet.cells.set(ref, cell);
|
|
84724
84848
|
workbook.emit({ type: "rows_deleted", sheet: sheetIndex, at: at2, count });
|
|
84725
84849
|
}
|
|
@@ -84736,11 +84860,13 @@ function deleteRowsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84736
84860
|
}
|
|
84737
84861
|
let mergeSnapshot = [];
|
|
84738
84862
|
let inertSnapshot = /* @__PURE__ */ new Map();
|
|
84863
|
+
let bandSnapshot = EMPTY_BAND;
|
|
84739
84864
|
return {
|
|
84740
84865
|
description: `Delete ${count} row${count > 1 ? "s" : ""} at ${at2}`,
|
|
84741
84866
|
execute() {
|
|
84742
84867
|
mergeSnapshot = [...sheet.mergedCells];
|
|
84743
84868
|
inertSnapshot = clampInertCells(sheet);
|
|
84869
|
+
bandSnapshot = snapshotAxisBand(sheet, "row", at2, count);
|
|
84744
84870
|
for (const ref of snapshot.keys()) sheet.cells.delete(ref);
|
|
84745
84871
|
const toMove = [];
|
|
84746
84872
|
for (const [ref] of sheet.cells) {
|
|
@@ -84753,12 +84879,15 @@ function deleteRowsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84753
84879
|
sheet.cells.delete(ref);
|
|
84754
84880
|
sheet.cells.set(rowColToRef(row - count, col), cell);
|
|
84755
84881
|
}
|
|
84882
|
+
shiftAxisMetadata(sheet, "row", at2, -count);
|
|
84756
84883
|
adjustAllFormulasForRowShift(sheet, at2, -count);
|
|
84757
84884
|
adjustMergedCellsForRowDelete(sheet, at2, count);
|
|
84758
84885
|
workbook.emit({ type: "rows_deleted", sheet: sheetIndex, at: at2, count });
|
|
84759
84886
|
},
|
|
84760
84887
|
undo() {
|
|
84761
84888
|
sheet.mergedCells = [...mergeSnapshot];
|
|
84889
|
+
shiftAxisMetadata(sheet, "row", at2, count);
|
|
84890
|
+
restoreAxisBand(sheet, "row", bandSnapshot);
|
|
84762
84891
|
const toMove = [];
|
|
84763
84892
|
for (const [ref] of sheet.cells) {
|
|
84764
84893
|
const rc = refToRowColSafe(ref);
|
|
@@ -84798,11 +84927,7 @@ function insertColsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84798
84927
|
sheet.cells.delete(ref);
|
|
84799
84928
|
sheet.cells.set(rowColToRef(row, col + count), cell);
|
|
84800
84929
|
}
|
|
84801
|
-
|
|
84802
|
-
for (const [c, w] of widthsToShift) {
|
|
84803
|
-
sheet.colWidths.delete(c);
|
|
84804
|
-
sheet.colWidths.set(c + count, w);
|
|
84805
|
-
}
|
|
84930
|
+
shiftAxisMetadata(sheet, "col", at2, count);
|
|
84806
84931
|
adjustAllFormulasForColShift(sheet, at2, count);
|
|
84807
84932
|
adjustMergedCellsForColInsert(sheet, at2, count);
|
|
84808
84933
|
workbook.emit({ type: "cols_inserted", sheet: sheetIndex, at: at2, count });
|
|
@@ -84824,12 +84949,7 @@ function insertColsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84824
84949
|
sheet.cells.delete(ref);
|
|
84825
84950
|
sheet.cells.set(rowColToRef(row, col - count), cell);
|
|
84826
84951
|
}
|
|
84827
|
-
|
|
84828
|
-
for (const [c, w] of widthsToShift) {
|
|
84829
|
-
sheet.colWidths.delete(c);
|
|
84830
|
-
sheet.colWidths.set(c - count, w);
|
|
84831
|
-
}
|
|
84832
|
-
for (let c = at2; c < at2 + count; c++) sheet.colWidths.delete(c);
|
|
84952
|
+
shiftAxisMetadata(sheet, "col", at2, -count);
|
|
84833
84953
|
for (const [ref, cell] of inertSnapshot) sheet.cells.set(ref, cell);
|
|
84834
84954
|
workbook.emit({ type: "cols_deleted", sheet: sheetIndex, at: at2, count });
|
|
84835
84955
|
}
|
|
@@ -84846,11 +84966,13 @@ function deleteColsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84846
84966
|
}
|
|
84847
84967
|
let mergeSnapshot = [];
|
|
84848
84968
|
let inertSnapshot = /* @__PURE__ */ new Map();
|
|
84969
|
+
let bandSnapshot = EMPTY_BAND;
|
|
84849
84970
|
return {
|
|
84850
84971
|
description: `Delete ${count} column${count > 1 ? "s" : ""} at ${at2}`,
|
|
84851
84972
|
execute() {
|
|
84852
84973
|
mergeSnapshot = [...sheet.mergedCells];
|
|
84853
84974
|
inertSnapshot = clampInertCells(sheet);
|
|
84975
|
+
bandSnapshot = snapshotAxisBand(sheet, "col", at2, count);
|
|
84854
84976
|
for (const ref of snapshot.keys()) sheet.cells.delete(ref);
|
|
84855
84977
|
const toMove = [];
|
|
84856
84978
|
for (const [ref] of sheet.cells) {
|
|
@@ -84863,12 +84985,15 @@ function deleteColsCommand(workbook, sheetIndex, at2, count) {
|
|
|
84863
84985
|
sheet.cells.delete(ref);
|
|
84864
84986
|
sheet.cells.set(rowColToRef(row, col - count), cell);
|
|
84865
84987
|
}
|
|
84988
|
+
shiftAxisMetadata(sheet, "col", at2, -count);
|
|
84866
84989
|
adjustAllFormulasForColShift(sheet, at2, -count);
|
|
84867
84990
|
adjustMergedCellsForColDelete(sheet, at2, count);
|
|
84868
84991
|
workbook.emit({ type: "cols_deleted", sheet: sheetIndex, at: at2, count });
|
|
84869
84992
|
},
|
|
84870
84993
|
undo() {
|
|
84871
84994
|
sheet.mergedCells = [...mergeSnapshot];
|
|
84995
|
+
shiftAxisMetadata(sheet, "col", at2, count);
|
|
84996
|
+
restoreAxisBand(sheet, "col", bandSnapshot);
|
|
84872
84997
|
const toMove = [];
|
|
84873
84998
|
for (const [ref] of sheet.cells) {
|
|
84874
84999
|
const rc = refToRowColSafe(ref);
|
|
@@ -91773,8 +91898,8 @@ Multiple workspaces in ${info.organization_name}. Run "lotics workspace select <
|
|
|
91773
91898
|
console.error(` Saved to the "${info.organization_name}" profile in ~/.lotics`);
|
|
91774
91899
|
}
|
|
91775
91900
|
}
|
|
91776
|
-
function requireClient(flags) {
|
|
91777
|
-
const ctx = resolveContext(flags);
|
|
91901
|
+
function requireClient(flags, appWorkspaceId) {
|
|
91902
|
+
const ctx = resolveContext(flags, appWorkspaceId);
|
|
91778
91903
|
if (!ctx) {
|
|
91779
91904
|
console.error('Not authenticated. Run "lotics auth signup", "lotics auth api-key <key>", or set LOTICS_API_KEY.');
|
|
91780
91905
|
process.exit(1);
|
|
@@ -91790,6 +91915,7 @@ var SOURCE_LABELS = {
|
|
|
91790
91915
|
env_key: "LOTICS_API_KEY env",
|
|
91791
91916
|
env_org: "LOTICS_ORG env",
|
|
91792
91917
|
local_pointer: "local .lotics/config.json (pin)",
|
|
91918
|
+
app_manifest_profile: "app manifest workspace \u2192 its saved profile",
|
|
91793
91919
|
global_profile: "global active profile"
|
|
91794
91920
|
};
|
|
91795
91921
|
function announceTarget(ctx, workspaceId) {
|
|
@@ -91803,12 +91929,15 @@ function announceTarget(ctx, workspaceId) {
|
|
|
91803
91929
|
}
|
|
91804
91930
|
console.error(`lotics \u2192 ${org} / ${workspaceId}`);
|
|
91805
91931
|
}
|
|
91806
|
-
function
|
|
91807
|
-
if (command !== "app") return;
|
|
91808
|
-
if (flags.workspace || process.env.LOTICS_WORKSPACE) return;
|
|
91809
|
-
if (subcommand === "create" || subcommand === "pull") return;
|
|
91932
|
+
function appManifestWorkspaceId(command, subcommand, pathArg, flags) {
|
|
91933
|
+
if (command !== "app") return void 0;
|
|
91934
|
+
if (flags.workspace || process.env.LOTICS_WORKSPACE) return void 0;
|
|
91935
|
+
if (subcommand === "create" || subcommand === "pull") return void 0;
|
|
91810
91936
|
const dir = pathArg && !pathArg.startsWith("-") ? pathArg : process.cwd();
|
|
91811
|
-
|
|
91937
|
+
return readAppWorkspaceId(dir) ?? void 0;
|
|
91938
|
+
}
|
|
91939
|
+
function applyAppManifestWorkspace(ctx, command, subcommand, pathArg, flags) {
|
|
91940
|
+
const workspaceId = appManifestWorkspaceId(command, subcommand, pathArg, flags);
|
|
91812
91941
|
if (workspaceId) ctx.workspaceId = workspaceId;
|
|
91813
91942
|
}
|
|
91814
91943
|
async function resolveWorkspace(client, ctx) {
|
|
@@ -92008,7 +92137,7 @@ async function main() {
|
|
|
92008
92137
|
}
|
|
92009
92138
|
if (command === "app" && subcommand === "codegen") {
|
|
92010
92139
|
const projectDir = toolArgs;
|
|
92011
|
-
const ctx2 = resolveContext(flags);
|
|
92140
|
+
const ctx2 = resolveContext(flags, appManifestWorkspaceId(command, subcommand, projectDir, flags));
|
|
92012
92141
|
if (!ctx2) {
|
|
92013
92142
|
await appCodegen({ projectDir });
|
|
92014
92143
|
return;
|
|
@@ -92125,7 +92254,11 @@ async function main() {
|
|
|
92125
92254
|
console.error("Downloads every file on the given file field into the output dir.");
|
|
92126
92255
|
process.exit(1);
|
|
92127
92256
|
}
|
|
92128
|
-
const
|
|
92257
|
+
const appPathArg = subcommand === "dev" ? toolArgs : void 0;
|
|
92258
|
+
const { client, ctx } = requireClient(
|
|
92259
|
+
flags,
|
|
92260
|
+
appManifestWorkspaceId(command, subcommand, appPathArg, flags)
|
|
92261
|
+
);
|
|
92129
92262
|
if (command === "workspace") {
|
|
92130
92263
|
if (subcommand === "doctor") {
|
|
92131
92264
|
await resolveWorkspace(client, ctx);
|
|
@@ -92239,7 +92372,7 @@ Available workspaces:`);
|
|
|
92239
92372
|
if (ctx.orgName) console.error(`Org: ${ctx.orgName}`);
|
|
92240
92373
|
return;
|
|
92241
92374
|
}
|
|
92242
|
-
applyAppManifestWorkspace(ctx, command, subcommand,
|
|
92375
|
+
applyAppManifestWorkspace(ctx, command, subcommand, appPathArg, flags);
|
|
92243
92376
|
await resolveWorkspace(client, ctx);
|
|
92244
92377
|
if (command === "knowledge") {
|
|
92245
92378
|
await runKnowledgeCommand(client, subcommand, toolArgs, flags);
|
package/dist/src/client.d.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import type { ContractConfigEntry, KnowledgeUpgradeEntry, ModifiedArtifact, PackageContentBinding, UpgradeResolutions } from "./package_content_types";
|
|
2
|
-
/**
|
|
3
|
-
* The error message for a non-ok response. A genuine JSON error (a 4xx carrying
|
|
4
|
-
* a `message`) surfaces verbatim; a non-JSON body (a gateway HTML page), any
|
|
5
|
-
* 5xx, or a JSON body without a `message` falls back to a body-free,
|
|
6
|
-
* status-derived message. `parsed` is the JSON.parse of the body, or `null`.
|
|
7
|
-
* In parity (by value, no shared dep) with `packages/app-sdk/src/rpc.ts`.
|
|
8
|
-
*/
|
|
9
|
-
export declare function transportErrorMessage(status: number, parsed: unknown): string;
|
|
10
2
|
/** One sort key forwarded to the app query RPC (wire shape of a `TableRecordSort` entry). */
|
|
11
3
|
export interface AppQuerySortKey {
|
|
12
4
|
field_key: string;
|
|
@@ -89,19 +81,20 @@ export interface ToolInfo {
|
|
|
89
81
|
}
|
|
90
82
|
/**
|
|
91
83
|
* A single knowledge doc with its HYDRATED body — the shape of
|
|
92
|
-
* `GET /v1/knowledge_docs/{id}
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* internally, so a CLI caller never needs to pass it.
|
|
84
|
+
* `GET /v1/knowledge_docs/{id}`, and the one content-read path a non-sandbox
|
|
85
|
+
* client has. `content_sha` is the concurrency token the REST PATCH echoes back
|
|
86
|
+
* as `expected_content_sha`; the `update_knowledge` TOOL CASes internally, so a
|
|
87
|
+
* CLI caller never needs to pass it.
|
|
97
88
|
*/
|
|
98
89
|
export interface KnowledgeDocDetail {
|
|
99
90
|
id: string;
|
|
100
91
|
workspace_id: string;
|
|
101
92
|
name: string;
|
|
102
93
|
description: string;
|
|
94
|
+
/** Folder address; "" is root. */
|
|
95
|
+
path: string;
|
|
103
96
|
content: string;
|
|
104
|
-
|
|
97
|
+
content_sha: string | null;
|
|
105
98
|
files: unknown[];
|
|
106
99
|
created_at: string;
|
|
107
100
|
updated_at: string;
|
package/dist/src/client.js
CHANGED
|
@@ -1,36 +1,6 @@
|
|
|
1
|
+
import { transportErrorMessage } from "@lotics/shared/transport_error";
|
|
1
2
|
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
/**
|
|
4
|
-
* A user-facing message for a transport/gateway failure — derived from the HTTP
|
|
5
|
-
* status, never from the response body. A 524 (edge timeout on a long run), any
|
|
6
|
-
* 5xx, or a non-JSON body (an HTML error page) must NOT surface its raw body. In
|
|
7
|
-
* parity (by value, no shared dep) with the published transport in
|
|
8
|
-
* `packages/app-sdk/src/rpc.ts`.
|
|
9
|
-
*/
|
|
10
|
-
function gatewayErrorMessage(status) {
|
|
11
|
-
if (status === 524) {
|
|
12
|
-
return "The request took too long to finish (gateway timeout). It may still be running — check back in a moment, or try again.";
|
|
13
|
-
}
|
|
14
|
-
if (status >= 500) {
|
|
15
|
-
return "The service is temporarily unavailable. Please try again shortly.";
|
|
16
|
-
}
|
|
17
|
-
return "The service returned an unexpected response. Please try again.";
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* The error message for a non-ok response. A genuine JSON error (a 4xx carrying
|
|
21
|
-
* a `message`) surfaces verbatim; a non-JSON body (a gateway HTML page), any
|
|
22
|
-
* 5xx, or a JSON body without a `message` falls back to a body-free,
|
|
23
|
-
* status-derived message. `parsed` is the JSON.parse of the body, or `null`.
|
|
24
|
-
* In parity (by value, no shared dep) with `packages/app-sdk/src/rpc.ts`.
|
|
25
|
-
*/
|
|
26
|
-
export function transportErrorMessage(status, parsed) {
|
|
27
|
-
const jsonMessage = parsed && typeof parsed.message === "string"
|
|
28
|
-
? parsed.message
|
|
29
|
-
: null;
|
|
30
|
-
return parsed === null || status >= 500 || jsonMessage === null
|
|
31
|
-
? gatewayErrorMessage(status)
|
|
32
|
-
: jsonMessage;
|
|
33
|
-
}
|
|
34
4
|
function findAvailableFilename(dir, filename, reserved) {
|
|
35
5
|
// `reserved` tracks absolute paths claimed by in-flight downloads in the same
|
|
36
6
|
// batch — required for parallel callers because the file may not be on disk
|