@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.6
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/CHANGELOG.md +69 -0
- package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-gs76k6wc.md} +69 -0
- package/dist/cli.js +4438 -3962
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/cli/args.d.ts +4 -1
- package/dist/types/cli/browser-relay-cli.d.ts +15 -0
- package/dist/types/cli/command-help.d.ts +99 -0
- package/dist/types/cli/gc-cli.d.ts +1 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- package/dist/types/cli/thinking-levels.d.ts +5 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/commands/browser-relay.d.ts +38 -0
- package/dist/types/commands/commit.d.ts +3 -0
- package/dist/types/commands/complete.d.ts +1 -1
- package/dist/types/commands/completions.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +3 -0
- package/dist/types/commands/join.d.ts +4 -0
- package/dist/types/commands/launch-help.d.ts +171 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/models.d.ts +3 -0
- package/dist/types/commands/say.d.ts +10 -0
- package/dist/types/commands/worktree.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/model-discovery.d.ts +2 -2
- package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/models-config.d.ts +1 -0
- package/dist/types/config/service-tier.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +69 -21
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/edit/index.d.ts +3 -3
- package/dist/types/edit/modes/replace.d.ts +22 -15
- package/dist/types/edit/renderer.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/spawn-options.d.ts +12 -16
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +15 -4
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +1 -1
- package/dist/types/launch/protocol.d.ts +19 -2
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/lsp/mux/daemon.d.ts +15 -0
- package/dist/types/lsp/mux/protocol.d.ts +57 -0
- package/dist/types/lsp/mux/server.d.ts +18 -0
- package/dist/types/lsp/types.d.ts +22 -2
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mnemopi/embed-client.d.ts +1 -1
- package/dist/types/mnemopi/state.d.ts +0 -23
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/btw-panel.d.ts +3 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/security/contracts/schemas.d.ts +405 -403
- package/dist/types/session/agent-session-types.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +26 -2
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/launch-completion.d.ts +10 -0
- package/dist/types/session/session-advisors.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-entries.d.ts +15 -1
- package/dist/types/session/session-maintenance.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +23 -11
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/session/yield-queue.d.ts +6 -1
- package/dist/types/system-prompt.d.ts +4 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/spawn-policy.d.ts +5 -0
- package/dist/types/thinking.d.ts +1 -7
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/browser/registry.d.ts +2 -1
- package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
- package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
- package/dist/types/tools/browser/relay/kind.d.ts +19 -0
- package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
- package/dist/types/tools/browser/relay/server.d.ts +35 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -0
- package/dist/types/tools/computer/exposure.d.ts +9 -7
- package/dist/types/tools/computer/protocol.d.ts +70 -17
- package/dist/types/tools/computer/supervisor.d.ts +23 -10
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +42 -7
- package/dist/types/tools/computer-renderer.d.ts +7 -5
- package/dist/types/tools/computer.d.ts +25 -44
- package/dist/types/tools/context.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/index.d.ts +9 -0
- package/dist/types/tools/render-utils.d.ts +2 -0
- package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/tools/xdev.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +2 -2
- package/dist/types/web/kagi.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +1 -0
- package/dist/types/web/search/providers/base.d.ts +2 -0
- package/dist/types/web/search/providers/brave.d.ts +1 -0
- package/dist/types/web/search/providers/browser-page.d.ts +1 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -0
- package/dist/types/web/search/providers/exa.d.ts +1 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/dist/types/web/search/providers/jina.d.ts +1 -0
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -0
- package/dist/types/web/search/providers/parallel.d.ts +1 -0
- package/dist/types/web/search/providers/perplexity.d.ts +1 -0
- package/dist/types/web/search/providers/searxng.d.ts +1 -0
- package/dist/types/web/search/providers/tavily.d.ts +1 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
- package/dist/types/web/search/providers/utils.d.ts +6 -9
- package/dist/types/web/search/providers/zai.d.ts +1 -0
- package/dist/types/web/search/types.d.ts +4 -0
- package/package.json +12 -12
- package/src/cli/args.ts +7 -87
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/command-help.ts +103 -0
- package/src/cli/completion-gen.ts +5 -5
- package/src/cli/flag-tables.ts +9 -0
- package/src/cli/gc-cli.ts +641 -21
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/setup-cli.ts +13 -21
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/update-cli.ts +26 -7
- package/src/cli-commands.ts +170 -33
- package/src/cli.ts +17 -5
- package/src/commands/acp.ts +3 -1
- package/src/commands/agents.ts +3 -2
- package/src/commands/auth-broker.ts +3 -2
- package/src/commands/auth-gateway.ts +3 -2
- package/src/commands/bench.ts +2 -3
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +2 -2
- package/src/commands/commit.ts +3 -2
- package/src/commands/complete.ts +2 -1
- package/src/commands/completions.ts +3 -2
- package/src/commands/config.ts +3 -2
- package/src/commands/dry-balance.ts +2 -2
- package/src/commands/gallery.ts +3 -2
- package/src/commands/gc.ts +3 -2
- package/src/commands/grep.ts +3 -2
- package/src/commands/grievances.ts +3 -2
- package/src/commands/install.ts +2 -2
- package/src/commands/join.ts +3 -2
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +7 -191
- package/src/commands/models.ts +3 -2
- package/src/commands/plugin.ts +3 -2
- package/src/commands/read.ts +3 -2
- package/src/commands/say.ts +3 -2
- package/src/commands/setup.ts +3 -2
- package/src/commands/shell.ts +3 -2
- package/src/commands/ssh.ts +3 -2
- package/src/commands/stats.ts +3 -2
- package/src/commands/tiny-models.ts +2 -2
- package/src/commands/token.ts +2 -2
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/update.ts +3 -2
- package/src/commands/usage.ts +3 -2
- package/src/commands/web-search.ts +3 -2
- package/src/commands/worktree.ts +3 -2
- package/src/config/keybindings.ts +5 -0
- package/src/config/model-discovery.ts +44 -27
- package/src/config/model-registry.ts +19 -13
- package/src/config/models-config-schema-bundle.ts +9 -0
- package/src/config/resolve-config-value.ts +2 -1
- package/src/config/service-tier.ts +5 -0
- package/src/config/settings-schema.ts +72 -20
- package/src/config/settings.ts +1 -1
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/edit/diff.ts +17 -8
- package/src/edit/index.ts +20 -7
- package/src/edit/modes/replace.ts +93 -40
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +14 -17
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/spawn-options.ts +24 -29
- package/src/export/html/index.ts +10 -3
- package/src/export/html/template.js +8 -26
- package/src/export/share.ts +4 -0
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +223 -7
- package/src/launch/client.ts +192 -21
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +1 -1
- package/src/launch/protocol.ts +54 -2
- package/src/lsp/client.ts +23 -2
- package/src/lsp/index.ts +8 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/types.ts +28 -2
- package/src/main.ts +20 -8
- package/src/mcp/config-writer.ts +1 -1
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/btw-panel.ts +41 -4
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +9 -0
- package/src/modes/components/read-tool-group.ts +10 -0
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/tool-execution.ts +8 -0
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/btw-controller.ts +55 -7
- package/src/modes/controllers/command-controller.ts +31 -0
- package/src/modes/controllers/event-controller.ts +17 -0
- package/src/modes/controllers/input-controller.ts +63 -8
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +20 -0
- package/src/modes/interactive-mode.ts +18 -2
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -10
- package/src/modes/workflow.ts +8 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/session/launch-completion.md +1 -0
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +26 -52
- package/src/prompts/system/workflow-notice.md +3 -3
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/computer.md +21 -21
- package/src/prompts/tools/glob.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/replace.md +5 -4
- package/src/prompts/tools/task.md +4 -4
- package/src/sdk.ts +49 -6
- package/src/secrets/index.ts +1 -1
- package/src/security/contracts/schemas.ts +205 -183
- package/src/security/contracts/validation.ts +5 -1
- package/src/security/store.ts +2 -2
- package/src/session/agent-session-types.ts +9 -1
- package/src/session/agent-session.ts +204 -15
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/launch-completion.ts +37 -0
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +2 -2
- package/src/session/session-context.ts +42 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-entries.ts +17 -1
- package/src/session/session-maintenance.ts +38 -4
- package/src/session/session-manager.ts +123 -67
- package/src/session/session-paths.ts +118 -55
- package/src/session/session-stats.ts +48 -3
- package/src/session/session-storage.ts +30 -22
- package/src/session/stream-guards.ts +1 -1
- package/src/session/yield-queue.ts +121 -16
- package/src/slash-commands/builtin-registry.ts +37 -24
- package/src/system-prompt.ts +8 -3
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +97 -14
- package/src/tools/browser/cmux/rpc.ts +2 -8
- package/src/tools/browser/registry.ts +53 -2
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +4 -1
- package/src/tools/browser/shared-daemon.ts +7 -58
- package/src/tools/browser/tab-supervisor.ts +5 -4
- package/src/tools/browser/tab-worker.ts +33 -12
- package/src/tools/browser.ts +26 -1
- package/src/tools/computer/exposure.ts +11 -35
- package/src/tools/computer/protocol.ts +51 -10
- package/src/tools/computer/supervisor.ts +227 -124
- package/src/tools/computer/worker-entry.ts +11 -6
- package/src/tools/computer/worker.ts +695 -81
- package/src/tools/computer-renderer.ts +104 -65
- package/src/tools/computer.ts +134 -428
- package/src/tools/context.ts +3 -0
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/hub/launch.ts +122 -6
- package/src/tools/index.ts +9 -0
- package/src/tools/inspect-image.ts +32 -6
- package/src/tools/render-utils.ts +2 -0
- package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/xdev.ts +29 -2
- package/src/utils/clipboard.ts +40 -14
- package/src/utils/command-args.ts +26 -28
- package/src/utils/tool-choice.ts +0 -13
- package/src/web/kagi.ts +2 -1
- package/src/web/search/index.ts +18 -2
- package/src/web/search/providers/anthropic.ts +4 -1
- package/src/web/search/providers/base.ts +2 -0
- package/src/web/search/providers/brave.ts +3 -1
- package/src/web/search/providers/browser-page.ts +6 -4
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/duckduckgo.ts +2 -1
- package/src/web/search/providers/ecosia.ts +2 -1
- package/src/web/search/providers/exa.ts +4 -2
- package/src/web/search/providers/firecrawl.ts +3 -1
- package/src/web/search/providers/gemini.ts +8 -2
- package/src/web/search/providers/google.ts +2 -1
- package/src/web/search/providers/jina.ts +12 -2
- package/src/web/search/providers/kagi.ts +3 -0
- package/src/web/search/providers/kimi.ts +5 -1
- package/src/web/search/providers/mojeek.ts +2 -1
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +6 -3
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/searxng.ts +11 -5
- package/src/web/search/providers/startpage.ts +10 -4
- package/src/web/search/providers/synthetic.ts +11 -5
- package/src/web/search/providers/tavily.ts +3 -1
- package/src/web/search/providers/tinyfish.ts +3 -1
- package/src/web/search/providers/utils.ts +12 -10
- package/src/web/search/providers/xai.ts +2 -2
- package/src/web/search/providers/zai.ts +18 -3
- package/src/web/search/types.ts +6 -0
- package/dist/types/config/file-lock.d.ts +0 -29
- package/src/config/file-lock.ts +0 -164
package/src/sdk.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
Model,
|
|
18
18
|
ModelUsageHealth,
|
|
19
19
|
ProviderSessionState,
|
|
20
|
+
ServiceTier,
|
|
20
21
|
SimpleStreamOptions,
|
|
21
22
|
} from "@oh-my-pi/pi-ai";
|
|
22
23
|
import { resolveApiKeyOnce } from "@oh-my-pi/pi-ai/auth-retry";
|
|
@@ -102,6 +103,7 @@ import {
|
|
|
102
103
|
import { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from "./extensibility/slash-commands";
|
|
103
104
|
import type { HindsightSessionState } from "./hindsight/state";
|
|
104
105
|
import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls";
|
|
106
|
+
import { setSharedLspEnabled } from "./lsp/client";
|
|
105
107
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events";
|
|
106
108
|
import {
|
|
107
109
|
deduplicateMCPToolsByName,
|
|
@@ -169,6 +171,7 @@ import {
|
|
|
169
171
|
} from "./system-prompt";
|
|
170
172
|
import { AgentOutputManager } from "./task/output-manager";
|
|
171
173
|
import { wrapStreamFnWithProviderConcurrency } from "./task/provider-concurrency";
|
|
174
|
+
import { isScoutSpawnable } from "./task/spawn-policy";
|
|
172
175
|
import type { StructuredSubagentSchemaMode } from "./task/types";
|
|
173
176
|
import {
|
|
174
177
|
AUTO_THINKING,
|
|
@@ -379,6 +382,8 @@ export interface CreateAgentSessionOptions {
|
|
|
379
382
|
thinkingLevel?: ConfiguredThinkingLevel;
|
|
380
383
|
/** Hard ceiling on the session's thinking effort (e.g. a task spawn's `task.maxEffort`-capped hint); retry-fallback recovery re-clamps to it. */
|
|
381
384
|
thinkingLevelCeiling?: Effort;
|
|
385
|
+
/** OpenAI service-tier override for this session. `null` omits `service_tier`. */
|
|
386
|
+
openAIServiceTier?: ServiceTier | null;
|
|
382
387
|
/** Models available for cycling (Ctrl+P in interactive mode) */
|
|
383
388
|
scopedModels?: Array<{ model: Model; thinkingLevel?: ThinkingLevel }>;
|
|
384
389
|
/** Prewalk from the starting model to a fast/cheap target at the first edit/write once the todo list exists. */
|
|
@@ -1681,6 +1686,7 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
1681
1686
|
// entries capture it at fetch time and are dropped at injection if a newer
|
|
1682
1687
|
// mutation (any tool) bumped it in the meantime.
|
|
1683
1688
|
const fileMutationVersions = new Map<string, number>();
|
|
1689
|
+
const disposeCallbacks = new Set<() => void>();
|
|
1684
1690
|
const activeToolNames = new Set<string>();
|
|
1685
1691
|
const toolRegistry = new Map<string, Tool>();
|
|
1686
1692
|
const setActiveToolNames = (names: Iterable<string>): void => {
|
|
@@ -1734,6 +1740,7 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
1734
1740
|
trackEvalExecution: (execution, abortController) =>
|
|
1735
1741
|
session ? session.trackEvalExecution(execution, abortController) : execution,
|
|
1736
1742
|
getSessionId: () => sessionManager.getSessionId?.() ?? null,
|
|
1743
|
+
isDisposed: () => session?.isDisposed ?? false,
|
|
1737
1744
|
getHindsightSessionState: () => session?.getHindsightSessionState(),
|
|
1738
1745
|
getMnemopiSessionState: () => session?.getMnemopiSessionState(),
|
|
1739
1746
|
getAgentId: () => resolvedAgentId,
|
|
@@ -1760,6 +1767,14 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
1760
1767
|
recordEvalSubagentUsage: output => sessionManager.recordEvalSubagentOutput(output),
|
|
1761
1768
|
getClientBridge: () => session?.clientBridge,
|
|
1762
1769
|
queueDeferredDiagnostics: entry => session?.yieldQueue.enqueue(LSP_LATE_DIAGNOSTIC_MESSAGE_TYPE, entry),
|
|
1770
|
+
queueLaunchCompletion: notification =>
|
|
1771
|
+
session?.queueLaunchCompletion(notification) ??
|
|
1772
|
+
Promise.reject(new Error("Session unavailable for launch completion delivery")),
|
|
1773
|
+
registerDisposeCallback: callback => {
|
|
1774
|
+
disposeCallbacks.add(callback);
|
|
1775
|
+
return () => disposeCallbacks.delete(callback);
|
|
1776
|
+
},
|
|
1777
|
+
registerSessionChangeCallback: callback => session?.registerSessionChangeCallback(callback),
|
|
1763
1778
|
bumpFileMutationVersion: path => {
|
|
1764
1779
|
const next = (fileMutationVersions.get(path) ?? 0) + 1;
|
|
1765
1780
|
fileMutationVersions.set(path, next);
|
|
@@ -2674,7 +2689,7 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
2674
2689
|
// a real tool.
|
|
2675
2690
|
//
|
|
2676
2691
|
// It must be a `replace`-mode instance. `PiEditExecArgs` carries
|
|
2677
|
-
// `
|
|
2692
|
+
// `old_string`/`new_string` replacements, which is exactly `replace`'s schema and
|
|
2678
2693
|
// nothing else's — under the default `hashline` mode the frame's args do
|
|
2679
2694
|
// not match the tool's parameters at all. The registry instance follows
|
|
2680
2695
|
// the session's configured mode, so the bridge builds its own.
|
|
@@ -2875,8 +2890,8 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
2875
2890
|
}
|
|
2876
2891
|
}
|
|
2877
2892
|
let appendPrompt: string | undefined = appendParts.length > 0 ? appendParts.join("\n\n") : undefined;
|
|
2878
|
-
// Owned/in-band tool dialects (non-native) require the
|
|
2879
|
-
//
|
|
2893
|
+
// Owned/in-band tool dialects (non-native) require the full functions-
|
|
2894
|
+
// namespace catalog; native tool calling lets the compact name list suffice.
|
|
2880
2895
|
const nativeTools = resolveDialect(settings.get("tools.format"), agent?.state.model ?? model) === undefined;
|
|
2881
2896
|
const promptTools = projectSystemPromptToolMetadata(
|
|
2882
2897
|
tools,
|
|
@@ -2910,6 +2925,10 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
2910
2925
|
eagerTasksAlways,
|
|
2911
2926
|
taskBatch: settings.get("task.batch"),
|
|
2912
2927
|
taskMaxConcurrency: settings.get("task.maxConcurrency"),
|
|
2928
|
+
scoutAvailable: isScoutSpawnable(
|
|
2929
|
+
settings.get("task.disabledAgents") as string[] | undefined,
|
|
2930
|
+
options.spawns ?? "*",
|
|
2931
|
+
),
|
|
2913
2932
|
taskIrcEnabled: !restrictToolNames && isIrcEnabled(settings, options.taskDepth ?? 0),
|
|
2914
2933
|
autoQaEnabled: !restrictToolNames && isAutoQaEnabled(settings),
|
|
2915
2934
|
secretsEnabled,
|
|
@@ -3143,13 +3162,19 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3143
3162
|
const openaiWebsocketSetting = settings.get("providers.openaiWebsockets") ?? "off";
|
|
3144
3163
|
const preferOpenAICodexWebsockets =
|
|
3145
3164
|
openaiWebsocketSetting === "on" ? true : openaiWebsocketSetting === "off" ? false : undefined;
|
|
3146
|
-
const
|
|
3165
|
+
const configuredServiceTierByFamily = hasServiceTierEntry
|
|
3147
3166
|
? (existingSession.serviceTier ?? {})
|
|
3148
3167
|
: buildServiceTierByFamily(
|
|
3149
3168
|
settings.get("tier.openai"),
|
|
3150
3169
|
settings.get("tier.anthropic"),
|
|
3151
3170
|
settings.get("tier.google"),
|
|
3152
3171
|
);
|
|
3172
|
+
const initialServiceTierByFamily = { ...configuredServiceTierByFamily };
|
|
3173
|
+
if (options.openAIServiceTier === null) {
|
|
3174
|
+
delete initialServiceTierByFamily.openai;
|
|
3175
|
+
} else if (options.openAIServiceTier !== undefined) {
|
|
3176
|
+
initialServiceTierByFamily.openai = options.openAIServiceTier;
|
|
3177
|
+
}
|
|
3153
3178
|
|
|
3154
3179
|
// One-shot launch-latency marker: fired the first time the loop dispatches
|
|
3155
3180
|
// a chat request to the provider transport. See onFirstChatDispatch.
|
|
@@ -3252,6 +3277,11 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3252
3277
|
// Restore messages if session has existing data
|
|
3253
3278
|
if (hasExistingSession) {
|
|
3254
3279
|
agent.replaceMessages(existingSession.messages);
|
|
3280
|
+
if (options.openAIServiceTier !== undefined) {
|
|
3281
|
+
sessionManager.appendServiceTierChange(
|
|
3282
|
+
Object.keys(initialServiceTierByFamily).length > 0 ? initialServiceTierByFamily : null,
|
|
3283
|
+
);
|
|
3284
|
+
}
|
|
3255
3285
|
} else {
|
|
3256
3286
|
// Save initial model, thinking level, and service tier for new sessions so they can be restored on resume.
|
|
3257
3287
|
if (model) {
|
|
@@ -3262,8 +3292,10 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3262
3292
|
// classification persists its concrete effort once a real user turn runs.
|
|
3263
3293
|
sessionManager.appendThinkingLevelChange(effectiveThinkingLevel);
|
|
3264
3294
|
}
|
|
3265
|
-
if (Object.keys(initialServiceTierByFamily).length > 0) {
|
|
3266
|
-
sessionManager.appendServiceTierChange(
|
|
3295
|
+
if (options.openAIServiceTier !== undefined || Object.keys(initialServiceTierByFamily).length > 0) {
|
|
3296
|
+
sessionManager.appendServiceTierChange(
|
|
3297
|
+
Object.keys(initialServiceTierByFamily).length > 0 ? initialServiceTierByFamily : null,
|
|
3298
|
+
);
|
|
3267
3299
|
}
|
|
3268
3300
|
}
|
|
3269
3301
|
|
|
@@ -3285,6 +3317,9 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3285
3317
|
const id = sessionManager.getSessionId?.();
|
|
3286
3318
|
return id ? `${id}-advisor` : null;
|
|
3287
3319
|
},
|
|
3320
|
+
queueLaunchCompletion: notification =>
|
|
3321
|
+
session?.queueLaunchCompletion(notification) ??
|
|
3322
|
+
Promise.reject(new Error("Session unavailable for launch completion delivery")),
|
|
3288
3323
|
getAgentId: () => "advisor",
|
|
3289
3324
|
// The primary's availability signals are wrong for advisors: their tool
|
|
3290
3325
|
// slate is filtered separately at runtime (default read/grep/glob, no
|
|
@@ -3341,6 +3376,7 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3341
3376
|
initialAdvisorCosts,
|
|
3342
3377
|
settings,
|
|
3343
3378
|
autoApprove: options.autoApprove,
|
|
3379
|
+
scoutAllowedBySpawnPolicy: isScoutSpawnable(undefined, options.spawns ?? "*"),
|
|
3344
3380
|
evalKernelOwnerId,
|
|
3345
3381
|
// Defined only for top-level sessions (creation is gated above).
|
|
3346
3382
|
// AgentSession uses this to decide whether it may dispose the global
|
|
@@ -3499,6 +3535,8 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3499
3535
|
unsubscribeCredentialDisabled?.();
|
|
3500
3536
|
unsubscribeMcpNotifications?.();
|
|
3501
3537
|
unregisterMcpPostmortem?.();
|
|
3538
|
+
for (const callback of disposeCallbacks) callback();
|
|
3539
|
+
disposeCallbacks.clear();
|
|
3502
3540
|
// Drop refs so the process-global postmortem list doesn't retain
|
|
3503
3541
|
// the bridge closure past explicit dispose.
|
|
3504
3542
|
unsubscribeMcpNotifications = undefined;
|
|
@@ -3543,6 +3581,11 @@ async function createAgentSessionScoped(options: CreateAgentSessionOptions): Pro
|
|
|
3543
3581
|
}
|
|
3544
3582
|
}
|
|
3545
3583
|
|
|
3584
|
+
// Broker-shared language servers: one server per project, multiplexed
|
|
3585
|
+
// across omp instances by the LSP mux daemon. Session-level because the
|
|
3586
|
+
// flag lives in module state consulted on every client cold-start.
|
|
3587
|
+
setSharedLspEnabled(enableLsp && settings.get("lsp.shared"));
|
|
3588
|
+
|
|
3546
3589
|
// Start LSP warmup in the background so startup does not block on language server initialization.
|
|
3547
3590
|
// With `lsp.lazy` (the default) the warmup is skipped: recognized servers are still discovered and
|
|
3548
3591
|
// surfaced in the UI as "available", but cold-start on first use — the lsp tool or an edit/write
|
package/src/secrets/index.ts
CHANGED
|
@@ -203,7 +203,7 @@ export function collectEnvSecrets(): SecretEntry[] {
|
|
|
203
203
|
* API keys) that are NOT configured via secrets.yml or the environment. Without
|
|
204
204
|
* these, such a token in a tool result falls through to pi-ai's irreversible
|
|
205
205
|
* provider-boundary redaction (`[openai_token_redacted]`); the model then echoes
|
|
206
|
-
* that placeholder into edit-tool `
|
|
206
|
+
* that placeholder into edit-tool `old_string`, which can never match the real
|
|
207
207
|
* bytes on disk (issue #6968). Routing the same shapes through the obfuscator
|
|
208
208
|
* mints reversible keyed placeholders that `deobfuscateToolArguments` restores
|
|
209
209
|
* before tool execution, keeping exact-match edits working while the credential
|
|
@@ -1,201 +1,223 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { once } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { scope } from "arktype";
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
-
|
|
4
|
+
export const getSecurityContractSchemas = once(() => {
|
|
5
|
+
// Security schemas validate only during security scans, so lazy construction
|
|
6
|
+
// with interpreted traversal avoids eager JIT startup tax without changing correctness.
|
|
7
|
+
const { type } = scope({}, { jitless: true });
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
name: "string > 0",
|
|
9
|
-
"version?": "string",
|
|
10
|
-
"vendor?": "string",
|
|
11
|
-
"revision?": "string",
|
|
12
|
-
"pluginVersion?": "string",
|
|
13
|
-
});
|
|
9
|
+
const stringRecordSchema = type({ "[string]": "string" });
|
|
10
|
+
const unknownRecordSchema = type({ "[string]": "unknown" });
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"vendorFingerprints?": stringRecordSchema,
|
|
21
|
-
"upstream?": {
|
|
22
|
-
"repository?": "string",
|
|
12
|
+
const securityProducerSchema = type({
|
|
13
|
+
kind: "'omp-native' | 'codex-security-bundle' | 'codex-security-cloud' | 'sarif-import'",
|
|
14
|
+
name: "string > 0",
|
|
15
|
+
"version?": "string",
|
|
16
|
+
"vendor?": "string",
|
|
23
17
|
"revision?": "string",
|
|
24
|
-
"packageVersion?": "string",
|
|
25
18
|
"pluginVersion?": "string",
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
"metadata?": unknownRecordSchema,
|
|
29
|
-
});
|
|
19
|
+
});
|
|
30
20
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
21
|
+
const securityProvenanceSchema = type({
|
|
22
|
+
producer: securityProducerSchema,
|
|
23
|
+
createdAt: "string > 0",
|
|
24
|
+
"importedAt?": "string",
|
|
25
|
+
"sourceIds?": stringRecordSchema,
|
|
26
|
+
"vendorFingerprints?": stringRecordSchema,
|
|
27
|
+
"upstream?": {
|
|
28
|
+
"repository?": "string",
|
|
29
|
+
"revision?": "string",
|
|
30
|
+
"packageVersion?": "string",
|
|
31
|
+
"pluginVersion?": "string",
|
|
32
|
+
"archiveSha256?": "string",
|
|
33
|
+
},
|
|
34
|
+
"metadata?": unknownRecordSchema,
|
|
35
|
+
});
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
});
|
|
37
|
+
const securityLocationSchema = type({
|
|
38
|
+
path: "string > 0",
|
|
39
|
+
startLine: "number.integer >= 1",
|
|
40
|
+
"endLine?": "number.integer >= 1",
|
|
41
|
+
"startColumn?": "number.integer >= 1",
|
|
42
|
+
"endColumn?": "number.integer >= 1",
|
|
43
|
+
"role?": "string",
|
|
44
|
+
});
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
const securityEvidenceSchema = type({
|
|
47
|
+
id: "string > 0",
|
|
48
|
+
kind: "'code' | 'trace' | 'validation' | 'note'",
|
|
49
|
+
label: "string > 0",
|
|
50
|
+
explanation: "string",
|
|
51
|
+
"location?": securityLocationSchema,
|
|
52
|
+
"excerpt?": "string",
|
|
53
|
+
});
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
fingerprint: "string > 0",
|
|
59
|
-
ruleId: "string > 0",
|
|
60
|
-
"anchor?": "string",
|
|
61
|
-
title: "string > 0",
|
|
62
|
-
summary: "string",
|
|
63
|
-
severity: {
|
|
64
|
-
level: "'critical' | 'high' | 'medium' | 'low' | 'informational'",
|
|
65
|
-
"score?": "number",
|
|
66
|
-
"scoringSystem?": "string",
|
|
67
|
-
"vector?": "string",
|
|
68
|
-
"rationale?": "string",
|
|
69
|
-
},
|
|
70
|
-
confidence: {
|
|
71
|
-
level: "'high' | 'medium' | 'low'",
|
|
72
|
-
"rationale?": "string",
|
|
73
|
-
},
|
|
74
|
-
taxonomy: {
|
|
75
|
-
category: "string > 0",
|
|
76
|
-
cwe: "string[]",
|
|
77
|
-
"tags?": "string[]",
|
|
78
|
-
},
|
|
79
|
-
occurrences: securityOccurrenceSchema.array().atLeastLength(1),
|
|
80
|
-
evidence: securityEvidenceSchema.array(),
|
|
81
|
-
"remediation?": "string",
|
|
82
|
-
validation: {
|
|
83
|
-
status: "'unvalidated' | 'validated' | 'rejected' | 'partial' | 'error'",
|
|
84
|
-
"summary?": "string",
|
|
55
|
+
const securityOccurrenceSchema = type({
|
|
56
|
+
id: "string > 0",
|
|
57
|
+
locations: securityLocationSchema.array().atLeastLength(1),
|
|
85
58
|
evidenceIds: "string[]",
|
|
86
|
-
|
|
87
|
-
},
|
|
88
|
-
disposition: {
|
|
89
|
-
status: "'open' | 'false_positive' | 'accepted_risk' | 'fixed' | 'wont_fix'",
|
|
90
|
-
"rationale?": "string",
|
|
91
|
-
"updatedAt?": "string",
|
|
92
|
-
"actor?": "string",
|
|
93
|
-
},
|
|
94
|
-
provenance: securityProvenanceSchema,
|
|
95
|
-
"extensions?": unknownRecordSchema,
|
|
96
|
-
});
|
|
59
|
+
});
|
|
97
60
|
|
|
98
|
-
|
|
99
|
-
mode: "'repository' | 'scoped_path' | 'diff' | 'working_tree' | 'deep_repository' | 'imported'",
|
|
100
|
-
completeness: "'complete' | 'partial' | 'unknown'",
|
|
101
|
-
inventoryStrategy: "'repository' | 'scoped_path' | 'diff' | 'directory' | 'custom' | 'imported'",
|
|
102
|
-
includePaths: "string[]",
|
|
103
|
-
excludePaths: "string[]",
|
|
104
|
-
surfaces: type({
|
|
105
|
-
id: "string > 0",
|
|
106
|
-
label: "string > 0",
|
|
107
|
-
disposition: "'reported' | 'no_issue_found' | 'rejected' | 'not_applicable' | 'needs_follow_up'",
|
|
108
|
-
receiptRefs: "string[]",
|
|
109
|
-
"riskArea?": "string",
|
|
110
|
-
"notes?": "string",
|
|
111
|
-
}).array(),
|
|
112
|
-
explicitExclusions: type({ pattern: "string", reason: "string" }).array(),
|
|
113
|
-
deferred: type({
|
|
61
|
+
const securityFindingSchema = type({
|
|
114
62
|
id: "string > 0",
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
63
|
+
scanId: "string > 0",
|
|
64
|
+
fingerprint: "string > 0",
|
|
65
|
+
ruleId: "string > 0",
|
|
66
|
+
"anchor?": "string",
|
|
67
|
+
title: "string > 0",
|
|
68
|
+
summary: "string",
|
|
69
|
+
severity: {
|
|
70
|
+
level: "'critical' | 'high' | 'medium' | 'low' | 'informational'",
|
|
71
|
+
"score?": "number",
|
|
72
|
+
"scoringSystem?": "string",
|
|
73
|
+
"vector?": "string",
|
|
74
|
+
"rationale?": "string",
|
|
75
|
+
},
|
|
76
|
+
confidence: {
|
|
77
|
+
level: "'high' | 'medium' | 'low'",
|
|
78
|
+
"rationale?": "string",
|
|
79
|
+
},
|
|
80
|
+
taxonomy: {
|
|
81
|
+
category: "string > 0",
|
|
82
|
+
cwe: "string[]",
|
|
83
|
+
"tags?": "string[]",
|
|
84
|
+
},
|
|
85
|
+
occurrences: securityOccurrenceSchema.array().atLeastLength(1),
|
|
86
|
+
evidence: securityEvidenceSchema.array(),
|
|
87
|
+
"remediation?": "string",
|
|
88
|
+
validation: {
|
|
89
|
+
status: "'unvalidated' | 'validated' | 'rejected' | 'partial' | 'error'",
|
|
90
|
+
"summary?": "string",
|
|
91
|
+
evidenceIds: "string[]",
|
|
92
|
+
"validatedAt?": "string",
|
|
93
|
+
},
|
|
94
|
+
disposition: {
|
|
95
|
+
status: "'open' | 'false_positive' | 'accepted_risk' | 'fixed' | 'wont_fix'",
|
|
96
|
+
"rationale?": "string",
|
|
97
|
+
"updatedAt?": "string",
|
|
98
|
+
"actor?": "string",
|
|
99
|
+
},
|
|
100
|
+
provenance: securityProvenanceSchema,
|
|
101
|
+
"extensions?": unknownRecordSchema,
|
|
102
|
+
});
|
|
121
103
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
104
|
+
const securityCoverageSchema = type({
|
|
105
|
+
mode: "'repository' | 'scoped_path' | 'diff' | 'working_tree' | 'deep_repository' | 'imported'",
|
|
106
|
+
completeness: "'complete' | 'partial' | 'unknown'",
|
|
107
|
+
inventoryStrategy: "'repository' | 'scoped_path' | 'diff' | 'directory' | 'custom' | 'imported'",
|
|
108
|
+
includePaths: "string[]",
|
|
109
|
+
excludePaths: "string[]",
|
|
110
|
+
surfaces: type({
|
|
111
|
+
id: "string > 0",
|
|
112
|
+
label: "string > 0",
|
|
113
|
+
disposition: "'reported' | 'no_issue_found' | 'rejected' | 'not_applicable' | 'needs_follow_up'",
|
|
114
|
+
receiptRefs: "string[]",
|
|
115
|
+
"riskArea?": "string",
|
|
116
|
+
"notes?": "string",
|
|
117
|
+
}).array(),
|
|
118
|
+
explicitExclusions: type({ pattern: "string", reason: "string" }).array(),
|
|
119
|
+
deferred: type({
|
|
120
|
+
id: "string > 0",
|
|
121
|
+
reason: "string > 0",
|
|
122
|
+
"paths?": "string[]",
|
|
123
|
+
"surfaceIds?": "string[]",
|
|
124
|
+
}).array(),
|
|
125
|
+
"openQuestions?": type({ question: "string > 0", "followUpPrompt?": "string" }).array(),
|
|
126
|
+
});
|
|
133
127
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
existingState: "'absent' | 'empty' | 'archivable'",
|
|
146
|
-
},
|
|
147
|
-
model: { provider: "string > 0", modelId: "string > 0", "thinkingLevel?": "string" },
|
|
148
|
-
account: {
|
|
149
|
-
provider: "string > 0",
|
|
150
|
-
credentialId: "number.integer >= 1",
|
|
151
|
-
"accountId?": "string",
|
|
152
|
-
"email?": "string",
|
|
153
|
-
"organizationId?": "string",
|
|
154
|
-
"organizationName?": "string",
|
|
155
|
-
},
|
|
156
|
-
configFingerprint: "string > 0",
|
|
157
|
-
workflowFingerprint: "string > 0",
|
|
158
|
-
fingerprint: "string > 0",
|
|
159
|
-
});
|
|
128
|
+
const securityTargetSchema = type({
|
|
129
|
+
kind: "'repository' | 'scoped_path' | 'ref_diff' | 'working_tree' | 'imported'",
|
|
130
|
+
repositoryRoot: "string > 0",
|
|
131
|
+
displayName: "string > 0",
|
|
132
|
+
"revision?": "string",
|
|
133
|
+
"baseRevision?": "string",
|
|
134
|
+
"headRevision?": "string",
|
|
135
|
+
includePaths: "string[]",
|
|
136
|
+
excludePaths: "string[]",
|
|
137
|
+
treeDigest: "string > 0",
|
|
138
|
+
});
|
|
160
139
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
140
|
+
const securityScanPlanSchema = type({
|
|
141
|
+
documentType: "'omp-security.scan-plan'",
|
|
142
|
+
schemaVersion: "'1.0'",
|
|
143
|
+
id: "string > 0",
|
|
144
|
+
createdAt: "string > 0",
|
|
145
|
+
repositoryRoot: "string > 0",
|
|
146
|
+
target: securityTargetSchema,
|
|
147
|
+
knowledgeBases: type({ path: "string > 0", sha256: "string > 0", size: "number.integer >= 0" }).array(),
|
|
148
|
+
output: {
|
|
149
|
+
root: "string > 0",
|
|
150
|
+
archiveExisting: "boolean",
|
|
151
|
+
existingState: "'absent' | 'empty' | 'archivable'",
|
|
152
|
+
},
|
|
153
|
+
model: { provider: "string > 0", modelId: "string > 0", "thinkingLevel?": "string" },
|
|
154
|
+
account: {
|
|
155
|
+
provider: "string > 0",
|
|
156
|
+
credentialId: "number.integer >= 1",
|
|
157
|
+
"accountId?": "string",
|
|
158
|
+
"email?": "string",
|
|
159
|
+
"organizationId?": "string",
|
|
160
|
+
"organizationName?": "string",
|
|
161
|
+
},
|
|
162
|
+
configFingerprint: "string > 0",
|
|
163
|
+
workflowFingerprint: "string > 0",
|
|
164
|
+
fingerprint: "string > 0",
|
|
165
|
+
});
|
|
174
166
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
167
|
+
const securityScanMetricsSchema = type({
|
|
168
|
+
"runtimeMs?": "number >= 0",
|
|
169
|
+
"tokenUsage?": {
|
|
170
|
+
input: "number >= 0",
|
|
171
|
+
output: "number >= 0",
|
|
172
|
+
reasoning: "number >= 0",
|
|
173
|
+
cacheRead: "number >= 0",
|
|
174
|
+
cacheWrite: "number >= 0",
|
|
175
|
+
total: "number >= 0",
|
|
176
|
+
},
|
|
177
|
+
"cost?": "number >= 0",
|
|
178
|
+
"premiumRequests?": "number >= 0",
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const securityScanSchema = type({
|
|
182
|
+
documentType: "'omp-security.scan'",
|
|
183
|
+
schemaVersion: "'1.0'",
|
|
184
|
+
id: "string > 0",
|
|
185
|
+
projectKey: "string > 0",
|
|
186
|
+
status: "'planned' | 'running' | 'completed' | 'partial' | 'cancelled' | 'failed'",
|
|
187
|
+
createdAt: "string > 0",
|
|
188
|
+
"startedAt?": "string",
|
|
189
|
+
"completedAt?": "string",
|
|
190
|
+
"plan?": securityScanPlanSchema,
|
|
191
|
+
target: securityTargetSchema,
|
|
192
|
+
producer: securityProducerSchema,
|
|
193
|
+
provenance: securityProvenanceSchema,
|
|
194
|
+
findingIds: "string[]",
|
|
195
|
+
coverage: securityCoverageSchema,
|
|
196
|
+
"reportRef?": "string",
|
|
197
|
+
"sarifRef?": "string",
|
|
198
|
+
"error?": "string",
|
|
199
|
+
"metrics?": securityScanMetricsSchema,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const securityScanBundleSchema = type({
|
|
203
|
+
scan: securityScanSchema,
|
|
204
|
+
findings: securityFindingSchema.array(),
|
|
205
|
+
"report?": "string",
|
|
206
|
+
"sarif?": unknownRecordSchema,
|
|
207
|
+
});
|
|
195
208
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
209
|
+
return {
|
|
210
|
+
securityProducerSchema,
|
|
211
|
+
securityProvenanceSchema,
|
|
212
|
+
securityLocationSchema,
|
|
213
|
+
securityEvidenceSchema,
|
|
214
|
+
securityOccurrenceSchema,
|
|
215
|
+
securityFindingSchema,
|
|
216
|
+
securityCoverageSchema,
|
|
217
|
+
securityTargetSchema,
|
|
218
|
+
securityScanPlanSchema,
|
|
219
|
+
securityScanMetricsSchema,
|
|
220
|
+
securityScanSchema,
|
|
221
|
+
securityScanBundleSchema,
|
|
222
|
+
};
|
|
201
223
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type } from "arktype";
|
|
2
|
-
import {
|
|
2
|
+
import { getSecurityContractSchemas } from "./schemas";
|
|
3
3
|
import type { SecurityFinding, SecurityScan, SecurityScanBundle, SecurityScanPlan } from "./types";
|
|
4
4
|
|
|
5
5
|
function schemaError(label: string, errors: type.errors): Error {
|
|
@@ -7,24 +7,28 @@ function schemaError(label: string, errors: type.errors): Error {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function parseSecurityFinding(value: unknown): SecurityFinding {
|
|
10
|
+
const { securityFindingSchema } = getSecurityContractSchemas();
|
|
10
11
|
const result = securityFindingSchema(value);
|
|
11
12
|
if (result instanceof type.errors) throw schemaError("Security finding", result);
|
|
12
13
|
return result as SecurityFinding;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function parseSecurityScan(value: unknown): SecurityScan {
|
|
17
|
+
const { securityScanSchema } = getSecurityContractSchemas();
|
|
16
18
|
const result = securityScanSchema(value);
|
|
17
19
|
if (result instanceof type.errors) throw schemaError("Security scan", result);
|
|
18
20
|
return result as SecurityScan;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export function parseSecurityScanPlan(value: unknown): SecurityScanPlan {
|
|
24
|
+
const { securityScanPlanSchema } = getSecurityContractSchemas();
|
|
22
25
|
const result = securityScanPlanSchema(value);
|
|
23
26
|
if (result instanceof type.errors) throw schemaError("Security scan plan", result);
|
|
24
27
|
return result as SecurityScanPlan;
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
export function parseSecurityScanBundle(value: unknown): SecurityScanBundle {
|
|
31
|
+
const { securityScanBundleSchema } = getSecurityContractSchemas();
|
|
28
32
|
const result = securityScanBundleSchema(value);
|
|
29
33
|
if (result instanceof type.errors) throw schemaError("Security scan bundle", result);
|
|
30
34
|
const bundle = result as SecurityScanBundle;
|
package/src/security/store.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { getSecurityProjectDir, isEnoent } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import { withFileLock } from "
|
|
4
|
+
import { withFileLock } from "@oh-my-pi/pi-utils/file-lock";
|
|
5
5
|
import * as git from "../utils/git";
|
|
6
6
|
import { compareSecurityLineage } from "./comparison";
|
|
7
7
|
import type {
|
|
@@ -34,7 +34,7 @@ const SECURITY_STORE_WRITE_CHAINS = new Map<string, Promise<unknown>>();
|
|
|
34
34
|
async function withSecurityStoreWrite<T>(key: string, operation: () => Promise<T>): Promise<T> {
|
|
35
35
|
const lockTarget = path.join(key, "index.json");
|
|
36
36
|
const run = (SECURITY_STORE_WRITE_CHAINS.get(key) ?? Promise.resolve()).then(() =>
|
|
37
|
-
withFileLock(lockTarget, operation, {
|
|
37
|
+
withFileLock(lockTarget, operation, { retries: 200, retryDelayMs: 50 }),
|
|
38
38
|
);
|
|
39
39
|
const guarded = run.catch(() => undefined);
|
|
40
40
|
SECURITY_STORE_WRITE_CHAINS.set(key, guarded);
|