open-multi-agent-kit 0.92.0 → 0.94.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.
Files changed (173) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/README.md +2 -2
  3. package/dist/core/agent-session.d.ts +36 -14
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +155 -357
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/compaction/branch-summarization.d.ts +5 -1
  8. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  9. package/dist/core/compaction/branch-summarization.js +5 -7
  10. package/dist/core/compaction/branch-summarization.js.map +1 -1
  11. package/dist/core/compaction/compaction.d.ts +12 -3
  12. package/dist/core/compaction/compaction.d.ts.map +1 -1
  13. package/dist/core/compaction/compaction.js +28 -15
  14. package/dist/core/compaction/compaction.js.map +1 -1
  15. package/dist/core/extensions/builtin/command-safety-gate.d.ts +8 -0
  16. package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
  17. package/dist/core/extensions/builtin/command-safety-gate.js +23 -0
  18. package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
  19. package/dist/core/extensions/runner.d.ts.map +1 -1
  20. package/dist/core/extensions/runner.js +4 -0
  21. package/dist/core/extensions/runner.js.map +1 -1
  22. package/dist/core/extensions/types.d.ts +2 -0
  23. package/dist/core/extensions/types.d.ts.map +1 -1
  24. package/dist/core/extensions/types.js.map +1 -1
  25. package/dist/core/keybindings.d.ts +5 -0
  26. package/dist/core/keybindings.d.ts.map +1 -1
  27. package/dist/core/keybindings.js +5 -0
  28. package/dist/core/keybindings.js.map +1 -1
  29. package/dist/core/model-resolver.d.ts +41 -3
  30. package/dist/core/model-resolver.d.ts.map +1 -1
  31. package/dist/core/model-resolver.js +17 -9
  32. package/dist/core/model-resolver.js.map +1 -1
  33. package/dist/core/package-manager.d.ts.map +1 -1
  34. package/dist/core/package-manager.js +11 -1
  35. package/dist/core/package-manager.js.map +1 -1
  36. package/dist/core/provider-resilience.d.ts.map +1 -1
  37. package/dist/core/provider-resilience.js +3 -1
  38. package/dist/core/provider-resilience.js.map +1 -1
  39. package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
  40. package/dist/core/reasoning-router-v4-weights.js +9 -3
  41. package/dist/core/reasoning-router-v4-weights.js.map +1 -1
  42. package/dist/core/reasoning-router-v4.d.ts.map +1 -1
  43. package/dist/core/reasoning-router-v4.js +94 -24
  44. package/dist/core/reasoning-router-v4.js.map +1 -1
  45. package/dist/core/resource-loader.d.ts.map +1 -1
  46. package/dist/core/resource-loader.js +11 -5
  47. package/dist/core/resource-loader.js.map +1 -1
  48. package/dist/core/sandbox/default-policy.d.ts +14 -0
  49. package/dist/core/sandbox/default-policy.d.ts.map +1 -0
  50. package/dist/core/sandbox/default-policy.js +58 -0
  51. package/dist/core/sandbox/default-policy.js.map +1 -0
  52. package/dist/core/sdk.d.ts.map +1 -1
  53. package/dist/core/sdk.js +1 -1
  54. package/dist/core/sdk.js.map +1 -1
  55. package/dist/core/session-bash-runtime.d.ts +62 -0
  56. package/dist/core/session-bash-runtime.d.ts.map +1 -0
  57. package/dist/core/session-bash-runtime.js +167 -0
  58. package/dist/core/session-bash-runtime.js.map +1 -0
  59. package/dist/core/session-bash-service.d.ts +61 -0
  60. package/dist/core/session-bash-service.d.ts.map +1 -0
  61. package/dist/core/session-bash-service.js +155 -0
  62. package/dist/core/session-bash-service.js.map +1 -0
  63. package/dist/core/session-compaction-service.d.ts +48 -0
  64. package/dist/core/session-compaction-service.d.ts.map +1 -0
  65. package/dist/core/session-compaction-service.js +250 -0
  66. package/dist/core/session-compaction-service.js.map +1 -0
  67. package/dist/core/session-file-compaction.d.ts.map +1 -1
  68. package/dist/core/session-file-compaction.js +39 -5
  69. package/dist/core/session-file-compaction.js.map +1 -1
  70. package/dist/core/session-termination.d.ts.map +1 -1
  71. package/dist/core/session-termination.js +1 -1
  72. package/dist/core/session-termination.js.map +1 -1
  73. package/dist/core/settings-manager.d.ts +3 -0
  74. package/dist/core/settings-manager.d.ts.map +1 -1
  75. package/dist/core/settings-manager.js +8 -0
  76. package/dist/core/settings-manager.js.map +1 -1
  77. package/dist/core/skills-catalog-cache.d.ts +25 -0
  78. package/dist/core/skills-catalog-cache.d.ts.map +1 -0
  79. package/dist/core/skills-catalog-cache.js +123 -0
  80. package/dist/core/skills-catalog-cache.js.map +1 -0
  81. package/dist/core/skills.d.ts +6 -0
  82. package/dist/core/skills.d.ts.map +1 -1
  83. package/dist/core/skills.js +25 -4
  84. package/dist/core/skills.js.map +1 -1
  85. package/dist/core/system-prompt.d.ts.map +1 -1
  86. package/dist/core/system-prompt.js +2 -2
  87. package/dist/core/system-prompt.js.map +1 -1
  88. package/dist/core/tools/bash.d.ts +5 -0
  89. package/dist/core/tools/bash.d.ts.map +1 -1
  90. package/dist/core/tools/bash.js +41 -13
  91. package/dist/core/tools/bash.js.map +1 -1
  92. package/dist/core/tools/diagnostics.d.ts +29 -0
  93. package/dist/core/tools/diagnostics.d.ts.map +1 -0
  94. package/dist/core/tools/diagnostics.js +325 -0
  95. package/dist/core/tools/diagnostics.js.map +1 -0
  96. package/dist/core/tools/index.d.ts +2 -1
  97. package/dist/core/tools/index.d.ts.map +1 -1
  98. package/dist/core/tools/index.js +18 -1
  99. package/dist/core/tools/index.js.map +1 -1
  100. package/dist/core/verified-bash-adapter.d.ts +18 -1
  101. package/dist/core/verified-bash-adapter.d.ts.map +1 -1
  102. package/dist/core/verified-bash-adapter.js +38 -1
  103. package/dist/core/verified-bash-adapter.js.map +1 -1
  104. package/dist/core/verified-bash-runtime.d.ts +13 -0
  105. package/dist/core/verified-bash-runtime.d.ts.map +1 -0
  106. package/dist/core/verified-bash-runtime.js +81 -0
  107. package/dist/core/verified-bash-runtime.js.map +1 -0
  108. package/dist/index.d.ts +4 -2
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +4 -2
  111. package/dist/index.js.map +1 -1
  112. package/dist/modes/interactive/components/control-panel-box.d.ts +27 -0
  113. package/dist/modes/interactive/components/control-panel-box.d.ts.map +1 -1
  114. package/dist/modes/interactive/components/control-panel-box.js +60 -8
  115. package/dist/modes/interactive/components/control-panel-box.js.map +1 -1
  116. package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
  117. package/dist/modes/interactive/components/control-panel-layout.js +100 -45
  118. package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
  119. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts +9 -0
  120. package/dist/modes/interactive/components/control-panel-runtime-status.d.ts.map +1 -1
  121. package/dist/modes/interactive/components/control-panel-runtime-status.js +10 -8
  122. package/dist/modes/interactive/components/control-panel-runtime-status.js.map +1 -1
  123. package/dist/modes/interactive/components/control-panel-sparkles.d.ts +5 -0
  124. package/dist/modes/interactive/components/control-panel-sparkles.d.ts.map +1 -1
  125. package/dist/modes/interactive/components/control-panel-sparkles.js +14 -9
  126. package/dist/modes/interactive/components/control-panel-sparkles.js.map +1 -1
  127. package/dist/modes/interactive/components/footer.d.ts +10 -0
  128. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  129. package/dist/modes/interactive/components/footer.js +3 -3
  130. package/dist/modes/interactive/components/footer.js.map +1 -1
  131. package/dist/modes/interactive/components/status-sidebar.d.ts +49 -0
  132. package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -0
  133. package/dist/modes/interactive/components/status-sidebar.js +253 -0
  134. package/dist/modes/interactive/components/status-sidebar.js.map +1 -0
  135. package/dist/modes/interactive/interactive-mode.d.ts +9 -0
  136. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  137. package/dist/modes/interactive/interactive-mode.js +94 -20
  138. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  139. package/dist/modes/interactive/theme/omk-neon-control.json +13 -13
  140. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  141. package/dist/modes/rpc/rpc-mode.js +1 -0
  142. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  143. package/dist/types/evidence.d.ts +1 -1
  144. package/dist/types/evidence.d.ts.map +1 -1
  145. package/dist/types/evidence.js.map +1 -1
  146. package/dist/utils/clipboard.d.ts.map +1 -1
  147. package/dist/utils/clipboard.js +19 -8
  148. package/dist/utils/clipboard.js.map +1 -1
  149. package/dist/utils/frontmatter.d.ts.map +1 -1
  150. package/dist/utils/frontmatter.js +31 -5
  151. package/dist/utils/frontmatter.js.map +1 -1
  152. package/docs/compaction.md +7 -0
  153. package/docs/docs.json +4 -0
  154. package/docs/environment-variables.md +94 -0
  155. package/docs/index.md +1 -0
  156. package/docs/rpc.md +5 -2
  157. package/docs/sdk.md +10 -4
  158. package/docs/settings.md +1 -0
  159. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  160. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  161. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  162. package/examples/extensions/gondolin/package-lock.json +2 -2
  163. package/examples/extensions/gondolin/package.json +1 -1
  164. package/examples/extensions/sandbox/package-lock.json +2 -2
  165. package/examples/extensions/sandbox/package.json +1 -1
  166. package/examples/extensions/subagent/agents.test.ts +86 -0
  167. package/examples/extensions/subagent/agents.ts +18 -4
  168. package/examples/extensions/subagent/capabilities.ts +15 -1
  169. package/examples/extensions/subagent/domain-profiles.ts +272 -0
  170. package/examples/extensions/with-deps/package-lock.json +2 -2
  171. package/examples/extensions/with-deps/package.json +1 -1
  172. package/npm-shrinkwrap.json +15 -15
  173. package/package.json +10 -7
