@scalequality/cli 0.4.11 → 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.
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "sdkVersion": "0.3.281",
3
- "sha256": "c2e9fefe31fcd4f9b46e4f5323336571b20380b6756c90b494584c1727d9f787",
4
- "sourceCommit": "6437124ad656162948b2c83adfd87e5afc2d82a7"
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) {
@@ -5201,7 +5249,7 @@ function limitInEngineText(text3) {
5201
5249
  // src/application/services/workspaceSandbox/scalequalityTools.ts
5202
5250
  var import_crypto4 = require("crypto");
5203
5251
 
5204
- // node_modules/zod/v3/external.js
5252
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/external.js
5205
5253
  var external_exports = {};
5206
5254
  __export(external_exports, {
5207
5255
  BRAND: () => BRAND,
@@ -5313,7 +5361,7 @@ __export(external_exports, {
5313
5361
  void: () => voidType
5314
5362
  });
5315
5363
 
5316
- // node_modules/zod/v3/helpers/util.js
5364
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/helpers/util.js
5317
5365
  var util;
5318
5366
  (function(util2) {
5319
5367
  util2.assertEqual = (_) => {
@@ -5447,7 +5495,7 @@ var getParsedType = (data) => {
5447
5495
  }
5448
5496
  };
5449
5497
 
5450
- // node_modules/zod/v3/ZodError.js
5498
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/ZodError.js
5451
5499
  var ZodIssueCode = util.arrayToEnum([
5452
5500
  "invalid_type",
5453
5501
  "invalid_literal",
@@ -5565,7 +5613,7 @@ ZodError.create = (issues) => {
5565
5613
  return error;
5566
5614
  };
5567
5615
 
5568
- // node_modules/zod/v3/locales/en.js
5616
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/locales/en.js
5569
5617
  var errorMap = (issue, _ctx) => {
5570
5618
  let message;
5571
5619
  switch (issue.code) {
@@ -5668,7 +5716,7 @@ var errorMap = (issue, _ctx) => {
5668
5716
  };
5669
5717
  var en_default = errorMap;
5670
5718
 
5671
- // node_modules/zod/v3/errors.js
5719
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/errors.js
5672
5720
  var overrideErrorMap = en_default;
5673
5721
  function setErrorMap(map) {
5674
5722
  overrideErrorMap = map;
@@ -5677,7 +5725,7 @@ function getErrorMap() {
5677
5725
  return overrideErrorMap;
5678
5726
  }
5679
5727
 
5680
- // node_modules/zod/v3/helpers/parseUtil.js
5728
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/helpers/parseUtil.js
5681
5729
  var makeIssue = (params) => {
5682
5730
  const { data, path, errorMaps, issueData } = params;
5683
5731
  const fullPath = [...path, ...issueData.path || []];
@@ -5787,14 +5835,14 @@ var isDirty = (x) => x.status === "dirty";
5787
5835
  var isValid = (x) => x.status === "valid";
5788
5836
  var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
5789
5837
 
5790
- // node_modules/zod/v3/helpers/errorUtil.js
5838
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/helpers/errorUtil.js
5791
5839
  var errorUtil;
5792
5840
  (function(errorUtil2) {
5793
5841
  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
5794
5842
  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
5795
5843
  })(errorUtil || (errorUtil = {}));
5796
5844
 
5797
- // node_modules/zod/v3/types.js
5845
+ // ../../scalequality-ai-governance-service/node_modules/zod/v3/types.js
5798
5846
  var ParseInputLazyPath = class {
5799
5847
  constructor(parent, value, path, key) {
5800
5848
  this._cachedPath = [];
@@ -9640,7 +9688,8 @@ var SdkEventMapper = class {
9640
9688
  startedAt: iso(startedAt)
9641
9689
  } });
9642
9690
  const target = activityTarget(name, input);
9643
- this.cb.emit({ type: "activity", data: { tool: name, ...target ? { target } : {} } });
9691
+ const description = d.code === "STEP_COMMAND_DESCRIBED" && typeof d.params?.description === "string" ? d.params.description : void 0;
9692
+ this.cb.emit({ type: "activity", data: { tool: name, ...target ? { target } : {}, ...description ? { description } : {} } });
9644
9693
  }
9645
9694
  stepDone(id, t, status, endedAt = this.now()) {
9646
9695
  this.cb.emit({ type: "step", data: {
@@ -9851,7 +9900,8 @@ function activityTarget(name, input) {
9851
9900
  for (const part of s("command").split(/&&|\|\||[;|\n]/)) {
9852
9901
  for (const token of part.trim().split(/\s+/)) {
9853
9902
  if (!token || token.includes("=") || COMMAND_WRAPPERS.has(token)) continue;
9854
- if (COMMAND_SETUP.has(token)) break;
9903
+ if (SHELL_PREFIX.has(token)) continue;
9904
+ if (COMMAND_SETUP.has(token) || SHELL_HEADER.has(token)) break;
9855
9905
  if (!/^[A-Za-z0-9._/-]+$/.test(token)) return void 0;
9856
9906
  const word = token.split("/").filter(Boolean).pop() ?? "";
9857
9907
  return word && word.length <= 40 ? word : void 0;
@@ -9862,6 +9912,8 @@ function activityTarget(name, input) {
9862
9912
  }
9863
9913
  var COMMAND_WRAPPERS = /* @__PURE__ */ new Set(["sudo", "env", "time", "nice", "exec", "command", "nohup"]);
9864
9914
  var COMMAND_SETUP = /* @__PURE__ */ new Set(["cd", "pushd", "popd", "export", "source", ".", "set", "unset"]);
9915
+ var SHELL_HEADER = /* @__PURE__ */ new Set(["for", "case", "select", "[", "[[", "test", "true", "false", ":"]);
9916
+ var SHELL_PREFIX = /* @__PURE__ */ new Set(["do", "then", "else", "elif", "if", "while", "until", "done", "fi", "esac", "!", "{", "}", "(", ")"]);
9865
9917
  function blockText(content) {
9866
9918
  if (typeof content === "string") return content;
9867
9919
  if (Array.isArray(content)) {
@@ -10863,6 +10915,8 @@ var WorkspaceEngine = class {
10863
10915
  thinkingTotals = /* @__PURE__ */ new Map();
10864
10916
  /** The imported history, fetched once when a turn needs it. */
10865
10917
  importedContext = null;
10918
+ /** The earlier part of this conversation (sessions before this one), fetched once when a turn needs it. */
10919
+ earlierContext = null;
10866
10920
  /** What the running turn ended with, for SQ Auto's next choice: its last command's exit code and whether it failed. */
10867
10921
  turnWatch = null;
10868
10922
  /** Why the previous turn ended in trouble (null when it did not): SQ Auto takes the hard-task model for the next one. */
@@ -11753,6 +11807,19 @@ ${String(item.content)}` : String(item.content);
11753
11807
  this.deps.log.warn("credential renewal failed", { error: this.redactor.text(e.message) });
11754
11808
  }
11755
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
+ }
11756
11823
  /**
11757
11824
  * STREAM_BUFFERED, once per reason: answers on this alias are shown only after the AI protection inspects them
11758
11825
  * (the organization's output rules, a semantic inspector, the application's own rules) or come whole from the
@@ -12169,6 +12236,7 @@ ${json}
12169
12236
  const switching = typeof payload.model === "string" && !!payload.model && payload.model !== this.boot.model;
12170
12237
  if (switching) await this.switchModel(payload.model);
12171
12238
  else if (this.refreshCredential) await this.renewCredential();
12239
+ else await this.refreshProtections();
12172
12240
  this.refreshCredential = false;
12173
12241
  const boot = this.boot;
12174
12242
  const sdk = this.sdk;
@@ -12224,7 +12292,7 @@ ${context.blocks.join("\n\n")}`);
12224
12292
  const forkAt = canResume ? this.resumeAt : null;
12225
12293
  this.resumeAt = null;
12226
12294
  const withImported = async (text3) => {
12227
- const block = await this.importedHistoryBlock();
12295
+ const block = [await this.earlierHistoryBlock(), await this.importedHistoryBlock()].filter(Boolean).join("\n\n");
12228
12296
  return !block ? text3 : slash ? `${text3}
12229
12297
 
12230
12298
  ${block}` : `${block}
@@ -12699,6 +12767,18 @@ ${text3}`;
12699
12767
  }
12700
12768
  }).finally(() => w.abort.abort());
12701
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
+ }
12702
12782
  /** The imported conversation as a context block (fetched once); null when there is none or it cannot be read. */
12703
12783
  importedHistoryBlock() {
12704
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.11",
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": {