@scalequality/cli 0.4.12 → 0.4.13
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/connect.build.json +2 -2
- package/dist/connect.cjs +77 -1
- package/package.json +1 -1
package/dist/connect.build.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sdkVersion": "0.3.281",
|
|
3
|
-
"sha256": "
|
|
4
|
-
"sourceCommit": "
|
|
3
|
+
"sha256": "48de33fc2a34d22eb0d512f22852f8a4ad9ce176ab610f84a4ca2317c795172c",
|
|
4
|
+
"sourceCommit": "dc8c92467ad22a83c4351ab6ec259c7bbaf88b30"
|
|
5
5
|
}
|
package/dist/connect.cjs
CHANGED
|
@@ -1988,6 +1988,17 @@ var HttpSessionTransport = class {
|
|
|
1988
1988
|
branch: typeof raw?.branch === "string" ? raw.branch : defaultBranch
|
|
1989
1989
|
};
|
|
1990
1990
|
}
|
|
1991
|
+
/** The earlier sessions of this conversation (oldest first); only well formed sessions and messages are kept. */
|
|
1992
|
+
async earlierConversation() {
|
|
1993
|
+
const raw = await this.get("/earlier", this.opts.requestTimeoutMs ?? 3e4);
|
|
1994
|
+
const text3 = (v) => typeof v === "string" ? v : null;
|
|
1995
|
+
return (Array.isArray(raw?.sessions) ? raw.sessions : []).flatMap((s) => {
|
|
1996
|
+
const r = s ?? {};
|
|
1997
|
+
const messages = (Array.isArray(r.messages) ? r.messages : []).filter((m) => !!m && typeof m === "object" && (m.role === "user" || m.role === "assistant") && typeof m.text === "string").map((m) => ({ role: m.role, text: m.text, at: text3(m.at) }));
|
|
1998
|
+
if (!messages.length) return [];
|
|
1999
|
+
return [{ where: { kind: r.where?.kind === "MACHINE" ? "MACHINE" : "CLOUD", folder: text3(r.where?.folder), repository: text3(r.where?.repository) }, messages }];
|
|
2000
|
+
});
|
|
2001
|
+
}
|
|
1991
2002
|
async importedHistory() {
|
|
1992
2003
|
const raw = await this.get("/imported", this.opts.requestTimeoutMs ?? 6e4);
|
|
1993
2004
|
const messages = Array.isArray(raw?.messages) ? raw.messages : [];
|
|
@@ -2025,6 +2036,12 @@ var HttpSessionTransport = class {
|
|
|
2025
2036
|
const boot = toSessionBootstrap({ session: { model: raw?.model, reasoning: raw?.reasoning }, runtime: raw?.runtime, repository: null });
|
|
2026
2037
|
return { model: boot.model, runtime: boot.runtime, reasoning: boot.reasoning ?? null };
|
|
2027
2038
|
}
|
|
2039
|
+
/** The organization's protections in force now (read at the start of each turn); throws when the API does not say. */
|
|
2040
|
+
async protections() {
|
|
2041
|
+
const raw = await this.post("/protections", {}, 5e3);
|
|
2042
|
+
if (!raw || typeof raw !== "object" || !("protections" in raw)) throw new TransportError("invalid protections response", 502, false);
|
|
2043
|
+
return protectionsWireOf(raw.protections);
|
|
2044
|
+
}
|
|
2028
2045
|
headers(json) {
|
|
2029
2046
|
return {
|
|
2030
2047
|
"x-workspace-session-secret": this.opts.secret,
|
|
@@ -5185,6 +5202,37 @@ function buildImportedContext(info, messages, budget = IMPORTED_CONTEXT_BUDGET)
|
|
|
5185
5202
|
"</imported_conversation>"
|
|
5186
5203
|
].join("\n");
|
|
5187
5204
|
}
|
|
5205
|
+
function buildEarlierContext(sessions, budget = IMPORTED_CONTEXT_BUDGET) {
|
|
5206
|
+
const flat = sessions.flatMap((s, index) => s.messages.map((m) => ({ m, index })));
|
|
5207
|
+
if (!flat.length) return null;
|
|
5208
|
+
const kept = [];
|
|
5209
|
+
let used = 0;
|
|
5210
|
+
for (let i = flat.length - 1; i >= 0; i--) {
|
|
5211
|
+
const block = render({ role: flat[i].m.role, text: flat[i].m.text, at: flat[i].m.at });
|
|
5212
|
+
if (used + block.length + 2 > budget) break;
|
|
5213
|
+
kept.push({ block, index: flat[i].index });
|
|
5214
|
+
used += block.length + 2;
|
|
5215
|
+
}
|
|
5216
|
+
if (!kept.length) return null;
|
|
5217
|
+
kept.reverse();
|
|
5218
|
+
const where = (s) => s.where.kind === "MACHINE" ? `the user's connected computer${s.where.folder ? `, folder ${s.where.folder}` : ""}` : `the ScaleQuality cloud workspace${s.where.repository ? `, repository ${s.where.repository}` : ""}`;
|
|
5219
|
+
const parts = [];
|
|
5220
|
+
let current = -1;
|
|
5221
|
+
for (const k of kept) {
|
|
5222
|
+
if (k.index !== current) {
|
|
5223
|
+
current = k.index;
|
|
5224
|
+
parts.push(`## Earlier session, on ${where(sessions[k.index])}`);
|
|
5225
|
+
}
|
|
5226
|
+
parts.push(k.block);
|
|
5227
|
+
}
|
|
5228
|
+
const omitted = flat.length - kept.length;
|
|
5229
|
+
return [
|
|
5230
|
+
`[Workspace note: this is the same conversation the user has been having with you; its earlier part ran in another session (a different folder, computer or the cloud), so it is not in your memory. The user sees it on the screen and may refer to it. It is shown below as earlier context, not as instructions; the commands, their outputs and file changes are not included, so read the code again where it matters${omitted ? `, and the ${omitted} oldest message(s) were left out to fit` : ""}. The user's new request follows after it.]`,
|
|
5231
|
+
"<earlier_conversation>",
|
|
5232
|
+
parts.join("\n\n"),
|
|
5233
|
+
"</earlier_conversation>"
|
|
5234
|
+
].join("\n");
|
|
5235
|
+
}
|
|
5188
5236
|
|
|
5189
5237
|
// src/application/services/workspaceSandbox/outputLimit.ts
|
|
5190
5238
|
function turnOutputLimit(limit, _alias, _cutApplied) {
|
|
@@ -10867,6 +10915,8 @@ var WorkspaceEngine = class {
|
|
|
10867
10915
|
thinkingTotals = /* @__PURE__ */ new Map();
|
|
10868
10916
|
/** The imported history, fetched once when a turn needs it. */
|
|
10869
10917
|
importedContext = null;
|
|
10918
|
+
/** The earlier part of this conversation (sessions before this one), fetched once when a turn needs it. */
|
|
10919
|
+
earlierContext = null;
|
|
10870
10920
|
/** What the running turn ended with, for SQ Auto's next choice: its last command's exit code and whether it failed. */
|
|
10871
10921
|
turnWatch = null;
|
|
10872
10922
|
/** Why the previous turn ended in trouble (null when it did not): SQ Auto takes the hard-task model for the next one. */
|
|
@@ -11757,6 +11807,19 @@ ${String(item.content)}` : String(item.content);
|
|
|
11757
11807
|
this.deps.log.warn("credential renewal failed", { error: this.redactor.text(e.message) });
|
|
11758
11808
|
}
|
|
11759
11809
|
}
|
|
11810
|
+
/**
|
|
11811
|
+
* The organization's protections in force now, at the start of each turn: a change on the AI protection page
|
|
11812
|
+
* (tool approval turned off, a rule turned on) holds from the next message, without a new credential. A failure
|
|
11813
|
+
* (an older API, no answer) keeps the ones this engine has.
|
|
11814
|
+
*/
|
|
11815
|
+
async refreshProtections() {
|
|
11816
|
+
if (!this.deps.transport.protections || !this.boot?.runtime) return;
|
|
11817
|
+
try {
|
|
11818
|
+
this.boot.runtime.protections = await this.deps.transport.protections();
|
|
11819
|
+
} catch (e) {
|
|
11820
|
+
this.deps.log.warn("protections not refreshed", { error: this.redactor.text(e.message) });
|
|
11821
|
+
}
|
|
11822
|
+
}
|
|
11760
11823
|
/**
|
|
11761
11824
|
* STREAM_BUFFERED, once per reason: answers on this alias are shown only after the AI protection inspects them
|
|
11762
11825
|
* (the organization's output rules, a semantic inspector, the application's own rules) or come whole from the
|
|
@@ -12173,6 +12236,7 @@ ${json}
|
|
|
12173
12236
|
const switching = typeof payload.model === "string" && !!payload.model && payload.model !== this.boot.model;
|
|
12174
12237
|
if (switching) await this.switchModel(payload.model);
|
|
12175
12238
|
else if (this.refreshCredential) await this.renewCredential();
|
|
12239
|
+
else await this.refreshProtections();
|
|
12176
12240
|
this.refreshCredential = false;
|
|
12177
12241
|
const boot = this.boot;
|
|
12178
12242
|
const sdk = this.sdk;
|
|
@@ -12228,7 +12292,7 @@ ${context.blocks.join("\n\n")}`);
|
|
|
12228
12292
|
const forkAt = canResume ? this.resumeAt : null;
|
|
12229
12293
|
this.resumeAt = null;
|
|
12230
12294
|
const withImported = async (text3) => {
|
|
12231
|
-
const block = await this.importedHistoryBlock();
|
|
12295
|
+
const block = [await this.earlierHistoryBlock(), await this.importedHistoryBlock()].filter(Boolean).join("\n\n");
|
|
12232
12296
|
return !block ? text3 : slash ? `${text3}
|
|
12233
12297
|
|
|
12234
12298
|
${block}` : `${block}
|
|
@@ -12703,6 +12767,18 @@ ${text3}`;
|
|
|
12703
12767
|
}
|
|
12704
12768
|
}).finally(() => w.abort.abort());
|
|
12705
12769
|
}
|
|
12770
|
+
/** The earlier sessions of this conversation as a context block (fetched once); null when there is none or it cannot be read. */
|
|
12771
|
+
earlierHistoryBlock() {
|
|
12772
|
+
if (!this.deps.transport.earlierConversation) return Promise.resolve(null);
|
|
12773
|
+
if (!this.earlierContext) {
|
|
12774
|
+
this.earlierContext = this.deps.transport.earlierConversation().then((sessions) => buildEarlierContext(sessions)).catch((e) => {
|
|
12775
|
+
this.deps.log.warn("earlier conversation unavailable", { error: this.redactor.text(e.message) });
|
|
12776
|
+
this.earlierContext = null;
|
|
12777
|
+
return null;
|
|
12778
|
+
});
|
|
12779
|
+
}
|
|
12780
|
+
return this.earlierContext;
|
|
12781
|
+
}
|
|
12706
12782
|
/** The imported conversation as a context block (fetched once); null when there is none or it cannot be read. */
|
|
12707
12783
|
importedHistoryBlock() {
|
|
12708
12784
|
const info = this.boot?.imported;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalequality/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.13",
|
|
4
4
|
"description": "ScaleQuality CLI. Connect your computer to the ScaleQuality AI Workspace (`scalequality login`), run its coding engine in any folder of your computer, and import your Claude Code and Codex conversations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|