pi-landstrip 0.11.7 → 0.11.9
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 +14 -5
- package/index.ts +187 -136
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,13 +23,22 @@ Project config takes precedence.
|
|
|
23
23
|
|
|
24
24
|
See [`sandbox.json`](./sandbox.json) for a starter config.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
26
|
+
Use Pi settings to toggle sandboxing:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"landstrip": {
|
|
31
|
+
"enabled": false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
30
34
|
```
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
Project Pi settings override global Pi settings.
|
|
37
|
+
The `/sandbox` UI updates the project setting when present, otherwise the global setting.
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
Use `/sandbox` inside Pi to show the active config and toggle the Pi setting.
|
|
33
42
|
|
|
34
43
|
## License
|
|
35
44
|
|
package/index.ts
CHANGED
|
@@ -62,6 +62,15 @@ interface SandboxConfig {
|
|
|
62
62
|
filesystem: SandboxFilesystemConfig;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
interface PiLandstripSettings {
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
landstrip?: {
|
|
68
|
+
enabled?: boolean;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type PiSettingsScope = 'global' | 'project';
|
|
73
|
+
|
|
65
74
|
interface LandstripPolicy {
|
|
66
75
|
network: {
|
|
67
76
|
allowNetwork: boolean;
|
|
@@ -184,6 +193,53 @@ function loadConfig(cwd: string): SandboxConfig {
|
|
|
184
193
|
return deepMerge(deepMerge(DEFAULT_CONFIG, globalConfig), projectConfig);
|
|
185
194
|
}
|
|
186
195
|
|
|
196
|
+
function getPiLandstripSettings(cwd: string): {
|
|
197
|
+
globalSettings: PiLandstripSettings;
|
|
198
|
+
projectSettings: PiLandstripSettings;
|
|
199
|
+
} {
|
|
200
|
+
const settings = SettingsManager.create(cwd);
|
|
201
|
+
return {
|
|
202
|
+
globalSettings: settings.getGlobalSettings() as PiLandstripSettings,
|
|
203
|
+
projectSettings: settings.getProjectSettings() as PiLandstripSettings,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function isSandboxEnabledInPiSettings(cwd: string): boolean {
|
|
208
|
+
const { globalSettings, projectSettings } = getPiLandstripSettings(cwd);
|
|
209
|
+
return projectSettings.landstrip?.enabled ?? globalSettings.landstrip?.enabled ?? true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function getPiSettingsWriteScope(cwd: string): PiSettingsScope {
|
|
213
|
+
const { projectSettings } = getPiLandstripSettings(cwd);
|
|
214
|
+
return projectSettings.landstrip?.enabled === undefined ? 'global' : 'project';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function getPiSettingsPath(cwd: string, scope: PiSettingsScope): string {
|
|
218
|
+
if (scope === 'project') return join(cwd, '.pi', 'settings.json');
|
|
219
|
+
return join(getAgentDir(), 'settings.json');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function readPiSettingsFile(settingsPath: string): PiLandstripSettings {
|
|
223
|
+
if (!existsSync(settingsPath)) return {};
|
|
224
|
+
return JSON.parse(readFileSync(settingsPath, 'utf-8')) as PiLandstripSettings;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function setPiSettingsSandboxEnabled(
|
|
228
|
+
cwd: string,
|
|
229
|
+
enabled: boolean,
|
|
230
|
+
): Promise<PiSettingsScope> {
|
|
231
|
+
const scope = getPiSettingsWriteScope(cwd);
|
|
232
|
+
const settingsPath = getPiSettingsPath(cwd, scope);
|
|
233
|
+
await withFileMutationQueue(settingsPath, async () => {
|
|
234
|
+
const settings = readPiSettingsFile(settingsPath);
|
|
235
|
+
settings.landstrip = { ...settings.landstrip, enabled };
|
|
236
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
237
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
return scope;
|
|
241
|
+
}
|
|
242
|
+
|
|
187
243
|
function mergeArray(base: string[], override?: string[]): string[] {
|
|
188
244
|
if (!override) return base;
|
|
189
245
|
return [...new Set([...base, ...override])];
|
|
@@ -1430,6 +1486,34 @@ export function createLandstripIntegration(
|
|
|
1430
1486
|
return true;
|
|
1431
1487
|
}
|
|
1432
1488
|
|
|
1489
|
+
let noSandboxFlag = false;
|
|
1490
|
+
function disableSandbox(ctx: ExtensionContext): void {
|
|
1491
|
+
sandboxEnabled = false;
|
|
1492
|
+
sandboxReady = false;
|
|
1493
|
+
setTuiStatus(ctx, 'sandbox', undefined);
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function ensureSandboxState(ctx: ExtensionContext): boolean {
|
|
1497
|
+
if (noSandboxFlag) {
|
|
1498
|
+
disableSandbox(ctx);
|
|
1499
|
+
return false;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
if (!isSandboxEnabledInPiSettings(ctx.cwd)) {
|
|
1503
|
+
disableSandbox(ctx);
|
|
1504
|
+
return false;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
const config = loadConfig(ctx.cwd);
|
|
1508
|
+
if (!config.enabled) {
|
|
1509
|
+
disableSandbox(ctx);
|
|
1510
|
+
return false;
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
if (!sandboxEnabled || !sandboxReady) return enableSandbox(ctx);
|
|
1514
|
+
return true;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1433
1517
|
function createBashTool(cwd: string, ctx?: ExtensionContext): LandstripBashTool {
|
|
1434
1518
|
const localBash = createPlainBashTool(cwd);
|
|
1435
1519
|
|
|
@@ -1438,7 +1522,7 @@ export function createLandstripIntegration(
|
|
|
1438
1522
|
label: 'bash (landstrip)',
|
|
1439
1523
|
async execute(id, params, signal, onUpdate, callCtx) {
|
|
1440
1524
|
const effectiveCtx = callCtx ?? ctx;
|
|
1441
|
-
if (!
|
|
1525
|
+
if (!effectiveCtx || !ensureSandboxState(effectiveCtx))
|
|
1442
1526
|
return localBash.execute(id, params, signal, onUpdate, effectiveCtx);
|
|
1443
1527
|
|
|
1444
1528
|
return runBashWithOptionalRetry(id, params, signal, onUpdate, effectiveCtx);
|
|
@@ -1462,9 +1546,8 @@ export function createLandstripIntegration(
|
|
|
1462
1546
|
if (shouldRegisterBashTool) pi.registerTool(createBashTool(localCwd));
|
|
1463
1547
|
|
|
1464
1548
|
pi.on('user_bash', async (event, ctx) => {
|
|
1465
|
-
if (!
|
|
1549
|
+
if (!ensureSandboxState(ctx)) return;
|
|
1466
1550
|
const config = loadConfig(ctx.cwd);
|
|
1467
|
-
if (!config.enabled) return;
|
|
1468
1551
|
|
|
1469
1552
|
if (!config.network.allowNetwork) {
|
|
1470
1553
|
const blockedDomain = await preflightCommandDomains(event.command, ctx);
|
|
@@ -1484,10 +1567,9 @@ export function createLandstripIntegration(
|
|
|
1484
1567
|
});
|
|
1485
1568
|
|
|
1486
1569
|
pi.on('tool_call', async (event, ctx) => {
|
|
1487
|
-
if (!
|
|
1570
|
+
if (!ensureSandboxState(ctx)) return;
|
|
1488
1571
|
|
|
1489
1572
|
const config = loadConfig(ctx.cwd);
|
|
1490
|
-
if (!config.enabled) return;
|
|
1491
1573
|
|
|
1492
1574
|
const { globalPath, projectPath } = getConfigPaths(ctx.cwd);
|
|
1493
1575
|
|
|
@@ -1544,60 +1626,33 @@ export function createLandstripIntegration(
|
|
|
1544
1626
|
|
|
1545
1627
|
pi.on('session_start', async (_event, ctx) => {
|
|
1546
1628
|
resetSessionAllowances();
|
|
1547
|
-
|
|
1629
|
+
noSandboxFlag = Boolean(maybePi.getFlag?.('no-sandbox'));
|
|
1548
1630
|
|
|
1549
|
-
if (
|
|
1550
|
-
|
|
1551
|
-
sandboxReady = false;
|
|
1631
|
+
if (noSandboxFlag) {
|
|
1632
|
+
disableSandbox(ctx);
|
|
1552
1633
|
notify(ctx, 'Sandbox disabled via --no-sandbox', 'warning');
|
|
1553
1634
|
return;
|
|
1554
1635
|
}
|
|
1555
1636
|
|
|
1637
|
+
if (!isSandboxEnabledInPiSettings(ctx.cwd)) {
|
|
1638
|
+
disableSandbox(ctx);
|
|
1639
|
+
notify(ctx, 'Sandbox disabled via pi settings', 'info');
|
|
1640
|
+
return;
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1556
1643
|
const config = loadConfig(ctx.cwd);
|
|
1557
1644
|
if (!config.enabled) {
|
|
1558
|
-
|
|
1559
|
-
sandboxReady = false;
|
|
1645
|
+
disableSandbox(ctx);
|
|
1560
1646
|
notify(ctx, 'Sandbox disabled via config', 'info');
|
|
1561
1647
|
return;
|
|
1562
1648
|
}
|
|
1563
1649
|
|
|
1564
1650
|
enableSandbox(ctx);
|
|
1565
1651
|
});
|
|
1566
|
-
|
|
1567
|
-
maybePi.registerCommand?.('sandbox-enable', {
|
|
1568
|
-
description: 'Enable the landstrip sandbox for this session',
|
|
1569
|
-
handler: async (_args, ctx) => {
|
|
1570
|
-
if (sandboxEnabled) {
|
|
1571
|
-
notify(ctx, 'Sandbox is already enabled', 'info');
|
|
1572
|
-
return;
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
if (enableSandbox(ctx)) notify(ctx, 'Sandbox enabled', 'info');
|
|
1576
|
-
},
|
|
1577
|
-
});
|
|
1578
|
-
|
|
1579
|
-
maybePi.registerCommand?.('sandbox-disable', {
|
|
1580
|
-
description: 'Disable the landstrip sandbox for this session',
|
|
1581
|
-
handler: async (_args, ctx) => {
|
|
1582
|
-
if (!sandboxEnabled) {
|
|
1583
|
-
notify(ctx, 'Sandbox is already disabled', 'info');
|
|
1584
|
-
return;
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
sandboxEnabled = false;
|
|
1588
|
-
sandboxReady = false;
|
|
1589
|
-
setTuiStatus(ctx, 'sandbox', undefined);
|
|
1590
|
-
notify(ctx, 'Sandbox disabled', 'info');
|
|
1591
|
-
},
|
|
1592
|
-
});
|
|
1593
|
-
|
|
1594
1652
|
maybePi.registerCommand?.('sandbox', {
|
|
1595
1653
|
description: 'Show sandbox configuration',
|
|
1596
1654
|
handler: async (_args, ctx) => {
|
|
1597
|
-
|
|
1598
|
-
notify(ctx, 'Sandbox is disabled', 'info');
|
|
1599
|
-
return;
|
|
1600
|
-
}
|
|
1655
|
+
let piSettingsEnabled = isSandboxEnabledInPiSettings(ctx.cwd);
|
|
1601
1656
|
|
|
1602
1657
|
const config = loadConfig(ctx.cwd);
|
|
1603
1658
|
const { globalPath, projectPath } = getConfigPaths(ctx.cwd);
|
|
@@ -1611,6 +1666,14 @@ export function createLandstripIntegration(
|
|
|
1611
1666
|
const text = (s: string) => theme.fg('text', s);
|
|
1612
1667
|
const borderFg = (s: string) => theme.fg('border', s);
|
|
1613
1668
|
|
|
1669
|
+
function sandboxStatus(): { color: 'success' | 'warning'; label: string } {
|
|
1670
|
+
if (noSandboxFlag) return { color: 'warning', label: 'Disabled (--no-sandbox)' };
|
|
1671
|
+
if (!piSettingsEnabled) return { color: 'warning', label: 'Disabled (Pi setting)' };
|
|
1672
|
+
if (!config.enabled) return { color: 'warning', label: 'Disabled (config)' };
|
|
1673
|
+
if (!sandboxEnabled || !sandboxReady) return { color: 'warning', label: 'Inactive' };
|
|
1674
|
+
return { color: 'success', label: 'Active' };
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1614
1677
|
function boolVal(v: boolean): string {
|
|
1615
1678
|
return v ? theme.fg('warning', 'yes') : theme.fg('success', 'no');
|
|
1616
1679
|
}
|
|
@@ -1623,120 +1686,108 @@ export function createLandstripIntegration(
|
|
|
1623
1686
|
|
|
1624
1687
|
return {
|
|
1625
1688
|
render(width: number): string[] {
|
|
1626
|
-
const innerW = width - 4;
|
|
1689
|
+
const innerW = Math.max(1, width - 4);
|
|
1627
1690
|
const border = borderFg('│');
|
|
1628
|
-
const row = (
|
|
1691
|
+
const row = (content: string) => makeRow(content, innerW, border);
|
|
1629
1692
|
const lines: string[] = [];
|
|
1693
|
+
const status = sandboxStatus();
|
|
1694
|
+
const toggleValue = piSettingsEnabled
|
|
1695
|
+
? theme.fg('success', 'enabled')
|
|
1696
|
+
: theme.fg('warning', 'disabled');
|
|
1697
|
+
|
|
1698
|
+
function topBorder(titleText: string): string {
|
|
1699
|
+
const title = accent(` ${titleText} `);
|
|
1700
|
+
const fill = borderFg('─'.repeat(Math.max(0, width - 4 - visibleWidth(title))));
|
|
1701
|
+
return `${borderFg('╭─')}${title}${fill}${borderFg('─╮')}`;
|
|
1702
|
+
}
|
|
1630
1703
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1704
|
+
function section(titleText: string, detail?: string): void {
|
|
1705
|
+
lines.push(row(''));
|
|
1706
|
+
lines.push(row(`${accent(titleText)}${detail ? dim(` · ${detail}`) : ''}`));
|
|
1707
|
+
}
|
|
1635
1708
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
lines.push(
|
|
1640
|
-
row(
|
|
1641
|
-
` ${statusDot} ${text('Active')} ${dim('·')} ${muted('landstrip:')} ${pathSnippet}`,
|
|
1642
|
-
),
|
|
1643
|
-
);
|
|
1709
|
+
function item(label: string, value: string): void {
|
|
1710
|
+
lines.push(row(` ${dim('•')} ${muted(label.padEnd(13))} ${value}`));
|
|
1711
|
+
}
|
|
1644
1712
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1713
|
+
function listValue(values: string[], maxWidth: number): string {
|
|
1714
|
+
const value = values.join(', ') || 'none';
|
|
1715
|
+
return text(truncateToWidth(value, Math.max(10, maxWidth)));
|
|
1716
|
+
}
|
|
1649
1717
|
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
const
|
|
1654
|
-
lines.push(row(` ${accent('Network')}${dim(netMode)}`));
|
|
1655
|
-
lines.push(
|
|
1656
|
-
row(
|
|
1657
|
-
` ${dim('•')} ${muted('Allow network:')} ${boolVal(config.network.allowNetwork)}`,
|
|
1658
|
-
),
|
|
1659
|
-
);
|
|
1660
|
-
const domainsStr = config.network.allowedDomains.join(', ') || '(none)';
|
|
1661
|
-
lines.push(
|
|
1662
|
-
row(
|
|
1663
|
-
` ${dim('•')} ${muted('Allowed:')} ${text(truncateToWidth(domainsStr, Math.max(10, innerW - 15)))}`,
|
|
1664
|
-
),
|
|
1665
|
-
);
|
|
1666
|
-
const denyStr = config.network.deniedDomains.join(', ') || '(none)';
|
|
1718
|
+
lines.push(topBorder('Sandbox'));
|
|
1719
|
+
|
|
1720
|
+
const statusDot = theme.fg(status.color, '●');
|
|
1721
|
+
const pathSnippet = text(truncateToWidth(binaryPath(), Math.max(20, innerW - 28)));
|
|
1667
1722
|
lines.push(
|
|
1668
1723
|
row(
|
|
1669
|
-
|
|
1724
|
+
`${statusDot} ${text(status.label)} ${dim('·')} Pi setting ${toggleValue} ${dim('·')} ${muted('landstrip')} ${pathSnippet}`,
|
|
1670
1725
|
),
|
|
1671
1726
|
);
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1727
|
+
|
|
1728
|
+
section('Config');
|
|
1729
|
+
item('project', text(projectPath));
|
|
1730
|
+
item('global', text(globalPath));
|
|
1731
|
+
|
|
1732
|
+
const netMode = config.network.allowNetwork ? 'unrestricted' : 'proxied';
|
|
1733
|
+
section('Network', netMode);
|
|
1734
|
+
item('allow network', boolVal(config.network.allowNetwork));
|
|
1735
|
+
item('allowed', listValue(config.network.allowedDomains, innerW - 17));
|
|
1736
|
+
item('denied', listValue(config.network.deniedDomains, innerW - 17));
|
|
1737
|
+
if (sessionAllowedDomains.length > 0)
|
|
1738
|
+
item('session', theme.fg('accent', sessionAllowedDomains.join(', ')));
|
|
1739
|
+
|
|
1740
|
+
section('Filesystem');
|
|
1741
|
+
item('deny read', listValue(config.filesystem.denyRead, innerW - 17));
|
|
1742
|
+
item('allow read', listValue(config.filesystem.allowRead, innerW - 17));
|
|
1743
|
+
item('allow write', listValue(config.filesystem.allowWrite, innerW - 17));
|
|
1744
|
+
item('deny write', listValue(config.filesystem.denyWrite, innerW - 17));
|
|
1745
|
+
|
|
1746
|
+
if (sessionAllowedReadPaths.length > 0 || sessionAllowedWritePaths.length > 0) {
|
|
1747
|
+
section('Session grants');
|
|
1748
|
+
if (sessionAllowedReadPaths.length > 0)
|
|
1749
|
+
item('read', theme.fg('accent', sessionAllowedReadPaths.join(', ')));
|
|
1750
|
+
if (sessionAllowedWritePaths.length > 0)
|
|
1751
|
+
item('write', theme.fg('accent', sessionAllowedWritePaths.join(', ')));
|
|
1678
1752
|
}
|
|
1679
1753
|
|
|
1680
|
-
// Filesystem section
|
|
1681
1754
|
lines.push(row(''));
|
|
1682
|
-
lines.push(row(`${'─'.repeat(innerW)}`));
|
|
1683
|
-
lines.push(row(` ${accent('Filesystem')}`));
|
|
1684
|
-
const denyReadStr = config.filesystem.denyRead.join(', ') || '(none)';
|
|
1685
1755
|
lines.push(
|
|
1686
|
-
row(
|
|
1687
|
-
` ${dim('•')} ${muted('Deny read:')} ${text(truncateToWidth(denyReadStr, Math.max(10, innerW - 16)))}`,
|
|
1688
|
-
),
|
|
1689
|
-
);
|
|
1690
|
-
const allowReadStr = config.filesystem.allowRead.join(', ') || '(none)';
|
|
1691
|
-
lines.push(
|
|
1692
|
-
row(
|
|
1693
|
-
` ${dim('•')} ${muted('Allow read:')} ${text(truncateToWidth(allowReadStr, Math.max(10, innerW - 17)))}`,
|
|
1694
|
-
),
|
|
1756
|
+
row(`${dim('t')} ${muted('toggle Pi setting')} ${dim('esc')} ${muted('close')}`),
|
|
1695
1757
|
);
|
|
1696
|
-
const allowWriteStr = config.filesystem.allowWrite.join(', ') || '(none)';
|
|
1697
1758
|
lines.push(
|
|
1698
|
-
|
|
1699
|
-
` ${dim('•')} ${muted('Allow write:')} ${text(truncateToWidth(allowWriteStr, Math.max(10, innerW - 18)))}`,
|
|
1700
|
-
),
|
|
1701
|
-
);
|
|
1702
|
-
const denyWriteStr = config.filesystem.denyWrite.join(', ') || '(none)';
|
|
1703
|
-
lines.push(
|
|
1704
|
-
row(
|
|
1705
|
-
` ${dim('•')} ${muted('Deny write:')} ${text(truncateToWidth(denyWriteStr, Math.max(10, innerW - 17)))}`,
|
|
1706
|
-
),
|
|
1759
|
+
`${borderFg('╰')}${borderFg('─'.repeat(Math.max(0, width - 2)))}${borderFg('╯')}`,
|
|
1707
1760
|
);
|
|
1708
1761
|
|
|
1709
|
-
// Session allowances
|
|
1710
|
-
if (sessionAllowedReadPaths.length > 0 || sessionAllowedWritePaths.length > 0) {
|
|
1711
|
-
lines.push(row(''));
|
|
1712
|
-
if (sessionAllowedReadPaths.length > 0) {
|
|
1713
|
-
lines.push(
|
|
1714
|
-
row(
|
|
1715
|
-
` ${dim('•')} ${muted('Session read:')} ${theme.fg('accent', sessionAllowedReadPaths.join(', '))}`,
|
|
1716
|
-
),
|
|
1717
|
-
);
|
|
1718
|
-
}
|
|
1719
|
-
if (sessionAllowedWritePaths.length > 0) {
|
|
1720
|
-
lines.push(
|
|
1721
|
-
row(
|
|
1722
|
-
` ${dim('•')} ${muted('Session write:')} ${theme.fg('accent', sessionAllowedWritePaths.join(', '))}`,
|
|
1723
|
-
),
|
|
1724
|
-
);
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
// Footer
|
|
1729
|
-
lines.push(row(''));
|
|
1730
|
-
lines.push(row(` ${dim('esc')} ${muted('or any key to close')}`));
|
|
1731
|
-
|
|
1732
|
-
// Bottom border
|
|
1733
|
-
lines.push(`${borderFg('╰')}${borderFg('─'.repeat(width - 2))}${borderFg('╯')}`);
|
|
1734
|
-
|
|
1735
1762
|
return lines;
|
|
1736
1763
|
},
|
|
1737
1764
|
|
|
1738
|
-
handleInput(): void {
|
|
1739
|
-
|
|
1765
|
+
handleInput(data: string): void {
|
|
1766
|
+
if (data !== 't' && data !== 'T') {
|
|
1767
|
+
done(undefined);
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
void (async () => {
|
|
1772
|
+
const enabled = !piSettingsEnabled;
|
|
1773
|
+
const scope = await setPiSettingsSandboxEnabled(ctx.cwd, enabled);
|
|
1774
|
+
piSettingsEnabled = isSandboxEnabledInPiSettings(ctx.cwd);
|
|
1775
|
+
|
|
1776
|
+
if (!enabled) {
|
|
1777
|
+
disableSandbox(ctx);
|
|
1778
|
+
notify(ctx, `Sandbox disabled via ${scope} Pi settings`, 'info');
|
|
1779
|
+
} else if (noSandboxFlag) {
|
|
1780
|
+
notify(ctx, 'Sandbox remains disabled via --no-sandbox', 'warning');
|
|
1781
|
+
} else if (!config.enabled) {
|
|
1782
|
+
notify(ctx, 'Sandbox remains disabled via config', 'info');
|
|
1783
|
+
} else if (enableSandbox(ctx)) {
|
|
1784
|
+
notify(ctx, `Sandbox enabled via ${scope} Pi settings`, 'info');
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
tui.requestRender();
|
|
1788
|
+
})().catch((error: unknown) => {
|
|
1789
|
+
notify(ctx, `Could not update Pi settings: ${error}`, 'error');
|
|
1790
|
+
});
|
|
1740
1791
|
},
|
|
1741
1792
|
|
|
1742
1793
|
invalidate(): void {},
|