toolroll 0.9.65 → 0.9.68
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/CHANGELOG.md +93 -0
- package/README.md +20 -2
- package/dist/acp-client.js +1 -3
- package/dist/agent-board.d.ts +0 -1
- package/dist/agent-board.js +0 -1
- package/dist/agent-fence.d.ts +69 -2
- package/dist/agent-fence.js +294 -11
- package/dist/agentconfig.js +4 -1
- package/dist/batch-checks.js +3 -2
- package/dist/browser/THIRD_PARTY_NOTICES.txt +46 -0
- package/dist/browser/terminal.js +134 -23
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +31 -29
- package/dist/builder.d.ts +4 -0
- package/dist/builder.js +56 -37
- package/dist/canonical-json.d.ts +14 -0
- package/dist/canonical-json.js +36 -0
- package/dist/chat-actions.js +1 -2
- package/dist/chat-admission.d.ts +19 -0
- package/dist/chat-admission.js +22 -0
- package/dist/chat-channel.js +1 -1
- package/dist/chat-delivery.js +0 -1
- package/dist/chat-follow.d.ts +17 -0
- package/dist/chat-follow.js +32 -0
- package/dist/chat-messages.js +0 -1
- package/dist/chat-settings-page.d.ts +23 -0
- package/dist/chat-settings-page.js +41 -0
- package/dist/claim.js +3 -6
- package/dist/claude-print.d.ts +12 -0
- package/dist/claude-print.js +34 -0
- package/dist/cli-http.d.ts +0 -7
- package/dist/cli-http.js +0 -21
- package/dist/cli.d.ts +3 -10
- package/dist/cli.js +15 -24
- package/dist/coding-provider.js +2 -1
- package/dist/coding-workspace.js +1 -1
- package/dist/{team-cli.d.ts → connect-cli.d.ts} +5 -9
- package/dist/connect-cli.js +331 -0
- package/dist/containment.d.ts +0 -2
- package/dist/containment.js +2 -6
- package/dist/contracts/chat-actions.d.ts +0 -1
- package/dist/contracts/chat-content.d.ts +0 -4
- package/dist/contracts/chat-content.js +0 -2
- package/dist/contracts/chat-tables.d.ts +0 -1
- package/dist/contracts/cli.d.ts +0 -62
- package/dist/contracts/cli.js +0 -4
- package/dist/contracts/coding-workspace.js +1 -1
- package/dist/contracts/console-api.d.ts +1 -0
- package/dist/contracts/console-api.js +1 -0
- package/dist/contracts/contract.js +1 -1
- package/dist/contracts/flow-card.d.ts +0 -1
- package/dist/contracts/flow-propose.d.ts +0 -1
- package/dist/contracts/flow-send.js +1 -1
- package/dist/contracts/gateway-tools.d.ts +0 -1
- package/dist/contracts/integration-metadata.js +1 -1
- package/dist/contracts/lead-tools.d.ts +0 -1
- package/dist/contracts/memory-pass.d.ts +0 -1
- package/dist/contracts/memory-pass.js +1 -1
- package/dist/contracts/plan.js +1 -1
- package/dist/contracts/project-knowledge.js +1 -1
- package/dist/contracts/project-skills.d.ts +0 -1
- package/dist/contracts/proof.js +1 -1
- package/dist/contracts/recipes.js +1 -1
- package/dist/contracts/scope.js +1 -1
- package/dist/contracts/scout-report.js +1 -1
- package/dist/contracts/teams-callback.d.ts +0 -1
- package/dist/converse.d.ts +0 -6
- package/dist/converse.js +0 -19
- package/dist/daemon.js +3 -2
- package/dist/decision.d.ts +1 -3
- package/dist/deprecations.d.ts +12 -4
- package/dist/deprecations.js +27 -4
- package/dist/desktop-update-recovery.js +1 -1
- package/dist/desktop-update.js +3 -2
- package/dist/discord-chat.js +4 -15
- package/dist/discord-settings.d.ts +2 -6
- package/dist/discord-settings.js +10 -38
- package/dist/discord.js +12 -23
- package/dist/evidence.d.ts +0 -1
- package/dist/evidence.js +0 -3
- package/dist/exec.d.ts +0 -9
- package/dist/exec.js +3 -81
- package/dist/flow-actions.js +0 -3
- package/dist/flow-draft.d.ts +1 -3
- package/dist/flow-draft.js +15 -28
- package/dist/flow-scripts.d.ts +1 -8
- package/dist/flow-scripts.js +0 -13
- package/dist/flow-send.js +1 -1
- package/dist/flow-share.d.ts +0 -2
- package/dist/flow-share.js +1 -6
- package/dist/flow-steps.js +1 -1
- package/dist/flow-triggers.d.ts +0 -1
- package/dist/flow-triggers.js +1 -2
- package/dist/flow-unattended.js +1 -12
- package/dist/flows.js +1 -1
- package/dist/health-cli.d.ts +2 -2
- package/dist/health-cli.js +1 -1
- package/dist/invoke.d.ts +18 -3
- package/dist/invoke.js +142 -17
- package/dist/is-record.d.ts +2 -0
- package/dist/is-record.js +2 -0
- package/dist/lead-doors.d.ts +1 -5
- package/dist/lead-doors.js +0 -4
- package/dist/lead-tools.js +3 -6
- package/dist/live-detail.d.ts +0 -1
- package/dist/live-detail.js +0 -6
- package/dist/live-terminal.d.ts +24 -13
- package/dist/live-terminal.js +81 -43
- package/dist/live.d.ts +0 -1
- package/dist/live.js +1 -2
- package/dist/mcp-core.js +0 -2
- package/dist/memory-pass.js +1 -1
- package/dist/model-catalog.js +1 -1
- package/dist/modes.js +1 -12
- package/dist/operate.d.ts +2 -0
- package/dist/operate.js +436 -745
- package/dist/password-bearer.d.ts +0 -2
- package/dist/password-bearer.js +0 -4
- package/dist/peek-cli.js +2 -1
- package/dist/peek.d.ts +2 -26
- package/dist/peek.js +2 -168
- package/dist/phase-routing.d.ts +0 -4
- package/dist/phase-routing.js +2 -21
- package/dist/planner-source.d.ts +2 -1
- package/dist/planner-source.js +2 -12
- package/dist/planner.js +2 -14
- package/dist/process-tree.d.ts +0 -2
- package/dist/process-tree.js +0 -10
- package/dist/project-delete-ui.d.ts +6 -0
- package/dist/project-delete-ui.js +20 -1
- package/dist/project-delete.d.ts +0 -2
- package/dist/project-delete.js +1 -3
- package/dist/project-learning.d.ts +0 -14
- package/dist/project-skills.d.ts +0 -1
- package/dist/project-skills.js +0 -14
- package/dist/project-tools.js +2 -10
- package/dist/provider.d.ts +0 -17
- package/dist/provider.js +0 -26
- package/dist/pulls.d.ts +0 -2
- package/dist/pulls.js +0 -9
- package/dist/release-adapters.d.ts +9 -0
- package/dist/release-adapters.js +81 -4
- package/dist/release.d.ts +7 -1
- package/dist/release.js +20 -7
- package/dist/remote-exec.d.ts +3 -2
- package/dist/remote-exec.js +3 -2
- package/dist/repos.d.ts +0 -5
- package/dist/repos.js +2 -10
- package/dist/repository-context.d.ts +0 -2
- package/dist/repository-context.js +0 -4
- package/dist/restart-certification.d.ts +0 -2
- package/dist/restart-certification.js +1 -5
- package/dist/result-follow-ups.d.ts +1 -4
- package/dist/result-follow-ups.js +4 -8
- package/dist/result-review.d.ts +0 -2
- package/dist/result-review.js +0 -2
- package/dist/retention.d.ts +0 -1
- package/dist/retention.js +0 -1
- package/dist/review-context.d.ts +0 -1
- package/dist/review-context.js +1 -12
- package/dist/reviewer.d.ts +0 -16
- package/dist/reviewer.js +0 -18
- package/dist/run-closeout.js +2 -1
- package/dist/scope.d.ts +13 -0
- package/dist/scope.js +11 -18
- package/dist/scout-browser.js +2 -1
- package/dist/serve.js +3 -2
- package/dist/server/chrome.d.ts +10 -1
- package/dist/server/chrome.js +45 -4
- package/dist/server/console.css +60 -137
- package/dist/server/flows.js +2 -2
- package/dist/server/http.d.ts +2 -0
- package/dist/server/http.js +5 -0
- package/dist/server/pages.js +2 -2
- package/dist/server/people-tokens.js +3 -4
- package/dist/server/remote.js +1 -6
- package/dist/server/render-chat.d.ts +9 -2
- package/dist/server/render-chat.js +53 -7
- package/dist/server/render-pages.d.ts +28 -3
- package/dist/server/render-pages.js +78 -9
- package/dist/server/render-results.d.ts +0 -6
- package/dist/server/render-results.js +3 -9
- package/dist/server/render-tasks.js +6 -6
- package/dist/server/route-table.d.ts +0 -4
- package/dist/server/route-table.js +1 -6
- package/dist/server/settings.js +43 -22
- package/dist/server/task-views.js +1 -1
- package/dist/server/tasks.js +10 -7
- package/dist/setup-guide.d.ts +2 -2
- package/dist/skills.d.ts +0 -6
- package/dist/skills.js +0 -8
- package/dist/slack-chat.d.ts +1 -7
- package/dist/slack-chat.js +5 -18
- package/dist/slack-settings.d.ts +2 -6
- package/dist/slack-settings.js +10 -38
- package/dist/slack.js +12 -23
- package/dist/sleep.d.ts +2 -0
- package/dist/sleep.js +2 -0
- package/dist/store.d.ts +11 -74
- package/dist/store.js +36 -179
- package/dist/structured-output.d.ts +0 -1
- package/dist/structured-output.js +0 -1
- package/dist/subagent-work.d.ts +0 -2
- package/dist/subagent-work.js +0 -2
- package/dist/subagents.d.ts +1 -3
- package/dist/subagents.js +20 -33
- package/dist/subscription-chat.d.ts +1 -3
- package/dist/subscription-chat.js +2 -3
- package/dist/task-sizing.d.ts +1 -4
- package/dist/task-sizing.js +3 -10
- package/dist/teams-chat.js +4 -11
- package/dist/teams.js +12 -19
- package/dist/teardown-git.d.ts +22 -0
- package/dist/teardown-git.js +136 -2
- package/dist/telegram-lead.js +2 -2
- package/dist/telegram.js +1 -1
- package/dist/token-notices.d.ts +0 -11
- package/dist/token-notices.js +1 -5
- package/dist/tool-broker.d.ts +12 -0
- package/dist/tool-broker.js +66 -2
- package/dist/tool-secret-store.d.ts +0 -3
- package/dist/tool-secret-store.js +2 -11
- package/dist/toolroll-update.d.ts +0 -2
- package/dist/toolroll-update.js +2 -2
- package/dist/unfenced-test-support.d.ts +2 -0
- package/dist/unfenced-test-support.js +11 -0
- package/dist/verification-evidence.d.ts +0 -1
- package/dist/verification-evidence.js +0 -1
- package/dist/webhooks.d.ts +0 -1
- package/dist/webhooks.js +0 -1
- package/dist/workspace-ui.d.ts +0 -8
- package/dist/workspace-ui.js +1 -6
- package/dist/writes-mode.d.ts +9 -0
- package/dist/writes-mode.js +8 -0
- package/package.json +5 -1
- package/dist/contracts/native-census.d.ts +0 -42
- package/dist/contracts/native-census.js +0 -36
- package/dist/process-recovery-anchor.d.ts +0 -75
- package/dist/process-recovery-anchor.js +0 -188
- package/dist/process-recovery-coalition.d.ts +0 -25
- package/dist/process-recovery-coalition.js +0 -105
- package/dist/process-recovery-eligibility.d.ts +0 -179
- package/dist/process-recovery-eligibility.js +0 -174
- package/dist/process-recovery-native.d.ts +0 -161
- package/dist/process-recovery-native.js +0 -595
- package/dist/process-recovery-provenance.d.ts +0 -163
- package/dist/process-recovery-provenance.js +0 -292
- package/dist/process-recovery-services.d.ts +0 -56
- package/dist/process-recovery-services.js +0 -191
- package/dist/process-recovery-settlement.d.ts +0 -32
- package/dist/process-recovery-settlement.js +0 -133
- package/dist/process-recovery.d.ts +0 -41
- package/dist/process-recovery.js +0 -91
- package/dist/session-brief.d.ts +0 -8
- package/dist/session-brief.js +0 -24
- package/dist/session-cli.d.ts +0 -42
- package/dist/session-cli.js +0 -271
- package/dist/session-contract.d.ts +0 -183
- package/dist/session-contract.js +0 -122
- package/dist/session-remote.d.ts +0 -19
- package/dist/session-remote.js +0 -86
- package/dist/session-service.d.ts +0 -22
- package/dist/session-service.js +0 -157
- package/dist/team-cli.js +0 -692
package/dist/agent-fence.js
CHANGED
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
import { INSTANCE_DIR } from "./console-instance.js";
|
|
44
44
|
import { ACP_AGENTS, ACP_PROVIDER_IDS } from "./acp-agents.js";
|
|
45
45
|
import { spawnSync } from "node:child_process";
|
|
46
|
-
import {
|
|
46
|
+
import { createHash } from "node:crypto";
|
|
47
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, realpathSync, statSync, writeFileSync } from "node:fs";
|
|
47
48
|
import { homedir, tmpdir } from "node:os";
|
|
48
49
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
49
50
|
import { readMonitoring } from "./monitoring-settings.js";
|
|
@@ -368,7 +369,7 @@ export function taskBoundary(options) {
|
|
|
368
369
|
}
|
|
369
370
|
/** The prefixes of every launch's private folders: its tools' config, a Codex build's own home, and a Linux build's
|
|
370
371
|
* network bridge (egress-bridge.ts). */
|
|
371
|
-
export const RUN_FOLDER_PREFIXES = ["so-tools-", "so-codex-", "so-net-"];
|
|
372
|
+
export const RUN_FOLDER_PREFIXES = ["so-tools-", "so-codex-", "so-net-", "so-cmd-"];
|
|
372
373
|
export function runFolders(own, root = tmpdir()) {
|
|
373
374
|
return { root: real(root), own: own === null ? null : real(own) };
|
|
374
375
|
}
|
|
@@ -383,6 +384,161 @@ function otherRunFolders(folders) {
|
|
|
383
384
|
}
|
|
384
385
|
return entries.filter(entry => RUN_FOLDER_PREFIXES.some(prefix => entry.startsWith(prefix))).map(entry => join(folders.root, entry)).filter(path => path !== folders.own);
|
|
385
386
|
}
|
|
387
|
+
export { isWritesMode, WRITES_DEFAULT } from "./writes-mode.js";
|
|
388
|
+
/** Claude's transcript folder for a working folder: its path with every character but a letter or digit made `-`
|
|
389
|
+
* (Claude Code's own naming; a name over 200 characters gets a suffix, so it is granted by prefix). */
|
|
390
|
+
export function claudeProjectFolder(home, cwd) {
|
|
391
|
+
const slug = cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
392
|
+
return slug.length > 200 ? { path: join(home, ".claude", "projects", slug.slice(0, 200)), byPrefix: true } : { path: join(home, ".claude", "projects", slug), byPrefix: false };
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* A folder a write grant may name: made when absent, then only as the real folder it is — never a link, nor reached
|
|
396
|
+
* through one (its real path is its parent's real path and its own name). A build can rewrite what it may write, so a
|
|
397
|
+
* folder it was given could otherwise come back as a link to anywhere and be granted, followed, on its next launch.
|
|
398
|
+
* Null when it isn't such a folder: nothing is granted, and the write it was for fails.
|
|
399
|
+
*/
|
|
400
|
+
export function grantFolder(path, create = true) {
|
|
401
|
+
if (create) {
|
|
402
|
+
try {
|
|
403
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
404
|
+
}
|
|
405
|
+
catch { /* checked below */ }
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const held = lstatSync(path);
|
|
409
|
+
if (held.isSymbolicLink() || !held.isDirectory())
|
|
410
|
+
return null;
|
|
411
|
+
// Nor through a link of this user's anywhere above it (a system alias, /var → /private/var, is root's and fine).
|
|
412
|
+
const uid = process.getuid?.();
|
|
413
|
+
for (let folder = dirname(resolve(path)); folder !== dirname(folder); folder = dirname(folder)) {
|
|
414
|
+
const above = lstatSync(folder);
|
|
415
|
+
if (above.isSymbolicLink() && (uid === undefined || above.uid === uid))
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
const at = realpathSync(path);
|
|
419
|
+
return at === join(realpathSync(dirname(path)), basename(path)) ? at : null;
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* The data folders an ACP agent writes besides a ~/.local/share|state root, per agent, only where known: Goose's
|
|
427
|
+
* sessions and state; Qwen Code (a Gemini CLI fork) its history and temp, as Gemini measured. An agent not listed
|
|
428
|
+
* (Cursor, Cline: their settings sit among their data) writes nothing of its own under a workspace build until its
|
|
429
|
+
* layout is measured; a project using one chooses `anywhere`.
|
|
430
|
+
*/
|
|
431
|
+
const ACP_DATA = {
|
|
432
|
+
goose: [".local/share/goose", ".local/state/goose"],
|
|
433
|
+
qwen: [".qwen/tmp", ".qwen/history"],
|
|
434
|
+
};
|
|
435
|
+
/** The suffix Claude Code gives a transcript folder whose name it shortened: `-` and a hash, nothing else. */
|
|
436
|
+
const CLAUDE_SHORTENED = "-[a-z0-9]+(/|$)";
|
|
437
|
+
/** A file and the temporary names it is replaced through (`name.tmp-1`, `name.json.12345`), never a folder below it. */
|
|
438
|
+
const ATOMIC_NAMES = "([.~][^/]*)?$";
|
|
439
|
+
/** The parts of a repository's shared Git data a commit in a worktree writes: objects, refs and their logs (and the
|
|
440
|
+
* packed refs). Its config, hooks, info, other worktrees' data and submodules' are never among them. */
|
|
441
|
+
function commitGitData(common) {
|
|
442
|
+
const made = (path) => { try {
|
|
443
|
+
mkdirSync(path, { recursive: true });
|
|
444
|
+
}
|
|
445
|
+
catch { /* granted as named */ } return real(path); };
|
|
446
|
+
return {
|
|
447
|
+
subpaths: ["objects", "refs", "logs"].map(name => grantFolder(join(common, name))).filter((path) => path !== null),
|
|
448
|
+
prefixes: [{ path: join(common, "packed-refs"), suffix: ATOMIC_NAMES }],
|
|
449
|
+
// Alternates there would let objects come from anywhere.
|
|
450
|
+
readOnly: [made(join(common, "objects", "info"))],
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* What a `workspace` build writes and what it loses (arc 2): its checkout, its checkout's Git data (less the shared
|
|
455
|
+
* repository's config, hooks and info, which Git runs or reads as commands), its own launch folder (its temp is there),
|
|
456
|
+
* its project's cache folder, the terminal devices, and only the provider state its CLI must write (measured: Claude's
|
|
457
|
+
* transcript folder for this checkout; Gemini's history, temp and project list; an ACP agent's own folders). The
|
|
458
|
+
* folders named here are made first, so the provider never has to make them where it can't. `deny` is what this
|
|
459
|
+
* provider must not even read (Claude's live sessions' keys).
|
|
460
|
+
*/
|
|
461
|
+
export function writeAllowlist(options) {
|
|
462
|
+
const home = real(options.home);
|
|
463
|
+
const worktree = real(options.worktree);
|
|
464
|
+
const subpaths = new Set([worktree]);
|
|
465
|
+
const prefixes = new Map();
|
|
466
|
+
const readOnly = new Set();
|
|
467
|
+
const deny = new Set();
|
|
468
|
+
const made = (path) => { try {
|
|
469
|
+
mkdirSync(path, { recursive: true, mode: 0o700 });
|
|
470
|
+
}
|
|
471
|
+
catch { /* granted as named either way */ } return real(path); };
|
|
472
|
+
const grant = (path, create = true) => { const at = grantFolder(path, create); if (at !== null)
|
|
473
|
+
subpaths.add(at); };
|
|
474
|
+
if (options.binding !== null) {
|
|
475
|
+
const common = real(join(options.binding.main, ".git"));
|
|
476
|
+
const gitdir = real(options.binding.gitdir);
|
|
477
|
+
grant(gitdir, false);
|
|
478
|
+
// The shared Git data a commit writes, and nothing Git reads as commands or settings: the shared config (filters,
|
|
479
|
+
// hooks path, fsmonitor), hooks, info (attributes, excludes), other worktrees' data and submodules' stay as they are.
|
|
480
|
+
const data = commitGitData(common);
|
|
481
|
+
for (const path of data.subpaths)
|
|
482
|
+
subpaths.add(path);
|
|
483
|
+
for (const one of data.prefixes)
|
|
484
|
+
prefixes.set(`${one.path}\0${one.suffix}`, one);
|
|
485
|
+
for (const path of data.readOnly)
|
|
486
|
+
readOnly.add(path);
|
|
487
|
+
// This worktree's own settings file, present (empty) so it is held read-only everywhere, a bind included.
|
|
488
|
+
const own = join(gitdir, "config.worktree");
|
|
489
|
+
try {
|
|
490
|
+
if (!existsSync(own))
|
|
491
|
+
writeFileSync(own, "", { mode: 0o644, flag: "wx" });
|
|
492
|
+
}
|
|
493
|
+
catch { /* held read-only by name */ }
|
|
494
|
+
readOnly.add(own);
|
|
495
|
+
}
|
|
496
|
+
if (options.launchFolder !== null)
|
|
497
|
+
grant(options.launchFolder, false);
|
|
498
|
+
if (options.cache !== null)
|
|
499
|
+
grant(options.cache);
|
|
500
|
+
if (options.provider === "claude") {
|
|
501
|
+
const folder = claudeProjectFolder(home, worktree);
|
|
502
|
+
if (folder.byPrefix) {
|
|
503
|
+
made(dirname(folder.path));
|
|
504
|
+
prefixes.set(folder.path, { path: folder.path, suffix: CLAUDE_SHORTENED });
|
|
505
|
+
}
|
|
506
|
+
else
|
|
507
|
+
grant(folder.path);
|
|
508
|
+
deny.add(join(home, ".claude", "sessions"));
|
|
509
|
+
}
|
|
510
|
+
else if (options.provider === "gemini") {
|
|
511
|
+
for (const name of ["history", "tmp"])
|
|
512
|
+
grant(join(home, ".gemini", name));
|
|
513
|
+
prefixes.set("gemini", { path: join(home, ".gemini", "projects.json"), suffix: ATOMIC_NAMES });
|
|
514
|
+
}
|
|
515
|
+
else if (Object.hasOwn(ACP_AGENTS, options.provider)) {
|
|
516
|
+
// An ACP agent's configuration stays read-only whole (its MCP servers, hooks, plugins, agents and commands could
|
|
517
|
+
// otherwise be planted for the operator's next session of it); only its known data folders are written (ACP_DATA).
|
|
518
|
+
for (const name of ACP_AGENTS[options.provider].home)
|
|
519
|
+
if (/^\.local\/(share|state)\//.test(name))
|
|
520
|
+
grant(join(home, name));
|
|
521
|
+
for (const name of ACP_DATA[options.provider] ?? [])
|
|
522
|
+
grant(join(home, name));
|
|
523
|
+
}
|
|
524
|
+
return { writes: { subpaths: [...subpaths].sort(), prefixes: [...prefixes.values()].sort((a, b) => a.path.localeCompare(b.path)) }, readOnly: [...readOnly].sort(), deny: [...deny].sort() };
|
|
525
|
+
}
|
|
526
|
+
/** Where a project's builds keep their package caches: one folder per project (one trust domain), never used by the
|
|
527
|
+
* plane's own tools, below the user's cache folder. */
|
|
528
|
+
export function buildCacheFolder(repo, home = homedir(), platform = process.platform, env = process.env) {
|
|
529
|
+
const root = platform === "darwin" ? join(home, "Library", "Caches") : env["XDG_CACHE_HOME"] !== undefined && isAbsolute(env["XDG_CACHE_HOME"]) ? env["XDG_CACHE_HOME"] : join(home, ".cache");
|
|
530
|
+
return join(root, "toolroll-builds", createHash("sha256").update(real(repo)).digest("hex").slice(0, 16));
|
|
531
|
+
}
|
|
532
|
+
/** The environment that points a build's package managers at its project's cache folder, not the user's own. */
|
|
533
|
+
export function buildCacheEnv(folder) {
|
|
534
|
+
const at = (name) => join(folder, name);
|
|
535
|
+
return {
|
|
536
|
+
npm_config_cache: at("npm"), npm_config_store_dir: at("pnpm"), YARN_CACHE_FOLDER: at("yarn"), BUN_INSTALL_CACHE_DIR: at("bun"),
|
|
537
|
+
COREPACK_HOME: at("corepack"), npm_config_devdir: at("node-gyp"), PIP_CACHE_DIR: at("pip"), UV_CACHE_DIR: at("uv"),
|
|
538
|
+
GOCACHE: at("go-build"), GOMODCACHE: at("go-mod"), CARGO_HOME: at("cargo"), GRADLE_USER_HOME: at("gradle"),
|
|
539
|
+
DENO_DIR: at("deno"), XDG_CACHE_HOME: at("xdg"),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
386
542
|
/**
|
|
387
543
|
* Services a sandboxed process could ask to act outside the sandbox for it (macOS): open a URL in a browser (Launch
|
|
388
544
|
* Services), script another application (Apple Events), fetch in the background (nsurlsessiond), look a name up
|
|
@@ -524,7 +680,14 @@ export function codexFenceArgv(fence, fullAccess, grants = NO_GRANTS) {
|
|
|
524
680
|
// Codex lets the more specific path win: no read grant inside a pool, but the build's own checkout.
|
|
525
681
|
const pooled = (path) => pool !== undefined && pool.deny.some(one => path === one || inside(path, one))
|
|
526
682
|
&& !(pool.own !== null && (path === pool.own || inside(path, pool.own)));
|
|
527
|
-
|
|
683
|
+
// Full access writes anywhere its fence allows, unless the build writes only its workspace (arc 2): then exactly its
|
|
684
|
+
// allowlist, in either mode, beside the workspace Codex's own profile gives.
|
|
685
|
+
// Codex's own workspace profile also writes the shared temp folders; a workspace build starts from its read-only
|
|
686
|
+
// profile instead, with exactly the allowlist (its checkout among it) written back.
|
|
687
|
+
if (grants.writes !== undefined)
|
|
688
|
+
for (const path of grants.writes.subpaths)
|
|
689
|
+
access.set(real(path), "write");
|
|
690
|
+
else if (fullAccess)
|
|
528
691
|
access.set("/", "write");
|
|
529
692
|
for (const path of readOnly)
|
|
530
693
|
if (!pooled(real(path)))
|
|
@@ -548,7 +711,7 @@ export function codexFenceArgv(fence, fullAccess, grants = NO_GRANTS) {
|
|
|
548
711
|
const filesystem = [...access].map(([path, mode]) => `${toml(path)}=${toml(mode)}`);
|
|
549
712
|
return [
|
|
550
713
|
"-c", 'default_permissions="standing-orders"',
|
|
551
|
-
"-c",
|
|
714
|
+
"-c", `permissions.standing-orders.extends=${grants.writes === undefined ? '":workspace"' : '":read-only"'}`,
|
|
552
715
|
"-c", `permissions.standing-orders.filesystem={${filesystem.join(",")}}`,
|
|
553
716
|
// Codex's command sandbox can't route through a proxy: its commands reach the network only when the run's sealed
|
|
554
717
|
// network is open (and Full access asked for it), and are offline otherwise.
|
|
@@ -700,6 +863,14 @@ export function macosFenceProfile(fence, grants = NO_GRANTS) {
|
|
|
700
863
|
return [
|
|
701
864
|
"(version 1)",
|
|
702
865
|
"(allow default)",
|
|
866
|
+
// A workspace build writes only its allowlist (and the terminal devices); every deny and read-only rule after this
|
|
867
|
+
// still holds inside it.
|
|
868
|
+
...(grants.writes === undefined ? [] : [
|
|
869
|
+
"(deny file-write*)",
|
|
870
|
+
`(allow file-write* (subpath "/dev")${grants.writes.subpaths.length === 0 ? "" : ` ${paths("subpath", grants.writes.subpaths)}`}${grants.writes.prefixes.map(one => ` (regex #"^${seatbeltRegex(one.path)}${one.suffix}")`).join("")})`,
|
|
871
|
+
// A granted folder itself can't be renamed, removed or replaced (by a link to anywhere, say): only what is in it.
|
|
872
|
+
...(grants.writes.subpaths.length === 0 ? [] : [`(deny file-write* ${paths("literal", grants.writes.subpaths)})`]),
|
|
873
|
+
]),
|
|
703
874
|
...(pool === undefined || pool.deny.length === 0 ? [] : [`(deny file-read* file-write* ${paths("subpath", pool.deny)})`]),
|
|
704
875
|
...(pool?.own == null ? [] : [
|
|
705
876
|
`(allow file-read* file-write* ${paths("subpath", [pool.own])})`,
|
|
@@ -712,6 +883,9 @@ export function macosFenceProfile(fence, grants = NO_GRANTS) {
|
|
|
712
883
|
...(grants.lookup.length === 0 ? [] : [`(allow file-read-metadata ${paths("literal", grants.lookup)})`]),
|
|
713
884
|
// Denied whole above, granted back narrowly here (a later rule wins): an entry made after launch beside it stays denied.
|
|
714
885
|
...(grants.readable.length === 0 ? [] : [`(allow file-read* file-test-existence ${paths("subpath", grants.readable)})`]),
|
|
886
|
+
// Each readable copy's own folder can be listed, never read: bundlers such as esbuild find node_modules by listing
|
|
887
|
+
// its parent, which a lookup alone refuses (the Linux and Codex fences list it as read-only already).
|
|
888
|
+
...(grants.readable.length === 0 ? [] : [`(allow file-read-data ${paths("literal", [...new Set(grants.readable.map(one => dirname(one)))])})`]),
|
|
715
889
|
...(folders?.own == null ? [] : [`(allow file-read* file-write* ${paths("subpath", [folders.own])})`]),
|
|
716
890
|
'(deny sysctl-read (sysctl-name-prefix "kern.procargs"))',
|
|
717
891
|
"(deny process-info-pidinfo)",
|
|
@@ -720,6 +894,14 @@ export function macosFenceProfile(fence, grants = NO_GRANTS) {
|
|
|
720
894
|
"(deny mach-task-name)",
|
|
721
895
|
...(above.length === 0 ? [] : [`(deny file-write* ${paths("literal", above)})`]),
|
|
722
896
|
...macosNetworkRules(grants.network),
|
|
897
|
+
// A workspace build reaches no unix socket but its own (a container engine's, an agent's, a database's would act
|
|
898
|
+
// outside its limits for it), whatever its network: a confined network has its own rule for this already. Its open
|
|
899
|
+
// network still names hosts: the system's DNS service answers on a unix socket, and without it nothing resolves.
|
|
900
|
+
...(grants.writes === undefined || grants.network?.mode === "allowlist" ? [] : [
|
|
901
|
+
"(deny network-outbound (remote unix-socket))",
|
|
902
|
+
`(allow network-outbound (remote unix-socket (path-literal ${seatbelt(MACOS_DNS_SOCKET)})))`,
|
|
903
|
+
...(grants.writes.subpaths.length === 0 ? [] : [`(allow network-outbound ${grants.writes.subpaths.map(root => `(remote unix-socket (subpath ${seatbelt(root)}))`).join(" ")})`]),
|
|
904
|
+
]),
|
|
723
905
|
].join("\n");
|
|
724
906
|
}
|
|
725
907
|
/**
|
|
@@ -741,6 +923,8 @@ export function macosNetworkRules(network) {
|
|
|
741
923
|
];
|
|
742
924
|
}
|
|
743
925
|
export const SANDBOX_EXEC = "/usr/bin/sandbox-exec";
|
|
926
|
+
/** Where macOS's resolver (mDNSResponder) answers: every name lookup on a Mac is a message to this socket. */
|
|
927
|
+
export const MACOS_DNS_SOCKET = "/private/var/run/mDNSResponder";
|
|
744
928
|
/** A process already inside a Seatbelt sandbox (an agent's, or a flow check zone's) can't apply another: sandbox-exec says so. */
|
|
745
929
|
const NESTED_SANDBOX = /sandbox_apply: Operation not permitted/;
|
|
746
930
|
let seatbeltWorks = null;
|
|
@@ -833,19 +1017,31 @@ export function linuxFenced(file, args, fence, grants = NO_GRANTS) {
|
|
|
833
1017
|
// mounted folder is not network, so they are masked), and the run's proxy and broker carried in by the forwarder.
|
|
834
1018
|
const isolated = network === null ? [] : [
|
|
835
1019
|
"--unshare-net", "--unshare-pid", "--proc", "/proc",
|
|
836
|
-
...linuxHostSockets().flatMap(mask),
|
|
1020
|
+
...linuxHostSockets(undefined, undefined, undefined, grants.writes !== undefined).flatMap(mask),
|
|
837
1021
|
"--ro-bind", network.bridge.folder, network.bridge.folder,
|
|
838
1022
|
];
|
|
839
1023
|
// A confined build gets a /tmp of its own (other programs' sockets, other runs' folders and anything planted there
|
|
840
1024
|
// all out of sight at once), with only its own folders there given back; every mask and grant below still applies.
|
|
841
|
-
|
|
1025
|
+
// A workspace build (arc 2) sees the whole filesystem read-only, a /dev of its own and a /tmp of its own, with only
|
|
1026
|
+
// its allowlist bound back writable; its own checkout's Git data is in that list.
|
|
1027
|
+
const writes = grants.writes;
|
|
1028
|
+
const root = writes === undefined ? ["--dev-bind", "/", "/"] : ["--ro-bind", "/", "/", "--dev", "/dev"];
|
|
1029
|
+
const writable = writes === undefined ? [] : [...writes.subpaths, ...writes.prefixes.map(one => one.path)].filter(path => existsSync(path)).flatMap(path => ["--bind", path, path]);
|
|
1030
|
+
// What a private /tmp gives back is read-only for a workspace build (its writable part is bound again after): the
|
|
1031
|
+
// checkout's whole shared Git data among it must not come back writable.
|
|
1032
|
+
// A confined network brings a /tmp of its own (arc 1); a workspace build with an open network sees the shared /tmp
|
|
1033
|
+
// read-only like the rest of the root, its own folders there bound back writable.
|
|
1034
|
+
const privateTmp = network === null ? [] : ["--tmpfs", "/tmp", ...(network?.keep ?? []).filter(path => inside(path, "/tmp") && existsSync(path)).flatMap(path => [writes === undefined ? "--bind" : "--ro-bind", path, path])];
|
|
1035
|
+
// A workspace build never reaches the host's own services either (a container engine would write anywhere for it),
|
|
1036
|
+
// whatever its network: confined networks mask them below already.
|
|
1037
|
+
const services = writes === undefined || network !== null ? [] : linuxHostSockets(undefined, undefined, undefined, true).flatMap(mask);
|
|
842
1038
|
const command = network === null ? [file, ...args]
|
|
843
1039
|
: [network.bridge.node, network.bridge.forwarder, network.bridge.folder, ...[network.proxyPort, ...network.brokerPorts].map(String), "--", file, ...args];
|
|
844
|
-
return { file: "bwrap", args: [
|
|
1040
|
+
return { file: "bwrap", args: [...root, ...privateTmp, ...writable, ...pool.flatMap(mask), ...own, ...fence.flatMap(mask), ...kept, ...services, ...isolated, "--die-with-parent", "--", ...command] };
|
|
845
1041
|
}
|
|
846
1042
|
/** The host's own sockets a process in a mounted filesystem could still talk to (D-Bus, the display, container
|
|
847
1043
|
* engines), wherever they exist here. */
|
|
848
|
-
export function linuxHostSockets(uid = process.getuid?.(), home = homedir(), tmp = "/tmp") {
|
|
1044
|
+
export function linuxHostSockets(uid = process.getuid?.(), home = homedir(), tmp = "/tmp", followLinks = false, env = process.env) {
|
|
849
1045
|
// The system's own, root-owned: resolved (/var/run is a link to /run) so bubblewrap mounts over the real path, once.
|
|
850
1046
|
const system = [
|
|
851
1047
|
...(uid === undefined ? [] : [`/run/user/${uid}`]), "/run/dbus", "/var/run/dbus", "/var/run/docker.sock", "/run/docker.sock", "/run/containerd", "/run/podman",
|
|
@@ -874,10 +1070,97 @@ export function linuxHostSockets(uid = process.getuid?.(), home = homedir(), tmp
|
|
|
874
1070
|
return false;
|
|
875
1071
|
}
|
|
876
1072
|
};
|
|
877
|
-
for (const path of [".docker", ".colima", ".orbstack", ".lima", ".rd", ".local/share/containers"].map(name => join(home, name)))
|
|
1073
|
+
for (const path of [".docker", ".colima", ".orbstack", ".lima", ".rd", ".local/share/containers"].map(name => join(home, name))) {
|
|
878
1074
|
if (owned(path))
|
|
879
1075
|
masks.add(path);
|
|
880
|
-
|
|
881
|
-
|
|
1076
|
+
// A workspace build can't plant a link in the home folder, so a link there is the operator's own: its target is
|
|
1077
|
+
// masked too (an engine moved elsewhere).
|
|
1078
|
+
else if (followLinks) {
|
|
1079
|
+
try {
|
|
1080
|
+
if (lstatSync(path).isSymbolicLink())
|
|
1081
|
+
masks.add(realpathSync(path));
|
|
1082
|
+
}
|
|
1083
|
+
catch { /* dangling */ }
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
// An engine Toolroll's own environment points at, wherever it is (never the build's to choose): always masked. So is
|
|
1087
|
+
// the SSH agent it names (it signs as you), which a shared /tmp would otherwise leave in reach.
|
|
1088
|
+
for (const name of ["DOCKER_HOST", "CONTAINER_HOST"]) {
|
|
1089
|
+
const socket = /^unix:\/\/(\/.+)$/.exec(env[name] ?? "")?.[1];
|
|
1090
|
+
if (socket !== undefined) {
|
|
1091
|
+
try {
|
|
1092
|
+
masks.add(realpathSync(socket));
|
|
1093
|
+
}
|
|
1094
|
+
catch { /* not there */ }
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
const agent = env["SSH_AUTH_SOCK"];
|
|
1098
|
+
if (agent !== undefined && isAbsolute(agent)) {
|
|
1099
|
+
try {
|
|
1100
|
+
const socket = realpathSync(agent);
|
|
1101
|
+
masks.add(socket);
|
|
1102
|
+
// The folder an agent makes for its socket (ssh-XXXX in /tmp) too, so a socket it makes next is out of reach.
|
|
1103
|
+
if (inside(socket, real(tmp)) && dirname(socket) !== real(tmp) && !lstatSync(dirname(socket)).isSymbolicLink())
|
|
1104
|
+
masks.add(dirname(socket));
|
|
1105
|
+
}
|
|
1106
|
+
catch { /* not there */ }
|
|
1107
|
+
}
|
|
1108
|
+
// A build that shares /tmp (a workspace build with an open network) reaches none of the sockets there either: every
|
|
1109
|
+
// socket two levels down (a multiplexer's, an agent's, a display's, an editor's), and the folder that holds it, taken
|
|
1110
|
+
// as it is (never through a link). Toolroll's own launch folders are fenced by name already.
|
|
1111
|
+
if (followLinks) {
|
|
1112
|
+
const socketIn = (folder, depth) => {
|
|
1113
|
+
let found = false;
|
|
1114
|
+
let entries = [];
|
|
1115
|
+
try {
|
|
1116
|
+
entries = readdirSync(folder);
|
|
1117
|
+
}
|
|
1118
|
+
catch {
|
|
1119
|
+
return false;
|
|
1120
|
+
}
|
|
1121
|
+
for (const entry of entries) {
|
|
1122
|
+
const path = join(folder, entry);
|
|
1123
|
+
if (RUN_FOLDER_PREFIXES.some(prefix => entry.startsWith(prefix)))
|
|
1124
|
+
continue;
|
|
1125
|
+
let held;
|
|
1126
|
+
try {
|
|
1127
|
+
held = lstatSync(path);
|
|
1128
|
+
}
|
|
1129
|
+
catch {
|
|
1130
|
+
continue;
|
|
1131
|
+
}
|
|
1132
|
+
if (held.isSocket()) {
|
|
1133
|
+
masks.add(path);
|
|
1134
|
+
found = true;
|
|
1135
|
+
}
|
|
1136
|
+
else if (held.isDirectory() && !held.isSymbolicLink() && depth > 0 && socketIn(path, depth - 1)) {
|
|
1137
|
+
masks.add(path);
|
|
1138
|
+
found = true;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
return found;
|
|
1142
|
+
};
|
|
1143
|
+
socketIn(tmp, 1);
|
|
1144
|
+
}
|
|
882
1145
|
return [...masks].sort();
|
|
883
1146
|
}
|
|
1147
|
+
/**
|
|
1148
|
+
* What each agent's fence gives it, by permission mode: the one table README's "What an agent can reach" shows
|
|
1149
|
+
* (fenceSummaryMarkdown; a test holds them equal).
|
|
1150
|
+
*/
|
|
1151
|
+
export const FENCE_SUMMARY = [
|
|
1152
|
+
{
|
|
1153
|
+
agent: "**Codex / OpenRouter** (any OS)",
|
|
1154
|
+
auto: "Codex's sandbox with the fence: writes only the checkout, its Git data and the project's caches (anywhere outside the fence, under a project set to write anywhere); no network",
|
|
1155
|
+
full: "the same writes, with the fence; its commands reach the network only when the project's network is open",
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
agent: "**Claude, Gemini, ACP agents**",
|
|
1159
|
+
auto: "macOS: inside a Seatbelt sandbox that denies the fence and writes only the checkout, its Git data, the project's caches, the run's temp folder and the agent's own session files. Linux: the same in bubblewrap, with a /tmp of its own. Neither (Windows, or Linux without bubblewrap): the build doesn't start, unless an instance operator allows unconfined agents",
|
|
1160
|
+
full: "same",
|
|
1161
|
+
},
|
|
1162
|
+
];
|
|
1163
|
+
/** FENCE_SUMMARY as README's markdown table. */
|
|
1164
|
+
export function fenceSummaryMarkdown() {
|
|
1165
|
+
return ["| | Auto | Full access |", "|---|---|---|", ...FENCE_SUMMARY.map(row => `| ${row.agent} | ${row.auto} | ${row.full} |`)].join("\n");
|
|
1166
|
+
}
|
package/dist/agentconfig.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* the caller snapshots it into the run row.
|
|
21
21
|
*/
|
|
22
22
|
import { PROJECT_NETWORK_DEFAULT, repositoryEcosystems, resolveNetwork } from "./egress.js";
|
|
23
|
+
import { WRITES_DEFAULT } from "./writes-mode.js";
|
|
23
24
|
import { isProviderId, validateSpec } from "./provider.js";
|
|
24
25
|
import { ACP_LIMITS, CLAUDE_LIMITS, CODEX_SHAPED_LIMITS, GEMINI_LIMITS } from "./scope.js";
|
|
25
26
|
import { ACP_AGENTS, isAcpProvider } from "./acp-agents.js";
|
|
@@ -196,7 +197,9 @@ export function resolveScopeProfile(store, repo, ref, flags) {
|
|
|
196
197
|
// What the build may reach (egress.ts): resolved now, from the project's setting, the provider's own hosts and the
|
|
197
198
|
// registries the repository's own HEAD names, and sealed with the rest of the profile.
|
|
198
199
|
const network = resolveNetwork(provider, repo === null ? PROJECT_NETWORK_DEFAULT : store.projectNetwork(repo), repo === null ? [] : repositoryEcosystems(repo));
|
|
199
|
-
|
|
200
|
+
// Where the build may write (writes-mode.ts): the project's setting, sealed likewise.
|
|
201
|
+
const writes = repo === null ? WRITES_DEFAULT : store.projectWrites(repo);
|
|
202
|
+
return { ok: true, profile: { ...profile, network, writes }, provenance: { resolvedFrom: build.source, repairFrom } };
|
|
200
203
|
}
|
|
201
204
|
const PHASE_NOUN = { plan: "planner", build: "builder", repair: "repair", review: "reviewer" };
|
|
202
205
|
export function resolveRouteCandidates(store, repo, pins = {}) {
|
package/dist/batch-checks.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* The queue is the follow-up check ledger (result-follow-ups.ts), with `batch` requests: the same
|
|
19
19
|
* claim, receipts, abandoned-check reading, status projection and Merge gate. The policy is an
|
|
20
20
|
* append-only ledger entry, like the check level. */
|
|
21
|
+
import { fencedCheckoutCommands } from "./invoke.js";
|
|
21
22
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
22
23
|
import { tmpdir } from "node:os";
|
|
23
24
|
import { join } from "node:path";
|
|
@@ -161,7 +162,7 @@ async function checkCohort(store, root, repo, cohort, deps) {
|
|
|
161
162
|
return { conflict: false, tested, outcome: { ran: false, failure: "The project's approved setup changed before the check started." }, setupFailed: false };
|
|
162
163
|
if (liveSetup !== null) {
|
|
163
164
|
const shell = approvedCommandShell(liveSetup.command);
|
|
164
|
-
const prepared = await runWithIsolatedDatabase(runner, shell.file, shell.args, { cwd: checkout, timeoutMs: liveSetup.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
|
|
165
|
+
const prepared = await runWithIsolatedDatabase(fencedCheckoutCommands(store, repo, checkout, runner), shell.file, shell.args, { cwd: checkout, timeoutMs: liveSetup.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
|
|
165
166
|
note(set, section(`${label} · approved project setup on ${tested.slice(0, 7)}`, liveSetup.command, prepared));
|
|
166
167
|
if (prepared.code !== 0 || prepared.timedOut || prepared.notFound)
|
|
167
168
|
return { conflict: false, tested, outcome: { ran: false, failure: "The project's setup failed, so the check didn't run." }, setupFailed: true };
|
|
@@ -170,7 +171,7 @@ async function checkCohort(store, root, repo, cohort, deps) {
|
|
|
170
171
|
if (live === null || live.digest !== command.digest)
|
|
171
172
|
return { conflict: false, tested, outcome: { ran: false, failure: "The approved check changed before it started." }, setupFailed: false };
|
|
172
173
|
const shell = approvedCommandShell(live.command);
|
|
173
|
-
const ran = await runWithIsolatedDatabase(runner, shell.file, shell.args, { cwd: checkout, timeoutMs: live.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
|
|
174
|
+
const ran = await runWithIsolatedDatabase(fencedCheckoutCommands(store, repo, checkout, runner), shell.file, shell.args, { cwd: checkout, timeoutMs: live.timeoutMs, processGroup: true, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST });
|
|
174
175
|
note(set, section(`${label} · full check on ${tested.slice(0, 7)}`, live.command, ran));
|
|
175
176
|
return { conflict: false, tested, setupFailed: false,
|
|
176
177
|
outcome: ran.timedOut ? { ran: false, failure: "The check ran out of time." } : ran.notFound ? { ran: false, failure: "The check couldn't start." } : { ran: true, exitCode: ran.code } };
|
|
@@ -1483,6 +1483,52 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
1483
1483
|
THE SOFTWARE.
|
|
1484
1484
|
|
|
1485
1485
|
|
|
1486
|
+
## Bundled dependency: @xterm/addon-unicode11 0.9.0
|
|
1487
|
+
|
|
1488
|
+
Copyright (c) 2019, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
|
1489
|
+
|
|
1490
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1491
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1492
|
+
in the Software without restriction, including without limitation the rights
|
|
1493
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1494
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1495
|
+
furnished to do so, subject to the following conditions:
|
|
1496
|
+
|
|
1497
|
+
The above copyright notice and this permission notice shall be included in
|
|
1498
|
+
all copies or substantial portions of the Software.
|
|
1499
|
+
|
|
1500
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1501
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1502
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1503
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1504
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1505
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1506
|
+
THE SOFTWARE.
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
## Bundled dependency: @xterm/addon-webgl 0.19.0
|
|
1510
|
+
|
|
1511
|
+
Copyright (c) 2018, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|
|
1512
|
+
|
|
1513
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1514
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
1515
|
+
in the Software without restriction, including without limitation the rights
|
|
1516
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1517
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
1518
|
+
furnished to do so, subject to the following conditions:
|
|
1519
|
+
|
|
1520
|
+
The above copyright notice and this permission notice shall be included in
|
|
1521
|
+
all copies or substantial portions of the Software.
|
|
1522
|
+
|
|
1523
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1524
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1525
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1526
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1527
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1528
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
1529
|
+
THE SOFTWARE.
|
|
1530
|
+
|
|
1531
|
+
|
|
1486
1532
|
## Bundled dependency: @xterm/xterm 6.0.0
|
|
1487
1533
|
|
|
1488
1534
|
Copyright (c) 2017-2019, The xterm.js authors (https://github.com/xtermjs/xterm.js)
|