@@ -1 +1 @@
1
- {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/types/evidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * Evidence and verification types for OMK v0.80.3+\n *\n * Defines contracts for agent completion evidence, replay persistence,\n * merge gating, and artifact validation.\n */\n\n// ============================================================================\n// Evidence Contract\n// ============================================================================\n\nexport type EvidenceCategory =\n\t| \"feature\"\n\t| \"bugfix\"\n\t| \"refactor\"\n\t| \"research\"\n\t| \"release\"\n\t| \"security\"\n\t| \"docs\"\n\t| \"orchestration\";\n\nexport type EvidenceStatus = \"pending\" | \"gathering\" | \"satisfied\" | \"failed\" | \"waived\";\n\nexport interface EvidenceItem {\n\t/** What this evidence proves. */\n\tclaim: string;\n\t/** Category of the task. */\n\tcategory: EvidenceCategory;\n\t/** Path to artifact or command that produced it. */\n\tartifactPath?: string;\n\t/** Command that can reproduce the evidence. */\n\tverificationCommand?: string;\n\t/** SHA-256 of the artifact for integrity. */\n\thash?: string;\n\t/** When the evidence was gathered. */\n\ttimestamp: string;\n\t/** Whether the evidence is available. */\n\tstatus: EvidenceStatus;\n\t/** Receipt v3 metadata consumed by receipt-aware evidence gates. */\n\treceiptId?: string;\n\treceiptSchemaVersion?: 3;\n\t/** Domain-separated digest of the exact structured command descriptor. */\n\treceiptCommandSha256?: Sha256Hex;\n\t/** Lane that executed the verification command, when lane-scoped. */\n\treceiptLaneId?: string;\n\t/** Reason if evidence is missing or waived. */\n\tgapReason?: string;\n}\n\nexport interface TaskContract {\n\t/** Unique task / goal identifier. */\n\tgoalId: string;\n\t/** One-sentence completion claim. */\n\tcompletionClaim: string;\n\t/** Required evidence items. */\n\trequiredEvidence: EvidenceItem[];\n\t/** Remaining risk note. */\n\tfinalRisk: string;\n\t/** Verdict: can the task be considered done? */\n\tverdict: \"pass\" | \"fail\" | \"conditional\";\n\t/** ISO-8601 timestamp of contract creation. */\n\tcreatedAt: string;\n\t/** ISO-8601 timestamp of last update. */\n\tupdatedAt: string;\n}\n\n// ============================================================================\n// Replay Ledger\n// ============================================================================\n\nexport type ReplayEventType =\n\t| \"session_start\"\n\t| \"tool_call\"\n\t| \"tool_result\"\n\t| \"message\"\n\t| \"guardrail_decision\"\n\t| \"lane_grant\"\n\t| \"merge_attempt\"\n\t| \"merge_blocked\"\n\t| \"evidence_gathered\"\n\t| \"evidence_receipt\"\n\t| \"contract_created\"\n\t| \"contract_updated\"\n\t| \"checkpoint\"\n\t| \"error\"\n\t| \"transcript_repaired\"\n\t| \"tool_timeout\"\n\t| \"tool_late_settlement\"\n\t| \"workspace_mutation\";\n\n/**\n * Payload contract for `workspace_mutation` replay events. Emitters live in the\n * agent runtime; evidence gates consume these fail-closed: an event whose payload\n * does not provably target other paths in the same workspace root is treated as\n * relevant to every scope.\n */\nexport interface WorkspaceMutationReplayPayload {\n\t/** Absolute workspace root the mutation applies to. */\n\treadonly root: string;\n\t/** Root-relative normalized paths that were mutated; empty means unknown/whole workspace. */\n\treadonly paths: readonly string[];\n}\n\n// ============================================================================\n// Execution-bound evidence receipts (v3)\n// ============================================================================\n\ndeclare const SHA256_HEX_BRAND: unique symbol;\n\n/** A validated lowercase SHA-256 digest encoded as exactly 64 hexadecimal characters. */\nexport type Sha256Hex = string & { readonly [SHA256_HEX_BRAND]: \"sha256-hex\" };\n\nexport interface ArgvCommandDescriptor {\n\treadonly kind: \"argv\";\n\t/** Exact executable identity supplied by the caller. */\n\treadonly executable: string;\n\t/** Exact argument boundaries; values are never joined or whitespace-normalized. */\n\treadonly argv: readonly string[];\n}\n\nexport interface ShellCommandDescriptor {\n\treadonly kind: \"shell\";\n\t/** Exact shell identity supplied by the caller. */\n\treadonly shell: string;\n\t/** Exact script bytes decoded as a string; whitespace is significant. */\n\treadonly script: string;\n}\n\nexport type EvidenceCommandDescriptor = ArgvCommandDescriptor | ShellCommandDescriptor;\n\nexport interface MissingArtifactState {\n\treadonly path: string;\n\treadonly state: \"missing\";\n}\n\nexport interface FileArtifactState {\n\treadonly path: string;\n\treadonly state: \"file\";\n\treadonly sha256: Sha256Hex;\n\treadonly size: number;\n}\n\nexport type ArtifactState = MissingArtifactState | FileArtifactState;\n\n/** Trusted caller-selected workspace root and root-relative artifact set. */\nexport interface WorkspaceScope {\n\treadonly root: string;\n\treadonly artifactPaths: readonly string[];\n}\n\n/** A point-in-time digest of only the selected artifact set; not an immutable-workspace proof. */\nexport interface ArtifactSetWorkspaceFingerprint {\n\treadonly kind: \"artifact-set\";\n\treadonly scope: WorkspaceScope;\n\treadonly artifacts: readonly ArtifactState[];\n\treadonly manifestSha256: Sha256Hex;\n}\n\n/** Scope-limited Git workspace facts committed by a git-kind fingerprint. */\nexport interface GitWorkspaceState {\n\t/** Full hex object name of HEAD, or null while HEAD is unborn. */\n\treadonly headCommit: string | null;\n\t/** Sorted root-relative paths git reports changed (staged, unstaged, or untracked) within scope. */\n\treadonly changedPaths: readonly string[];\n\t/** SHA-256 of the scope-limited staged diff bytes (index vs HEAD). */\n\treadonly stagedDiffSha256: Sha256Hex;\n\t/** SHA-256 of the scope-limited unstaged diff bytes (work tree vs index). */\n\treadonly unstagedDiffSha256: Sha256Hex;\n\t/** Canonical digest committing changed paths, both diff digests, and every selected artifact state. */\n\treadonly dirtySha256: Sha256Hex;\n}\n\n/**\n * A point-in-time digest of a Git work-tree root: HEAD, scope-limited staged and\n * unstaged diffs, and direct states for every selected path. Direct states keep\n * ignored and index-flagged work-tree bytes content-bound independently of Git.\n */\nexport interface GitWorkspaceFingerprint {\n\treadonly kind: \"git\";\n\treadonly scope: WorkspaceScope;\n\treadonly artifacts: readonly ArtifactState[];\n\treadonly git: GitWorkspaceState;\n\treadonly manifestSha256: Sha256Hex;\n}\n\nexport type WorkspaceFingerprint = ArtifactSetWorkspaceFingerprint | GitWorkspaceFingerprint;\n\nexport interface EvidenceOutputDigest {\n\treadonly sha256: Sha256Hex;\n\treadonly byteCount: number;\n}\n\n/** Digests only; receipt v3 never carries raw output or excerpts. */\nexport interface EvidenceOutputCapture {\n\treadonly redactionPolicyId: string;\n\treadonly stdout: EvidenceOutputDigest;\n\treadonly stderr: EvidenceOutputDigest;\n}\n\n/** CLI form that produced one or more `[REDACTED]` placeholders in a persisted command. */\nexport type CommandRedactionPlaceholderType =\n\t| \"api-key-header\"\n\t| \"authorization-header\"\n\t| \"basic-auth\"\n\t| \"bearer-token\"\n\t| \"cli-option-inline\"\n\t| \"cli-option-value\"\n\t| \"cookie-header\"\n\t| \"env-assignment\"\n\t| \"known-token\"\n\t| \"url-credential\"\n\t| \"url-query\";\n\nexport interface CommandRedactionPlaceholder {\n\treadonly type: CommandRedactionPlaceholderType;\n\treadonly count: number;\n}\n\n/** Bounded description of the placeholders applied to a persisted redacted command. */\nexport interface CommandRedactionSummary {\n\treadonly policyId: string;\n\t/** Unique types in ascending order; empty when nothing was redacted. */\n\treadonly placeholders: readonly CommandRedactionPlaceholder[];\n}\n\n/**\n * Keyed commitment to the original (pre-redaction) command. The HMAC key is\n * process-internal and never persisted or exported, so this value is not\n * verifiable (and not brute-forceable) outside the executing trust boundary.\n */\nexport interface CommandHmacBinding {\n\treadonly algorithm: \"hmac-sha256\";\n\t/** Identifies the ephemeral process key generation, not the key itself. */\n\treadonly keyId: string;\n\t/** Per-binding random nonce; makes persisted MACs non-comparable. */\n\treadonly nonce: string;\n\treadonly mac: Sha256Hex;\n}\n\nexport type EvidenceReceiptStatus = \"passed\" | \"failed\" | \"timeout\" | \"aborted\";\n\nexport type EvidenceReceiptDisposition =\n\t| { readonly status: \"passed\"; readonly exitCode: 0 }\n\t| { readonly status: \"failed\"; readonly exitCode: number }\n\t| { readonly status: \"timeout\"; readonly exitCode: null }\n\t| { readonly status: \"aborted\"; readonly exitCode: null };\n\nexport type EvidenceExecutor = \"bash-tool\" | \"ci-runner\" | \"mcp\" | \"internal\";\n\nexport interface EvidenceReceiptCoreFields {\n\treadonly schemaVersion: 3;\n\treadonly receiptId: string;\n\treadonly goalId: string;\n\treadonly laneId?: string;\n\treadonly claim: string;\n\treadonly command: EvidenceCommandDescriptor;\n\treadonly cwd: string;\n\treadonly timeoutMs: number | null;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly durationMs: number;\n\treadonly workspaceBefore: WorkspaceFingerprint;\n\treadonly workspaceAfter: WorkspaceFingerprint;\n\treadonly output: EvidenceOutputCapture;\n\treadonly executor: EvidenceExecutor;\n\treadonly toolCallId?: string;\n\t/** Redaction metadata for the persisted `command` representation. */\n\treadonly commandRedaction?: CommandRedactionSummary;\n\t/** Keyed binding of the ORIGINAL command; required when placeholders were applied. */\n\treadonly commandBinding?: CommandHmacBinding;\n}\n\n/** Immutable execution facts. Envelope metadata is deliberately excluded from this core. */\nexport type EvidenceReceiptCore = EvidenceReceiptCoreFields & EvidenceReceiptDisposition;\n\nexport interface EvidenceReceiptLedgerBinding {\n\treadonly seq: number;\n\treadonly eventHash: Sha256Hex;\n}\n\n/**\n * Opaque metadata for an attestation verified by a separately configured trust anchor.\n * Its presence alone does not make a receipt trusted proof.\n */\nexport interface TrustedEvidenceAttestation {\n\treadonly attesterId: string;\n\treadonly keyId: string;\n\treadonly algorithm: \"ed25519\";\n\treadonly signature: string;\n\treadonly issuedAt: string;\n}\n\nexport interface EvidenceReceiptEnvelope {\n\treadonly coreSha256: Sha256Hex;\n\treadonly ledgerBinding?: EvidenceReceiptLedgerBinding;\n\treadonly trustedAttestation?: TrustedEvidenceAttestation;\n}\n\nexport interface EvidenceReceipt {\n\treadonly core: EvidenceReceiptCore;\n\treadonly envelope: EvidenceReceiptEnvelope;\n}\n\n/** Replay payload intentionally commits only the immutable core, avoiding a ledger/hash cycle. */\nexport interface EvidenceReceiptReplayPayload {\n\treadonly receiptId: string;\n\treadonly coreSha256: Sha256Hex;\n}\n\nexport interface ReplayEvent {\n\t/** Monotonic sequence number within a session. */\n\tseq: number;\n\t/** Event type. */\n\ttype: ReplayEventType;\n\t/** ISO-8601 timestamp. */\n\ttimestamp: string;\n\t/** Goal or session identifier. */\n\tgoalId: string;\n\t/** Optional lane identifier. */\n\tlaneId?: string;\n\t/** Event-specific payload. */\n\tpayload: unknown;\n\t/** SHA-256 of the serialized payload for integrity. */\n\tpayloadHash: string;\n\t/** eventHash of the previous event in the chain (\"genesis\" for the first event). */\n\tprevHash: string;\n\t/** SHA-256 over [seq, type, timestamp, goalId, laneId, payloadHash, prevHash]. */\n\teventHash: string;\n}\n\nexport interface ReplayLedgerFileIdentity {\n\treadonly dev: string;\n\treadonly ino: string;\n}\n\n/** Durable CAS tuple published atomically beside the replay JSONL. */\nexport interface ReplayLedgerHead {\n\treadonly fileIdentity: ReplayLedgerFileIdentity | null;\n\treadonly size: number;\n\treadonly lastSeq: number;\n\treadonly lastHash: string;\n}\n\n/** One chain- and committed-head-verified point-in-time ledger source. */\nexport interface VerifiedReplayLedgerSnapshot {\n\treadonly events: readonly ReplayEvent[];\n\treadonly head: ReplayLedgerHead;\n}\n\nexport interface ReplayLedger {\n\t/** Session / goal this ledger belongs to. */\n\tgoalId: string;\n\t/** Ordered event log. */\n\tevents: ReplayEvent[];\n\t/** Path where the ledger is persisted. */\n\tledgerPath: string;\n\t/** Last persisted sequence number. */\n\tlastPersistedSeq: number;\n}\n\n// ============================================================================\n// Merge Gates\n// ============================================================================\n\nexport type MergeGateStatus = \"open\" | \"blocked\" | \"conditional\";\n\n/** Compatibility policy for execution-bound evidence receipts. */\nexport type EvidenceReceiptMode = \"strict\" | \"prefer\" | \"legacy\";\n\nexport interface MergeGateResult {\n\t/** Gate identifier. */\n\tgateId: string;\n\t/** Current status. */\n\tstatus: MergeGateStatus;\n\t/** Human-readable reason. */\n\treason: string;\n\t/** Suggested remediation. */\n\tsuggestion?: string;\n\t/** Evidence that was checked. */\n\tevidenceChecked: EvidenceItem[];\n}\n\nexport interface EvidenceGateCheck {\n\t/** Which evidence item was checked. */\n\tevidenceClaim: string;\n\t/** Whether it is satisfied. */\n\tsatisfied: boolean;\n\t/** Reason if not satisfied. */\n\treason?: string;\n}\n\n// ============================================================================\n// Verify Reporter v2\n// ============================================================================\n\nexport interface OmkVerifyResultV2 {\n\tgoalId: string;\n\tstatus: \"completed\" | \"failed\" | \"blocked\" | \"partial\";\n\tsummary: string;\n\tchangedFiles: string[];\n\tevidence: EvidenceItem[];\n\trisks: string[];\n\tnextAction: string;\n\t/** Associated task contract. */\n\tcontract?: TaskContract;\n\t/** Replay ledger path. */\n\treplayLedgerPath?: string;\n\t/** Merge gate results. */\n\tmergeGates: MergeGateResult[];\n}\n\nexport interface CiReportV2 {\n\tgoalId: string;\n\tstatus: string;\n\tsummary: string;\n\tchangedFilesCount: number;\n\tevidenceCount: number;\n\trisks: string[];\n\tmarkdown: string;\n\tcontractVerdict?: string;\n\tmergeGateStatus?: string;\n}\n"]}
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/types/evidence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * Evidence and verification types for OMK v0.80.3+\n *\n * Defines contracts for agent completion evidence, replay persistence,\n * merge gating, and artifact validation.\n */\n\n// ============================================================================\n// Evidence Contract\n// ============================================================================\n\nexport type EvidenceCategory =\n\t| \"feature\"\n\t| \"bugfix\"\n\t| \"refactor\"\n\t| \"research\"\n\t| \"release\"\n\t| \"security\"\n\t| \"docs\"\n\t| \"orchestration\";\n\nexport type EvidenceStatus = \"pending\" | \"gathering\" | \"satisfied\" | \"failed\" | \"waived\";\n\nexport interface EvidenceItem {\n\t/** What this evidence proves. */\n\tclaim: string;\n\t/** Category of the task. */\n\tcategory: EvidenceCategory;\n\t/** Path to artifact or command that produced it. */\n\tartifactPath?: string;\n\t/** Command that can reproduce the evidence. */\n\tverificationCommand?: string;\n\t/** SHA-256 of the artifact for integrity. */\n\thash?: string;\n\t/** When the evidence was gathered. */\n\ttimestamp: string;\n\t/** Whether the evidence is available. */\n\tstatus: EvidenceStatus;\n\t/** Receipt v3 metadata consumed by receipt-aware evidence gates. */\n\treceiptId?: string;\n\treceiptSchemaVersion?: 3;\n\t/** Domain-separated digest of the exact structured command descriptor. */\n\treceiptCommandSha256?: Sha256Hex;\n\t/** Lane that executed the verification command, when lane-scoped. */\n\treceiptLaneId?: string;\n\t/** Reason if evidence is missing or waived. */\n\tgapReason?: string;\n}\n\nexport interface TaskContract {\n\t/** Unique task / goal identifier. */\n\tgoalId: string;\n\t/** One-sentence completion claim. */\n\tcompletionClaim: string;\n\t/** Required evidence items. */\n\trequiredEvidence: EvidenceItem[];\n\t/** Remaining risk note. */\n\tfinalRisk: string;\n\t/** Verdict: can the task be considered done? */\n\tverdict: \"pass\" | \"fail\" | \"conditional\";\n\t/** ISO-8601 timestamp of contract creation. */\n\tcreatedAt: string;\n\t/** ISO-8601 timestamp of last update. */\n\tupdatedAt: string;\n}\n\n// ============================================================================\n// Replay Ledger\n// ============================================================================\n\nexport type ReplayEventType =\n\t| \"session_start\"\n\t| \"tool_call\"\n\t| \"tool_result\"\n\t| \"message\"\n\t| \"guardrail_decision\"\n\t| \"lane_grant\"\n\t| \"merge_attempt\"\n\t| \"merge_blocked\"\n\t| \"evidence_gathered\"\n\t| \"evidence_receipt\"\n\t| \"contract_created\"\n\t| \"contract_updated\"\n\t| \"checkpoint\"\n\t| \"error\"\n\t| \"transcript_repaired\"\n\t| \"tool_timeout\"\n\t| \"tool_late_settlement\"\n\t| \"workspace_mutation\"\n\t| \"sandbox_audit\";\n\n/**\n * Payload contract for `workspace_mutation` replay events. Emitters live in the\n * agent runtime; evidence gates consume these fail-closed: an event whose payload\n * does not provably target other paths in the same workspace root is treated as\n * relevant to every scope.\n */\nexport interface WorkspaceMutationReplayPayload {\n\t/** Absolute workspace root the mutation applies to. */\n\treadonly root: string;\n\t/** Root-relative normalized paths that were mutated; empty means unknown/whole workspace. */\n\treadonly paths: readonly string[];\n}\n\n// ============================================================================\n// Execution-bound evidence receipts (v3)\n// ============================================================================\n\ndeclare const SHA256_HEX_BRAND: unique symbol;\n\n/** A validated lowercase SHA-256 digest encoded as exactly 64 hexadecimal characters. */\nexport type Sha256Hex = string & { readonly [SHA256_HEX_BRAND]: \"sha256-hex\" };\n\nexport interface ArgvCommandDescriptor {\n\treadonly kind: \"argv\";\n\t/** Exact executable identity supplied by the caller. */\n\treadonly executable: string;\n\t/** Exact argument boundaries; values are never joined or whitespace-normalized. */\n\treadonly argv: readonly string[];\n}\n\nexport interface ShellCommandDescriptor {\n\treadonly kind: \"shell\";\n\t/** Exact shell identity supplied by the caller. */\n\treadonly shell: string;\n\t/** Exact script bytes decoded as a string; whitespace is significant. */\n\treadonly script: string;\n}\n\nexport type EvidenceCommandDescriptor = ArgvCommandDescriptor | ShellCommandDescriptor;\n\nexport interface MissingArtifactState {\n\treadonly path: string;\n\treadonly state: \"missing\";\n}\n\nexport interface FileArtifactState {\n\treadonly path: string;\n\treadonly state: \"file\";\n\treadonly sha256: Sha256Hex;\n\treadonly size: number;\n}\n\nexport type ArtifactState = MissingArtifactState | FileArtifactState;\n\n/** Trusted caller-selected workspace root and root-relative artifact set. */\nexport interface WorkspaceScope {\n\treadonly root: string;\n\treadonly artifactPaths: readonly string[];\n}\n\n/** A point-in-time digest of only the selected artifact set; not an immutable-workspace proof. */\nexport interface ArtifactSetWorkspaceFingerprint {\n\treadonly kind: \"artifact-set\";\n\treadonly scope: WorkspaceScope;\n\treadonly artifacts: readonly ArtifactState[];\n\treadonly manifestSha256: Sha256Hex;\n}\n\n/** Scope-limited Git workspace facts committed by a git-kind fingerprint. */\nexport interface GitWorkspaceState {\n\t/** Full hex object name of HEAD, or null while HEAD is unborn. */\n\treadonly headCommit: string | null;\n\t/** Sorted root-relative paths git reports changed (staged, unstaged, or untracked) within scope. */\n\treadonly changedPaths: readonly string[];\n\t/** SHA-256 of the scope-limited staged diff bytes (index vs HEAD). */\n\treadonly stagedDiffSha256: Sha256Hex;\n\t/** SHA-256 of the scope-limited unstaged diff bytes (work tree vs index). */\n\treadonly unstagedDiffSha256: Sha256Hex;\n\t/** Canonical digest committing changed paths, both diff digests, and every selected artifact state. */\n\treadonly dirtySha256: Sha256Hex;\n}\n\n/**\n * A point-in-time digest of a Git work-tree root: HEAD, scope-limited staged and\n * unstaged diffs, and direct states for every selected path. Direct states keep\n * ignored and index-flagged work-tree bytes content-bound independently of Git.\n */\nexport interface GitWorkspaceFingerprint {\n\treadonly kind: \"git\";\n\treadonly scope: WorkspaceScope;\n\treadonly artifacts: readonly ArtifactState[];\n\treadonly git: GitWorkspaceState;\n\treadonly manifestSha256: Sha256Hex;\n}\n\nexport type WorkspaceFingerprint = ArtifactSetWorkspaceFingerprint | GitWorkspaceFingerprint;\n\nexport interface EvidenceOutputDigest {\n\treadonly sha256: Sha256Hex;\n\treadonly byteCount: number;\n}\n\n/** Digests only; receipt v3 never carries raw output or excerpts. */\nexport interface EvidenceOutputCapture {\n\treadonly redactionPolicyId: string;\n\treadonly stdout: EvidenceOutputDigest;\n\treadonly stderr: EvidenceOutputDigest;\n}\n\n/** CLI form that produced one or more `[REDACTED]` placeholders in a persisted command. */\nexport type CommandRedactionPlaceholderType =\n\t| \"api-key-header\"\n\t| \"authorization-header\"\n\t| \"basic-auth\"\n\t| \"bearer-token\"\n\t| \"cli-option-inline\"\n\t| \"cli-option-value\"\n\t| \"cookie-header\"\n\t| \"env-assignment\"\n\t| \"known-token\"\n\t| \"url-credential\"\n\t| \"url-query\";\n\nexport interface CommandRedactionPlaceholder {\n\treadonly type: CommandRedactionPlaceholderType;\n\treadonly count: number;\n}\n\n/** Bounded description of the placeholders applied to a persisted redacted command. */\nexport interface CommandRedactionSummary {\n\treadonly policyId: string;\n\t/** Unique types in ascending order; empty when nothing was redacted. */\n\treadonly placeholders: readonly CommandRedactionPlaceholder[];\n}\n\n/**\n * Keyed commitment to the original (pre-redaction) command. The HMAC key is\n * process-internal and never persisted or exported, so this value is not\n * verifiable (and not brute-forceable) outside the executing trust boundary.\n */\nexport interface CommandHmacBinding {\n\treadonly algorithm: \"hmac-sha256\";\n\t/** Identifies the ephemeral process key generation, not the key itself. */\n\treadonly keyId: string;\n\t/** Per-binding random nonce; makes persisted MACs non-comparable. */\n\treadonly nonce: string;\n\treadonly mac: Sha256Hex;\n}\n\nexport type EvidenceReceiptStatus = \"passed\" | \"failed\" | \"timeout\" | \"aborted\";\n\nexport type EvidenceReceiptDisposition =\n\t| { readonly status: \"passed\"; readonly exitCode: 0 }\n\t| { readonly status: \"failed\"; readonly exitCode: number }\n\t| { readonly status: \"timeout\"; readonly exitCode: null }\n\t| { readonly status: \"aborted\"; readonly exitCode: null };\n\nexport type EvidenceExecutor = \"bash-tool\" | \"ci-runner\" | \"mcp\" | \"internal\";\n\nexport interface EvidenceReceiptCoreFields {\n\treadonly schemaVersion: 3;\n\treadonly receiptId: string;\n\treadonly goalId: string;\n\treadonly laneId?: string;\n\treadonly claim: string;\n\treadonly command: EvidenceCommandDescriptor;\n\treadonly cwd: string;\n\treadonly timeoutMs: number | null;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly durationMs: number;\n\treadonly workspaceBefore: WorkspaceFingerprint;\n\treadonly workspaceAfter: WorkspaceFingerprint;\n\treadonly output: EvidenceOutputCapture;\n\treadonly executor: EvidenceExecutor;\n\treadonly toolCallId?: string;\n\t/** Redaction metadata for the persisted `command` representation. */\n\treadonly commandRedaction?: CommandRedactionSummary;\n\t/** Keyed binding of the ORIGINAL command; required when placeholders were applied. */\n\treadonly commandBinding?: CommandHmacBinding;\n}\n\n/** Immutable execution facts. Envelope metadata is deliberately excluded from this core. */\nexport type EvidenceReceiptCore = EvidenceReceiptCoreFields & EvidenceReceiptDisposition;\n\nexport interface EvidenceReceiptLedgerBinding {\n\treadonly seq: number;\n\treadonly eventHash: Sha256Hex;\n}\n\n/**\n * Opaque metadata for an attestation verified by a separately configured trust anchor.\n * Its presence alone does not make a receipt trusted proof.\n */\nexport interface TrustedEvidenceAttestation {\n\treadonly attesterId: string;\n\treadonly keyId: string;\n\treadonly algorithm: \"ed25519\";\n\treadonly signature: string;\n\treadonly issuedAt: string;\n}\n\nexport interface EvidenceReceiptEnvelope {\n\treadonly coreSha256: Sha256Hex;\n\treadonly ledgerBinding?: EvidenceReceiptLedgerBinding;\n\treadonly trustedAttestation?: TrustedEvidenceAttestation;\n}\n\nexport interface EvidenceReceipt {\n\treadonly core: EvidenceReceiptCore;\n\treadonly envelope: EvidenceReceiptEnvelope;\n}\n\n/** Replay payload intentionally commits only the immutable core, avoiding a ledger/hash cycle. */\nexport interface EvidenceReceiptReplayPayload {\n\treadonly receiptId: string;\n\treadonly coreSha256: Sha256Hex;\n}\n\nexport interface ReplayEvent {\n\t/** Monotonic sequence number within a session. */\n\tseq: number;\n\t/** Event type. */\n\ttype: ReplayEventType;\n\t/** ISO-8601 timestamp. */\n\ttimestamp: string;\n\t/** Goal or session identifier. */\n\tgoalId: string;\n\t/** Optional lane identifier. */\n\tlaneId?: string;\n\t/** Event-specific payload. */\n\tpayload: unknown;\n\t/** SHA-256 of the serialized payload for integrity. */\n\tpayloadHash: string;\n\t/** eventHash of the previous event in the chain (\"genesis\" for the first event). */\n\tprevHash: string;\n\t/** SHA-256 over [seq, type, timestamp, goalId, laneId, payloadHash, prevHash]. */\n\teventHash: string;\n}\n\nexport interface ReplayLedgerFileIdentity {\n\treadonly dev: string;\n\treadonly ino: string;\n}\n\n/** Durable CAS tuple published atomically beside the replay JSONL. */\nexport interface ReplayLedgerHead {\n\treadonly fileIdentity: ReplayLedgerFileIdentity | null;\n\treadonly size: number;\n\treadonly lastSeq: number;\n\treadonly lastHash: string;\n}\n\n/** One chain- and committed-head-verified point-in-time ledger source. */\nexport interface VerifiedReplayLedgerSnapshot {\n\treadonly events: readonly ReplayEvent[];\n\treadonly head: ReplayLedgerHead;\n}\n\nexport interface ReplayLedger {\n\t/** Session / goal this ledger belongs to. */\n\tgoalId: string;\n\t/** Ordered event log. */\n\tevents: ReplayEvent[];\n\t/** Path where the ledger is persisted. */\n\tledgerPath: string;\n\t/** Last persisted sequence number. */\n\tlastPersistedSeq: number;\n}\n\n// ============================================================================\n// Merge Gates\n// ============================================================================\n\nexport type MergeGateStatus = \"open\" | \"blocked\" | \"conditional\";\n\n/** Compatibility policy for execution-bound evidence receipts. */\nexport type EvidenceReceiptMode = \"strict\" | \"prefer\" | \"legacy\";\n\nexport interface MergeGateResult {\n\t/** Gate identifier. */\n\tgateId: string;\n\t/** Current status. */\n\tstatus: MergeGateStatus;\n\t/** Human-readable reason. */\n\treason: string;\n\t/** Suggested remediation. */\n\tsuggestion?: string;\n\t/** Evidence that was checked. */\n\tevidenceChecked: EvidenceItem[];\n}\n\nexport interface EvidenceGateCheck {\n\t/** Which evidence item was checked. */\n\tevidenceClaim: string;\n\t/** Whether it is satisfied. */\n\tsatisfied: boolean;\n\t/** Reason if not satisfied. */\n\treason?: string;\n}\n\n// ============================================================================\n// Verify Reporter v2\n// ============================================================================\n\nexport interface OmkVerifyResultV2 {\n\tgoalId: string;\n\tstatus: \"completed\" | \"failed\" | \"blocked\" | \"partial\";\n\tsummary: string;\n\tchangedFiles: string[];\n\tevidence: EvidenceItem[];\n\trisks: string[];\n\tnextAction: string;\n\t/** Associated task contract. */\n\tcontract?: TaskContract;\n\t/** Replay ledger path. */\n\treplayLedgerPath?: string;\n\t/** Merge gate results. */\n\tmergeGates: MergeGateResult[];\n}\n\nexport interface CiReportV2 {\n\tgoalId: string;\n\tstatus: string;\n\tsummary: string;\n\tchangedFilesCount: number;\n\tevidenceCount: number;\n\trisks: string[];\n\tmarkdown: string;\n\tcontractVerdict?: string;\n\tmergeGateStatus?: string;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"AAkCA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4FjE","sourcesContent":["import { execSync, spawn } from \"child_process\";\nimport { platform } from \"os\";\nimport { isWaylandSession } from \"./clipboard-image.ts\";\nimport { clipboard } from \"./clipboard-native.ts\";\n\ntype NativeClipboardExecOptions = {\n\tinput: string;\n\ttimeout: number;\n\tstdio: [\"pipe\", \"ignore\", \"ignore\"];\n};\n\nfunction copyToX11Clipboard(options: NativeClipboardExecOptions): void {\n\ttry {\n\t\texecSync(\"xclip -selection clipboard\", options);\n\t} catch {\n\t\texecSync(\"xsel --clipboard --input\", options);\n\t}\n}\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tlet copied = false;\n\n\tconst p = platform();\n\n\t// Prefer direct clipboard writes. Emitting OSC 52 first can make terminals\n\t// write the same native clipboard concurrently with the addon, and very large\n\t// OSC 52 payloads can desynchronize terminal rendering.\n\t//\n\t// On Linux, skip the native addon. The underlying `clipboard-rs` crate is\n\t// X11-only and does not retain selection ownership after `set_text`\n\t// resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even\n\t// some X11 sessions the call resolves successfully without populating the\n\t// clipboard. The platform tools below (wl-copy, xclip, xsel) properly\n\t// daemonize and keep ownership.\n\ttry {\n\t\tif (clipboard && p !== \"linux\") {\n\t\t\tawait clipboard.setText(text);\n\t\t\tcopied = true;\n\t\t}\n\t} catch {\n\t\t// Fall through to platform-specific clipboard tools.\n\t}\n\n\tconst remote = isRemoteSession();\n\tif (copied && !remote) {\n\t\treturn;\n\t}\n\n\tconst options: NativeClipboardExecOptions = { input: text, timeout: 5000, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n\n\tif (!copied) {\n\t\ttry {\n\t\t\tif (p === \"darwin\") {\n\t\t\t\texecSync(\"pbcopy\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else if (p === \"win32\") {\n\t\t\t\texecSync(\"clip\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else {\n\t\t\t\t// Linux. Try Termux, Wayland, or X11 clipboard tools.\n\t\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\texecSync(\"termux-clipboard-set\", options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to Wayland or X11 tools.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!copied) {\n\t\t\t\t\tconst hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n\t\t\t\t\tconst hasX11Display = Boolean(process.env.DISPLAY);\n\t\t\t\t\tconst isWayland = isWaylandSession();\n\t\t\t\t\tif (isWayland && hasWaylandDisplay) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Verify wl-copy exists (spawn errors are async and won't be caught)\n\t\t\t\t\t\t\texecSync(\"which wl-copy\", { stdio: \"ignore\" });\n\t\t\t\t\t\t\t// wl-copy with execSync hangs due to fork behavior; use spawn instead\n\t\t\t\t\t\t\tconst proc = spawn(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n\t\t\t\t\t\t\tproc.stdin.on(\"error\", () => {\n\t\t\t\t\t\t\t\t// Ignore EPIPE errors if wl-copy exits early\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tproc.stdin.write(text);\n\t\t\t\t\t\t\tproc.stdin.end();\n\t\t\t\t\t\t\tproc.unref();\n\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tif (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to OSC 52 fallback.\n\t\t}\n\t}\n\n\tif (remote || !copied) {\n\t\tconst osc52Copied = emitOsc52(text);\n\t\tcopied = copied || osc52Copied;\n\t}\n\n\tif (!copied) {\n\t\tthrow new Error(\"Failed to copy to clipboard\");\n\t}\n}\n"]}
1
+ {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"AAkCA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsGjE","sourcesContent":["import { execSync, spawn } from \"child_process\";\nimport { platform } from \"os\";\nimport { isWaylandSession } from \"./clipboard-image.ts\";\nimport { clipboard } from \"./clipboard-native.ts\";\n\ntype NativeClipboardExecOptions = {\n\tinput: string;\n\ttimeout: number;\n\tstdio: [\"pipe\", \"ignore\", \"ignore\"];\n};\n\nfunction copyToX11Clipboard(options: NativeClipboardExecOptions): void {\n\ttry {\n\t\texecSync(\"xclip -selection clipboard\", options);\n\t} catch {\n\t\texecSync(\"xsel --clipboard --input\", options);\n\t}\n}\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tlet copied = false;\n\n\tconst p = platform();\n\n\t// Prefer direct clipboard writes. Emitting OSC 52 first can make terminals\n\t// write the same native clipboard concurrently with the addon, and very large\n\t// OSC 52 payloads can desynchronize terminal rendering.\n\t//\n\t// On Linux, skip the native addon. The underlying `clipboard-rs` crate is\n\t// X11-only and does not retain selection ownership after `set_text`\n\t// resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even\n\t// some X11 sessions the call resolves successfully without populating the\n\t// clipboard. The platform tools below (wl-copy, xclip, xsel) properly\n\t// daemonize and keep ownership.\n\ttry {\n\t\tif (clipboard && p !== \"linux\") {\n\t\t\tawait clipboard.setText(text);\n\t\t\tcopied = true;\n\t\t}\n\t} catch {\n\t\t// Fall through to platform-specific clipboard tools.\n\t}\n\n\tconst remote = isRemoteSession();\n\tif (copied && !remote) {\n\t\treturn;\n\t}\n\n\tconst options: NativeClipboardExecOptions = { input: text, timeout: 5000, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n\n\tif (!copied) {\n\t\ttry {\n\t\t\tif (p === \"darwin\") {\n\t\t\t\texecSync(\"pbcopy\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else if (p === \"win32\") {\n\t\t\t\texecSync(\"clip\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else {\n\t\t\t\t// Linux. Try Termux, Wayland, or X11 clipboard tools.\n\t\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\texecSync(\"termux-clipboard-set\", options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to Wayland or X11 tools.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!copied) {\n\t\t\t\t\tconst hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n\t\t\t\t\tconst hasX11Display = Boolean(process.env.DISPLAY);\n\t\t\t\t\tconst isWayland = isWaylandSession();\n\t\t\t\t\tif (isWayland && hasWaylandDisplay) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Verify wl-copy exists (spawn errors are async and won't be caught)\n\t\t\t\t\t\t\texecSync(\"which wl-copy\", { stdio: \"ignore\" });\n\t\t\t\t\t\t\t// wl-copy with execSync hangs due to fork behavior; use spawn instead.\n\t\t\t\t\t\t\t// Await the exit code and only claim success on a clean exit, so a\n\t\t\t\t\t\t\t// failed wl-copy falls through to the xclip/OSC 52 fallbacks.\n\t\t\t\t\t\t\tconst wlCopyExit = await new Promise<number>((resolve) => {\n\t\t\t\t\t\t\t\tconst proc = spawn(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n\t\t\t\t\t\t\t\tproc.on(\"error\", () => resolve(1));\n\t\t\t\t\t\t\t\tproc.on(\"close\", (code) => resolve(code ?? 1));\n\t\t\t\t\t\t\t\tproc.stdin.on(\"error\", () => {\n\t\t\t\t\t\t\t\t\t// Ignore EPIPE errors if wl-copy exits early\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tproc.stdin.write(text);\n\t\t\t\t\t\t\t\tproc.stdin.end();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (wlCopyExit === 0) {\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tif (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to OSC 52 fallback.\n\t\t}\n\t}\n\n\tif (remote || !copied) {\n\t\tconst osc52Copied = emitOsc52(text);\n\t\tcopied = copied || osc52Copied;\n\t}\n\n\tif (!copied) {\n\t\tthrow new Error(\"Failed to copy to clipboard\");\n\t}\n}\n"]}
@@ -78,15 +78,26 @@ export async function copyToClipboard(text) {
78
78
  try {
79
79
  // Verify wl-copy exists (spawn errors are async and won't be caught)
80
80
  execSync("which wl-copy", { stdio: "ignore" });
81
- // wl-copy with execSync hangs due to fork behavior; use spawn instead
82
- const proc = spawn("wl-copy", [], { stdio: ["pipe", "ignore", "ignore"] });
83
- proc.stdin.on("error", () => {
84
- // Ignore EPIPE errors if wl-copy exits early
81
+ // wl-copy with execSync hangs due to fork behavior; use spawn instead.
82
+ // Await the exit code and only claim success on a clean exit, so a
83
+ // failed wl-copy falls through to the xclip/OSC 52 fallbacks.
84
+ const wlCopyExit = await new Promise((resolve) => {
85
+ const proc = spawn("wl-copy", [], { stdio: ["pipe", "ignore", "ignore"] });
86
+ proc.on("error", () => resolve(1));
87
+ proc.on("close", (code) => resolve(code ?? 1));
88
+ proc.stdin.on("error", () => {
89
+ // Ignore EPIPE errors if wl-copy exits early
90
+ });
91
+ proc.stdin.write(text);
92
+ proc.stdin.end();
85
93
  });
86
- proc.stdin.write(text);
87
- proc.stdin.end();
88
- proc.unref();
89
- copied = true;
94
+ if (wlCopyExit === 0) {
95
+ copied = true;
96
+ }
97
+ else if (hasX11Display) {
98
+ copyToX11Clipboard(options);
99
+ copied = true;
100
+ }
90
101
  }
91
102
  catch {
92
103
  if (hasX11Display) {
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawn } from \"child_process\";\nimport { platform } from \"os\";\nimport { isWaylandSession } from \"./clipboard-image.ts\";\nimport { clipboard } from \"./clipboard-native.ts\";\n\ntype NativeClipboardExecOptions = {\n\tinput: string;\n\ttimeout: number;\n\tstdio: [\"pipe\", \"ignore\", \"ignore\"];\n};\n\nfunction copyToX11Clipboard(options: NativeClipboardExecOptions): void {\n\ttry {\n\t\texecSync(\"xclip -selection clipboard\", options);\n\t} catch {\n\t\texecSync(\"xsel --clipboard --input\", options);\n\t}\n}\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tlet copied = false;\n\n\tconst p = platform();\n\n\t// Prefer direct clipboard writes. Emitting OSC 52 first can make terminals\n\t// write the same native clipboard concurrently with the addon, and very large\n\t// OSC 52 payloads can desynchronize terminal rendering.\n\t//\n\t// On Linux, skip the native addon. The underlying `clipboard-rs` crate is\n\t// X11-only and does not retain selection ownership after `set_text`\n\t// resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even\n\t// some X11 sessions the call resolves successfully without populating the\n\t// clipboard. The platform tools below (wl-copy, xclip, xsel) properly\n\t// daemonize and keep ownership.\n\ttry {\n\t\tif (clipboard && p !== \"linux\") {\n\t\t\tawait clipboard.setText(text);\n\t\t\tcopied = true;\n\t\t}\n\t} catch {\n\t\t// Fall through to platform-specific clipboard tools.\n\t}\n\n\tconst remote = isRemoteSession();\n\tif (copied && !remote) {\n\t\treturn;\n\t}\n\n\tconst options: NativeClipboardExecOptions = { input: text, timeout: 5000, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n\n\tif (!copied) {\n\t\ttry {\n\t\t\tif (p === \"darwin\") {\n\t\t\t\texecSync(\"pbcopy\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else if (p === \"win32\") {\n\t\t\t\texecSync(\"clip\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else {\n\t\t\t\t// Linux. Try Termux, Wayland, or X11 clipboard tools.\n\t\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\texecSync(\"termux-clipboard-set\", options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to Wayland or X11 tools.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!copied) {\n\t\t\t\t\tconst hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n\t\t\t\t\tconst hasX11Display = Boolean(process.env.DISPLAY);\n\t\t\t\t\tconst isWayland = isWaylandSession();\n\t\t\t\t\tif (isWayland && hasWaylandDisplay) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Verify wl-copy exists (spawn errors are async and won't be caught)\n\t\t\t\t\t\t\texecSync(\"which wl-copy\", { stdio: \"ignore\" });\n\t\t\t\t\t\t\t// wl-copy with execSync hangs due to fork behavior; use spawn instead\n\t\t\t\t\t\t\tconst proc = spawn(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n\t\t\t\t\t\t\tproc.stdin.on(\"error\", () => {\n\t\t\t\t\t\t\t\t// Ignore EPIPE errors if wl-copy exits early\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tproc.stdin.write(text);\n\t\t\t\t\t\t\tproc.stdin.end();\n\t\t\t\t\t\t\tproc.unref();\n\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tif (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to OSC 52 fallback.\n\t\t}\n\t}\n\n\tif (remote || !copied) {\n\t\tconst osc52Copied = emitOsc52(text);\n\t\tcopied = copied || osc52Copied;\n\t}\n\n\tif (!copied) {\n\t\tthrow new Error(\"Failed to copy to clipboard\");\n\t}\n}\n"]}
1
+ {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync, spawn } from \"child_process\";\nimport { platform } from \"os\";\nimport { isWaylandSession } from \"./clipboard-image.ts\";\nimport { clipboard } from \"./clipboard-native.ts\";\n\ntype NativeClipboardExecOptions = {\n\tinput: string;\n\ttimeout: number;\n\tstdio: [\"pipe\", \"ignore\", \"ignore\"];\n};\n\nfunction copyToX11Clipboard(options: NativeClipboardExecOptions): void {\n\ttry {\n\t\texecSync(\"xclip -selection clipboard\", options);\n\t} catch {\n\t\texecSync(\"xsel --clipboard --input\", options);\n\t}\n}\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tlet copied = false;\n\n\tconst p = platform();\n\n\t// Prefer direct clipboard writes. Emitting OSC 52 first can make terminals\n\t// write the same native clipboard concurrently with the addon, and very large\n\t// OSC 52 payloads can desynchronize terminal rendering.\n\t//\n\t// On Linux, skip the native addon. The underlying `clipboard-rs` crate is\n\t// X11-only and does not retain selection ownership after `set_text`\n\t// resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even\n\t// some X11 sessions the call resolves successfully without populating the\n\t// clipboard. The platform tools below (wl-copy, xclip, xsel) properly\n\t// daemonize and keep ownership.\n\ttry {\n\t\tif (clipboard && p !== \"linux\") {\n\t\t\tawait clipboard.setText(text);\n\t\t\tcopied = true;\n\t\t}\n\t} catch {\n\t\t// Fall through to platform-specific clipboard tools.\n\t}\n\n\tconst remote = isRemoteSession();\n\tif (copied && !remote) {\n\t\treturn;\n\t}\n\n\tconst options: NativeClipboardExecOptions = { input: text, timeout: 5000, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n\n\tif (!copied) {\n\t\ttry {\n\t\t\tif (p === \"darwin\") {\n\t\t\t\texecSync(\"pbcopy\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else if (p === \"win32\") {\n\t\t\t\texecSync(\"clip\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else {\n\t\t\t\t// Linux. Try Termux, Wayland, or X11 clipboard tools.\n\t\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\texecSync(\"termux-clipboard-set\", options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to Wayland or X11 tools.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!copied) {\n\t\t\t\t\tconst hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n\t\t\t\t\tconst hasX11Display = Boolean(process.env.DISPLAY);\n\t\t\t\t\tconst isWayland = isWaylandSession();\n\t\t\t\t\tif (isWayland && hasWaylandDisplay) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Verify wl-copy exists (spawn errors are async and won't be caught)\n\t\t\t\t\t\t\texecSync(\"which wl-copy\", { stdio: \"ignore\" });\n\t\t\t\t\t\t\t// wl-copy with execSync hangs due to fork behavior; use spawn instead.\n\t\t\t\t\t\t\t// Await the exit code and only claim success on a clean exit, so a\n\t\t\t\t\t\t\t// failed wl-copy falls through to the xclip/OSC 52 fallbacks.\n\t\t\t\t\t\t\tconst wlCopyExit = await new Promise<number>((resolve) => {\n\t\t\t\t\t\t\t\tconst proc = spawn(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n\t\t\t\t\t\t\t\tproc.on(\"error\", () => resolve(1));\n\t\t\t\t\t\t\t\tproc.on(\"close\", (code) => resolve(code ?? 1));\n\t\t\t\t\t\t\t\tproc.stdin.on(\"error\", () => {\n\t\t\t\t\t\t\t\t\t// Ignore EPIPE errors if wl-copy exits early\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tproc.stdin.write(text);\n\t\t\t\t\t\t\t\tproc.stdin.end();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (wlCopyExit === 0) {\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tif (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to OSC 52 fallback.\n\t\t}\n\t}\n\n\tif (remote || !copied) {\n\t\tconst osc52Copied = emitOsc52(text);\n\t\tcopied = copied || osc52Copied;\n\t}\n\n\tif (!copied) {\n\t\tthrow new Error(\"Failed to copy to clipboard\");\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAEA,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC3D,WAAW,EAAE,CAAC,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb,CAAC;AAsBF,eAAO,MAAM,gBAAgB,GAAI,CAAC,oGASjC,CAAC;AAEF,eAAO,MAAM,gBAAgB,6BAA8D,CAAC","sourcesContent":["import { parse } from \"yaml\";\n\ntype ParsedFrontmatter<T extends Record<string, unknown>> = {\n\tfrontmatter: T;\n\tbody: string;\n};\n\nconst normalizeNewlines = (value: string): string => value.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\nconst extractFrontmatter = (content: string): { yamlString: string | null; body: string } => {\n\tconst normalized = normalizeNewlines(content);\n\n\tif (!normalized.startsWith(\"---\")) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\tconst endIndex = normalized.indexOf(\"\\n---\", 3);\n\tif (endIndex === -1) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\treturn {\n\t\tyamlString: normalized.slice(4, endIndex),\n\t\tbody: normalized.slice(endIndex + 4).trim(),\n\t};\n};\n\nexport const parseFrontmatter = <T extends Record<string, unknown> = Record<string, unknown>>(\n\tcontent: string,\n): ParsedFrontmatter<T> => {\n\tconst { yamlString, body } = extractFrontmatter(content);\n\tif (!yamlString) {\n\t\treturn { frontmatter: {} as T, body };\n\t}\n\tconst parsed = parse(yamlString);\n\treturn { frontmatter: (parsed ?? {}) as T, body };\n};\n\nexport const stripFrontmatter = (content: string): string => parseFrontmatter(content).body;\n"]}
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAEA,KAAK,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI;IAC3D,WAAW,EAAE,CAAC,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb,CAAC;AAuDF,eAAO,MAAM,gBAAgB,GAAI,CAAC,oGASjC,CAAC;AAEF,eAAO,MAAM,gBAAgB,6BAA8D,CAAC","sourcesContent":["import { parse } from \"yaml\";\n\ntype ParsedFrontmatter<T extends Record<string, unknown>> = {\n\tfrontmatter: T;\n\tbody: string;\n};\n\nconst normalizeNewlines = (value: string): string => value.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\nconst FRONTMATTER_OPEN = /^---(?:[ \\t]*\\r?\\n|$)/m;\n\n/**\n * Locate YAML frontmatter even when a short preamble (comments/HTML) precedes the opening fence.\n * bigpowers and similar skill packs emit story markers before `---`.\n */\nconst extractFrontmatter = (content: string): { yamlString: string | null; body: string } => {\n\tconst normalized = normalizeNewlines(content);\n\n\tconst openMatch = FRONTMATTER_OPEN.exec(normalized);\n\tif (!openMatch || openMatch.index === undefined) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\t// Reject preambles that already look like document body (too long / has headings beyond comments).\n\tconst preamble = normalized.slice(0, openMatch.index);\n\tif (preamble.length > 0) {\n\t\tconst preambleLines = preamble.split(\"\\n\").filter((line) => line.trim().length > 0);\n\t\tconst onlyPreambleNoise = preambleLines.every(\n\t\t\t(line) =>\n\t\t\t\tline.trimStart().startsWith(\"#\") ||\n\t\t\t\tline.trimStart().startsWith(\"<!--\") ||\n\t\t\t\tline.trim() === \"-->\" ||\n\t\t\t\t/^ARCHIVED:/i.test(line.trim()),\n\t\t);\n\t\tif (!onlyPreambleNoise || preambleLines.length > 32) {\n\t\t\treturn { yamlString: null, body: normalized };\n\t\t}\n\t}\n\n\tconst yamlStart = openMatch.index + openMatch[0].length;\n\tconst endIndex = normalized.indexOf(\"\\n---\", yamlStart - 1);\n\tif (endIndex === -1 || endIndex < yamlStart) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\t// Closing fence must be a line that is exactly `---` (optional trailing spaces).\n\tconst afterClose = normalized.slice(endIndex + 1); // starts at ---\n\tif (!/^---[ \\t]*(?:\\n|$)/.test(afterClose)) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\tconst closeLineEnd = afterClose.search(/\\n/);\n\tconst bodyStart = closeLineEnd === -1 ? normalized.length : endIndex + 1 + closeLineEnd + 1;\n\n\treturn {\n\t\tyamlString: normalized.slice(yamlStart, endIndex),\n\t\tbody: normalized.slice(bodyStart).trim(),\n\t};\n};\n\nexport const parseFrontmatter = <T extends Record<string, unknown> = Record<string, unknown>>(\n\tcontent: string,\n): ParsedFrontmatter<T> => {\n\tconst { yamlString, body } = extractFrontmatter(content);\n\tif (!yamlString) {\n\t\treturn { frontmatter: {} as T, body };\n\t}\n\tconst parsed = parse(yamlString);\n\treturn { frontmatter: (parsed ?? {}) as T, body };\n};\n\nexport const stripFrontmatter = (content: string): string => parseFrontmatter(content).body;\n"]}
@@ -1,17 +1,43 @@
1
1
  import { parse } from "yaml";
