iteration-cli 0.13.0 → 0.14.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 +1 -1
- package/dist/cli.js +6114 -5345
- package/dist/cursor-hook-entry.js +66 -5049
- package/dist/launcher.js +163 -34
- package/package.json +2 -2
package/dist/launcher.js
CHANGED
|
@@ -6,13 +6,13 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/launcher.ts
|
|
9
|
-
import { promises as
|
|
9
|
+
import { promises as fs3 } from "node:fs";
|
|
10
10
|
import { pathToFileURL } from "node:url";
|
|
11
11
|
|
|
12
12
|
// src/runtime.ts
|
|
13
|
-
import { promises as
|
|
13
|
+
import { promises as fs2 } from "node:fs";
|
|
14
14
|
import os from "node:os";
|
|
15
|
-
import
|
|
15
|
+
import path2 from "node:path";
|
|
16
16
|
import { setTimeout as delay } from "node:timers/promises";
|
|
17
17
|
|
|
18
18
|
// ../../node_modules/.pnpm/zod@4.6.4/node_modules/zod/v4/core/util.js
|
|
@@ -251,10 +251,10 @@ function mergeDefs(...defs) {
|
|
|
251
251
|
function cloneDef(schema) {
|
|
252
252
|
return mergeDefs(schema._zod.def);
|
|
253
253
|
}
|
|
254
|
-
function getElementAtPath(obj,
|
|
255
|
-
if (!
|
|
254
|
+
function getElementAtPath(obj, path3) {
|
|
255
|
+
if (!path3)
|
|
256
256
|
return obj;
|
|
257
|
-
return
|
|
257
|
+
return path3.reduce((acc, key) => acc?.[key], obj);
|
|
258
258
|
}
|
|
259
259
|
function promiseAllObject(promisesObj) {
|
|
260
260
|
const keys = Object.keys(promisesObj);
|
|
@@ -594,11 +594,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
594
594
|
}
|
|
595
595
|
return false;
|
|
596
596
|
}
|
|
597
|
-
function prefixIssues(
|
|
597
|
+
function prefixIssues(path3, issues) {
|
|
598
598
|
return issues.map((iss) => {
|
|
599
599
|
var _a3;
|
|
600
600
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
601
|
-
iss.path.unshift(
|
|
601
|
+
iss.path.unshift(path3);
|
|
602
602
|
return iss;
|
|
603
603
|
});
|
|
604
604
|
}
|
|
@@ -1044,16 +1044,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
|
|
|
1044
1044
|
}
|
|
1045
1045
|
function formatError(error2, mapper = (issue2) => issue2.message) {
|
|
1046
1046
|
const fieldErrors = { _errors: [] };
|
|
1047
|
-
const processError = (error3,
|
|
1047
|
+
const processError = (error3, path3 = []) => {
|
|
1048
1048
|
for (const issue2 of error3.issues) {
|
|
1049
1049
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
1050
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
1050
|
+
issue2.errors.map((issues) => processError({ issues }, [...path3, ...issue2.path]));
|
|
1051
1051
|
} else if (issue2.code === "invalid_key") {
|
|
1052
|
-
processError({ issues: issue2.issues }, [...
|
|
1052
|
+
processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
|
|
1053
1053
|
} else if (issue2.code === "invalid_element") {
|
|
1054
|
-
processError({ issues: issue2.issues }, [...
|
|
1054
|
+
processError({ issues: issue2.issues }, [...path3, ...issue2.path]);
|
|
1055
1055
|
} else {
|
|
1056
|
-
const fullpath = [...
|
|
1056
|
+
const fullpath = [...path3, ...issue2.path];
|
|
1057
1057
|
if (fullpath.length === 0) {
|
|
1058
1058
|
fieldErrors._errors.push(mapper(issue2));
|
|
1059
1059
|
} else {
|
|
@@ -6545,19 +6545,149 @@ var collectorEnrollmentResponseSchema = discriminatedUnion("status", [
|
|
|
6545
6545
|
}).strict()
|
|
6546
6546
|
]);
|
|
6547
6547
|
|
|
6548
|
+
// src/private-storage.ts
|
|
6549
|
+
import { promises as fs } from "node:fs";
|
|
6550
|
+
|
|
6551
|
+
// src/windows-powershell.ts
|
|
6552
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
6553
|
+
import path from "node:path";
|
|
6554
|
+
import { promisify } from "node:util";
|
|
6555
|
+
var execFile = promisify(execFileCallback);
|
|
6556
|
+
function windowsPowerShellPath() {
|
|
6557
|
+
return path.join(
|
|
6558
|
+
process.env.SystemRoot ?? "C:\\Windows",
|
|
6559
|
+
"System32",
|
|
6560
|
+
"WindowsPowerShell",
|
|
6561
|
+
"v1.0",
|
|
6562
|
+
"powershell.exe"
|
|
6563
|
+
);
|
|
6564
|
+
}
|
|
6565
|
+
function powershellLiteral(value) {
|
|
6566
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
6567
|
+
}
|
|
6568
|
+
function encodedPowerShell(script) {
|
|
6569
|
+
return Buffer.from(script, "utf16le").toString("base64");
|
|
6570
|
+
}
|
|
6571
|
+
async function runWindowsPowerShell(operation, script) {
|
|
6572
|
+
try {
|
|
6573
|
+
const { stdout } = await execFile(
|
|
6574
|
+
windowsPowerShellPath(),
|
|
6575
|
+
[
|
|
6576
|
+
"-NoLogo",
|
|
6577
|
+
"-NoProfile",
|
|
6578
|
+
"-NonInteractive",
|
|
6579
|
+
"-EncodedCommand",
|
|
6580
|
+
encodedPowerShell(
|
|
6581
|
+
`$ErrorActionPreference = 'Stop'
|
|
6582
|
+
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
|
6583
|
+
${script}`
|
|
6584
|
+
)
|
|
6585
|
+
],
|
|
6586
|
+
{
|
|
6587
|
+
timeout: 3e4,
|
|
6588
|
+
maxBuffer: 1024 * 1024,
|
|
6589
|
+
windowsHide: true
|
|
6590
|
+
}
|
|
6591
|
+
);
|
|
6592
|
+
return stdout.trim();
|
|
6593
|
+
} catch (error2) {
|
|
6594
|
+
const failure2 = object({ stderr: string2() }).safeParse(error2);
|
|
6595
|
+
const detail = failure2.success ? failure2.data.stderr.trim().slice(0, 4096) : "";
|
|
6596
|
+
throw new Error(
|
|
6597
|
+
`Windows could not ${operation}.${detail ? `
|
|
6598
|
+
${detail}` : ""}`,
|
|
6599
|
+
{ cause: error2 }
|
|
6600
|
+
);
|
|
6601
|
+
}
|
|
6602
|
+
}
|
|
6603
|
+
|
|
6604
|
+
// src/private-storage.ts
|
|
6605
|
+
var securedDirectories = /* @__PURE__ */ new Map();
|
|
6606
|
+
var MAX_SECURED_DIRECTORIES = 128;
|
|
6607
|
+
async function secureWindowsDirectory(directory) {
|
|
6608
|
+
await runWindowsPowerShell(
|
|
6609
|
+
"secure private collector storage",
|
|
6610
|
+
`
|
|
6611
|
+
$root = ${powershellLiteral(directory)}
|
|
6612
|
+
$owner = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
6613
|
+
$principals = @($owner, [System.Security.Principal.SecurityIdentifier]::new('S-1-5-18'), [System.Security.Principal.SecurityIdentifier]::new('S-1-5-32-544'))
|
|
6614
|
+
$pending = [System.Collections.Generic.Stack[string]]::new()
|
|
6615
|
+
$pending.Push($root)
|
|
6616
|
+
$count = 0
|
|
6617
|
+
while ($pending.Count -gt 0) {
|
|
6618
|
+
$entry = $pending.Pop()
|
|
6619
|
+
try {
|
|
6620
|
+
$item = Get-Item -LiteralPath $entry -Force
|
|
6621
|
+
if (($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'Private storage cannot contain filesystem links.' }
|
|
6622
|
+
if (++$count -gt 65536) { throw 'Private storage has too many entries to secure.' }
|
|
6623
|
+
if ($item.PSIsContainer) {
|
|
6624
|
+
$acl = [System.Security.AccessControl.DirectorySecurity]::new()
|
|
6625
|
+
$inheritance = [System.Security.AccessControl.InheritanceFlags]'ContainerInherit, ObjectInherit'
|
|
6626
|
+
} else {
|
|
6627
|
+
$acl = [System.Security.AccessControl.FileSecurity]::new()
|
|
6628
|
+
$inheritance = [System.Security.AccessControl.InheritanceFlags]::None
|
|
6629
|
+
}
|
|
6630
|
+
$acl.SetOwner($owner)
|
|
6631
|
+
$acl.SetAccessRuleProtection($true, $false)
|
|
6632
|
+
foreach ($principal in $principals) {
|
|
6633
|
+
$acl.AddAccessRule([System.Security.AccessControl.FileSystemAccessRule]::new($principal, 'FullControl', $inheritance, 'None', 'Allow'))
|
|
6634
|
+
}
|
|
6635
|
+
# Set-Acl may request audit privileges on a protected DACL. Persist only
|
|
6636
|
+
# the changed owner and access rules so repair needs no elevation.
|
|
6637
|
+
$item.SetAccessControl($acl)
|
|
6638
|
+
$actual = Get-Acl -LiteralPath $item.FullName
|
|
6639
|
+
if (!$actual.AreAccessRulesProtected -or $actual.GetOwner([System.Security.Principal.SecurityIdentifier]).Value -ne $owner.Value) { throw 'Private storage ACL verification failed.' }
|
|
6640
|
+
foreach ($rule in $actual.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier])) {
|
|
6641
|
+
if ($rule.AccessControlType -ne 'Allow' -or $principals.Value -notcontains $rule.IdentityReference.Value) { throw 'Private storage contains an unexpected access rule.' }
|
|
6642
|
+
}
|
|
6643
|
+
if ($item.PSIsContainer) {
|
|
6644
|
+
foreach ($child in [System.IO.Directory]::EnumerateFileSystemEntries($item.FullName)) {
|
|
6645
|
+
if ($count + $pending.Count -ge 65536) { throw 'Private storage has too many entries to secure.' }
|
|
6646
|
+
$pending.Push($child)
|
|
6647
|
+
}
|
|
6648
|
+
}
|
|
6649
|
+
} catch [System.Management.Automation.ItemNotFoundException] {
|
|
6650
|
+
if ($entry -eq $root) { throw }
|
|
6651
|
+
}
|
|
6652
|
+
}
|
|
6653
|
+
`
|
|
6654
|
+
);
|
|
6655
|
+
}
|
|
6656
|
+
async function ensurePrivateDirectory(directory) {
|
|
6657
|
+
await fs.mkdir(directory, { recursive: true, mode: 448 });
|
|
6658
|
+
if (process.platform !== "win32") {
|
|
6659
|
+
await fs.chmod(directory, 448);
|
|
6660
|
+
return;
|
|
6661
|
+
}
|
|
6662
|
+
const resolved = await fs.realpath(directory);
|
|
6663
|
+
let secured = securedDirectories.get(resolved);
|
|
6664
|
+
if (secured === void 0) {
|
|
6665
|
+
if (securedDirectories.size >= MAX_SECURED_DIRECTORIES) {
|
|
6666
|
+
const oldest = securedDirectories.keys().next().value;
|
|
6667
|
+
if (oldest !== void 0) securedDirectories.delete(oldest);
|
|
6668
|
+
}
|
|
6669
|
+
secured = secureWindowsDirectory(resolved).catch((error2) => {
|
|
6670
|
+
securedDirectories.delete(resolved);
|
|
6671
|
+
throw error2;
|
|
6672
|
+
});
|
|
6673
|
+
securedDirectories.set(resolved, secured);
|
|
6674
|
+
}
|
|
6675
|
+
await secured;
|
|
6676
|
+
}
|
|
6677
|
+
|
|
6548
6678
|
// src/runtime.ts
|
|
6549
6679
|
function runtimePaths(home = os.homedir()) {
|
|
6550
|
-
const root =
|
|
6680
|
+
const root = path2.join(home, ".config", "iteration", "runtime");
|
|
6551
6681
|
return {
|
|
6552
6682
|
home,
|
|
6553
6683
|
root,
|
|
6554
|
-
versions:
|
|
6555
|
-
staging:
|
|
6556
|
-
state:
|
|
6557
|
-
settings:
|
|
6558
|
-
lock:
|
|
6559
|
-
updateLock:
|
|
6560
|
-
launcher:
|
|
6684
|
+
versions: path2.join(root, "versions"),
|
|
6685
|
+
staging: path2.join(root, "staging"),
|
|
6686
|
+
state: path2.join(root, "state.json"),
|
|
6687
|
+
settings: path2.join(root, "settings.json"),
|
|
6688
|
+
lock: path2.join(root, "state.lock"),
|
|
6689
|
+
updateLock: path2.join(root, "update.lock"),
|
|
6690
|
+
launcher: path2.join(root, "launcher.js")
|
|
6561
6691
|
};
|
|
6562
6692
|
}
|
|
6563
6693
|
var MAX_TRIAL_STARTS = 3;
|
|
@@ -6601,25 +6731,24 @@ function isVersion(value) {
|
|
|
6601
6731
|
}
|
|
6602
6732
|
async function ensureRuntimeDirectory(paths) {
|
|
6603
6733
|
for (const directory of [paths.root, paths.versions, paths.staging]) {
|
|
6604
|
-
await
|
|
6605
|
-
await fs.chmod(directory, 448);
|
|
6734
|
+
await ensurePrivateDirectory(directory);
|
|
6606
6735
|
}
|
|
6607
6736
|
}
|
|
6608
6737
|
async function writeFileAtomic(filename, contents, mode) {
|
|
6609
6738
|
const temporary = `${filename}.${process.pid}.${Date.now()}.tmp`;
|
|
6610
|
-
const handle = await
|
|
6739
|
+
const handle = await fs2.open(temporary, "w", mode);
|
|
6611
6740
|
try {
|
|
6612
6741
|
await handle.writeFile(contents, "utf8");
|
|
6613
6742
|
await handle.sync();
|
|
6614
6743
|
} finally {
|
|
6615
6744
|
await handle.close();
|
|
6616
6745
|
}
|
|
6617
|
-
await
|
|
6746
|
+
await fs2.rename(temporary, filename);
|
|
6618
6747
|
}
|
|
6619
6748
|
async function readRuntimeState(paths) {
|
|
6620
6749
|
let contents;
|
|
6621
6750
|
try {
|
|
6622
|
-
contents = await
|
|
6751
|
+
contents = await fs2.readFile(paths.state, "utf8");
|
|
6623
6752
|
} catch (error2) {
|
|
6624
6753
|
if (errorCode(error2) === "ENOENT") return null;
|
|
6625
6754
|
throw error2;
|
|
@@ -6653,19 +6782,19 @@ var LockBusyError = class extends Error {
|
|
|
6653
6782
|
async function tryLock(filename) {
|
|
6654
6783
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
6655
6784
|
try {
|
|
6656
|
-
const handle = await
|
|
6785
|
+
const handle = await fs2.open(filename, "wx", 384);
|
|
6657
6786
|
await handle.writeFile(`${process.pid}
|
|
6658
6787
|
`, "utf8");
|
|
6659
6788
|
await handle.close();
|
|
6660
6789
|
return async () => {
|
|
6661
|
-
const owner = await
|
|
6790
|
+
const owner = await fs2.readFile(filename, "utf8").catch(() => "");
|
|
6662
6791
|
if (owner.trim() === String(process.pid))
|
|
6663
|
-
await
|
|
6792
|
+
await fs2.rm(filename, { force: true });
|
|
6664
6793
|
};
|
|
6665
6794
|
} catch (error2) {
|
|
6666
6795
|
if (errorCode(error2) !== "EEXIST") throw error2;
|
|
6667
6796
|
const owner = Number(
|
|
6668
|
-
(await
|
|
6797
|
+
(await fs2.readFile(filename, "utf8").catch(() => "")).trim()
|
|
6669
6798
|
);
|
|
6670
6799
|
if (Number.isSafeInteger(owner) && owner > 1) {
|
|
6671
6800
|
try {
|
|
@@ -6675,7 +6804,7 @@ async function tryLock(filename) {
|
|
|
6675
6804
|
if (errorCode(processError) !== "ESRCH") throw processError;
|
|
6676
6805
|
}
|
|
6677
6806
|
}
|
|
6678
|
-
await
|
|
6807
|
+
await fs2.rm(filename, { force: true });
|
|
6679
6808
|
}
|
|
6680
6809
|
}
|
|
6681
6810
|
throw new LockBusyError(`Could not obtain ${filename}.`);
|
|
@@ -6740,10 +6869,10 @@ function launchDecision(state, command, source, nowMs) {
|
|
|
6740
6869
|
function versionDirectory(paths, version2) {
|
|
6741
6870
|
if (!isVersion(version2))
|
|
6742
6871
|
throw new Error(`Invalid Iteration version ${version2}.`);
|
|
6743
|
-
return
|
|
6872
|
+
return path2.join(paths.versions, version2);
|
|
6744
6873
|
}
|
|
6745
6874
|
function versionEntry(paths, version2, entry) {
|
|
6746
|
-
return
|
|
6875
|
+
return path2.join(versionDirectory(paths, version2), "dist", entry);
|
|
6747
6876
|
}
|
|
6748
6877
|
var packageSchema = object({ name: literal("iteration-cli"), version: versionSchema }).loose();
|
|
6749
6878
|
|
|
@@ -6784,7 +6913,7 @@ async function launch() {
|
|
|
6784
6913
|
command === "cursor-hook" ? "cursor-hook-entry.js" : "cli.js"
|
|
6785
6914
|
);
|
|
6786
6915
|
if (command === "launcher-check") {
|
|
6787
|
-
await
|
|
6916
|
+
await fs3.access(entry);
|
|
6788
6917
|
process.stdout.write(`${version2}
|
|
6789
6918
|
`);
|
|
6790
6919
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iteration-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@secretlint/secretlint-rule-preset-recommend": "13.0.6",
|
|
23
23
|
"esbuild": "0.28.2",
|
|
24
24
|
"zod": "4.6.4",
|
|
25
|
-
"iteration-trace-contracts": "0.
|
|
25
|
+
"iteration-trace-contracts": "0.11.0"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "pnpm --filter iteration-trace-contracts build && tsc -p tsconfig.json --noEmit && node build.mjs"
|