@chainingintention/pi-web-cn 1.202608.6 → 1.202608.7

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.
Files changed (50) hide show
  1. package/dist/cli.js +8 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/config.js +69 -0
  4. package/dist/config.js.map +1 -1
  5. package/dist/server/app.js +4 -1
  6. package/dist/server/app.js.map +1 -1
  7. package/dist/server/audit/managementAuditStore.js +211 -0
  8. package/dist/server/audit/managementAuditStore.js.map +1 -0
  9. package/dist/server/audit/normalToolAuditCli.js +143 -0
  10. package/dist/server/audit/normalToolAuditCli.js.map +1 -0
  11. package/dist/server/audit/normalToolAuditStore.js +264 -0
  12. package/dist/server/audit/normalToolAuditStore.js.map +1 -0
  13. package/dist/server/managementEmbed.js +19 -1
  14. package/dist/server/managementEmbed.js.map +1 -1
  15. package/dist/server/requestLogging.js +10 -7
  16. package/dist/server/requestLogging.js.map +1 -1
  17. package/dist/server/sessiond/sessionProxyRoutes.js +13 -7
  18. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  19. package/dist/server/sessiond.js +90 -4
  20. package/dist/server/sessiond.js.map +1 -1
  21. package/dist/server/sessions/managementPermissionSystem.js +8 -8
  22. package/dist/server/sessions/managementPermissionSystem.js.map +1 -1
  23. package/dist/server/sessions/piSessionService.js +118 -7
  24. package/dist/server/sessions/piSessionService.js.map +1 -1
  25. package/dist/server/sessions/sessionRoutes.js +6 -2
  26. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  27. package/dist/server/workbench/accessStateRoutes.js +30 -0
  28. package/dist/server/workbench/accessStateRoutes.js.map +1 -0
  29. package/dist/server/workbench/accessStateStore.js +29 -0
  30. package/dist/server/workbench/accessStateStore.js.map +1 -0
  31. package/dist/server/workbench/capabilitySearch.js +62 -0
  32. package/dist/server/workbench/capabilitySearch.js.map +1 -0
  33. package/dist/server/workbench/gatewayIntegration.js +56 -0
  34. package/dist/server/workbench/gatewayIntegration.js.map +1 -0
  35. package/dist/server/workbench/mcpClient.js +148 -0
  36. package/dist/server/workbench/mcpClient.js.map +1 -0
  37. package/dist/server/workbench/skillSync.js +375 -0
  38. package/dist/server/workbench/skillSync.js.map +1 -0
  39. package/dist/server/workbench/types.js +2 -0
  40. package/dist/server/workbench/types.js.map +1 -0
  41. package/dist/server/workbench/workbenchClient.js +136 -0
  42. package/dist/server/workbench/workbenchClient.js.map +1 -0
  43. package/dist/server/workbench/workbenchTools.js +145 -0
  44. package/dist/server/workbench/workbenchTools.js.map +1 -0
  45. package/dist/shared/apiTypes.d.ts +25 -0
  46. package/dist/shared/apiTypes.js.map +1 -1
  47. package/dist/shared/piWebConfigParsing.js +94 -0
  48. package/dist/shared/piWebConfigParsing.js.map +1 -1
  49. package/docs/config.md +65 -0
  50. 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,41 @@ 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 policyAgentDir = await writeManagementPermissionSystemPolicy(agentDir, cwd, managementContext);
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 workbenchToolNames = workbenchTools.map((tool) => tool.name);
406
+ const policyAgentDir = await writeManagementPermissionSystemPolicy(agentDir, cwd, managementContext, workbenchToolNames);
356
407
  return withRuntimeCreationEnvironment({ [PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR]: policyAgentDir }, async () => {
357
408
  const settingsManager = await createScopedSettingsManager({
358
409
  cwd,
@@ -366,7 +417,7 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, spaw
366
417
  settingsManager,
367
418
  resourceLoaderOptions: {
368
419
  agentsFilesOverride: (base) => filterManagedGlobalContextFiles(cwd, agentDir, base),
369
- skillsOverride: (base) => filterManagedProjectSkills(cwd, base),
420
+ skillsOverride: (base) => receipt === undefined ? filterManagedProjectSkills(cwd, base) : filterManagedWorkbenchSkills(cwd, base, receipt),
370
421
  },
371
422
  });
372
423
  const managedToolOptions = createManagedAgentToolOptions(cwd);
@@ -385,13 +436,14 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, spaw
385
436
  ...(delegationToolsEnabled && scopedSpawn !== undefined ? [defineTool(createSpawnSessionToolDefinition(cwd, { spawn: scopedSpawn }))] : []),
386
437
  ...(delegationToolsEnabled && scopedSubsessions !== undefined ? createSubsessionToolDefinitions(cwd, scopedSubsessions).map((tool) => defineTool(tool)) : []),
387
438
  ...(askUser === undefined ? [] : [createAskUserToolDefinition(askUser)]),
439
+ ...workbenchTools,
388
440
  ];
389
441
  const options = {
390
442
  services,
391
443
  sessionManager,
392
444
  ...(sessionStartEvent === undefined ? {} : { sessionStartEvent }),
393
445
  customTools,
394
- tools: managementAgentToolNames(managementContext),
446
+ tools: managementAgentToolNames(managementContext, workbenchToolNames),
395
447
  ...(initialModel === undefined ? {} : { model: initialModel }),
396
448
  ...(initialThinkingLevel === undefined ? {} : { thinkingLevel: initialThinkingLevel }),
397
449
  };
@@ -521,6 +573,9 @@ export class PiSessionService {
521
573
  this.spawnTargets = deps.spawnTargets;
522
574
  this.projectWorkspaces = deps.projectWorkspaces;
523
575
  this.logger = deps.logger ?? noopLogger;
576
+ this.normalToolAudit = deps.normalToolAudit;
577
+ this.managementAudit = deps.managementAudit;
578
+ this.managementProjectIdForCwd = deps.managementProjectIdForCwd;
524
579
  this.now = deps.now ?? (() => new Date());
525
580
  this.notificationStore = deps.notificationStore ?? new SessionNotificationStore();
526
581
  this.unreadStore = deps.unreadStore ?? new SessionUnreadStore();
@@ -538,7 +593,7 @@ export class PiSessionService {
538
593
  list: (parentSessionId, parentSessionFile) => this.listSubsessions(parentSessionId, parentSessionFile),
539
594
  check: (parentSessionId, sessionId, parentSessionFile) => this.checkSubsession(parentSessionId, sessionId, parentSessionFile),
540
595
  read: (parentSessionId, sessionId, query, parentSessionFile) => this.readSubsession(parentSessionId, sessionId, query, parentSessionFile),
541
- }, deps.askUserEnabled === true ? { open: (input) => this.openAsk(input) } : undefined);
596
+ }, deps.askUserEnabled === true ? { open: (input) => this.openAsk(input) } : undefined, deps.workbench, this.logger, this.managementAudit, this.managementProjectIdForCwd);
542
597
  this.createAgentRuntime = deps.createAgentRuntime ?? defaultCreateAgentRuntime;