2
2
  const normalizeNewlines = (value) => value.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3
+ const FRONTMATTER_OPEN = /^---(?:[ \t]*\r?\n|$)/m;
4
+ /**
5
+ * Locate YAML frontmatter even when a short preamble (comments/HTML) precedes the opening fence.
6
+ * bigpowers and similar skill packs emit story markers before `---`.
7
+ */
3
8
  const extractFrontmatter = (content) => {
4
9
  const normalized = normalizeNewlines(content);
5
- if (!normalized.startsWith("---")) {
10
+ const openMatch = FRONTMATTER_OPEN.exec(normalized);
11
+ if (!openMatch || openMatch.index === undefined) {
6
12
  return { yamlString: null, body: normalized };
7
13
  }
8
- const endIndex = normalized.indexOf("\n---", 3);
9
- if (endIndex === -1) {
14
+ // Reject preambles that already look like document body (too long / has headings beyond comments).
15
+ const preamble = normalized.slice(0, openMatch.index);
16
+ if (preamble.length > 0) {
17
+ const preambleLines = preamble.split("\n").filter((line) => line.trim().length > 0);
18
+ const onlyPreambleNoise = preambleLines.every((line) => line.trimStart().startsWith("#") ||
19
+ line.trimStart().startsWith("<!--") ||
20
+ line.trim() === "-->" ||
21
+ /^ARCHIVED:/i.test(line.trim()));
22
+ if (!onlyPreambleNoise || preambleLines.length > 32) {
23
+ return { yamlString: null, body: normalized };
24
+ }
25
+ }
26
+ const yamlStart = openMatch.index + openMatch[0].length;
27
+ const endIndex = normalized.indexOf("\n---", yamlStart - 1);
28
+ if (endIndex === -1 || endIndex < yamlStart) {
29
+ return { yamlString: null, body: normalized };
30
+ }
31
+ // Closing fence must be a line that is exactly `---` (optional trailing spaces).
32
+ const afterClose = normalized.slice(endIndex + 1); // starts at ---
33
+ if (!/^---[ \t]*(?:\n|$)/.test(afterClose)) {
10
34
  return { yamlString: null, body: normalized };
11
35
  }
36
+ const closeLineEnd = afterClose.search(/\n/);
37
+ const bodyStart = closeLineEnd === -1 ? normalized.length : endIndex + 1 + closeLineEnd + 1;
12
38
  return {
13
- yamlString: normalized.slice(4, endIndex),
14
- body: normalized.slice(endIndex + 4).trim(),
39
+ yamlString: normalized.slice(yamlStart, endIndex),
40
+ body: normalized.slice(bodyStart).trim(),
15
41
  };
16
42
  };
17
43
  export const parseFrontmatter = (content) => {
@@ -1 +1 @@
1
- {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAO7B,MAAM,iBAAiB,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAEvG,MAAM,kBAAkB,GAAG,CAAC,OAAe,EAA+C,EAAE,CAAC;IAC5F,MAAM,UAAU,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE9C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAChD,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC/C,CAAC;IAED,OAAO;QACN,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;QACzC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;KAC3C,CAAC;AAAA,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC/B,OAAe,EACQ,EAAE,CAAC;IAC1B,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACzD,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,EAAE,WAAW,EAAE,EAAO,EAAE,IAAI,EAAE,CAAC;IACvC,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,EAAE,WAAW,EAAE,CAAC,MAAM,IAAI,EAAE,CAAM,EAAE,IAAI,EAAE,CAAC;AAAA,CAClD,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAe,EAAU,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC","sourcesContent":["import { parse } from \"yaml\";\n\ntype ParsedFrontmatter<T extends Record<string, unknown>> = {\n\tfrontmatter: T;\n\tbody: string;\n};\n\nconst normalizeNewlines = (value: string): string => value.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\nconst extractFrontmatter = (content: string): { yamlString: string | null; body: string } => {\n\tconst normalized = normalizeNewlines(content);\n\n\tif (!normalized.startsWith(\"---\")) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\tconst endIndex = normalized.indexOf(\"\\n---\", 3);\n\tif (endIndex === -1) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\treturn {\n\t\tyamlString: normalized.slice(4, endIndex),\n\t\tbody: normalized.slice(endIndex + 4).trim(),\n\t};\n};\n\nexport const parseFrontmatter = <T extends Record<string, unknown> = Record<string, unknown>>(\n\tcontent: string,\n): ParsedFrontmatter<T> => {\n\tconst { yamlString, body } = extractFrontmatter(content);\n\tif (!yamlString) {\n\t\treturn { frontmatter: {} as T, body };\n\t}\n\tconst parsed = parse(yamlString);\n\treturn { frontmatter: (parsed ?? {}) as T, body };\n};\n\nexport const stripFrontmatter = (content: string): string => parseFrontmatter(content).body;\n"]}
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/utils/frontmatter.ts"],"names":[],"mappings":"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","sourcesContent":["import { parse } from \"yaml\";\n\ntype ParsedFrontmatter<T extends Record<string, unknown>> = {\n\tfrontmatter: T;\n\tbody: string;\n};\n\nconst normalizeNewlines = (value: string): string => value.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\nconst FRONTMATTER_OPEN = /^---(?:[ \\t]*\\r?\\n|$)/m;\n\n/**\n * Locate YAML frontmatter even when a short preamble (comments/HTML) precedes the opening fence.\n * bigpowers and similar skill packs emit story markers before `---`.\n */\nconst extractFrontmatter = (content: string): { yamlString: string | null; body: string } => {\n\tconst normalized = normalizeNewlines(content);\n\n\tconst openMatch = FRONTMATTER_OPEN.exec(normalized);\n\tif (!openMatch || openMatch.index === undefined) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\t// Reject preambles that already look like document body (too long / has headings beyond comments).\n\tconst preamble = normalized.slice(0, openMatch.index);\n\tif (preamble.length > 0) {\n\t\tconst preambleLines = preamble.split(\"\\n\").filter((line) => line.trim().length > 0);\n\t\tconst onlyPreambleNoise = preambleLines.every(\n\t\t\t(line) =>\n\t\t\t\tline.trimStart().startsWith(\"#\") ||\n\t\t\t\tline.trimStart().startsWith(\"<!--\") ||\n\t\t\t\tline.trim() === \"-->\" ||\n\t\t\t\t/^ARCHIVED:/i.test(line.trim()),\n\t\t);\n\t\tif (!onlyPreambleNoise || preambleLines.length > 32) {\n\t\t\treturn { yamlString: null, body: normalized };\n\t\t}\n\t}\n\n\tconst yamlStart = openMatch.index + openMatch[0].length;\n\tconst endIndex = normalized.indexOf(\"\\n---\", yamlStart - 1);\n\tif (endIndex === -1 || endIndex < yamlStart) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\t// Closing fence must be a line that is exactly `---` (optional trailing spaces).\n\tconst afterClose = normalized.slice(endIndex + 1); // starts at ---\n\tif (!/^---[ \\t]*(?:\\n|$)/.test(afterClose)) {\n\t\treturn { yamlString: null, body: normalized };\n\t}\n\n\tconst closeLineEnd = afterClose.search(/\\n/);\n\tconst bodyStart = closeLineEnd === -1 ? normalized.length : endIndex + 1 + closeLineEnd + 1;\n\n\treturn {\n\t\tyamlString: normalized.slice(yamlStart, endIndex),\n\t\tbody: normalized.slice(bodyStart).trim(),\n\t};\n};\n\nexport const parseFrontmatter = <T extends Record<string, unknown> = Record<string, unknown>>(\n\tcontent: string,\n): ParsedFrontmatter<T> => {\n\tconst { yamlString, body } = extractFrontmatter(content);\n\tif (!yamlString) {\n\t\treturn { frontmatter: {} as T, body };\n\t}\n\tconst parsed = parse(yamlString);\n\treturn { frontmatter: (parsed ?? {}) as T, body };\n};\n\nexport const stripFrontmatter = (content: string): string => parseFrontmatter(content).body;\n"]}
@@ -62,6 +62,13 @@ You can also trigger manually with `/compact [instructions]`, where optional ins
62
62
 
