@scalequality/cli 0.4.10 → 0.4.11
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 +89 -28
- 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": "c2e9fefe31fcd4f9b46e4f5323336571b20380b6756c90b494584c1727d9f787",
|
|
4
|
+
"sourceCommit": "6437124ad656162948b2c83adfd87e5afc2d82a7"
|
|
5
5
|
}
|
package/dist/connect.cjs
CHANGED
|
@@ -1290,13 +1290,14 @@ async function decideToolUse(toolName, input, ctx) {
|
|
|
1290
1290
|
}
|
|
1291
1291
|
|
|
1292
1292
|
// src/application/services/workspaceSandbox/protections.ts
|
|
1293
|
-
var NO_PROTECTIONS = Object.freeze({ secretFiles: false, protectedPush: false, deployApproval: false, destructiveCommands: false, unknownPackage: null });
|
|
1293
|
+
var NO_PROTECTIONS = Object.freeze({ secretFiles: false, protectedPush: false, deployApproval: false, destructiveCommands: false, unknownPackage: null, toolApproval: false });
|
|
1294
1294
|
var KNOWN_RULES = {
|
|
1295
1295
|
"secret-files": ["block"],
|
|
1296
1296
|
"protected-push": ["require"],
|
|
1297
1297
|
"deploy-approval": ["require"],
|
|
1298
1298
|
"destructive-commands": ["require"],
|
|
1299
|
-
"unknown-package": ["block", "warn"]
|
|
1299
|
+
"unknown-package": ["block", "warn"],
|
|
1300
|
+
"tool-approval": ["require"]
|
|
1300
1301
|
};
|
|
1301
1302
|
function protectionsWireOf(raw) {
|
|
1302
1303
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
@@ -1318,7 +1319,8 @@ function parseProtections(raw) {
|
|
|
1318
1319
|
protectedPush: r["protected-push"] === "require",
|
|
1319
1320
|
deployApproval: r["deploy-approval"] === "require",
|
|
1320
1321
|
destructiveCommands: r["destructive-commands"] === "require",
|
|
1321
|
-
unknownPackage: r["unknown-package"] === "block" || r["unknown-package"] === "warn" ? r["unknown-package"] : null
|
|
1322
|
+
unknownPackage: r["unknown-package"] === "block" || r["unknown-package"] === "warn" ? r["unknown-package"] : null,
|
|
1323
|
+
toolApproval: r["tool-approval"] === "require"
|
|
1322
1324
|
};
|
|
1323
1325
|
}
|
|
1324
1326
|
var SECRET_FILE_MESSAGE = "Blocked by your organization's protection: secret files are never sent to the model. Do not try to read this file another way; ask the user for the specific value your task needs, or use the example file (such as .env.example).";
|
|
@@ -1857,6 +1859,7 @@ var RegistryChecker = class {
|
|
|
1857
1859
|
}
|
|
1858
1860
|
};
|
|
1859
1861
|
function mayNeedProtection(command, p) {
|
|
1862
|
+
if (p.toolApproval) return true;
|
|
1860
1863
|
if (p.destructiveCommands && isDestructiveCommand(command)) return true;
|
|
1861
1864
|
if (p.deployApproval && isDeployCommand(command)) return true;
|
|
1862
1865
|
if (p.protectedPush && gitPushes(command).length > 0) return true;
|
|
@@ -1889,6 +1892,7 @@ async function protectionVerdict(command, p, deps) {
|
|
|
1889
1892
|
if (p.destructiveCommands && isDestructiveCommand(command)) reasons.push("PROTECTION_DESTRUCTIVE_COMMAND");
|
|
1890
1893
|
if (p.deployApproval && isDeployCommand(command)) reasons.push("PROTECTION_DEPLOY");
|
|
1891
1894
|
if (p.protectedPush && await isProtectedPush(command, deps.currentBranch)) reasons.push("PROTECTION_PROTECTED_PUSH");
|
|
1895
|
+
if (p.toolApproval && !reasons.length) reasons.push("PROTECTION_TOOL_APPROVAL");
|
|
1892
1896
|
if (!reasons.length) return { kind: "allow" };
|
|
1893
1897
|
return { kind: "ask", reasons, ...pkg ? { package: pkg.name, packageReason: pkg.reason } : {} };
|
|
1894
1898
|
}
|
|
@@ -1896,7 +1900,12 @@ var PROTECTION_MESSAGES = {
|
|
|
1896
1900
|
rejected: "Your organization's protection requires a person to approve this command, and the user denied it. It did not run. Do not run it again or another way unless the user asks.",
|
|
1897
1901
|
timedOut: (minutes) => `Your organization's protection requires a person to approve this command, and nobody answered within ${minutes} minutes. It did not run. Ask the user before trying it again.`,
|
|
1898
1902
|
stopped: "The request was stopped before the command ran.",
|
|
1899
|
-
unavailable: "Your organization's protection requires a person to approve this command, and the approval could not be requested. It did not run. Tell the user; do not try to run it another way."
|
|
1903
|
+
unavailable: "Your organization's protection requires a person to approve this command, and the approval could not be requested. It did not run. Tell the user; do not try to run it another way.",
|
|
1904
|
+
// A file change under tool-approval.
|
|
1905
|
+
editRejected: (path) => `Your organization's protection requires a person to approve every change, and the user denied this change to ${path}. The file was not changed. Do not change it another way unless the user asks.`,
|
|
1906
|
+
editTimedOut: (path, minutes) => `Your organization's protection requires a person to approve every change, and nobody answered about ${path} within ${minutes} minutes. The file was not changed. Ask the user before trying again.`,
|
|
1907
|
+
editStopped: "The request was stopped before the file was changed.",
|
|
1908
|
+
editUnavailable: (path) => `Your organization's protection requires a person to approve every change, and the approval for ${path} could not be requested. The file was not changed. Tell the user; do not change it another way.`
|
|
1900
1909
|
};
|
|
1901
1910
|
|
|
1902
1911
|
// src/application/services/workspaceSandbox/SessionTransport.ts
|
|
@@ -3031,6 +3040,15 @@ var BrowserCommandGate = class {
|
|
|
3031
3040
|
this.chain = next.catch(() => void 0);
|
|
3032
3041
|
return next;
|
|
3033
3042
|
}
|
|
3043
|
+
checkProtectedEdit(path, opts = {}) {
|
|
3044
|
+
const next = this.chain.then(() => this.ask(`edit ${path}`, {
|
|
3045
|
+
signal: opts.signal,
|
|
3046
|
+
edit: { path, ...opts.preview ? { preview: opts.preview } : {} },
|
|
3047
|
+
protection: { reasons: ["PROTECTION_TOOL_APPROVAL"] }
|
|
3048
|
+
}));
|
|
3049
|
+
this.chain = next.catch(() => void 0);
|
|
3050
|
+
return next;
|
|
3051
|
+
}
|
|
3034
3052
|
checkEdit(path, opts = {}) {
|
|
3035
3053
|
const next = this.chain.then(() => this.ask(`edit ${path}`, { signal: opts.signal, edit: { path, ...opts.preview ? { preview: opts.preview } : {} } }));
|
|
3036
3054
|
this.chain = next.catch(() => void 0);
|
|
@@ -3047,7 +3065,7 @@ var BrowserCommandGate = class {
|
|
|
3047
3065
|
command,
|
|
3048
3066
|
cwd: this.o.root,
|
|
3049
3067
|
...opts.description ? { description: opts.description.slice(0, 1e3) } : {},
|
|
3050
|
-
reasons:
|
|
3068
|
+
reasons: protection ? [...protection.reasons, ...opts.edit ? [] : approvalReasons(command)] : opts.edit ? [] : approvalReasons(command),
|
|
3051
3069
|
suggestedRule: opts.edit || protection ? null : suggestRule(command),
|
|
3052
3070
|
...opts.edit ? { edit: { path: opts.edit.path, ...opts.edit.preview ? { preview: opts.edit.preview.slice(0, 4e3) } : {} } } : {},
|
|
3053
3071
|
...protection?.package ? { package: protection.package, ...protection.packageReason ? { packageReason: protection.packageReason } : {} } : {}
|
|
@@ -3055,6 +3073,7 @@ var BrowserCommandGate = class {
|
|
|
3055
3073
|
} catch (e) {
|
|
3056
3074
|
this.o.log?.(`command approval could not be requested: ${e.message}`);
|
|
3057
3075
|
const code = e instanceof CommandApprovalError ? e.code : null;
|
|
3076
|
+
if (protection && opts.edit) return { allow: false, message: PROTECTION_MESSAGES.editUnavailable(opts.edit.path) };
|
|
3058
3077
|
if (protection && code !== "COMMAND_NOT_ALLOWED") return { allow: false, message: PROTECTION_MESSAGES.unavailable };
|
|
3059
3078
|
return {
|
|
3060
3079
|
allow: false,
|
|
@@ -3072,10 +3091,12 @@ var BrowserCommandGate = class {
|
|
|
3072
3091
|
if (!decision) {
|
|
3073
3092
|
const reason = opts.signal?.aborted ? "STOPPED" : "TIMED_OUT";
|
|
3074
3093
|
void this.o.api.cancel(approvalId, reason).catch(() => void 0);
|
|
3094
|
+
if (protection && opts.edit) return { allow: false, message: reason === "STOPPED" ? PROTECTION_MESSAGES.editStopped : PROTECTION_MESSAGES.editTimedOut(opts.edit.path, Math.round(timeoutMs / 6e4)) };
|
|
3075
3095
|
if (protection) return { allow: false, message: reason === "STOPPED" ? PROTECTION_MESSAGES.stopped : PROTECTION_MESSAGES.timedOut(Math.round(timeoutMs / 6e4)) };
|
|
3076
3096
|
return reason === "STOPPED" ? { allow: false, message: STOPPED } : { allow: false, message: `The user did not answer the approval for this command within ${Math.round(timeoutMs / 6e4)} minutes, so it did not run. Ask the user before trying it again.` };
|
|
3077
3097
|
}
|
|
3078
3098
|
if (decision.decision === "REJECT") {
|
|
3099
|
+
if (protection && opts.edit) return { allow: false, message: PROTECTION_MESSAGES.editRejected(opts.edit.path) };
|
|
3079
3100
|
if (protection) return { allow: false, message: PROTECTION_MESSAGES.rejected };
|
|
3080
3101
|
return opts.edit ? { allow: false, message: `The user declined this change to ${opts.edit.path} in the browser. The file was not changed. Ask the user what to do differently.` } : { allow: false, message: "The user denied this command in the browser. It did not run. Do not run the same command again unless the user asks; continue another way or ask the user." };
|
|
3081
3102
|
}
|
|
@@ -4821,6 +4842,8 @@ function sandboxTestEnv() {
|
|
|
4821
4842
|
"BUNDLE_PATH",
|
|
4822
4843
|
"PUB_CACHE",
|
|
4823
4844
|
"FLUTTER_ROOT",
|
|
4845
|
+
"MIX_HOME",
|
|
4846
|
+
"HEX_HOME",
|
|
4824
4847
|
"MISE_DATA_DIR",
|
|
4825
4848
|
"MISE_CACHE_DIR",
|
|
4826
4849
|
"ELIXIR_ERL_OPTIONS"
|
|
@@ -4943,6 +4966,8 @@ var ENGINE_MESSAGES = {
|
|
|
4943
4966
|
// Pull requests.
|
|
4944
4967
|
BASE_ADVANCED: "The pull request could not be opened: the base branch in the repository is not at the commit this change was made on.",
|
|
4945
4968
|
PR_FAILED: "The pull request could not be opened.",
|
|
4969
|
+
PROVIDER_CONNECTION_REQUIRED: "The pull request could not be opened: the provider connection of {repoFullName} needs to be reconnected in ScaleQuality.",
|
|
4970
|
+
REPOSITORY_NOT_IN_PROJECT: "The pull request could not be opened: {repoFullName} is no longer a repository of this project.",
|
|
4946
4971
|
// Attachments and mentions.
|
|
4947
4972
|
ATTACHMENT_SKIPPED: "An attached image could not be read and was left out.",
|
|
4948
4973
|
MENTION_SKIPPED: "{path} could not be attached ({reason}).",
|
|
@@ -10000,12 +10025,16 @@ var TurnTiming = class {
|
|
|
10000
10025
|
// src/application/services/workspaceSandbox/protectionApproval.ts
|
|
10001
10026
|
function gateProtectionApprover(gate) {
|
|
10002
10027
|
if (!gate.checkProtected) return null;
|
|
10003
|
-
return {
|
|
10028
|
+
return {
|
|
10029
|
+
ask: (command, check) => gate.checkProtected(command, check),
|
|
10030
|
+
...gate.checkProtectedEdit ? { askEdit: (path, check) => gate.checkProtectedEdit(path, check) } : {}
|
|
10031
|
+
};
|
|
10004
10032
|
}
|
|
10005
10033
|
function cloudProtectionApprover(o) {
|
|
10006
10034
|
let chain = Promise.resolve();
|
|
10007
10035
|
const ask = async (command, check) => {
|
|
10008
|
-
|
|
10036
|
+
const edit = check.edit;
|
|
10037
|
+
if (check.signal?.aborted) return { allow: false, message: edit ? PROTECTION_MESSAGES.editStopped : PROTECTION_MESSAGES.stopped };
|
|
10009
10038
|
let approvalId;
|
|
10010
10039
|
try {
|
|
10011
10040
|
({ approvalId } = await o.calls.requestCommandApproval({
|
|
@@ -10014,11 +10043,12 @@ function cloudProtectionApprover(o) {
|
|
|
10014
10043
|
...check.description ? { description: check.description.slice(0, 1e3) } : {},
|
|
10015
10044
|
reasons: [...check.reasons],
|
|
10016
10045
|
suggestedRule: null,
|
|
10046
|
+
...edit ? { edit: { path: edit.path, ...edit.preview ? { preview: edit.preview.slice(0, 4e3) } : {} } } : {},
|
|
10017
10047
|
...check.package ? { package: check.package, ...check.packageReason ? { packageReason: check.packageReason } : {} } : {}
|
|
10018
10048
|
}));
|
|
10019
10049
|
} catch (e) {
|
|
10020
10050
|
o.log?.(`protection approval could not be requested: ${e.message}`);
|
|
10021
|
-
return { allow: false, message: PROTECTION_MESSAGES.unavailable };
|
|
10051
|
+
return { allow: false, message: edit ? PROTECTION_MESSAGES.editUnavailable(edit.path) : PROTECTION_MESSAGES.unavailable };
|
|
10022
10052
|
}
|
|
10023
10053
|
const timeoutMs = o.timeoutMs ?? COMMAND_APPROVAL_TIMEOUT_MS;
|
|
10024
10054
|
const timer = new AbortController();
|
|
@@ -10029,16 +10059,21 @@ function cloudProtectionApprover(o) {
|
|
|
10029
10059
|
if (!decision) {
|
|
10030
10060
|
const reason = check.signal?.aborted ? "STOPPED" : "TIMED_OUT";
|
|
10031
10061
|
void o.calls.cancelCommandApproval(approvalId, reason).catch(() => void 0);
|
|
10032
|
-
|
|
10062
|
+
const minutes = Math.round(timeoutMs / 6e4);
|
|
10063
|
+
if (edit) return { allow: false, message: reason === "STOPPED" ? PROTECTION_MESSAGES.editStopped : PROTECTION_MESSAGES.editTimedOut(edit.path, minutes) };
|
|
10064
|
+
return { allow: false, message: reason === "STOPPED" ? PROTECTION_MESSAGES.stopped : PROTECTION_MESSAGES.timedOut(minutes) };
|
|
10033
10065
|
}
|
|
10034
|
-
|
|
10066
|
+
if (decision.decision === "APPROVE") return { allow: true };
|
|
10067
|
+
return { allow: false, message: edit ? PROTECTION_MESSAGES.editRejected(edit.path) : PROTECTION_MESSAGES.rejected };
|
|
10068
|
+
};
|
|
10069
|
+
const queued = (run2) => {
|
|
10070
|
+
const next = chain.then(run2);
|
|
10071
|
+
chain = next.catch(() => void 0);
|
|
10072
|
+
return next;
|
|
10035
10073
|
};
|
|
10036
10074
|
return {
|
|
10037
|
-
ask(command, check)
|
|
10038
|
-
|
|
10039
|
-
chain = next.catch(() => void 0);
|
|
10040
|
-
return next;
|
|
10041
|
-
}
|
|
10075
|
+
ask: (command, check) => queued(() => ask(command, check)),
|
|
10076
|
+
askEdit: (path, check) => queued(() => ask(`edit ${path}`, { reasons: ["PROTECTION_TOOL_APPROVAL"], signal: check.signal, edit: { path, ...check.preview ? { preview: check.preview } : {} } }))
|
|
10042
10077
|
};
|
|
10043
10078
|
}
|
|
10044
10079
|
|
|
@@ -13150,16 +13185,33 @@ _Measured on an earlier version of this change._`);
|
|
|
13150
13185
|
if (e instanceof TransportError && e.code === REPOSITORY_NOT_IN_SCOPE) {
|
|
13151
13186
|
return text(`${REPOSITORY_NOT_IN_SCOPE}: ${target} left this session's scope before the pull request was opened. It was not opened.`, true);
|
|
13152
13187
|
}
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
return text(`The pull request could not be opened: the base branch in the repository is not at the commit this change was made on.${where} Tell the user; do not retry without being asked.`, true);
|
|
13157
|
-
}
|
|
13158
|
-
this.error("PR_FAILED", { repoFullName: target });
|
|
13159
|
-
return text("The pull request could not be opened. Tell the user; do not retry without being asked.", true);
|
|
13188
|
+
const failure = pullRequestFailure(status, e instanceof TransportError ? e.code : void 0, target, this.local);
|
|
13189
|
+
this.error(failure.code, failure.params);
|
|
13190
|
+
return text(`${failure.say} Tell the user; do not retry without being asked.`, true);
|
|
13160
13191
|
}
|
|
13161
13192
|
}
|
|
13162
13193
|
};
|
|
13194
|
+
function pullRequestFailure(status, code, repoFullName, local) {
|
|
13195
|
+
if (status === 409 && code === "PROVIDER_CONNECTION_REQUIRED") return {
|
|
13196
|
+
code: "PROVIDER_CONNECTION_REQUIRED",
|
|
13197
|
+
params: { repoFullName },
|
|
13198
|
+
say: `The pull request could not be opened: the provider connection of ${repoFullName} needs to be reconnected in ScaleQuality.`
|
|
13199
|
+
};
|
|
13200
|
+
if (status === 409 && code === "REPOSITORY_NOT_IN_PROJECT") return {
|
|
13201
|
+
code: "REPOSITORY_NOT_IN_PROJECT",
|
|
13202
|
+
params: { repoFullName },
|
|
13203
|
+
say: `The pull request could not be opened: ${repoFullName} is no longer a repository of this project.`
|
|
13204
|
+
};
|
|
13205
|
+
if (status === 409 && (!code || code === "BASE_ADVANCED")) {
|
|
13206
|
+
const where = local ? " Update this folder to the latest commit of the base branch (git pull), then ask again." : "";
|
|
13207
|
+
return {
|
|
13208
|
+
code: "BASE_ADVANCED",
|
|
13209
|
+
params: { repoFullName, local },
|
|
13210
|
+
say: `The pull request could not be opened: the base branch in the repository is not at the commit this change was made on.${where}`
|
|
13211
|
+
};
|
|
13212
|
+
}
|
|
13213
|
+
return { code: "PR_FAILED", params: { repoFullName, ...code ? { reason: code } : {} }, say: "The pull request could not be opened." };
|
|
13214
|
+
}
|
|
13163
13215
|
var LOCAL_ENV_PASSTHROUGH = [
|
|
13164
13216
|
"LOGNAME",
|
|
13165
13217
|
"COLORTERM",
|
|
@@ -13312,11 +13364,11 @@ function buildQueryOptions(o) {
|
|
|
13312
13364
|
}
|
|
13313
13365
|
const protections = o.protections?.() ?? NO_PROTECTIONS;
|
|
13314
13366
|
const d = await decideToolUse(name, input.tool_input ?? {}, { ...o.policy, protections });
|
|
13315
|
-
const guarded = d.behavior === "allow" && name === "Bash" && mayNeedProtection(String(d.updatedInput.command ?? ""), protections);
|
|
13367
|
+
const guarded = d.behavior === "allow" && (name === "Bash" && mayNeedProtection(String(d.updatedInput.command ?? ""), protections) || protections.toolApproval && !o.plan && name in WRITE_TOOL_PATHS);
|
|
13316
13368
|
const gated = guarded || d.behavior === "allow" && !!gate && (name === "Bash" || !!gate.checkEdit && !o.plan && name in WRITE_TOOL_PATHS);
|
|
13317
13369
|
if (d.behavior === "allow" && !gated) await beforeWrite(name, d.updatedInput);
|
|
13318
13370
|
if (gated) {
|
|
13319
|
-
return { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "ask", permissionDecisionReason: guarded ? "This
|
|
13371
|
+
return { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "ask", permissionDecisionReason: guarded ? "This action follows the organization's protections." : "Commands and changes on this machine follow the person's permission mode." } };
|
|
13320
13372
|
}
|
|
13321
13373
|
return d.behavior === "allow" ? { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "allow", updatedInput: d.updatedInput } } : { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: d.message } };
|
|
13322
13374
|
};
|
|
@@ -13354,10 +13406,18 @@ function buildQueryOptions(o) {
|
|
|
13354
13406
|
protectionApproved = true;
|
|
13355
13407
|
}
|
|
13356
13408
|
}
|
|
13357
|
-
|
|
13409
|
+
const changes = !o.plan && toolName in WRITE_TOOL_PATHS;
|
|
13410
|
+
const changePath = () => {
|
|
13358
13411
|
const field = WRITE_TOOL_PATHS[toolName];
|
|
13359
|
-
|
|
13360
|
-
|
|
13412
|
+
return typeof d.updatedInput[field] === "string" ? (0, import_path15.relative)(o.root, d.updatedInput[field]) || String(d.updatedInput[field]) : "";
|
|
13413
|
+
};
|
|
13414
|
+
if (changes && protections.toolApproval) {
|
|
13415
|
+
const path = changePath(), askEdit = o.protection?.approver?.askEdit;
|
|
13416
|
+
if (!askEdit) return { behavior: "deny", message: PROTECTION_MESSAGES.editUnavailable(path) };
|
|
13417
|
+
const r = await askEdit(path, { preview: editPreview(toolName, d.updatedInput), signal: opts?.signal ?? o.abortController.signal });
|
|
13418
|
+
if (!r.allow) return { behavior: "deny", message: r.message };
|
|
13419
|
+
} else if (gate?.checkEdit && changes) {
|
|
13420
|
+
const r = await gate.checkEdit(changePath(), { preview: editPreview(toolName, d.updatedInput), signal: opts?.signal ?? o.abortController.signal });
|
|
13361
13421
|
if (!r.allow) return { behavior: "deny", message: r.message };
|
|
13362
13422
|
}
|
|
13363
13423
|
await beforeWrite(toolName, d.updatedInput);
|
|
@@ -13420,7 +13480,8 @@ function timedGate(gate, took) {
|
|
|
13420
13480
|
return {
|
|
13421
13481
|
check: (command, opts) => timed(() => gate.check(command, opts)),
|
|
13422
13482
|
...gate.checkEdit ? { checkEdit: (path, opts) => timed(() => gate.checkEdit(path, opts)) } : {},
|
|
13423
|
-
...gate.checkProtected ? { checkProtected: (command, opts) => timed(() => gate.checkProtected(command, opts)) } : {}
|
|
13483
|
+
...gate.checkProtected ? { checkProtected: (command, opts) => timed(() => gate.checkProtected(command, opts)) } : {},
|
|
13484
|
+
...gate.checkProtectedEdit ? { checkProtectedEdit: (path, opts) => timed(() => gate.checkProtectedEdit(path, opts)) } : {}
|
|
13424
13485
|
};
|
|
13425
13486
|
}
|
|
13426
13487
|
async function hasLocalTranscript(configDir, sessionId) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalequality/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
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": {
|