543
598
  this.workspaceActivity = deps.workspaceActivity;
544
599
  this.heartbeat = setInterval(() => { this.publishHeartbeats(); }, deps.heartbeatIntervalMs ?? 2000);
@@ -2435,6 +2490,7 @@ export class PiSessionService {
2435
2490
  }
2436
2491
  active.unsubscribe = session.subscribe((event) => {
2437
2492
  this.events.publish(session.sessionId, toClientEvent(event, session.thinkingLevel), active.eventScope);
2493
+ this.auditToolExecutionEvent(active, event);
2438
2494
  this.publishActivityForEvent(session, event);
2439
2495
  const eventType = getString(event, "type");
2440
2496
  if (eventType === "agent_end")
@@ -2763,6 +2819,46 @@ export class PiSessionService {
2763
2819
  if (this.hasActiveWork(session))
2764
2820
  this.publishActivity(session, "正在处理", "active");
2765
2821
  }
2822
+ auditToolExecutionEvent(active, event) {
2823
+ const eventType = getString(event, "type");
2824
+ if (eventType !== "tool_execution_start" && eventType !== "tool_execution_end")
2825
+ return;
2826
+ const isEnd = eventType === "tool_execution_end";
2827
+ const auditEvent = {
2828
+ sessionId: active.runtime.session.sessionId,
2829
+ cwd: active.runtime.cwd,
2830
+ toolName: getString(event, "toolName") ?? "unknown",
2831
+ toolCallId: getString(event, "toolCallId") ?? "unknown",
2832
+ status: isEnd ? (getBoolean(event, "isError") === true ? "failed" : "completed") : "started",
2833
+ };
2834
+ const managementIdentity = active.managementAuditIdentity;
2835
+ this.logger.info({
2836
+ mode: active.managementContextKey === undefined ? "normal" : "management",
2837
+ ...(managementIdentity ?? {}),
2838
+ ...auditEvent,
2839
+ }, "Pi tool execution audit");
2840
+ if (managementIdentity !== undefined) {
2841
+ try {
2842
+ this.managementAudit?.record({ action: "tool_execution", ...managementIdentity, ...auditEvent });
2843
+ }
2844
+ catch (error) {
2845
+ this.logger.info({ sessionId: auditEvent.sessionId, toolCallId: auditEvent.toolCallId, error: error instanceof Error ? error.message : String(error) }, "failed to enqueue management-mode tool audit");
2846
+ }
2847
+ return;
2848
+ }
2849
+ if (this.normalToolAudit === undefined)
2850
+ return;
2851
+ try {
2852
+ this.normalToolAudit.record(auditEvent);
2853
+ }
2854
+ catch (error) {
2855
+ this.logger.info({
2856
+ sessionId: auditEvent.sessionId,
2857
+ toolCallId: auditEvent.toolCallId,
2858
+ error: error instanceof Error ? error.message : String(error),
2859
+ }, "failed to persist ordinary-mode tool audit");
2860
+ }
2861
+ }
2766
2862
  /**
2767
2863
  * Build the reporter for one session construction.
2768
2864
  *
@@ -3036,6 +3132,9 @@ export class PiSessionService {
3036
3132
  unsubscribe: noop,
3037
3133
  managementContextKey: managementContextKey(options.managementContext),
3038
3134
  eventScope: eventScopeFromManagementContext(options.managementContext),
3135
+ ...(options.managementContext === undefined ? {} : {
3136
+ managementAuditIdentity: await resolveManagementAuditIdentity(cwd, options.managementContext, this.managementProjectIdForCwd, this.logger),
3137
+ }),
3039
3138
  };
3040
3139
  let boundSession = runtime.session;
3041
3140
  let notificationGeneration = options.notificationGeneration;
@@ -3708,4 +3807,16 @@ function finalAssistantText(messages) {
3708
3807
  function isRecord(value) {
3709
3808
  return typeof value === "object" && value !== null;
3710
3809
  }
3810
+ async function resolveManagementAuditIdentity(cwd, context, resolveProjectId, logger) {
3811
+ let projectId = context.projects[0]?.id ?? "default-project";
3812
+ if (resolveProjectId !== undefined) {
3813
+ try {
3814
+ projectId = await resolveProjectId(cwd, context);
3815
+ }
3816
+ catch (error) {
3817
+ 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");
3818
+ }
3819
+ }
3820
+ return { userId: context.user.id, rootUserId: context.user.rootUserId, projectId };
3821
+ }
3711
3822
  //# sourceMappingURL=piSessionService.js.map