63
63
  By default, compaction uses the active session model. Set `compaction.model` to an authenticated canonical `provider/model` reference when summaries should use a different model. For example, `zai/glm-5.2` keeps an interactive Claude session while using GLM only for auto-compaction and `/compact`.
64
64
 
65
+ ### Summarization Requests
66
+
67
+ Every compaction and branch-summary LLM call flows through one choke point (`completeSummarization`):
68
+
69
+ - **Retries**: transient stream drops (`terminated`, socket close, 5xx, DNS/transport errors) follow the configured `retry` settings (`enabled`, `maxRetries`, `baseDelayMs`) with exponential backoff instead of failing the whole operation on the first attempt. Quota/billing errors fail fast, and aborts are never retried. Retry progress is emitted as `summarization_retry_scheduled` / `summarization_retry_attempt_start` / `summarization_retry_finished` session events (surfaced in the TUI and RPC stream).
70
+ - **Isolation**: each summarization request runs with prompt caching disabled (`cacheRetention: "none"`) and a fresh routing `sessionId`, so summaries never write unusable provider cache entries or inherit interactive session affinity.
71
+
65
72
  ### How It Works
66
73
 
67
74
  1. **Find cut point**: Walk backwards from newest message, accumulating token estimates until `keepRecentTokens` (default 20k, configurable in `~/.omk/agent/settings.json` or `<project-dir>/.omk/settings.json`) is reached
