@chainingintention/pi-web-cn 1.202608.6 → 1.202608.8
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/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.js +69 -0
- package/dist/config.js.map +1 -1
- package/dist/server/app.js +4 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/audit/managementAuditStore.js +211 -0
- package/dist/server/audit/managementAuditStore.js.map +1 -0
- package/dist/server/audit/normalToolAuditCli.js +143 -0
- package/dist/server/audit/normalToolAuditCli.js.map +1 -0
- package/dist/server/audit/normalToolAuditStore.js +264 -0
- package/dist/server/audit/normalToolAuditStore.js.map +1 -0
- package/dist/server/managementEmbed.js +19 -1
- package/dist/server/managementEmbed.js.map +1 -1
- package/dist/server/requestLogging.js +10 -7
- package/dist/server/requestLogging.js.map +1 -1
- package/dist/server/sessiond/sessionProxyRoutes.js +13 -7
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
- package/dist/server/sessiond.js +90 -4
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/managementPermissionSystem.js +8 -8
- package/dist/server/sessions/managementPermissionSystem.js.map +1 -1
- package/dist/server/sessions/piSessionService.js +133 -19
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/sessionRoutes.js +6 -2
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/workbench/accessStateRoutes.js +30 -0
- package/dist/server/workbench/accessStateRoutes.js.map +1 -0
- package/dist/server/workbench/accessStateStore.js +29 -0
- package/dist/server/workbench/accessStateStore.js.map +1 -0
- package/dist/server/workbench/capabilitySearch.js +62 -0
- package/dist/server/workbench/capabilitySearch.js.map +1 -0
- package/dist/server/workbench/gatewayIntegration.js +56 -0
- package/dist/server/workbench/gatewayIntegration.js.map +1 -0
- package/dist/server/workbench/mcpClient.js +148 -0
- package/dist/server/workbench/mcpClient.js.map +1 -0
- package/dist/server/workbench/skillSync.js +375 -0
- package/dist/server/workbench/skillSync.js.map +1 -0
- package/dist/server/workbench/types.js +2 -0
- package/dist/server/workbench/types.js.map +1 -0
- package/dist/server/workbench/workbenchClient.js +136 -0
- package/dist/server/workbench/workbenchClient.js.map +1 -0
- package/dist/server/workbench/workbenchTools.js +145 -0
- package/dist/server/workbench/workbenchTools.js.map +1 -0
- package/dist/shared/apiTypes.d.ts +25 -0
- package/dist/shared/apiTypes.js.map +1 -1
- package/dist/shared/piWebConfigParsing.js +94 -0
- package/dist/shared/piWebConfigParsing.js.map +1 -1
- package/docs/config.md +65 -0
- package/package.json +7 -3
|
@@ -23,6 +23,7 @@ import { canonicalizeStoredCwd, cwdPathsEqual } from "../workingDirectory.js";
|
|
|
23
23
|
import { readSessionHeaderSummary } from "./sessionFileHeader.js";
|
|
24
24
|
import { countOutOfListingChildren, locateOutOfListingParents } from "./parentSessionLocator.js";
|
|
25
25
|
import { siblingWorkspaceCwds } from "../workspaces/projectWorkspaceCwds.js";
|
|
26
|
+
import { workbenchAccessHandle } from "../managementEmbed.js";
|
|
26
27
|
import { DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS, piWebDataDir } from "../../config.js";
|
|
27
28
|
import { createScopedSettingsManager, resolveSettingsScopeDirectory } from "./projectSettingsScope.js";
|
|
28
29
|
import { createAskUserToolDefinition } from "./askUserTool.js";
|
|
@@ -40,6 +41,8 @@ import { plainTextTheme } from "./plainTextTheme.js";
|
|
|
40
41
|
import { SessionUnreadStore } from "./sessionUnreadStore.js";
|
|
41
42
|
import { archiveCandidateFromActiveSession, archiveCandidateFromArchivedRecord, archiveCandidateFromListEntry, archiveInputFromActiveSession, archiveInputFromCandidate, archiveInputFromListEntry, clientSessionFromArchivedRecord, compareArchivedRecords, } from "./sessionArchiveMapping.js";
|
|
42
43
|
import { annotateAssistantThinkingLevel, getBoolean, getProperty, getString, toClientEvent } from "./sessionUiEvents.js";
|
|
44
|
+
import { WorkbenchHttpError } from "../workbench/workbenchClient.js";
|
|
45
|
+
import { createWorkbenchToolDefinitions } from "../workbench/workbenchTools.js";
|
|
43
46
|
const noopLogger = { info() { } };
|
|
44
47
|
const DEFAULT_UNREAD_PUBLICATION_RETRY_MS = 1_000;
|
|
45
48
|
/**
|
|
@@ -177,6 +180,22 @@ export function filterManagedProjectSkills(cwd, base) {
|
|
|
177
180
|
}),
|
|
178
181
|
};
|
|
179
182
|
}
|
|
183
|
+
export function filterManagedWorkbenchSkills(cwd, base, receipt) {
|
|
184
|
+
const projectRoot = realpathSync(cwd);
|
|
185
|
+
const allowedDirectories = new Set(receipt.skills.map((skill) => resolve(projectRoot, ".pi", "skills", skill.directory)));
|
|
186
|
+
return {
|
|
187
|
+
...base,
|
|
188
|
+
skills: base.skills.filter((skill) => {
|
|
189
|
+
try {
|
|
190
|
+
const path = realpathSync(skill.filePath);
|
|
191
|
+
return [...allowedDirectories].some((directory) => pathInsideOrEqual(directory, path));
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
}),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
180
199
|
function pathInsideOrEqual(parent, child) {
|
|
181
200
|
const normalizedParent = resolve(parent);
|
|
182
201
|
const normalizedChild = resolve(child);
|
|
@@ -318,11 +337,11 @@ function createRuntimeWithContextAndOneShotSessionOptions(createRuntime, managem
|
|
|
318
337
|
});
|
|
319
338
|
};
|
|
320
339
|
}
|
|
321
|
-
function createDefaultRuntimeFactory(normalModelRuntimeForCwd, managementModelRuntime, resolveSettingsScope, spawn, subsessions, askUser) {
|
|
340
|
+
function createDefaultRuntimeFactory(normalModelRuntimeForCwd, managementModelRuntime, resolveSettingsScope, spawn, subsessions, askUser, workbench, logger = noopLogger, managementAudit, managementProjectIdForCwd) {
|
|
322
341
|
return async ({ cwd, agentDir, sessionManager, sessionStartEvent, managementContext, initialModel, initialThinkingLevel, delegationToolsEnabled = true }) => {
|
|
323
342
|
const scopedModelRuntime = managementContext === undefined ? await normalModelRuntimeForCwd(cwd) : await managementModelRuntime();
|
|
324
343
|
if (managementContext !== undefined) {
|
|
325
|
-
return createManagementRuntimeFactory(scopedModelRuntime, resolveSettingsScope, spawn, subsessions, askUser, managementContext)({
|
|
344
|
+
return createManagementRuntimeFactory(scopedModelRuntime, resolveSettingsScope, spawn, subsessions, askUser, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd)({
|
|
326
345
|
cwd,
|
|
327
346
|
agentDir,
|
|
328
347
|
sessionManager,
|
|
@@ -350,9 +369,56 @@ function createDefaultRuntimeFactory(normalModelRuntimeForCwd, managementModelRu
|
|
|
350
369
|
return { ...result, services, diagnostics: services.diagnostics };
|
|
351
370
|
};
|
|
352
371
|
}
|
|
353
|
-
function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, spawn, subsessions, askUser, managementContext) {
|
|
372
|
+
function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, spawn, subsessions, askUser, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd) {
|
|
354
373
|
return async ({ cwd, agentDir, sessionManager, sessionStartEvent, initialModel, initialThinkingLevel, delegationToolsEnabled = true }) => {
|
|
355
|
-
const
|
|
374
|
+
const auditIdentity = await resolveManagementAuditIdentity(cwd, managementContext, managementProjectIdForCwd, logger);
|
|
375
|
+
const accessHandle = workbenchAccessHandle(managementContext);
|
|
376
|
+
const state = workbench === undefined ? undefined : workbench.accessStates.require(accessHandle);
|
|
377
|
+
let receipt;
|
|
378
|
+
try {
|
|
379
|
+
receipt = state === undefined ? undefined : await workbench?.skills.synchronize(cwd, state, {
|
|
380
|
+
...(managementAudit === undefined ? {} : { recorder: managementAudit }),
|
|
381
|
+
...auditIdentity,
|
|
382
|
+
sessionId: sessionManager.getSessionId(),
|
|
383
|
+
cwd,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
if (error instanceof WorkbenchHttpError && error.status === 401 && accessHandle !== undefined)
|
|
388
|
+
workbench?.accessStates.delete(accessHandle);
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
const workbenchTools = state === undefined || workbench === undefined ? [] : createWorkbenchToolDefinitions({
|
|
392
|
+
getState: () => workbench.accessStates.require(accessHandle),
|
|
393
|
+
workbench: workbench.client,
|
|
394
|
+
mcp: workbench.mcp,
|
|
395
|
+
invalidate: () => { if (accessHandle !== undefined)
|
|
396
|
+
workbench.accessStates.delete(accessHandle); },
|
|
397
|
+
logger,
|
|
398
|
+
...(managementAudit === undefined ? {} : { audit: managementAudit }),
|
|
399
|
+
auditContext: {
|
|
400
|
+
...auditIdentity,
|
|
401
|
+
sessionId: sessionManager.getSessionId(),
|
|
402
|
+
cwd,
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
const scopedSpawn = spawn === undefined
|
|
406
|
+
? undefined
|
|
407
|
+
: (input) => spawn({ ...input, managementContext });
|
|
408
|
+
const scopedSubsessions = subsessions === undefined
|
|
409
|
+
? undefined
|
|
410
|
+
: {
|
|
411
|
+
...subsessions,
|
|
412
|
+
spawn: (input) => subsessions.spawn({ ...input, managementContext }),
|
|
413
|
+
};
|
|
414
|
+
const controlledManagementTools = [
|
|
415
|
+
...(delegationToolsEnabled && scopedSpawn !== undefined ? [defineTool(createSpawnSessionToolDefinition(cwd, { spawn: scopedSpawn }))] : []),
|
|
416
|
+
...(delegationToolsEnabled && scopedSubsessions !== undefined ? createSubsessionToolDefinitions(cwd, scopedSubsessions).map((tool) => defineTool(tool)) : []),
|
|
417
|
+
...(askUser === undefined ? [] : [createAskUserToolDefinition(askUser)]),
|
|
418
|
+
...workbenchTools,
|
|
419
|
+
];
|
|
420
|
+
const controlledManagementToolNames = controlledManagementTools.map((tool) => tool.name);
|
|
421
|
+
const policyAgentDir = await writeManagementPermissionSystemPolicy(agentDir, cwd, managementContext, controlledManagementToolNames);
|
|
356
422
|
return withRuntimeCreationEnvironment({ [PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR]: policyAgentDir }, async () => {
|
|
357
423
|
const settingsManager = await createScopedSettingsManager({
|
|
358
424
|
cwd,
|
|
@@ -366,32 +432,21 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, spaw
|
|
|
366
432
|
settingsManager,
|
|
367
433
|
resourceLoaderOptions: {
|
|
368
434
|
agentsFilesOverride: (base) => filterManagedGlobalContextFiles(cwd, agentDir, base),
|
|
369
|
-
skillsOverride: (base) => filterManagedProjectSkills(cwd, base),
|
|
435
|
+
skillsOverride: (base) => receipt === undefined ? filterManagedProjectSkills(cwd, base) : filterManagedWorkbenchSkills(cwd, base, receipt),
|
|
370
436
|
},
|
|
371
437
|
});
|
|
372
438
|
const managedToolOptions = createManagedAgentToolOptions(cwd);
|
|
373
|
-
const scopedSpawn = spawn === undefined
|
|
374
|
-
? undefined
|
|
375
|
-
: (input) => spawn({ ...input, managementContext });
|
|
376
|
-
const scopedSubsessions = subsessions === undefined
|
|
377
|
-
? undefined
|
|
378
|
-
: {
|
|
379
|
-
...subsessions,
|
|
380
|
-
spawn: (input) => subsessions.spawn({ ...input, managementContext }),
|
|
381
|
-
};
|
|
382
439
|
const customTools = [
|
|
383
440
|
...managedAgentToolDefinitions(cwd, managedToolOptions),
|
|
384
441
|
createManagedPythonToolDefinition(cwd, managementContext),
|
|
385
|
-
...
|
|
386
|
-
...(delegationToolsEnabled && scopedSubsessions !== undefined ? createSubsessionToolDefinitions(cwd, scopedSubsessions).map((tool) => defineTool(tool)) : []),
|
|
387
|
-
...(askUser === undefined ? [] : [createAskUserToolDefinition(askUser)]),
|
|
442
|
+
...controlledManagementTools,
|
|
388
443
|
];
|
|
389
444
|
const options = {
|
|
390
445
|
services,
|
|
391
446
|
sessionManager,
|
|
392
447
|
...(sessionStartEvent === undefined ? {} : { sessionStartEvent }),
|
|
393
448
|
customTools,
|
|
394
|
-
tools: managementAgentToolNames(managementContext),
|
|
449
|
+
tools: managementAgentToolNames(managementContext, controlledManagementToolNames),
|
|
395
450
|
...(initialModel === undefined ? {} : { model: initialModel }),
|
|
396
451
|
...(initialThinkingLevel === undefined ? {} : { thinkingLevel: initialThinkingLevel }),
|
|
397
452
|
};
|
|
@@ -521,6 +576,9 @@ export class PiSessionService {
|
|
|
521
576
|
this.spawnTargets = deps.spawnTargets;
|
|
522
577
|
this.projectWorkspaces = deps.projectWorkspaces;
|
|
523
578
|
this.logger = deps.logger ?? noopLogger;
|
|
579
|
+
this.normalToolAudit = deps.normalToolAudit;
|
|
580
|
+
this.managementAudit = deps.managementAudit;
|
|
581
|
+
this.managementProjectIdForCwd = deps.managementProjectIdForCwd;
|
|
524
582
|
this.now = deps.now ?? (() => new Date());
|
|
525
583
|
this.notificationStore = deps.notificationStore ?? new SessionNotificationStore();
|
|
526
584
|
this.unreadStore = deps.unreadStore ?? new SessionUnreadStore();
|
|
@@ -538,7 +596,7 @@ export class PiSessionService {
|
|
|
538
596
|
list: (parentSessionId, parentSessionFile) => this.listSubsessions(parentSessionId, parentSessionFile),
|
|
539
597
|
check: (parentSessionId, sessionId, parentSessionFile) => this.checkSubsession(parentSessionId, sessionId, parentSessionFile),
|
|
540
598
|
read: (parentSessionId, sessionId, query, parentSessionFile) => this.readSubsession(parentSessionId, sessionId, query, parentSessionFile),
|
|
541
|
-
}, deps.askUserEnabled === true ? { open: (input) => this.openAsk(input) } : undefined);
|
|
599
|
+
}, deps.askUserEnabled === true ? { open: (input) => this.openAsk(input) } : undefined, deps.workbench, this.logger, this.managementAudit, this.managementProjectIdForCwd);
|
|
542
600
|
this.createAgentRuntime = deps.createAgentRuntime ?? defaultCreateAgentRuntime;
|
|
543
601
|
this.workspaceActivity = deps.workspaceActivity;
|
|
544
602
|
this.heartbeat = setInterval(() => { this.publishHeartbeats(); }, deps.heartbeatIntervalMs ?? 2000);
|
|
@@ -2435,6 +2493,7 @@ export class PiSessionService {
|
|
|
2435
2493
|
}
|
|
2436
2494
|
active.unsubscribe = session.subscribe((event) => {
|
|
2437
2495
|
this.events.publish(session.sessionId, toClientEvent(event, session.thinkingLevel), active.eventScope);
|
|
2496
|
+
this.auditToolExecutionEvent(active, event);
|
|
2438
2497
|
this.publishActivityForEvent(session, event);
|
|
2439
2498
|
const eventType = getString(event, "type");
|
|
2440
2499
|
if (eventType === "agent_end")
|
|
@@ -2763,6 +2822,46 @@ export class PiSessionService {
|
|
|
2763
2822
|
if (this.hasActiveWork(session))
|
|
2764
2823
|
this.publishActivity(session, "正在处理", "active");
|
|
2765
2824
|
}
|
|
2825
|
+
auditToolExecutionEvent(active, event) {
|
|
2826
|
+
const eventType = getString(event, "type");
|
|
2827
|
+
if (eventType !== "tool_execution_start" && eventType !== "tool_execution_end")
|
|
2828
|
+
return;
|
|
2829
|
+
const isEnd = eventType === "tool_execution_end";
|
|
2830
|
+
const auditEvent = {
|
|
2831
|
+
sessionId: active.runtime.session.sessionId,
|
|
2832
|
+
cwd: active.runtime.cwd,
|
|
2833
|
+
toolName: getString(event, "toolName") ?? "unknown",
|
|
2834
|
+
toolCallId: getString(event, "toolCallId") ?? "unknown",
|
|
2835
|
+
status: isEnd ? (getBoolean(event, "isError") === true ? "failed" : "completed") : "started",
|
|
2836
|
+
};
|
|
2837
|
+
const managementIdentity = active.managementAuditIdentity;
|
|
2838
|
+
this.logger.info({
|
|
2839
|
+
mode: active.managementContextKey === undefined ? "normal" : "management",
|
|
2840
|
+
...(managementIdentity ?? {}),
|
|
2841
|
+
...auditEvent,
|
|
2842
|
+
}, "Pi tool execution audit");
|
|
2843
|
+
if (managementIdentity !== undefined) {
|
|
2844
|
+
try {
|
|
2845
|
+
this.managementAudit?.record({ action: "tool_execution", ...managementIdentity, ...auditEvent });
|
|
2846
|
+
}
|
|
2847
|
+
catch (error) {
|
|
2848
|
+
this.logger.info({ sessionId: auditEvent.sessionId, toolCallId: auditEvent.toolCallId, error: error instanceof Error ? error.message : String(error) }, "failed to enqueue management-mode tool audit");
|
|
2849
|
+
}
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
if (this.normalToolAudit === undefined)
|
|
2853
|
+
return;
|
|
2854
|
+
try {
|
|
2855
|
+
this.normalToolAudit.record(auditEvent);
|
|
2856
|
+
}
|
|
2857
|
+
catch (error) {
|
|
2858
|
+
this.logger.info({
|
|
2859
|
+
sessionId: auditEvent.sessionId,
|
|
2860
|
+
toolCallId: auditEvent.toolCallId,
|
|
2861
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2862
|
+
}, "failed to persist ordinary-mode tool audit");
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2766
2865
|
/**
|
|
2767
2866
|
* Build the reporter for one session construction.
|
|
2768
2867
|
*
|
|
@@ -3036,6 +3135,9 @@ export class PiSessionService {
|
|
|
3036
3135
|
unsubscribe: noop,
|
|
3037
3136
|
managementContextKey: managementContextKey(options.managementContext),
|
|
3038
3137
|
eventScope: eventScopeFromManagementContext(options.managementContext),
|
|
3138
|
+
...(options.managementContext === undefined ? {} : {
|
|
3139
|
+
managementAuditIdentity: await resolveManagementAuditIdentity(cwd, options.managementContext, this.managementProjectIdForCwd, this.logger),
|
|
3140
|
+
}),
|
|
3039
3141
|
};
|
|
3040
3142
|
let boundSession = runtime.session;
|
|
3041
3143
|
let notificationGeneration = options.notificationGeneration;
|
|
@@ -3708,4 +3810,16 @@ function finalAssistantText(messages) {
|
|
|
3708
3810
|
function isRecord(value) {
|
|
3709
3811
|
return typeof value === "object" && value !== null;
|
|
3710
3812
|
}
|
|
3813
|
+
async function resolveManagementAuditIdentity(cwd, context, resolveProjectId, logger) {
|
|
3814
|
+
let projectId = context.projects[0]?.id ?? "default-project";
|
|
3815
|
+
if (resolveProjectId !== undefined) {
|
|
3816
|
+
try {
|
|
3817
|
+
projectId = await resolveProjectId(cwd, context);
|
|
3818
|
+
}
|
|
3819
|
+
catch (error) {
|
|
3820
|
+
logger.info({ userId: context.user.id, cwd, error: error instanceof Error ? error.message : String(error) }, "failed to resolve management audit project; using the authorized default");
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
return { userId: context.user.id, rootUserId: context.user.rootUserId, projectId };
|
|
3824
|
+
}
|
|
3711
3825
|
//# sourceMappingURL=piSessionService.js.map
|