crewx-pi-kit 0.1.13 → 0.1.15
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.
|
@@ -11,8 +11,24 @@ type JsonRecord = Record<string, unknown>;
|
|
|
11
11
|
const CONTROL_PATH_PATTERN = /(?:\/proc\/[^/]+\/environ|\.config\/crewx(?:-cloud)?\/|\.local\/state\/crewx\/|bootstrap\.env|bridge\/config\.json)/i;
|
|
12
12
|
const CONTROL_VALUE_PATTERN = /\bCREWX_(?:TOKEN|URL|CLI_PATH|RUNTIME_PROXY_[A-Z0-9_]+)\b/;
|
|
13
13
|
|
|
14
|
-
function containsControlCredential(value: unknown): boolean {
|
|
15
|
-
|
|
14
|
+
function containsControlCredential(value: unknown, toolName: string): boolean {
|
|
15
|
+
// The work CLI path is managed configuration, but executing the documented
|
|
16
|
+
// work commands is intentional. Exempt only that executable-position token;
|
|
17
|
+
// still inspect all arguments, extra input fields and subsequent commands.
|
|
18
|
+
let inspected = value;
|
|
19
|
+
if (toolName === "bash" && value && typeof value === "object") {
|
|
20
|
+
const input = value as JsonRecord;
|
|
21
|
+
if (typeof input.command === "string") {
|
|
22
|
+
inspected = {
|
|
23
|
+
...input,
|
|
24
|
+
command: input.command.replace(
|
|
25
|
+
/^(\s*node\s+)"\$(?:CREWX_CLI_PATH|\{CREWX_CLI_PATH\})"(?=\s+(?:task|doc|memory|integration|file|preview)(?:\s|$))/,
|
|
26
|
+
'$1"[CrewX work CLI]"',
|
|
27
|
+
),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const serialized = JSON.stringify(inspected);
|
|
16
32
|
return CONTROL_PATH_PATTERN.test(serialized) || CONTROL_VALUE_PATTERN.test(serialized);
|
|
17
33
|
}
|
|
18
34
|
|
|
@@ -214,7 +230,7 @@ export default function crewxTools(pi: ExtensionAPI) {
|
|
|
214
230
|
pi.on("tool_call", async (event, ctx) => {
|
|
215
231
|
if (
|
|
216
232
|
["bash", "read", "write", "edit"].includes(event.toolName) &&
|
|
217
|
-
containsControlCredential(event.input)
|
|
233
|
+
containsControlCredential(event.input, event.toolName)
|
|
218
234
|
) {
|
|
219
235
|
return {
|
|
220
236
|
block: true,
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ContextEvent, ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
|
|
3
|
+
const SNAPSHOT = '\n\n## Workspace snapshot\n\n```json\n';
|
|
4
|
+
|
|
5
|
+
function isEnvelope(text: string): boolean {
|
|
6
|
+
return text.startsWith('# CrewX assignment\n') &&
|
|
7
|
+
text.includes('\n# Operating context\n') &&
|
|
8
|
+
text.includes(SNAPSHOT) && text.endsWith('\n```');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Model-facing projection only: never rewrite Pi's persisted session ledger. */
|
|
12
|
+
export function latestWorkspaceSnapshot(messages: ContextEvent['messages']): ContextEvent['messages'] {
|
|
13
|
+
let latest = -1;
|
|
14
|
+
for (let index = 0; index < messages.length; index++) {
|
|
15
|
+
const message = messages[index];
|
|
16
|
+
if (message.role !== 'user') continue;
|
|
17
|
+
const texts = typeof message.content === 'string'
|
|
18
|
+
? [message.content] : message.content.filter(item => item.type === 'text').map(item => item.text);
|
|
19
|
+
if (texts.some(isEnvelope)) latest = index;
|
|
20
|
+
}
|
|
21
|
+
if (latest < 0) return messages;
|
|
22
|
+
const trim = (text: string): string => isEnvelope(text)
|
|
23
|
+
? text.slice(0, text.lastIndexOf(SNAPSHOT)) +
|
|
24
|
+
'\n\n[Historical CrewX workspace snapshot omitted. Use the latest assignment snapshot; the original task and tool history are retained.]'
|
|
25
|
+
: text;
|
|
26
|
+
return messages.map((message, index) => {
|
|
27
|
+
if (index >= latest || message.role !== 'user') return message;
|
|
28
|
+
return { ...message, content: typeof message.content === 'string'
|
|
29
|
+
? trim(message.content)
|
|
30
|
+
: message.content.map(item => item.type === 'text' ? { ...item, text: trim(item.text) } : item) };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default function sessionContext(pi: ExtensionAPI): void {
|
|
35
|
+
pi.on('context', event => ({ messages: latestWorkspaceSnapshot(event.messages) }));
|
|
36
|
+
}
|