package/docs/docs.json CHANGED
@@ -27,6 +27,10 @@
27
27
  "title": "Settings",
28
28
  "path": "settings.md"
29
29
  },
30
+ {
31
+ "title": "Environment Variables",
32
+ "path": "environment-variables.md"
33
+ },
30
34
  {
31
35
  "title": "Keybindings",
32
36
  "path": "keybindings.md"
@@ -0,0 +1,94 @@
1
+ # Environment Variables
2
+
3
+ OMK uses environment variables in three ways:
4
+
5
+ - Variables such as `OMK_OFFLINE` configure the OMK process.
6
+ - OMK sets `OMK_CODING_AGENT` so child processes can detect that they run inside OMK.
7
+ - Commands run by the LLM-callable bash tool receive `PI_*` variables describing the current session.
8
+
9
+ Provider API-key variables are documented separately in [Providers](providers.md).
10
+
11
+ ## Process Marker
12
+
13
+ The CLI and RPC entry points set `OMK_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside OMK. It is not session-specific and is not set automatically when OMK is embedded through the SDK.
14
+
15
+ ## Bash Tool Session Environment
16
+
17
+ Commands run by the bash tool receive the current session state (the `PI_*` names are kept for upstream Pi compatibility):
18
+
19
+ | Variable | Description |
20
+ | --- | --- |
21
+ | `PI_SESSION_ID` | Current session ID |
22
+ | `PI_SESSION_FILE` | Absolute path to the current session JSONL file; unset for ephemeral sessions |
23
+ | `PI_PROVIDER` | Currently selected model provider |
24
+ | `PI_MODEL` | Currently selected model ID |
25
+ | `PI_REASONING_LEVEL` | Current effective reasoning level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, or `max` |
26
+
27
+ The values are resolved when each command starts. Switching models or changing the reasoning level therefore affects the next bash command without restarting OMK. `PI_PROVIDER` and `PI_MODEL` identify the selected OMK model, not a different upstream model that a router may choose internally.
28
+
29
+ Inherited parent-process values for these variables are always stripped first, so a nested OMK session never exposes stale parent-session metadata.
30
+
31
+ When asked which model or provider is running, inspect these variables instead of inferring the answer from the system prompt:
32
+
33
+ ```bash
34
+ printf '%s/%s\n' "$PI_PROVIDER" "$PI_MODEL"
35
+ printf 'reasoning=%s session=%s\n' "$PI_REASONING_LEVEL" "$PI_SESSION_ID"
36
+ ```
37
+
38
+ The session file can be inspected directly when the session is persistent:
39
+
40
+ ```bash
41
+ if [ -n "$PI_SESSION_FILE" ]; then
42
+ tail -n 1 "$PI_SESSION_FILE"
43
+ fi
44
+ ```
45
+
46
+ These variables are injected into the LLM-callable bash tool. They are not injected into user-entered `!` or `!!` commands.
47
+
48
+ ### Custom Bash Tools
49
+
50
+ Bash tools created with `createBashTool()` expose the session environment by default. Injection happens before `spawnHook`, so a hook receives the variables in `ctx.env`:
51
+
52
+ ```typescript
53
+ const bashTool = createBashTool(cwd, {
54
+ spawnHook: (ctx) => ({
55
+ ...ctx,
56
+ env: { ...ctx.env, CI: "1" },
57
+ }),
58
+ });
59
+ ```
60
+
61
+ Disable session metadata independently of the spawn hook:
62
+
63
+ ```typescript
64
+ const bashTool = createBashTool(cwd, {
65
+ exposeSessionEnvironment: false,
66
+ spawnHook: (ctx) => ctx,
67
+ });
68
+ ```
69
+
70
+ When disabled, OMK removes inherited values for these variables so nested OMK processes do not expose stale parent-session metadata.
71
+
72
+ ## OMK Process Configuration
73
+
74
+ These variables are read by OMK itself:
75
+
76
+ | Variable | Description |
77
+ | --- | --- |
78
+ | `OMK_CODING_AGENT_DIR` | Override the config directory; default is `~/.omk/agent` |
79
+ | `OMK_CODING_AGENT_SESSION_DIR` | Override session storage; overridden by `--session-dir` |
80
+ | `OMK_PACKAGE_DIR` | Override the package directory, useful for Nix/Guix store paths |
81
+ | `OMK_OFFLINE` | Disable startup network operations, including update checks and install/update telemetry |
82
+ | `OMK_SKIP_VERSION_CHECK` | Disable the latest-version request |
83
+ | `OMK_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no` |
84
+ | `OMK_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
85
+ | `OMK_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
86
+ | `OMK_CONTEXT_GOVERNOR` | Configure the context-budget governor; see `context-budget-*` sources |
87
+ | `OMK_VERIFIED_BASH` | Default-on verified bash adapter for AgentSession/CLI bash. Set to `0` to opt out and use the legacy unverified path (see [SDK — Evidence and Verification](sdk.md#evidence-and-verification)) |
88
+ | `OMK_BASH_SANDBOX` | Bash sandbox mode: `audit` (default — unwrapped spawn, every decision recorded to the replay ledger), `enforce` (wrap with macOS `sandbox-exec` / Linux `bwrap`, fail closed when no backend), `0`/`off` to disable. `session.setBashSandboxMode()` overrides at runtime |
89
+ | `LIVE_E2E` | Test-only: keep provider credentials so live-API e2e suites run on purpose (default scrubbed for hermetic tests) |
90
+ | `OMK_OMP_SEAMS` | Default-on OMP pure seams for `read`/`grep`. Set to `0` to opt out |
91
+ | `VISUAL`, `EDITOR` | External editor fallback when `externalEditor` is unset |
92
+ | `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
93
+
94
+ Provider credentials such as `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and cloud-provider configuration are listed in [Providers](providers.md).
package/docs/index.md CHANGED
@@ -37,6 +37,7 @@ For the full first-run flow, see [Quickstart](quickstart.md).
37
37
  - [Providers](providers.md) - subscription and API-key setup for built-in providers.
38
38
  - [Containerization](containerization.md) - sandbox omk with OpenShell, Gondolin, or Docker.
39
39
  - [Settings](settings.md) - global and project settings.
40
+ - [Environment Variables](environment-variables.md) - process configuration and bash-tool session environment.
40
41
  - [Keybindings](keybindings.md) - default shortcuts and custom keybindings.
41
42
  - [Sessions](sessions.md) - session management, branching, and tree navigation.
42
43
  - [Compaction](compaction.md) - context compaction and branch summarization.
package/docs/rpc.md CHANGED
@@ -424,12 +424,14 @@ Response:
424
424
 
425
425
  #### bash
426
426
 
427
- Execute a shell command and add output to conversation context.
427
+ Execute a shell command and add output to conversation context. Output streams as `bash_execution_update` events while the command runs; the response contains the final result.
428
428
 
429
429
  ```json
430
- {"type": "bash", "command": "ls -la"}
430
+ {"id": "req-1", "type": "bash", "command": "ls -la"}
431
431
  ```
432
432
 
433
+ Include an `id` to associate streamed `bash_execution_update` events with this command.
434
+
433
435
  Response:
434
436
  ```json
435
437
  {
@@ -753,6 +755,7 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
753
755
  | `message_start` | Message begins |
754
756
  | `message_update` | Streaming update (text/thinking/toolcall deltas) |
755
757
  | `message_end` | Message completes |
758
+ | `bash_execution_update` | Direct RPC bash command output chunk (includes originating command `id`) |
756
759
  | `tool_execution_start` | Tool begins execution |
757
760
  | `tool_execution_update` | Tool execution progress (streaming output) |
758
761
  | `tool_execution_end` | Tool completes |
package/docs/sdk.md CHANGED
@@ -505,14 +505,16 @@ const { session } = await createAgentSession({ resourceLoader: loader });
505
505
 
506
506
  Specify which built-in tools to enable:
507
507
 
508
- - Built-in tool names: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`
509
- - Default built-ins: `read`, `bash`, `edit`, `write`
508
+ - Built-in tool names: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`, `diagnostics`
509
+ - Default built-ins: `read`, `bash`, `edit`, `write`, `diagnostics`
510
510
  - `noTools: "all"` disables all tools
511
511
  - `noTools: "builtin"` disables default built-ins while keeping extension and custom tools enabled
512
512
  - `excludeTools` disables specific built-in, extension, or custom tool names after any `tools` allowlist is applied
513
513
 
514
514
  The `edit` tool returns `details.diff` for OMK's TUI display and `details.patch` as a standard unified patch for SDK consumers.
515
515
 
516
+ The `diagnostics` tool runs the project's own checkers and normalizes the result — `tsc --noEmit` for TypeScript, `pyright`/`ruff` for Python, `go vet` for Go, `cargo check` for Rust. Missing checkers or project markers are reported as `skipped` in the tool result instead of failing. Output is capped at 50 diagnostics and cached for 5 s.
517
+
516
518
  ```typescript
517
519
  import { createAgentSession } from "open-multi-agent-kit";
518
520
 
@@ -1130,7 +1132,11 @@ RPC mode is preferred when:
1130
1132
 
1131
1133
  ## Evidence and Verification
1132
1134
 
1133
- Execution-bound evidence is an optional, application-driven layer. It records a declared verification command and reported outcome between two artifact-set snapshots, then binds that record to a tamper-evident ledger. `VerifiedEvidenceExecutor` never executes the declared command. The opt-in `executeVerifiedBash()` adapter invokes caller-supplied `BashOperations`; `executeVerifiedLocalBash()` instead derives the shell identity and runner from OMK's built-in local backend. The default CLI and AgentSession bash paths remain unverified. The repository CI workflow is the sole built-in callsite: it runs the release-consistency verifier through the local adapter.
1135
+ Execution-bound evidence records a declared verification command and reported outcome between two artifact-set snapshots, then binds that record to a tamper-evident ledger. `VerifiedEvidenceExecutor` never executes the declared command. `executeVerifiedBash()` invokes caller-supplied `BashOperations`; `executeVerifiedLocalBash()` derives the shell identity and runner from OMK's built-in local backend.
1136
+
1137
+ **Default path (opt-out):** when an AgentSession has a replay ledger (persisted sessions create one automatically), LLM-callable `bash` and interactive/RPC `executeBash` bind through `executeVerifiedBash` with `executor: "bash-tool"` and receipts under `<sessionFile>.evidence/receipts` (or `cwd/.omk/session-evidence/<goalId>/receipts` for ephemeral sessions). Session workspace scope is git-aware: inside a worktree, the receipt binds the toplevel plus the sorted dirty set (capped at 32 paths, 1 s TTL). Set `OMK_VERIFIED_BASH=0` to restore the legacy unverified path. Custom `createBashTool()` calls stay unverified unless the caller wraps operations with `createVerifiedBashOperations()`. CI still runs release-consistency through `executeVerifiedLocalBash()` with `executor: "ci-runner"`.
1138
+
1139
+ **Default sandbox (opt-out):** session bash also carries a default `audit`-mode sandbox preflight (workspace-write policy rooted at the session cwd). The spawn stays unwrapped, but every decision is appended to the replay ledger as a `sandbox_audit` event, giving a tamper-evident audit trail. `OMK_BASH_SANDBOX=enforce` activates the real OS backend — macOS `sandbox-exec` seatbelt or Linux `bwrap` bubblewrap — and fails closed when neither is installed; `OMK_BASH_SANDBOX=0` disables the preflight entirely.
1134
1140
 
1135
1141
  ### Recorded and invoked inputs
1136
1142
 
@@ -1164,7 +1170,7 @@ Injected runners must follow the built-in terminal protocol: return an integer e
1164
1170
 
1165
1171
  `.github/workflows/ci.yml` invokes the compiled `dist/verify-ci.js` entry after the normal repository check. That entry runs only `node scripts/check-release-consistency.mjs` through `executeVerifiedLocalBash()` with `executor: "ci-runner"`, applies a strict `EvidenceGate`, writes receipts, ledger, and report under `.omk/ci-evidence`, and returns a non-zero process exit when the gate is blocked. CI uploads that directory as `verified-release-consistency`.
1166
1172
 
1167
- This callsite does not wrap the full build, check, or test suite and does not enable receipts for interactive, RPC, or SDK-created AgentSession bash calls. Its workspace freshness scope is limited to the root and coding-agent package manifests.
1173
+ This callsite does not wrap the full build, check, or test suite. Session bash receipts (default-on above) use an empty artifact set and do not replace CI's manifest-scoped release-consistency gate. CI workspace freshness remains limited to the root and coding-agent package manifests.
1168
1174
 
1169
1175
  ### Execution ordering
1170
1176
 
package/docs/settings.md CHANGED
@@ -77,6 +77,7 @@ Advisory-only hint source for the v4 auto thinking-level resolver. Read from the
77
77
  | `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
78
78
  | `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
79
79
  | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
80
+ | `pinStatusSidebar` | boolean | `false` | Pin the bottom status bar as a responsive right rail (opencode-style): width scales with the terminal (~26%, 34–48 cols), the MCP roster grows on taller terminals, and the content column shrinks to match so the prompt is never covered. Toggle anytime with `Ctrl+Q`. Also enabled by `OMK_PIN_STATUS_SIDEBAR=1` |
80
81
 
81
82
  ### Telemetry and update checks
82
83
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omk-extension-custom-provider-anthropic",
3
- "version": "0.92.0",
3
+ "version": "0.94.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omk-extension-custom-provider-anthropic",
9
- "version": "0.92.0",
9
+ "version": "0.94.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "omk-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.92.0",
4
+ "version": "0.94.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "omk-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.92.0",
4
+ "version": "0.94.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omk-extension-gondolin",
3
- "version": "0.92.0",
3
+ "version": "0.94.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omk-extension-gondolin",
9
- "version": "0.92.0",
9
+ "version": "0.94.0",
10
10
  "dependencies": {
11
11
  "@earendil-works/gondolin": "0.12.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "omk-extension-gondolin",
3
3
  "private": true,
4
- "version": "0.92.0",
4
+ "version": "0.94.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omk-extension-sandbox",
3
- "version": "0.92.0",
3
+ "version": "0.94.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omk-extension-sandbox",
9
- "version": "0.92.0",
9
+ "version": "0.94.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "omk-extension-sandbox",
3
3
  "private": true,
4
- "version": "0.92.0",
4
+ "version": "0.94.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",