pi-landstrip 0.17.7 → 0.17.12
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/package.json +2 -2
- package/subagents.ts +49 -38
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-landstrip",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.12",
|
|
4
4
|
"description": "Sandbox-aware Pi subagents and interactive command permissions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"landstrip",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@earendil-works/pi-tui": "^0.80.6",
|
|
41
|
-
"@landstrip/landstrip": "^0.17.
|
|
41
|
+
"@landstrip/landstrip": "^0.17.12",
|
|
42
42
|
"minimatch": "^10.2.5"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
package/subagents.ts
CHANGED
|
@@ -69,54 +69,37 @@ export function isSupportedPiVersion(version: readonly number[]): boolean {
|
|
|
69
69
|
);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
// Resolve the
|
|
73
|
-
// extension is loaded by the running Pi and imports
|
|
74
|
-
// `@earendil-works/pi-coding-agent`, so the nearest `node_modules` copy
|
|
75
|
-
// reachable from `packageDir` is the running Pi itself. Reading its
|
|
72
|
+
// Resolve the Pi package used by this extension import. Reading its
|
|
76
73
|
// `package.json` instead of spawning `pi --version` avoids depending on
|
|
77
74
|
// `process.argv[1]`, which is not the Pi CLI entry when Pi runs as an embedded
|
|
78
75
|
// or extension host and would otherwise report the Node version instead.
|
|
79
76
|
export function resolvePiPackage(): PiPackage | undefined {
|
|
80
77
|
if (piPackageResolved) return cachedPiPackage;
|
|
81
78
|
piPackageResolved = true;
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const entry = fileURLToPath(import.meta.resolve('@earendil-works/pi-coding-agent'));
|
|
82
|
+
let dir = dirname(entry);
|
|
83
|
+
for (;;) {
|
|
84
|
+
const pkgPath = join(dir, 'package.json');
|
|
85
|
+
if (existsSync(pkgPath)) {
|
|
86
|
+
const pkg = readPiPackage(pkgPath);
|
|
87
|
+
if (pkg) return pkg;
|
|
88
|
+
}
|
|
89
|
+
const parent = dirname(dir);
|
|
90
|
+
if (parent === dir) break;
|
|
91
|
+
dir = parent;
|
|
92
|
+
}
|
|
93
|
+
} catch {
|
|
94
|
+
// Fall back to package discovery for runtimes without import.meta.resolve.
|
|
95
|
+
}
|
|
96
|
+
|
|
82
97
|
let dir = packageDir;
|
|
83
98
|
for (;;) {
|
|
84
99
|
const pkgPath = join(dir, 'node_modules', '@earendil-works', 'pi-coding-agent', 'package.json');
|
|
85
100
|
if (existsSync(pkgPath)) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (
|
|
89
|
-
isRecord(value) &&
|
|
90
|
-
value.name === '@earendil-works/pi-coding-agent' &&
|
|
91
|
-
typeof value.version === 'string'
|
|
92
|
-
) {
|
|
93
|
-
const parts = value.version.split('.').map(Number);
|
|
94
|
-
if (parts.length >= 3 && parts.slice(0, 3).every((n) => Number.isInteger(n))) {
|
|
95
|
-
const version = parts.slice(0, 3) as [number, number, number];
|
|
96
|
-
const binFile =
|
|
97
|
-
typeof value.bin === 'string'
|
|
98
|
-
? value.bin
|
|
99
|
-
: isRecord(value.bin) && typeof value.bin.pi === 'string'
|
|
100
|
-
? value.bin.pi
|
|
101
|
-
: undefined;
|
|
102
|
-
if (binFile) {
|
|
103
|
-
const cliEntry = join(
|
|
104
|
-
dir,
|
|
105
|
-
'node_modules',
|
|
106
|
-
'@earendil-works',
|
|
107
|
-
'pi-coding-agent',
|
|
108
|
-
binFile,
|
|
109
|
-
);
|
|
110
|
-
if (existsSync(cliEntry)) {
|
|
111
|
-
cachedPiPackage = { cliEntry, version };
|
|
112
|
-
return cachedPiPackage;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
} catch {
|
|
118
|
-
// Malformed package.json; keep walking ancestors.
|
|
119
|
-
}
|
|
101
|
+
const pkg = readPiPackage(pkgPath);
|
|
102
|
+
if (pkg) return pkg;
|
|
120
103
|
}
|
|
121
104
|
const parent = dirname(dir);
|
|
122
105
|
if (parent === dir) return undefined;
|
|
@@ -124,6 +107,34 @@ export function resolvePiPackage(): PiPackage | undefined {
|
|
|
124
107
|
}
|
|
125
108
|
}
|
|
126
109
|
|
|
110
|
+
function readPiPackage(pkgPath: string): PiPackage | undefined {
|
|
111
|
+
try {
|
|
112
|
+
const value: unknown = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
113
|
+
if (
|
|
114
|
+
!isRecord(value) ||
|
|
115
|
+
value.name !== '@earendil-works/pi-coding-agent' ||
|
|
116
|
+
typeof value.version !== 'string'
|
|
117
|
+
) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const parts = value.version.split('.').map(Number);
|
|
121
|
+
if (parts.length < 3 || !parts.slice(0, 3).every((n) => Number.isInteger(n))) return undefined;
|
|
122
|
+
const binFile =
|
|
123
|
+
typeof value.bin === 'string'
|
|
124
|
+
? value.bin
|
|
125
|
+
: isRecord(value.bin) && typeof value.bin.pi === 'string'
|
|
126
|
+
? value.bin.pi
|
|
127
|
+
: undefined;
|
|
128
|
+
if (!binFile) return undefined;
|
|
129
|
+
const cliEntry = join(dirname(pkgPath), binFile);
|
|
130
|
+
if (!existsSync(cliEntry)) return undefined;
|
|
131
|
+
cachedPiPackage = { cliEntry, version: parts.slice(0, 3) as [number, number, number] };
|
|
132
|
+
return cachedPiPackage;
|
|
133
|
+
} catch {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
127
138
|
const taskParameters = Type.Object({
|
|
128
139
|
description: Type.String({ description: 'A short 3-5 word description of the task' }),
|
|
129
140
|
prompt: Type.String({ description: 'The complete task for the subagent' }),
|