@mrclrchtr/supi-consulting 11.0.1 → 11.2.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 +46 -6
- package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +41 -1
- package/package.json +2 -2
- package/scripts/live-probe.ts +6 -3
- package/src/agents/antigravity/adapter.ts +6 -2
- package/src/agents/antigravity/isolated-home.ts +1 -7
- package/src/agents/antigravity/process/event-values.ts +39 -13
- package/src/agents/antigravity/process/events.ts +154 -131
- package/src/agents/antigravity/process/hooks.ts +9 -1
- package/src/agents/antigravity/process/permission-diagnostics.ts +260 -0
- package/src/agents/antigravity/process/protocol.ts +57 -1
- package/src/agents/antigravity/process/runner.ts +50 -19
- package/src/agents/errors.ts +190 -10
- package/src/agents/types.ts +2 -0
- package/src/config.ts +60 -4
- package/src/runtime.ts +3 -1
- package/src/settings.ts +21 -2
- package/src/tool/consulting_run/execute.ts +13 -0
- package/src/tool/consulting_run/guidance.ts +1 -1
- package/src/tool/consulting_run/register.ts +3 -0
package/src/config.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { access, realpath, stat } from "node:fs/promises";
|
|
3
|
+
import { isAbsolute } from "node:path";
|
|
4
|
+
import { loadSupiConfig, loadSupiConfigForScope } from "@mrclrchtr/supi-core/config";
|
|
2
5
|
|
|
3
6
|
/** The persisted SuPi configuration section owned by this package. */
|
|
4
7
|
export const CONSULTING_CONFIG_SECTION = "consulting";
|
|
@@ -7,20 +10,73 @@ export const CONSULTING_CONFIG_SECTION = "consulting";
|
|
|
7
10
|
export interface ConsultingConfig extends Record<string, unknown> {
|
|
8
11
|
/** Enable agent availability discovery and the consulting_run tool. */
|
|
9
12
|
agentToolEnabled: boolean;
|
|
13
|
+
/** Absolute directories available for inspection with either Workspace Access selection. */
|
|
14
|
+
additionalReadOnlyDirectories: readonly string[];
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
/** Default Consulting configuration. */
|
|
13
18
|
export const CONSULTING_DEFAULTS: ConsultingConfig = Object.freeze({
|
|
14
19
|
agentToolEnabled: true,
|
|
20
|
+
additionalReadOnlyDirectories: Object.freeze([]),
|
|
15
21
|
});
|
|
16
22
|
|
|
17
|
-
/** Load
|
|
18
|
-
export function loadConsultingConfig(
|
|
19
|
-
|
|
23
|
+
/** Load trusted scoped configuration; untrusted projects cannot grant external directory access. */
|
|
24
|
+
export function loadConsultingConfig(
|
|
25
|
+
cwd: string,
|
|
26
|
+
homeDir?: string,
|
|
27
|
+
projectTrusted = true,
|
|
28
|
+
): ConsultingConfig {
|
|
29
|
+
const raw = projectTrusted
|
|
30
|
+
? loadSupiConfig(CONSULTING_CONFIG_SECTION, cwd, CONSULTING_DEFAULTS, { homeDir })
|
|
31
|
+
: loadSupiConfigForScope(CONSULTING_CONFIG_SECTION, cwd, CONSULTING_DEFAULTS, {
|
|
32
|
+
scope: "global",
|
|
33
|
+
homeDir,
|
|
34
|
+
});
|
|
20
35
|
return {
|
|
21
36
|
agentToolEnabled:
|
|
22
37
|
typeof raw.agentToolEnabled === "boolean"
|
|
23
38
|
? raw.agentToolEnabled
|
|
24
39
|
: CONSULTING_DEFAULTS.agentToolEnabled,
|
|
40
|
+
additionalReadOnlyDirectories: validateAdditionalReadOnlyDirectories(
|
|
41
|
+
raw.additionalReadOnlyDirectories,
|
|
42
|
+
),
|
|
25
43
|
};
|
|
26
44
|
}
|
|
45
|
+
|
|
46
|
+
/** Validate directory-list syntax before persistence or execution; paths are literal, not globs. */
|
|
47
|
+
export function validateAdditionalReadOnlyDirectories(value: unknown): string[] {
|
|
48
|
+
if (
|
|
49
|
+
!Array.isArray(value) ||
|
|
50
|
+
value.some((path) => typeof path !== "string" || !isAbsolute(path) || path.includes("\0"))
|
|
51
|
+
) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
"consulting.additionalReadOnlyDirectories must be a list of absolute directory paths.",
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return [...new Set(value)];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Resolve current scoped grants for each run, following directory aliases and failing before process work. */
|
|
60
|
+
export async function resolveAdditionalReadOnlyDirectories(
|
|
61
|
+
cwd: string,
|
|
62
|
+
homeDir?: string,
|
|
63
|
+
projectTrusted = true,
|
|
64
|
+
): Promise<string[]> {
|
|
65
|
+
const config = loadConsultingConfig(cwd, homeDir, projectTrusted);
|
|
66
|
+
const directories = await Promise.all(
|
|
67
|
+
config.additionalReadOnlyDirectories.map(async (path) => {
|
|
68
|
+
try {
|
|
69
|
+
const canonical = await realpath(path);
|
|
70
|
+
if (!(await stat(canonical)).isDirectory()) throw new Error("Not a directory.");
|
|
71
|
+
await access(canonical, constants.R_OK | constants.X_OK);
|
|
72
|
+
return canonical;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Consulting additional read-only directory is missing, inaccessible, or not a directory: ${path}`,
|
|
76
|
+
{ cause: error },
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
return [...new Set(directories)];
|
|
82
|
+
}
|
package/src/runtime.ts
CHANGED
|
@@ -17,6 +17,7 @@ type FooterState = "idle" | "checking" | "ready";
|
|
|
17
17
|
/** Context needed to report availability and update the footer. */
|
|
18
18
|
export type ConsultingRefreshContext = {
|
|
19
19
|
ui: Pick<ExtensionContext["ui"], "notify" | "setStatus">;
|
|
20
|
+
isProjectTrusted?: ExtensionContext["isProjectTrusted"];
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
/** Session runtime for immutable availability and Conversation Handle state. */
|
|
@@ -85,7 +86,7 @@ export class ConsultingRuntime {
|
|
|
85
86
|
if (context) this.#statusUi = context.ui;
|
|
86
87
|
this.#stopSpinner();
|
|
87
88
|
this.#setFooterState("idle");
|
|
88
|
-
const config = loadConsultingConfig(cwd, this.#homeDir);
|
|
89
|
+
const config = loadConsultingConfig(cwd, this.#homeDir, context?.isProjectTrusted?.() ?? true);
|
|
89
90
|
if (!config.agentToolEnabled) {
|
|
90
91
|
this.#deactivateTool();
|
|
91
92
|
return;
|
|
@@ -141,6 +142,7 @@ export class ConsultingRuntime {
|
|
|
141
142
|
adapter: this.adapter,
|
|
142
143
|
availability,
|
|
143
144
|
handles: this.handles,
|
|
145
|
+
homeDir: this.#homeDir,
|
|
144
146
|
});
|
|
145
147
|
this.#toolRegistered = true;
|
|
146
148
|
}
|
package/src/settings.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { defineConfigSettings, registerSettings } from "@mrclrchtr/supi-core/settings";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
CONSULTING_CONFIG_SECTION,
|
|
5
|
+
CONSULTING_DEFAULTS,
|
|
6
|
+
validateAdditionalReadOnlyDirectories,
|
|
7
|
+
} from "./config.ts";
|
|
4
8
|
import type { ConsultingRuntime } from "./runtime.ts";
|
|
5
9
|
|
|
6
10
|
/** Register the Consulting setting with an awaited availability refresh. */
|
|
@@ -21,6 +25,13 @@ export function registerConsultingSettings(
|
|
|
21
25
|
label: "Consultation tool",
|
|
22
26
|
description: "Enable consulting_run and its availability checks.",
|
|
23
27
|
},
|
|
28
|
+
{
|
|
29
|
+
kind: "stringList" as const,
|
|
30
|
+
key: "additionalReadOnlyDirectories",
|
|
31
|
+
label: "Additional read-only directories",
|
|
32
|
+
description:
|
|
33
|
+
"Comma-separated absolute directories for every Consultation, including without Workspace Access. No shell expansion or globs; broad paths can expose sensitive files.",
|
|
34
|
+
},
|
|
24
35
|
],
|
|
25
36
|
...(homeDir ? { homeDir } : {}),
|
|
26
37
|
});
|
|
@@ -28,9 +39,17 @@ export function registerConsultingSettings(
|
|
|
28
39
|
registerSettings(pi, {
|
|
29
40
|
...fixedSettings,
|
|
30
41
|
apply: async (request) => {
|
|
42
|
+
if (request.fieldKey === "additionalReadOnlyDirectories" && request.action.kind === "set") {
|
|
43
|
+
validateAdditionalReadOnlyDirectories(
|
|
44
|
+
request.action.value
|
|
45
|
+
.split(",")
|
|
46
|
+
.map((path) => path.trim())
|
|
47
|
+
.filter(Boolean),
|
|
48
|
+
);
|
|
49
|
+
}
|
|
31
50
|
const result = await fixedSettings.apply(request);
|
|
32
51
|
if (request.fieldKey === "agentToolEnabled") {
|
|
33
|
-
await runtime.refresh(request.cwd, request.ctx
|
|
52
|
+
await runtime.refresh(request.cwd, request.ctx);
|
|
34
53
|
}
|
|
35
54
|
return result;
|
|
36
55
|
},
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
ExtensionContext,
|
|
6
6
|
} from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import type { ConsultingAgentAdapter, ConsultingAgentAvailability } from "../../agents/types.ts";
|
|
8
|
+
import { resolveAdditionalReadOnlyDirectories } from "../../config.ts";
|
|
8
9
|
import {
|
|
9
10
|
appendHandleCreated,
|
|
10
11
|
appendHandleRetired,
|
|
@@ -19,6 +20,8 @@ export interface ConsultingRunDependencies {
|
|
|
19
20
|
adapter: ConsultingAgentAdapter;
|
|
20
21
|
availability: ConsultingAgentAvailability;
|
|
21
22
|
handles: ConversationHandleStore;
|
|
23
|
+
/** Override the user home for scoped configuration loading. */
|
|
24
|
+
homeDir?: string;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
type ConsultingExecute = NonNullable<Parameters<ExtensionAPI["registerTool"]>[0]["execute"]>;
|
|
@@ -84,6 +87,11 @@ async function runNew(options: NewRunOptions): Promise<ReturnType<typeof buildCo
|
|
|
84
87
|
model: input.new.model,
|
|
85
88
|
canonicalWorkingDirectory: cwd,
|
|
86
89
|
workspaceAccess,
|
|
90
|
+
additionalReadOnlyDirectories: await resolveAdditionalReadOnlyDirectories(
|
|
91
|
+
ctx.cwd,
|
|
92
|
+
dependencies.homeDir,
|
|
93
|
+
ctx.isProjectTrusted(),
|
|
94
|
+
),
|
|
87
95
|
signal,
|
|
88
96
|
onProgress: progress,
|
|
89
97
|
onWarning: (warning) => {
|
|
@@ -136,6 +144,11 @@ async function runContinue(
|
|
|
136
144
|
model: record.model,
|
|
137
145
|
canonicalWorkingDirectory: record.canonicalWorkingDirectory,
|
|
138
146
|
workspaceAccess: record.workspaceAccess,
|
|
147
|
+
additionalReadOnlyDirectories: await resolveAdditionalReadOnlyDirectories(
|
|
148
|
+
ctx.cwd,
|
|
149
|
+
dependencies.homeDir,
|
|
150
|
+
ctx.isProjectTrusted(),
|
|
151
|
+
),
|
|
139
152
|
continuation: record.continuation,
|
|
140
153
|
signal,
|
|
141
154
|
onProgress: progress,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Selection guidance for the dynamically activated consulting_run tool. */
|
|
2
2
|
export const toolDescription =
|
|
3
|
-
"Consult
|
|
3
|
+
"Consult an external agent for web research, design advice, workspace analysis, or an independent second opinion. Use direct tools for repository facts. Expose the current workspace only when the Consultation needs repository evidence. Configured extra read-only directories apply to either workspace selection.";
|
|
@@ -12,6 +12,8 @@ export interface RegisterConsultingRunOptions {
|
|
|
12
12
|
adapter: ConsultingAgentAdapter;
|
|
13
13
|
availability: ConsultingAgentAvailability;
|
|
14
14
|
handles: ConversationHandleStore;
|
|
15
|
+
/** Override the user home for scoped configuration loading. */
|
|
16
|
+
homeDir?: string;
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
/** Register consulting_run from one immutable availability snapshot. */
|
|
@@ -31,6 +33,7 @@ export function registerConsultingRunTool(options: RegisterConsultingRunOptions)
|
|
|
31
33
|
adapter: options.adapter,
|
|
32
34
|
availability: options.availability,
|
|
33
35
|
handles: options.handles,
|
|
36
|
+
homeDir: options.homeDir,
|
|
34
37
|
}),
|
|
35
38
|
});
|
|
36
39
|
}
|