@overdeck/desktop 0.30.1 → 0.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server/public/assets/{chunk-BO2N2NFS-CjzCvQMQ.js → chunk-BO2N2NFS-Cwc4lXp8.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-B1mpK1Bv.js → diagram-OG6HWLK6-BV1cva-G.js} +1 -1
- package/server/public/assets/{dist-Bjux0aN_.js → dist-9_3cMWAu.js} +3 -3
- package/server/public/assets/{dist-D6NF8U3N.js → dist-B3-NBXNY.js} +1 -1
- package/server/public/assets/{ganttDiagram-6RSMTGT7-CMztT_U2.js → ganttDiagram-6RSMTGT7-pdYgAHyY.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-DFxe8Imf.js → highlighted-body-OFNGDK62-DmF_yp4o.js} +1 -1
- package/server/public/assets/index-CtG7LH4D.css +1 -0
- package/server/public/assets/{index-DtYTWOQ8.js → index-DfbVwpxY.js} +139 -138
- package/server/public/assets/{linear-DwYwoRdv.js → linear-DcZ83rN-.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-CtuRwlIT.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-BkjaiAxk.js → pieDiagram-4H26LBE5-BzCaErrK.js} +1 -1
- package/server/public/assets/{prod-D5kET3Ov.js → prod-Dgylk8o0.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-CwMk2BkV.js → quadrantDiagram-W4KKPZXB-BfeRAr-V.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-CA549BVM.js → sankeyDiagram-5OEKKPKP-DQ6JjCv-.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-WyNBIQBE.js → xychartDiagram-2RQKCTM6-B5QvPHe8.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/server.js +696 -991
- package/server/public/assets/index--mf7PRYx.css +0 -1
- package/server/public/assets/mermaid-GHXKKRXX-YYK67xv6.js +0 -1
package/server/server.js
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, o as __toESM, t as __commonJSMin } from "./chunk-HkwdBwDg.js";
|
|
2
|
-
import { C as isDevMode, S as init_paths, T as
|
|
2
|
+
import { C as isDevMode, E as sessionFilePath, S as init_paths, T as resolveOhmypiExtensionPath, _ as SYNC_SOURCES, l as LOGS_DIR, o as CLAUDE_DIR, t as AGENTS_DIR, u as OVERDECK_HOME, w as packageRoot, x as getOverdeckHome, y as encodeClaudeProjectDir } from "./paths-CC7BDxY0.js";
|
|
3
3
|
import { a as FsError, d as ProcessSpawnError, h as init_errors, p as TrackerError, s as GitHubApiError } from "./errors-LhRGtRIA.js";
|
|
4
|
-
import { A as
|
|
4
|
+
import { A as getAgentJsonlMtime, B as isTrustedOriginForHost, C as resolveAgentHarness, D as resolvePiSessionPath, E as resolveJsonlPath, F as init_agent_input_detection, G as init_codex_auth, H as validateOrigin$1, I as parseCodexApprovalPrompt, K as httpHandler, L as getHeaderFromMap, M as scanPendingInputsPromise, N as detectAwaitingInputForAgent, O as computeAgentEnrichment, P as detectAwaitingInputFromPaneSync, S as readLauncherPinnedSessionId, T as resolveCodexRolloutPath, U as validateOriginHeaders, W as checkCodexAuthStatus, X as init_http_helpers, Z as jsonResponse, _ as getRuntimeForAgent, a as init_agent_projection, b as init_health, c as init_git_info, d as getSystemHealthSnapshot, f as init_system_health_service, g as init_service, h as getCloisterService, j as init_agent_enrichment, n as init_agents, o as saveAgentStateAndEmitEvent, q as init_http_handler, s as saveAgentStateAndEmitEventProgram, t as agentsRouteLayer, u as resolveConversationGitInfo, v as init_runtimes, w as resolveClaudeSessionId, x as init_jsonl_resolver, y as getAgentHealth, z as init_origin_validation } from "./agents-DCDyboA-.js";
|
|
5
5
|
import { a as init_activity_logger, i as emitDashboardLifecycleSync, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-U396zbXm.js";
|
|
6
|
-
import { A as
|
|
6
|
+
import { A as init_paths$1, O as OVERDECK_MIGRATION_PATH, d as getOverdeckDatabaseSync, f as init_infra, i as DbLive, k as getOverdeckDatabasePath, u as TmuxLive } from "./infra-BUUcHyyN.js";
|
|
7
7
|
import { n as openDatabase, t as init_driver } from "./driver-CmBD8_I7.js";
|
|
8
8
|
import { t as require_dist$1 } from "./dist-CChAhNVv.js";
|
|
9
9
|
import { a as parseIssueIdSync, n as extractPrefixSync, r as init_issue_id } from "./issue-id-ChfDs-cT.js";
|
|
10
|
-
import { E as registerProjectSync, N as setProjectAutoMergeDefaultSync, O as resolveProjectFromIssue, _ as init_projects, b as listProjects, d as getProjectSync, k as resolveProjectFromIssueSync, l as getIssuePrefix, r as extractTeamPrefix, s as findProjectByTeamSync, x as listProjectsSync } from "./projects-
|
|
11
|
-
import { A as mergeTtsDaemonConfigs, C as isTldrEnabledSync, D as mergeConfigs, E as loadConfigSync, F as defaultBackgroundAiFeatures, I as init_registry, L as init_js_yaml, P as updateConversationsConfig, R as jsYaml, T as loadConfigNoMigration, a as PARENT_MODEL_REF, b as init_config_yaml, c as clearConfigCache, d as getConversationsConfig, g as getGlobalConfigPath, h as getDefaultTtsDaemonConfig, i as DEFAULT_WORKHORSES, o as ROLE_EFFORTS, r as DEFAULT_ROLES, t as COMPLIANCE_MODES, u as getConversationSearchConfigSync, x as isClaudeCodeChannelsEnabled } from "./config-yaml-
|
|
12
|
-
import { a as
|
|
13
|
-
import { B as init_ui_theme, D as listSessionNames, F as sessionExists, G as init_child_env, H as BLANKED_PROVIDER_ENV, L as setOption, N as sendKeys, P as sendRawKeystroke, S as isHarnessProcessAlive, U as buildChildEnvSync, V as setUiTheme, W as buildChildEnvWithoutTmuxSync, b as getWindowDimensions, c as ensureManagedTmuxContextOnce, d as exactPaneTarget, i as capturePane, j as resizeWindow, k as listSessionsSync, n as buildTmuxArgs, o as createSession, p as findManagedServerPidSync, w as killSession, x as init_tmux } from "./tmux-
|
|
14
|
-
import { a as init_event_store, i as initEventStore, n as getEventStore, r as getSharedDb } from "./event-store-
|
|
15
|
-
import { d as
|
|
16
|
-
import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-
|
|
17
|
-
import { a as
|
|
18
|
-
import { n as AgentsResolverLive, o as init_agents } from "./agents-
|
|
19
|
-
import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-
|
|
20
|
-
import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-
|
|
21
|
-
import { a as diffAgainstMainFiles, c as diffFilesAgainstHead, d as findCommitAtTime, i as diffAgainstMain, l as diffPatchFilesAgainstHead, o as diffCheckpointFiles, p as
|
|
22
|
-
import { a as
|
|
23
|
-
import { n as AgentStateServiceLive } from "./agent-state-service-
|
|
24
|
-
import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-
|
|
25
|
-
import { l as WorkspaceCreateError, n as AgentStartError, r as BeadsNotInitialized, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-
|
|
26
|
-
import { r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-
|
|
27
|
-
import { r as GitHubClientOptionalLive } from "./github-client-
|
|
28
|
-
import { r as RallyClientOptionalLive } from "./rally-client-
|
|
29
|
-
import {
|
|
30
|
-
import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-
|
|
31
|
-
import { i as ensureInternalTokenSync, s as init_internal_token } from "./internal-token-
|
|
32
|
-
import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-
|
|
33
|
-
import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates, r as getAllReviewStatusesFromDb } from "./review-status-sync-
|
|
34
|
-
import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as init_cost_sync } from "./cost-sync-
|
|
35
|
-
import { C as transitionToMerging, _ as markFailed, c as isFlywheelGloballyPaused, d as listDuePendingAutoMerges, f as listProblemAutoMerges, g as markBlocked, n as getActionableAutoMerge, o as init_merge_sync, t as cancelPending, u as listActiveAutoMerges, v as markMerged, x as scheduleAutoMergeWithResult, y as requeueToPending } from "./merge-sync-
|
|
36
|
-
import {
|
|
37
|
-
import { A as PAN_CONTINUE_FILENAME, I as init_types, _ as findSpecByIssue, a as init_io, j as PAN_DIRNAME, l as readWorkspacePlan, n as findPlan, s as readPlan, y as init_specs } from "./io-
|
|
38
|
-
import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-
|
|
39
|
-
import { f as init_config, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-
|
|
10
|
+
import { E as registerProjectSync, N as setProjectAutoMergeDefaultSync, O as resolveProjectFromIssue, _ as init_projects, b as listProjects, d as getProjectSync, k as resolveProjectFromIssueSync, l as getIssuePrefix, r as extractTeamPrefix, s as findProjectByTeamSync, x as listProjectsSync } from "./projects-DF5T4DAb.js";
|
|
11
|
+
import { A as mergeTtsDaemonConfigs, C as isTldrEnabledSync, D as mergeConfigs, E as loadConfigSync, F as defaultBackgroundAiFeatures, I as init_registry, L as init_js_yaml, P as updateConversationsConfig, R as jsYaml, T as loadConfigNoMigration, a as PARENT_MODEL_REF, b as init_config_yaml, c as clearConfigCache, d as getConversationsConfig, g as getGlobalConfigPath, h as getDefaultTtsDaemonConfig, i as DEFAULT_WORKHORSES, o as ROLE_EFFORTS, r as DEFAULT_ROLES, t as COMPLIANCE_MODES, u as getConversationSearchConfigSync, x as isClaudeCodeChannelsEnabled } from "./config-yaml-DUGsL46H.js";
|
|
12
|
+
import { a as hasModelCapabilitySync, c as resolveModelIdSync, i as getModelEffortLevelsSync, n as MODEL_DEPRECATIONS, o as init_model_capabilities, s as modelSupportsImagesSync, t as MODEL_CAPABILITIES } from "./model-capabilities-DzrmNh9F.js";
|
|
13
|
+
import { B as init_ui_theme, D as listSessionNames, F as sessionExists, G as init_child_env, H as BLANKED_PROVIDER_ENV, L as setOption, N as sendKeys, P as sendRawKeystroke, S as isHarnessProcessAlive, U as buildChildEnvSync, V as setUiTheme, W as buildChildEnvWithoutTmuxSync, b as getWindowDimensions, c as ensureManagedTmuxContextOnce, d as exactPaneTarget, i as capturePane, j as resizeWindow, k as listSessionsSync, n as buildTmuxArgs, o as createSession, p as findManagedServerPidSync, w as killSession, x as init_tmux } from "./tmux-C0RZWQ5S.js";
|
|
14
|
+
import { a as init_event_store, i as initEventStore, n as getEventStore, r as getSharedDb } from "./event-store-DaXPWThb.js";
|
|
15
|
+
import { _ as MemoryObservation, d as PanRpcGroup, f as WS_METHODS, h as EDITORS, i as FlywheelStats, m as FlywheelStatus, n as ContextLayerSaveRequest, p as FlywheelRunId, r as ContextPreviewRequest, t as init_src, u as PanRpcError } from "./src-xz0_FrSc.js";
|
|
16
|
+
import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness-_gBwIK-o.js";
|
|
17
|
+
import { a as EventStoreService, c as ReadModelService, d as init_read_model, f as toAgentResolution, i as init_issue_lifecycle, l as ReadModelServiceLive, m as toRole, n as IssueLifecycleLive, o as EventStoreServiceLive, p as toAgentStatus, s as init_domain_services } from "./issue-lifecycle-DQNY7Voi.js";
|
|
18
|
+
import { n as AgentsResolverLive, o as init_agents$1 } from "./agents-C2UPLUyP.js";
|
|
19
|
+
import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-C4a4MFTH.js";
|
|
20
|
+
import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-Dxq9Ki0z.js";
|
|
21
|
+
import { a as diffAgainstMainFiles, c as diffFilesAgainstHead, d as findCommitAtTime, i as diffAgainstMain, l as diffPatchFilesAgainstHead, m as listCheckpoints, o as diffCheckpointFiles, p as init_checkpoint_manager, s as diffCheckpoints, t as captureCheckpoint, u as diffPatchSinceCommit } from "./checkpoint-manager-CyxF3jLY.js";
|
|
22
|
+
import { _ as init_cost, a as init_costs, c as init_reconciler, d as migrateAllSessionsSync, f as getCostsForIssueSync, g as CostResolverLive, h as CostResolver, i as resolveIssueHeadlineCost, l as reconcile, m as syncCacheSync, n as init_running_agents_cache, o as init_sync_wal, p as rebuildCacheSync, r as init_issue_cost_resolver, s as syncWalFromAllProjects, t as getCachedRunningAgents, u as reconcilePiTranscripts } from "./running-agents-cache-CYw5Xnmw.js";
|
|
23
|
+
import { i as init_agent_state_service, n as AgentStateServiceLive } from "./agent-state-service-r2kuZLya.js";
|
|
24
|
+
import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-C0oOKrs5.js";
|
|
25
|
+
import { d as init_typed_errors, l as WorkspaceCreateError, n as AgentStartError, r as BeadsNotInitialized, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-DG3nrArx.js";
|
|
26
|
+
import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-LhrJ-6UJ.js";
|
|
27
|
+
import { i as init_github_client, r as GitHubClientOptionalLive } from "./github-client-CqmZy-AQ.js";
|
|
28
|
+
import { i as init_rally_client, r as RallyClientOptionalLive } from "./rally-client-DfPdFRtS.js";
|
|
29
|
+
import { i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-CdTEubvB.js";
|
|
30
|
+
import { a as CacheService, i as startSharedIssueService, n as init_issue_service_singleton, o as init_cache_service, r as issue_service_singleton_exports, s as parseIntegerHeader, t as getSharedIssueService } from "./issue-service-singleton-Cemym5sC.js";
|
|
31
|
+
import { i as ensureInternalTokenSync, s as init_internal_token } from "./internal-token-V1t_XVES.js";
|
|
32
|
+
import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-yfbLZ66F.js";
|
|
33
|
+
import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates, r as getAllReviewStatusesFromDb } from "./review-status-sync-DlQCDXOn.js";
|
|
34
|
+
import { a as getCostForIssueAggregateSync, c as getDailyTrendsSync, l as getModelRollupSync, n as getBackgroundCostBySourceSync, r as getCavemanExperimentDataSync, s as getCostsByIssueSync, u as init_cost_sync } from "./cost-sync-zTeJiiWF.js";
|
|
35
|
+
import { C as transitionToMerging, _ as markFailed, c as isFlywheelGloballyPaused, d as listDuePendingAutoMerges, f as listProblemAutoMerges, g as markBlocked, n as getActionableAutoMerge, o as init_merge_sync, t as cancelPending, u as listActiveAutoMerges, v as markMerged, x as scheduleAutoMergeWithResult, y as requeueToPending } from "./merge-sync-C1ojtBCQ.js";
|
|
36
|
+
import { _ as setReviewStatus, a as fixStuckCommentedReviews, c as getReviewStatusSync, l as init_review_status, n as clearReviewStatus, o as fixStuckReadyForMerge, r as clearStuckMergeStatuses, s as getReviewStatus, u as loadReviewStatuses } from "./review-status-DlZpTmJb.js";
|
|
37
|
+
import { A as PAN_CONTINUE_FILENAME, I as init_types, _ as findSpecByIssue, a as init_io, j as PAN_DIRNAME, l as readWorkspacePlan, n as findPlan, s as readPlan, y as init_specs } from "./io-Z4rUYasM.js";
|
|
38
|
+
import { C as restartCliproxy, S as readPidFile, T as stopCliproxy, b as isCliproxyInstalled, d as getCliproxyAuthDir, o as bridgeCodexAuthToCliproxy, v as init_cliproxy, w as startCliproxy, x as isCliproxyRunning, y as installCliproxy } from "./cliproxy-DSHuOfBZ.js";
|
|
39
|
+
import { f as init_config, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-CxoqEywB.js";
|
|
40
40
|
import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-M91UIf3c.js";
|
|
41
|
-
import { A as listConversations, B as
|
|
42
|
-
import { a as init_conversation_service, c as
|
|
43
|
-
import { i as getClaudePermissionFlagsStringSync, o as init_claude_permissions, s as resolvePermissionModeSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-
|
|
44
|
-
import {
|
|
45
|
-
import { $t as
|
|
46
|
-
import { a as getBuiltInDefaultHarness, c as getProviderForModelSync, l as init_providers, o as getKimiAnthropicBaseUrl, u as piProviderForModel } from "./providers-
|
|
47
|
-
import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-
|
|
48
|
-
import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-
|
|
49
|
-
import { t as init_pan_dir } from "./pan-dir-
|
|
50
|
-
import { n as init_launcher_generator, t as generateLauncherScriptSync } from "./launcher-generator-
|
|
51
|
-
import { a as globalContextFile$1, d as workspaceContextFile, l as projectContextFile, n as codexGlobalContextFile, o as init_layers, r as ensureProjectLayer, s as piGlobalContextFile } from "./layers-
|
|
52
|
-
import { i as init_harness_policy, n as resolveHarness, r as canUseHarnessSync, t as init_harness_resolve } from "./harness-resolve-
|
|
53
|
-
import { c as init_docker_stats } from "./stack-health-
|
|
54
|
-
import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health, t as init_providers$1 } from "./providers-
|
|
55
|
-
import { a as getSetting, b as setSetting, c as isDeaconGloballyPausedSync, d as isFlywheelRequireUatBeforeMerge, f as isMergeTrainEnabled, g as setFlywheelAutoPickupBacklog, l as isFlywheelAutoPickupBacklog, m as setDeaconGloballyPausedSync, o as init_control_settings, u as isFlywheelGloballyPaused$1, v as setFlywheelRequireUatBeforeMerge, y as setMergeTrainEnabled } from "./control-settings-
|
|
56
|
-
import { a as parseRelativeTime, n as CostThresholdError, s as embed } from "./scanner-
|
|
57
|
-
import { n as deduplicateEventsSync, o as readEventsSync, s as tailEventsSync } from "./events-
|
|
58
|
-
import { n as recordBackgroundAiCost, t as init_cost } from "./cost-
|
|
59
|
-
import { a as startUatTrainReconciler, c as openFlywheelRunReportForDashboard, d as resumeFlywheelRunForDashboard, f as startFlywheelRunForDashboard, l as pauseFlywheelRunForDashboard, o as stopUatTrainReconciler, p as runDashboardDbJob, s as abortFlywheelRunForDashboard, u as readCurrentFlywheelStatusForDashboard } from "./uat-train-
|
|
60
|
-
import {
|
|
61
|
-
import { f as workspacesRouteLayer, g as getWorkspacePathForIssue, h as processPendingFeedbackDeliveries, m as resumeQueuedMerges, p as enrichReviewStatus } from "./workspaces-
|
|
62
|
-
import {
|
|
63
|
-
import { a as getShadowState, s as init_shadow_state } from "./shadow-state-
|
|
64
|
-
import {
|
|
65
|
-
import { a as
|
|
66
|
-
import { O as init_specialists, b as getReviewerSessionName } from "./specialists-
|
|
67
|
-
import {
|
|
68
|
-
import {
|
|
69
|
-
import {
|
|
70
|
-
import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-
|
|
71
|
-
import { n as writeSequenceMd, t as
|
|
72
|
-
import { c as
|
|
73
|
-
import { _ as sendToRemoteAgent, a as getRemoteAgentOutput, n as checkRemoteSpendCap, o as init_remote_agents, p as loadRemoteAgentState, u as killRemoteAgent, v as spawnRemoteAgent } from "./remote-agents-
|
|
74
|
-
import {
|
|
41
|
+
import { $ as updateSpawnError, A as listConversations, B as setClearedToConvId, C as getStuckForks, E as init_conversations, G as setForkRequest, H as setConversationHarness, J as updateConversationDeliveryMethod, K as unarchiveConversation, L as recordConversationHandoff, M as markConversationActive, N as markConversationEnded, O as listActiveConversations, P as markConversationRunning, Q as updateLastAttached, R as removeFavorite, S as getConversationByTmuxSession, T as incrementForkRetryCount, U as setConversationModel, V as setConversationClaudeSessionId, W as setFavorite, X as updateConversationTitle, Y as updateConversationForkFallbackReason, Z as updateForkStatus, _ as canReplaceTitle, b as getConversationById, g as backfillConversationModel, h as archiveConversation, j as listFavoritedIds, k as listArchivedConversationsWithEnrichment, q as updateConversationCost, v as createConversation, w as hasOtherActiveConversationOnTmuxSession, x as getConversationByName, y as getConversationByClaudeSessionId } from "./conversations-DLvWHK2i.js";
|
|
42
|
+
import { _ as init_codex_conversation_parser, a as init_conversation_service, c as parseFromLastCompactBoundary, d as init_ohmypi_conversation_parser, f as isOhmypiSessionFile, g as parsePiConversationMessages, h as isPiSessionFile, i as gateSnapshotEmission, l as summarizeConversationActivity, m as init_pi_conversation_parser, n as contextUsageFromParseResult, o as parseConversationMessages, p as parseOhmypiConversationMessages, t as computeContextUsage, u as watchConversation, v as parseCodexConversationMessages } from "./conversation-service-BLnGgpGK.js";
|
|
43
|
+
import { i as getClaudePermissionFlagsStringSync, o as init_claude_permissions, s as resolvePermissionModeSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-BHhkuJLN.js";
|
|
44
|
+
import { l as init_codex, s as findRolloutPath } from "./codex-CAqD-NbA.js";
|
|
45
|
+
import { $t as init_claude_auth, A as getAgentStateFilePath, At as init_operator_interventions, B as init_agents$2, Bt as init_pty_token, C as dismissDevChannelsDialog, D as getAgentRuntimeState, Dt as captureTranscriptUserRecordSnapshot, E as getAgentRuntimeBaseCommand, Et as writeChannelsBridgeMcpConfig, F as getProviderEnvForModel, G as listAgentStates, Ht as init_bridge_token, I as getProviderExportsForModel, K as listRunningAgents, O as getAgentRuntimeStateSync, Ot as init_transcript_landing, P as getProviderAuthMode, Qt as getClaudeAuthStatus, Rt as init_pi_fifo, St as waitForReadySignal, T as getAgentDir, Ut as writeBridgeTokenSync, V as injectPiConversationMemory, Vt as writePtyToken, Z as messageAgent, en as getOpenAIAuthStatus, h as clearReadySignal, j as getAgentStateSync, jt as operatorInterventionEvent, k as getAgentState, kt as probeTranscriptSince, tn as init_openai_auth, v as deliverAgentMessage, zt as piFifoPaths } from "./agents-hLt-Rr4P.js";
|
|
46
|
+
import { a as getBuiltInDefaultHarness, c as getProviderForModelSync, l as init_providers, o as getKimiAnthropicBaseUrl, u as piProviderForModel } from "./providers-CA5H_tiu.js";
|
|
47
|
+
import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-C69va1rT.js";
|
|
48
|
+
import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-D_0oOxVa.js";
|
|
49
|
+
import { t as init_pan_dir } from "./pan-dir-8hycoLIn.js";
|
|
50
|
+
import { n as init_launcher_generator, t as generateLauncherScriptSync } from "./launcher-generator-CQI4Wi8N.js";
|
|
51
|
+
import { a as globalContextFile$1, d as workspaceContextFile, l as projectContextFile, n as codexGlobalContextFile, o as init_layers, r as ensureProjectLayer, s as piGlobalContextFile } from "./layers-BhmZ9Xjw.js";
|
|
52
|
+
import { i as init_harness_policy, n as resolveHarness, r as canUseHarnessSync, t as init_harness_resolve } from "./harness-resolve-zjwwqUyX.js";
|
|
53
|
+
import { c as init_docker_stats } from "./stack-health-qc0DMiOU.js";
|
|
54
|
+
import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health$1, t as init_providers$1 } from "./providers-BVXfagAf.js";
|
|
55
|
+
import { a as getSetting, b as setSetting, c as isDeaconGloballyPausedSync, d as isFlywheelRequireUatBeforeMerge, f as isMergeTrainEnabled, g as setFlywheelAutoPickupBacklog, l as isFlywheelAutoPickupBacklog, m as setDeaconGloballyPausedSync, o as init_control_settings, u as isFlywheelGloballyPaused$1, v as setFlywheelRequireUatBeforeMerge, y as setMergeTrainEnabled } from "./control-settings-nrCd7a15.js";
|
|
56
|
+
import { a as parseRelativeTime, n as CostThresholdError, s as embed } from "./scanner-nBZUh3Z-.js";
|
|
57
|
+
import { n as deduplicateEventsSync, o as readEventsSync, s as tailEventsSync } from "./events-DlidSJfB.js";
|
|
58
|
+
import { n as recordBackgroundAiCost, t as init_cost$1 } from "./cost-CshfLVLS.js";
|
|
59
|
+
import { a as startUatTrainReconciler, c as openFlywheelRunReportForDashboard, d as resumeFlywheelRunForDashboard, f as startFlywheelRunForDashboard, l as pauseFlywheelRunForDashboard, o as stopUatTrainReconciler, p as runDashboardDbJob, s as abortFlywheelRunForDashboard, u as readCurrentFlywheelStatusForDashboard } from "./uat-train-iwQ7DuuA.js";
|
|
60
|
+
import { S as subscribeLatestFlywheelStatus, _ as listFlywheelRuns, g as isFlywheelRunId, h as init_flywheel_run_state, l as buildClassifyLookups, p as getFlywheelRunDetail, u as init_lookups, w as writeLatestFlywheelStatus, x as resolveLiveFlywheelRunId, y as readCurrentLatestFlywheelStatus } from "./flywheel-B5jy_sgt.js";
|
|
61
|
+
import { f as workspacesRouteLayer, g as getWorkspacePathForIssue, h as processPendingFeedbackDeliveries, m as resumeQueuedMerges, p as enrichReviewStatus } from "./workspaces-CXng3UsG.js";
|
|
62
|
+
import { _ as init_platform, g as detectPlatform } from "./workspace-manager-CDuomoTM.js";
|
|
63
|
+
import { a as getShadowState, s as init_shadow_state } from "./shadow-state-CVp1QwER.js";
|
|
64
|
+
import { C as init_dashboard_auth, D as init_review_status$1, E as rejectUnsafeDashboardMutationRequest, S as hasDashboardInternalToken, T as rejectUnauthorizedDashboardSessionMintRequest, _ as groupResourceAllocatedIssuesByProject, b as dashboardCsrfToken, g as getCachedResourceAllocatedIssues, m as issuesRouteLayer, p as init_issues, v as init_resource_discovery, w as rejectUnauthorizedDashboardRequest, x as dashboardSessionCookieHeader, y as sanitizeResourceAllocatedIssues } from "./issues-CaZ8H94W.js";
|
|
65
|
+
import { a as loadCloisterConfigSync, i as loadCloisterConfig, o as saveCloisterConfigSync, r as init_config$1, s as shouldAutoStart } from "./config-DHYPHDxW.js";
|
|
66
|
+
import { O as init_specialists, b as getReviewerSessionName } from "./specialists-B3b3zCCR.js";
|
|
67
|
+
import { H as init_deacon, _t as init_concurrency, ct as setMergeReadyNotifier, gt as emergencyBrake, ht as withConcurrencyLimit, i as autoResumeStoppedWorkAgents, mt as init_concurrency$1, ot as setAgentStatusChangedNotifier, st as setAgentStoppedNotifier } from "./deacon-BE8F3tlB.js";
|
|
68
|
+
import { n as getNoResumeMode, r as init_no_resume_mode, t as disableNoResumeMode } from "./no-resume-mode-DeRX_RrX.js";
|
|
69
|
+
import { c as init_prd_locations, s as findPrdAtStatusSync } from "./archive-planning-Bn8NdLWB.js";
|
|
70
|
+
import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-M6ArcFFB.js";
|
|
71
|
+
import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-JIDLRyzK.js";
|
|
72
|
+
import { _ as init_pickup, c as BLOCKS_MAIN_LABEL, d as VETOED_LABEL, f as classifyIssue, g as computeWaves, h as computeStats, l as PARKED_LABEL, m as computeLanes, p as computeCohort, u as READY_LABEL, v as normalizeGate } from "./flywheel-merge-order-CEIqRtni.js";
|
|
73
|
+
import { _ as sendToRemoteAgent, a as getRemoteAgentOutput, n as checkRemoteSpendCap, o as init_remote_agents, p as loadRemoteAgentState, u as killRemoteAgent, v as spawnRemoteAgent } from "./remote-agents-CxrbmI9_.js";
|
|
74
|
+
import { _ as init_git_activity, v as listGitOperationsSync } from "./merge-agent-Dpkezdnp.js";
|
|
75
75
|
import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-G1HK5zsr.js";
|
|
76
|
-
import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-
|
|
77
|
-
import {
|
|
78
|
-
import { r as specialistsRouteLayer } from "./specialists-
|
|
79
|
-
import { t as getAgentCommandSync } from "./settings-
|
|
80
|
-
import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-
|
|
81
|
-
import {
|
|
76
|
+
import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-DYsLK5RG.js";
|
|
77
|
+
import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-D8AxgJpA.js";
|
|
78
|
+
import { r as specialistsRouteLayer } from "./specialists-q3ihCaib.js";
|
|
79
|
+
import { t as getAgentCommandSync } from "./settings-BAejBGHF.js";
|
|
80
|
+
import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-B_OxVPgn.js";
|
|
81
|
+
import { i as isRemoteAvailable, r as init_remote, t as createFlyProviderFromConfig } from "./remote-DD99dxJA.js";
|
|
82
82
|
import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-DdI3J1rj.js";
|
|
83
|
-
import { a as init_query_expansion, i as clearQueryExpansionCache, n as init_injection, o as buildMatchQuery, r as injectPromptTimeMemory, s as init_search } from "./injection-
|
|
84
|
-
import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-
|
|
85
|
-
import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting
|
|
86
|
-
import { a as init_render, d as validateTemplate, i as hasManagedRegion, l as init_harness, o as userContentOutsideRegion, t as init_context_layers, u as renderForHarness } from "./context-layers-
|
|
83
|
+
import { a as init_query_expansion, i as clearQueryExpansionCache, n as init_injection, o as buildMatchQuery, r as injectPromptTimeMemory, s as init_search } from "./injection-DEXsy0T8.js";
|
|
84
|
+
import { _ as init_transcript_adapter, a as generateFallbackSummary, c as handoffPreconditionFallbackReason, d as prependFallbackFocus, f as requestHandoffFromAgent, g as getTranscriptAdapter, i as copySessionFromCompactBoundary, l as init_summary_fork, o as generateSummaryForFork, p as reserveSummaryForkSession, r as authorHandoffExternal, s as handoffFailureReason, u as logHandoffFallback } from "./summary-fork-CRstXkJ_.js";
|
|
85
|
+
import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-BMeD-rqy.js";
|
|
86
|
+
import { a as init_render, d as validateTemplate, i as hasManagedRegion, l as init_harness, o as userContentOutsideRegion, t as init_context_layers, u as renderForHarness } from "./context-layers-CDdkuSCl.js";
|
|
87
87
|
import { c as init_github_app, s as getPullRequestState } from "./github-app-DAbOi7t-.js";
|
|
88
|
-
import {
|
|
89
|
-
import {
|
|
90
|
-
import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-
|
|
88
|
+
import { i as parseArtifactRef, r as init_forge } from "./forge-DGbYPb6g.js";
|
|
89
|
+
import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-JLfhLLC6.js";
|
|
90
|
+
import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-CHIwn3hr.js";
|
|
91
91
|
import { createRequire } from "node:module";
|
|
92
92
|
import { Cause, Context, Data, Effect, Exit, Fiber, FileSystem, Layer, Option, Path, Queue, Result, Schedule, Schema, Stream } from "effect";
|
|
93
93
|
import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
@@ -303,6 +303,8 @@ const ServerConfigLayer = Layer.effect(ServerConfig, Effect.sync(() => {
|
|
|
303
303
|
}));
|
|
304
304
|
//#endregion
|
|
305
305
|
//#region services/terminal-service.ts
|
|
306
|
+
init_http_helpers();
|
|
307
|
+
init_activity_logger();
|
|
306
308
|
init_paths$1();
|
|
307
309
|
init_driver();
|
|
308
310
|
var import_dist = /* @__PURE__ */ __toESM(require_dist$1(), 1);
|
|
@@ -312,7 +314,13 @@ init_registry();
|
|
|
312
314
|
init_config_yaml();
|
|
313
315
|
init_ui_theme();
|
|
314
316
|
init_infra();
|
|
315
|
-
|
|
317
|
+
init_event_store();
|
|
318
|
+
init_agents$1();
|
|
319
|
+
init_read_model();
|
|
320
|
+
init_checkpoint_manager();
|
|
321
|
+
init_domain_services();
|
|
322
|
+
init_cost();
|
|
323
|
+
init_agent_state_service();
|
|
316
324
|
/**
|
|
317
325
|
* TerminalService — dual-runtime PTY terminal streaming (PAN-428 B20)
|
|
318
326
|
*
|
|
@@ -325,6 +333,7 @@ init_agents();
|
|
|
325
333
|
* toggle dimensions to force SIGWINCH + full repaint.
|
|
326
334
|
* - On stream/close: do NOT kill the PTY — just remove from tracking.
|
|
327
335
|
*/
|
|
336
|
+
init_src();
|
|
328
337
|
init_tmux();
|
|
329
338
|
init_child_env();
|
|
330
339
|
function isBun() {
|
|
@@ -592,12 +601,23 @@ const TerminalServiceLive = Layer.effect(TerminalService, Effect.sync(() => {
|
|
|
592
601
|
}));
|
|
593
602
|
//#endregion
|
|
594
603
|
//#region services/agent-spawner.ts
|
|
604
|
+
init_issue_id();
|
|
605
|
+
init_projects();
|
|
606
|
+
init_tracker_config();
|
|
607
|
+
init_linear_client();
|
|
608
|
+
init_github_client();
|
|
609
|
+
init_rally_client();
|
|
610
|
+
init_tracker_utils();
|
|
611
|
+
init_cache_service();
|
|
612
|
+
init_issue_service_singleton();
|
|
613
|
+
init_issue_lifecycle();
|
|
595
614
|
/**
|
|
596
615
|
* AgentSpawner Effect service (PAN-449)
|
|
597
616
|
*
|
|
598
617
|
* Wraps agents.ts in an Effect service with typed errors.
|
|
599
618
|
* Route handlers use this instead of importing from lib/agents.ts directly.
|
|
600
619
|
*/
|
|
620
|
+
init_typed_errors();
|
|
601
621
|
var AgentSpawner = class extends Context.Service()("overdeck/dashboard/AgentSpawner") {};
|
|
602
622
|
const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
603
623
|
startWork: (issueId, opts) => Effect.tryPromise({
|
|
@@ -611,7 +631,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
611
631
|
const beadsDir = join$1(workspacePath, ".beads");
|
|
612
632
|
const projectBeadsDir = join$1(workspacePath, "..", "..", ".beads");
|
|
613
633
|
if (!(existsSync$1(beadsDir) || existsSync$1(projectBeadsDir))) throw new BeadsNotInitialized({ workspace: workspacePath });
|
|
614
|
-
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-
|
|
634
|
+
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-DdvrDsH42.js");
|
|
615
635
|
const normalizedId = normalizeAgentId(issueId);
|
|
616
636
|
if ((await Effect.runPromise(getAgentState(normalizedId)))?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
|
|
617
637
|
return {
|
|
@@ -642,7 +662,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
642
662
|
const { workspacePath, projectPath, issue } = opts;
|
|
643
663
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
644
664
|
const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
|
|
645
|
-
const { spawnPlanningSession } = await import("./spawn-planning-session-
|
|
665
|
+
const { spawnPlanningSession } = await import("./spawn-planning-session-caXjx8yu.js");
|
|
646
666
|
const result = await spawnPlanningSession({
|
|
647
667
|
issue: {
|
|
648
668
|
id: issue.id,
|
|
@@ -675,14 +695,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
675
695
|
}),
|
|
676
696
|
kill: (agentId) => Effect.tryPromise({
|
|
677
697
|
try: async () => {
|
|
678
|
-
const { stopAgent } = await import("./agents-
|
|
698
|
+
const { stopAgent } = await import("./agents-DdvrDsH42.js");
|
|
679
699
|
await Effect.runPromise(stopAgent(agentId));
|
|
680
700
|
},
|
|
681
701
|
catch: () => void 0
|
|
682
702
|
}).pipe(Effect.ignore),
|
|
683
703
|
message: (agentId, msg) => Effect.tryPromise({
|
|
684
704
|
try: async () => {
|
|
685
|
-
const { messageAgent } = await import("./agents-
|
|
705
|
+
const { messageAgent } = await import("./agents-DdvrDsH42.js");
|
|
686
706
|
await messageAgent(agentId, msg);
|
|
687
707
|
},
|
|
688
708
|
catch: (err) => new AgentStartError({
|
|
@@ -693,8 +713,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
693
713
|
}),
|
|
694
714
|
deepWipe: (issueId, opts) => Effect.tryPromise({
|
|
695
715
|
try: async () => {
|
|
696
|
-
const { deepWipe } = await import("./workflows-
|
|
697
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
716
|
+
const { deepWipe } = await import("./workflows-D6j_6rZF.js");
|
|
717
|
+
const { resolveProjectFromIssueSync } = await import("./projects-LkdoL5F9.js");
|
|
698
718
|
const project = resolveProjectFromIssueSync(issueId);
|
|
699
719
|
const projectPath = project?.projectPath ?? process.cwd();
|
|
700
720
|
await Effect.runPromise(deepWipe({
|
|
@@ -722,7 +742,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
722
742
|
* Wraps workspace-manager.ts in an Effect service with typed errors.
|
|
723
743
|
* Route handlers and AgentSpawner use this instead of calling workspace-manager directly.
|
|
724
744
|
*/
|
|
725
|
-
|
|
745
|
+
init_typed_errors();
|
|
726
746
|
const execAsync$8 = promisify(exec);
|
|
727
747
|
var WorkspaceService = class extends Context.Service()("overdeck/dashboard/WorkspaceService") {};
|
|
728
748
|
const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
@@ -750,8 +770,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
750
770
|
const { workspacePath, branch } = getWorkspacePath(issueId);
|
|
751
771
|
const issueLower = issueId.toLowerCase();
|
|
752
772
|
if (existsSync$1(workspacePath)) return workspacePath;
|
|
753
|
-
const { createWorkspace } = await import("./workspace-manager-
|
|
754
|
-
const { loadProjectsConfigSync } = await import("./projects-
|
|
773
|
+
const { createWorkspace } = await import("./workspace-manager-C1Ocyoqn.js");
|
|
774
|
+
const { loadProjectsConfigSync } = await import("./projects-LkdoL5F9.js");
|
|
755
775
|
const { projects } = loadProjectsConfigSync();
|
|
756
776
|
const project = resolveProjectFromIssueSync(issueId);
|
|
757
777
|
if (!project) throw new WorkspaceCreateError({
|
|
@@ -786,7 +806,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
786
806
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
787
807
|
const issueLower = issueId.toLowerCase();
|
|
788
808
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
789
|
-
const { removeWorkspace } = await import("./workspace-manager-
|
|
809
|
+
const { removeWorkspace } = await import("./workspace-manager-C1Ocyoqn.js");
|
|
790
810
|
const project = resolveProjectFromIssueSync(issueId);
|
|
791
811
|
if (!project) throw new WorkspaceCreateError({
|
|
792
812
|
id: issueId,
|
|
@@ -817,7 +837,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
817
837
|
try: async () => {
|
|
818
838
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
819
839
|
const issueLower = issueId.toLowerCase();
|
|
820
|
-
const { stopWorkspaceDocker } = await import("./workspace-manager-
|
|
840
|
+
const { stopWorkspaceDocker } = await import("./workspace-manager-C1Ocyoqn.js");
|
|
821
841
|
await Effect.runPromise(stopWorkspaceDocker(workspacePath, issueLower));
|
|
822
842
|
},
|
|
823
843
|
catch: () => void 0
|
|
@@ -886,7 +906,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
886
906
|
join$1(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
|
|
887
907
|
];
|
|
888
908
|
if (!composePaths.find((p) => existsSync$1(p))) {
|
|
889
|
-
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-
|
|
909
|
+
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-C1oOwQUK.js");
|
|
890
910
|
const ensure = ensureDevcontainerSync({
|
|
891
911
|
workspacePath,
|
|
892
912
|
issueId
|
|
@@ -915,7 +935,6 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
915
935
|
}));
|
|
916
936
|
//#endregion
|
|
917
937
|
//#region services/openrouter-service.ts
|
|
918
|
-
init_issue_id();
|
|
919
938
|
/**
|
|
920
939
|
* OpenRouter Service
|
|
921
940
|
*
|
|
@@ -1060,6 +1079,7 @@ function getDefaultCwd() {
|
|
|
1060
1079
|
}
|
|
1061
1080
|
//#endregion
|
|
1062
1081
|
//#region services/open.ts
|
|
1082
|
+
init_src();
|
|
1063
1083
|
const execAsync$7 = promisify(exec);
|
|
1064
1084
|
function getFileManagerCommand() {
|
|
1065
1085
|
switch (process.platform) {
|
|
@@ -4766,9 +4786,12 @@ function removeClientFromHub(hubs, sessionName, ws) {
|
|
|
4766
4786
|
}
|
|
4767
4787
|
//#endregion
|
|
4768
4788
|
//#region routes/codex-auth.ts
|
|
4789
|
+
init_http_handler();
|
|
4790
|
+
init_codex_auth();
|
|
4769
4791
|
init_cliproxy();
|
|
4770
4792
|
init_tmux();
|
|
4771
4793
|
init_config();
|
|
4794
|
+
init_origin_validation();
|
|
4772
4795
|
const reauthSessions = /* @__PURE__ */ new Map();
|
|
4773
4796
|
const SESSION_MAX_AGE_MS = 3600 * 1e3;
|
|
4774
4797
|
const readJsonBody$13 = Effect.gen(function* () {
|
|
@@ -4973,6 +4996,7 @@ async function waitForSessionRespawn(sessionName, timeoutMs) {
|
|
|
4973
4996
|
//#endregion
|
|
4974
4997
|
//#region ws-terminal.ts
|
|
4975
4998
|
init_tmux();
|
|
4999
|
+
init_origin_validation();
|
|
4976
5000
|
init_child_env();
|
|
4977
5001
|
const RESPAWN_WAIT_MS = 35e3;
|
|
4978
5002
|
const ATTACH_TIMEOUT_MS = 5e3;
|
|
@@ -28470,6 +28494,9 @@ function createTurnQueue(emitter, onTurn) {
|
|
|
28470
28494
|
//#endregion
|
|
28471
28495
|
//#region routes/voice.ts
|
|
28472
28496
|
init_paths();
|
|
28497
|
+
init_http_helpers();
|
|
28498
|
+
init_http_handler();
|
|
28499
|
+
init_origin_validation();
|
|
28473
28500
|
const MAX_VOICE_SETTINGS_BODY_BYTES = 16384;
|
|
28474
28501
|
const DEFAULT_VOICE_SETTINGS = {
|
|
28475
28502
|
stt: {
|
|
@@ -28621,6 +28648,7 @@ const putVoiceSettingsRoute = HttpRouter.add("PUT", "/api/voice/settings", httpH
|
|
|
28621
28648
|
const voiceRouteLayer = Layer.mergeAll(getVoiceSettingsRoute, putVoiceSettingsRoute);
|
|
28622
28649
|
//#endregion
|
|
28623
28650
|
//#region ws-voice.ts
|
|
28651
|
+
init_origin_validation();
|
|
28624
28652
|
function sendJson$1(ws, payload) {
|
|
28625
28653
|
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(payload));
|
|
28626
28654
|
}
|
|
@@ -28836,6 +28864,7 @@ function boundedAutoPresoElements(elements) {
|
|
|
28836
28864
|
}
|
|
28837
28865
|
//#endregion
|
|
28838
28866
|
//#region ws-autopreso.ts
|
|
28867
|
+
init_origin_validation();
|
|
28839
28868
|
function sendJson(ws, payload) {
|
|
28840
28869
|
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(payload));
|
|
28841
28870
|
}
|
|
@@ -28886,220 +28915,17 @@ function setupAutoPresoWebSocket(server) {
|
|
|
28886
28915
|
});
|
|
28887
28916
|
}
|
|
28888
28917
|
//#endregion
|
|
28889
|
-
//#region
|
|
28918
|
+
//#region services/read-workspace-file.ts
|
|
28919
|
+
init_briefing_freshness();
|
|
28920
|
+
init_internal_token();
|
|
28921
|
+
init_pipeline_notifier();
|
|
28922
|
+
init_review_status_sync();
|
|
28923
|
+
init_review_status();
|
|
28890
28924
|
init_conversations();
|
|
28891
28925
|
init_codex_conversation_parser();
|
|
28892
28926
|
init_pi_conversation_parser();
|
|
28927
|
+
init_ohmypi_conversation_parser();
|
|
28893
28928
|
init_conversation_service();
|
|
28894
|
-
/**
|
|
28895
|
-
* JSONL transcript resolver for the Command Deck (PAN-830).
|
|
28896
|
-
*
|
|
28897
|
-
* Maps an agent ID (e.g. `agent-pan-830`, `planning-pan-830`, or a canonical
|
|
28898
|
-
* specialist tmux session name) to the agent's JSONL transcript file on disk.
|
|
28899
|
-
*
|
|
28900
|
-
* Codex agents (PAN-1805) write rollout JSONLs under the per-agent
|
|
28901
|
-
* `codex-home/sessions/` tree — resolution dispatches on the harness recorded
|
|
28902
|
-
* in state.json (thread-id fast path, then latest-rollout fallback).
|
|
28903
|
-
*
|
|
28904
|
-
* For claude-code agents the JSONL filename is the *Claude session ID* (a UUID
|
|
28905
|
-
* written by Claude Code itself), NOT the agent/tmux name. Lookup order:
|
|
28906
|
-
* 1. session.id — single UUID written by auto-suspend
|
|
28907
|
-
* 2. sessions.json — array of UUIDs the agent has used; the heartbeat hook
|
|
28908
|
-
* APPENDS new IDs and dedupes, so once a session has been
|
|
28909
|
-
* seen its array index never moves. After a `pan resume`
|
|
28910
|
-
* brings an older session back as the live one, the array
|
|
28911
|
-
* order no longer reflects time-recency. We disambiguate
|
|
28912
|
-
* across all listed IDs by JSONL mtime.
|
|
28913
|
-
* 3. runtime state — in-process mirror, populated by hooks
|
|
28914
|
-
*
|
|
28915
|
-
* Async-only (fs/promises) because this code path runs inside the dashboard
|
|
28916
|
-
* server's event loop.
|
|
28917
|
-
*/
|
|
28918
|
-
init_agents$1();
|
|
28919
|
-
init_paths();
|
|
28920
|
-
init_agent_rollback_state();
|
|
28921
|
-
async function pathExists$5(p) {
|
|
28922
|
-
return access(p).then(() => true, () => false);
|
|
28923
|
-
}
|
|
28924
|
-
async function readOptional$3(p) {
|
|
28925
|
-
return readFile(p, "utf-8").catch(() => null);
|
|
28926
|
-
}
|
|
28927
|
-
/**
|
|
28928
|
-
* Pick the candidate UUID whose JSONL transcript has the most recent mtime.
|
|
28929
|
-
*
|
|
28930
|
-
* The heartbeat hook appends to sessions.json and dedupes — so once an ID is
|
|
28931
|
-
* recorded, its array index never moves even if a later resume makes it the
|
|
28932
|
-
* current session again. Choosing by JSONL mtime is the only reliable signal
|
|
28933
|
-
* for "which session is actually live right now."
|
|
28934
|
-
*
|
|
28935
|
-
* Returns null if no candidate has a corresponding JSONL on disk. Falls back
|
|
28936
|
-
* to scanning every project dir if the workspace path can't be resolved
|
|
28937
|
-
* (covers specialist sessions whose workspace lives elsewhere).
|
|
28938
|
-
*/
|
|
28939
|
-
async function pickFreshestSessionId(candidates, agentId, opts) {
|
|
28940
|
-
if (candidates.length === 0) return null;
|
|
28941
|
-
if (candidates.length === 1) return candidates[0];
|
|
28942
|
-
const projectsRoot = opts.claudeProjectsDirOverride ?? join$1(homedir$1(), ".claude", "projects");
|
|
28943
|
-
let candidatePaths = [];
|
|
28944
|
-
try {
|
|
28945
|
-
const workspace = await Effect.runPromise(getAgentWorkspace(agentId));
|
|
28946
|
-
if (workspace) {
|
|
28947
|
-
const projectDir = join$1(projectsRoot, encodeClaudeProjectDir(workspace));
|
|
28948
|
-
candidatePaths = candidates.map((id) => ({
|
|
28949
|
-
id,
|
|
28950
|
-
path: join$1(projectDir, `${id}.jsonl`)
|
|
28951
|
-
}));
|
|
28952
|
-
}
|
|
28953
|
-
} catch {}
|
|
28954
|
-
if (candidatePaths.length === 0) try {
|
|
28955
|
-
const dirs = await readdir(projectsRoot);
|
|
28956
|
-
const SAFE_DIR = /^[a-zA-Z0-9_.-]+$/;
|
|
28957
|
-
for (const id of candidates) for (const dir of dirs) {
|
|
28958
|
-
if (!SAFE_DIR.test(dir)) continue;
|
|
28959
|
-
candidatePaths.push({
|
|
28960
|
-
id,
|
|
28961
|
-
path: join$1(projectsRoot, dir, `${id}.jsonl`)
|
|
28962
|
-
});
|
|
28963
|
-
}
|
|
28964
|
-
} catch {}
|
|
28965
|
-
let best = null;
|
|
28966
|
-
for (const { id, path } of candidatePaths) try {
|
|
28967
|
-
const s = await stat$1(path);
|
|
28968
|
-
if (!best || s.mtimeMs > best.mtimeMs) best = {
|
|
28969
|
-
id,
|
|
28970
|
-
mtimeMs: s.mtimeMs
|
|
28971
|
-
};
|
|
28972
|
-
} catch {}
|
|
28973
|
-
return best ? best.id : candidates[candidates.length - 1] ?? null;
|
|
28974
|
-
}
|
|
28975
|
-
/** Async equivalent of getLatestSessionId from lib/agents.ts. */
|
|
28976
|
-
async function resolveClaudeSessionId(agentId, opts = {}) {
|
|
28977
|
-
const agentDir = join$1(opts.agentsDirOverride ?? join$1(getOverdeckHome(), "agents"), agentId);
|
|
28978
|
-
const sessionIdTrimmed = (await readOptional$3(join$1(agentDir, "session.id")))?.trim();
|
|
28979
|
-
if (sessionIdTrimmed) return sessionIdTrimmed;
|
|
28980
|
-
const sessionsRaw = await readOptional$3(join$1(agentDir, "sessions.json"));
|
|
28981
|
-
if (sessionsRaw) try {
|
|
28982
|
-
const parsed = JSON.parse(sessionsRaw);
|
|
28983
|
-
if (Array.isArray(parsed)) {
|
|
28984
|
-
const fresh = await pickFreshestSessionId(parsed.filter((v) => typeof v === "string" && v.trim().length > 0), agentId, opts);
|
|
28985
|
-
if (fresh) return fresh;
|
|
28986
|
-
}
|
|
28987
|
-
} catch {}
|
|
28988
|
-
try {
|
|
28989
|
-
const runtimeState = await (opts.getRuntimeStateAsync ?? ((id) => Effect.runPromise(getAgentRuntimeState(id))))(agentId);
|
|
28990
|
-
if (runtimeState?.claudeSessionId) return runtimeState.claudeSessionId;
|
|
28991
|
-
} catch {}
|
|
28992
|
-
return null;
|
|
28993
|
-
}
|
|
28994
|
-
/**
|
|
28995
|
-
* Read the Claude session id PINNED into an agent/conversation launcher.sh.
|
|
28996
|
-
*
|
|
28997
|
-
* The launcher is what spawns the live tmux pane: it runs
|
|
28998
|
-
* `claude … --session-id <uuid>` (or `--resume <uuid>`), so the pinned id is the
|
|
28999
|
-
* EXACT session the Terminal tab attaches to — the only deterministic ground
|
|
29000
|
-
* truth for "which session is live right now." Resolving the transcript panel
|
|
29001
|
-
* from this id makes the Conversation tab match the Terminal tab by construction,
|
|
29002
|
-
* instead of guessing via JSONL mtime (racy: an older session's file gets touched
|
|
29003
|
-
* by a compaction summary write-back or a transient relaunch, its mtime jumps
|
|
29004
|
-
* ahead of the live session's, and the panel renders the wrong transcript).
|
|
29005
|
-
*
|
|
29006
|
-
* Checks the conversation launcher dir first, then the agent launcher dir.
|
|
29007
|
-
* Returns the uuid, or null when no launcher exists or it pins no session id.
|
|
29008
|
-
*/
|
|
29009
|
-
const LAUNCHER_UUID = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
|
|
29010
|
-
const LAUNCHER_SESSION_ID_RE = new RegExp(`--session-id\\s+'?(${LAUNCHER_UUID})'?`);
|
|
29011
|
-
const LAUNCHER_RESUME_RE = new RegExp(`--resume\\s+'?(${LAUNCHER_UUID})'?`);
|
|
29012
|
-
async function readLauncherPinnedSessionId(tmuxSession, opts = {}) {
|
|
29013
|
-
const home = opts.overdeckHomeOverride ?? getOverdeckHome();
|
|
29014
|
-
const candidates = [join$1(home, "conversations", tmuxSession, "launcher.sh"), join$1(home, "agents", tmuxSession, "launcher.sh")];
|
|
29015
|
-
for (const path of candidates) {
|
|
29016
|
-
const text = await readOptional$3(path);
|
|
29017
|
-
if (!text) continue;
|
|
29018
|
-
const match = LAUNCHER_SESSION_ID_RE.exec(text) ?? LAUNCHER_RESUME_RE.exec(text);
|
|
29019
|
-
if (match) return match[1];
|
|
29020
|
-
}
|
|
29021
|
-
return null;
|
|
29022
|
-
}
|
|
29023
|
-
/** Read the harness recorded in the agent's state.json, or null when absent. */
|
|
29024
|
-
async function resolveAgentHarness(agentId, opts = {}) {
|
|
29025
|
-
if (opts.agentsDirOverride) return readRollbackAgentHarnessFromDir(opts.agentsDirOverride, agentId);
|
|
29026
|
-
return getAgentStateSync(agentId)?.harness ?? null;
|
|
29027
|
-
}
|
|
29028
|
-
/**
|
|
29029
|
-
* Resolve the Codex rollout JSONL for a codex-harness agent (PAN-1805).
|
|
29030
|
-
*
|
|
29031
|
-
* Fast path: the persisted codex-thread-id maps directly to its rollout file.
|
|
29032
|
-
* Lazy fallback (same shape as the conversation panel's PAN-1690 fix): codex
|
|
29033
|
-
* writes the rollout only on the first turn, so a spawn-time thread-id capture
|
|
29034
|
-
* can miss it — the per-agent CODEX_HOME holds only this agent's rollouts, so
|
|
29035
|
-
* the newest one is its current thread.
|
|
29036
|
-
*/
|
|
29037
|
-
async function resolveCodexRolloutPath(agentId, opts = {}) {
|
|
29038
|
-
const agentDir = join$1(opts.agentsDirOverride ?? join$1(getOverdeckHome(), "agents"), agentId);
|
|
29039
|
-
const codexHome = join$1(agentDir, "codex-home");
|
|
29040
|
-
if (!await pathExists$5(codexHome)) return null;
|
|
29041
|
-
const { findRolloutPath, findLatestRollout } = await import("./codex-D3QWVTal.js");
|
|
29042
|
-
const threadId = (await readOptional$3(join$1(agentDir, "codex-thread-id")))?.trim();
|
|
29043
|
-
if (threadId) {
|
|
29044
|
-
const rollout = findRolloutPath(codexHome, threadId);
|
|
29045
|
-
if (rollout) return rollout;
|
|
29046
|
-
}
|
|
29047
|
-
return findLatestRollout(codexHome);
|
|
29048
|
-
}
|
|
29049
|
-
/**
|
|
29050
|
-
* Resolve the pi/kimi session JSONL (PAN-1908). Pi writes its session transcript
|
|
29051
|
-
* as `<iso-ts>_<session-id>.jsonl` either in the agent dir's `sessions/` subdir
|
|
29052
|
-
* (conversations) OR in the agent dir root (work agents) — so check both. The dir
|
|
29053
|
-
* also holds `cost-events.jsonl` / `activity.jsonl`, which are NOT transcripts.
|
|
29054
|
-
* Return the freshest transcript by mtime, or null if pi hasn't written one yet.
|
|
29055
|
-
*/
|
|
29056
|
-
async function resolvePiSessionPath(agentId, opts = {}) {
|
|
29057
|
-
const agentDir = join$1(opts.agentsDirOverride ?? join$1(getOverdeckHome(), "agents"), agentId);
|
|
29058
|
-
const NON_TRANSCRIPT = new Set(["cost-events.jsonl", "activity.jsonl"]);
|
|
29059
|
-
let best = null;
|
|
29060
|
-
for (const dir of [join$1(agentDir, "sessions"), agentDir]) {
|
|
29061
|
-
let entries;
|
|
29062
|
-
try {
|
|
29063
|
-
entries = await readdir(dir);
|
|
29064
|
-
} catch {
|
|
29065
|
-
continue;
|
|
29066
|
-
}
|
|
29067
|
-
for (const name of entries) {
|
|
29068
|
-
if (!name.endsWith(".jsonl") || NON_TRANSCRIPT.has(name)) continue;
|
|
29069
|
-
const p = join$1(dir, name);
|
|
29070
|
-
try {
|
|
29071
|
-
const m = (await stat$1(p)).mtimeMs;
|
|
29072
|
-
if (!best || m > best.mtime) best = {
|
|
29073
|
-
path: p,
|
|
29074
|
-
mtime: m
|
|
29075
|
-
};
|
|
29076
|
-
} catch {}
|
|
29077
|
-
}
|
|
29078
|
-
}
|
|
29079
|
-
return best?.path ?? null;
|
|
29080
|
-
}
|
|
29081
|
-
/**
|
|
29082
|
-
* Resolve the JSONL transcript for an agent.
|
|
29083
|
-
*
|
|
29084
|
-
* Codex agents resolve to their rollout JSONL (PAN-1805). For claude-code
|
|
29085
|
-
* agents, returns the absolute path if both the claudeSessionId is known AND
|
|
29086
|
-
* the corresponding JSONL file exists; otherwise null.
|
|
29087
|
-
*/
|
|
29088
|
-
async function resolveJsonlPath(agentId, workspacePath, opts = {}) {
|
|
29089
|
-
const harness = await resolveAgentHarness(agentId, opts);
|
|
29090
|
-
if (harness === "codex") return resolveCodexRolloutPath(agentId, opts);
|
|
29091
|
-
if (harness === "pi") return resolvePiSessionPath(agentId, opts);
|
|
29092
|
-
const claudeSessionId = await resolveClaudeSessionId(agentId, opts);
|
|
29093
|
-
if (!claudeSessionId) return null;
|
|
29094
|
-
const jsonlPath = join$1(opts.claudeProjectsDirOverride ?? join$1(homedir$1(), ".claude", "projects"), encodeClaudeProjectDir(workspacePath), `${claudeSessionId}.jsonl`);
|
|
29095
|
-
if (await pathExists$5(jsonlPath)) return jsonlPath;
|
|
29096
|
-
return null;
|
|
29097
|
-
}
|
|
29098
|
-
//#endregion
|
|
29099
|
-
//#region services/read-workspace-file.ts
|
|
29100
|
-
init_activity_logger();
|
|
29101
|
-
init_event_store();
|
|
29102
|
-
init_briefing_freshness();
|
|
29103
28929
|
init_claude_permissions();
|
|
29104
28930
|
init_codex();
|
|
29105
28931
|
init_providers();
|
|
@@ -29115,6 +28941,12 @@ init_pi_fifo();
|
|
|
29115
28941
|
init_control_settings();
|
|
29116
28942
|
init_operator_interventions();
|
|
29117
28943
|
init_transcript_landing();
|
|
28944
|
+
init_agents$2();
|
|
28945
|
+
init_agent_input_detection();
|
|
28946
|
+
init_agent_enrichment();
|
|
28947
|
+
init_jsonl_resolver();
|
|
28948
|
+
init_flywheel_run_state();
|
|
28949
|
+
init_src();
|
|
29118
28950
|
init_projects();
|
|
29119
28951
|
const MAX_WORKSPACE_FILE_BYTES = 256 * 1024;
|
|
29120
28952
|
const DEFAULT_CONTEXT_LINES = 10;
|
|
@@ -29283,6 +29115,7 @@ function readWorkspaceFileEffect(input) {
|
|
|
29283
29115
|
* out of cwd is no broader than what the caller could query directly
|
|
29284
29116
|
* with an absolute path.
|
|
29285
29117
|
*/
|
|
29118
|
+
init_src();
|
|
29286
29119
|
const MAX_PATH_LENGTH = 4096;
|
|
29287
29120
|
async function resolveFilePathExists(input) {
|
|
29288
29121
|
const { cwd, path } = input;
|
|
@@ -29334,9 +29167,12 @@ function resolveFilePathExistsEffect(input) {
|
|
|
29334
29167
|
* Terminal RPC methods (subscribeTerminal, terminalOpen/Write/Resize/Close)
|
|
29335
29168
|
* are implemented via TerminalService (dual-runtime PTY, B20).
|
|
29336
29169
|
*/
|
|
29170
|
+
init_src();
|
|
29337
29171
|
init_paths();
|
|
29338
29172
|
init_tmux();
|
|
29339
29173
|
init_projects();
|
|
29174
|
+
init_origin_validation();
|
|
29175
|
+
init_http_helpers();
|
|
29340
29176
|
function storedToDomainEvent(stored) {
|
|
29341
29177
|
return {
|
|
29342
29178
|
type: stored.type,
|
|
@@ -29359,7 +29195,7 @@ function normalizedIssueId(value) {
|
|
|
29359
29195
|
function conversationDiscoveringStream() {
|
|
29360
29196
|
return Stream.succeed({ kind: "discovering" }).pipe(Stream.repeat(Schedule.fixed("2 seconds")));
|
|
29361
29197
|
}
|
|
29362
|
-
function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
29198
|
+
function streamResolvedFullParseSnapshots(resolve, parse, model, unresolvedMeansEmpty = false) {
|
|
29363
29199
|
return Stream.callback((queue) => Effect.acquireRelease(Effect.promise(async () => {
|
|
29364
29200
|
let stopped = false;
|
|
29365
29201
|
let resolving = false;
|
|
@@ -29369,6 +29205,14 @@ function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
|
29369
29205
|
let parsing = false;
|
|
29370
29206
|
let pendingReparse = false;
|
|
29371
29207
|
let sessionFile = null;
|
|
29208
|
+
let announcedEmpty = false;
|
|
29209
|
+
let hasContent = false;
|
|
29210
|
+
const stopDiscovery = () => {
|
|
29211
|
+
if (discoveryTimer) {
|
|
29212
|
+
clearInterval(discoveryTimer);
|
|
29213
|
+
discoveryTimer = null;
|
|
29214
|
+
}
|
|
29215
|
+
};
|
|
29372
29216
|
const offer = (event) => {
|
|
29373
29217
|
try {
|
|
29374
29218
|
Queue.offerUnsafe(queue, event);
|
|
@@ -29383,6 +29227,10 @@ function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
|
29383
29227
|
parsing = true;
|
|
29384
29228
|
try {
|
|
29385
29229
|
const result = await parse(sessionFile);
|
|
29230
|
+
if (result.messages.length > 0 && !hasContent) {
|
|
29231
|
+
hasContent = true;
|
|
29232
|
+
stopDiscovery();
|
|
29233
|
+
}
|
|
29386
29234
|
offer({
|
|
29387
29235
|
kind: "messages",
|
|
29388
29236
|
messages: result.messages,
|
|
@@ -29401,36 +29249,56 @@ function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
|
29401
29249
|
}
|
|
29402
29250
|
}
|
|
29403
29251
|
};
|
|
29252
|
+
const watchFile = (file) => {
|
|
29253
|
+
try {
|
|
29254
|
+
watcher = watch(file, () => {
|
|
29255
|
+
if (debounce) return;
|
|
29256
|
+
debounce = setTimeout(() => {
|
|
29257
|
+
debounce = null;
|
|
29258
|
+
emit();
|
|
29259
|
+
}, 300);
|
|
29260
|
+
});
|
|
29261
|
+
} catch {}
|
|
29262
|
+
};
|
|
29404
29263
|
const tryResolve = async () => {
|
|
29405
|
-
if (stopped || resolving ||
|
|
29264
|
+
if (stopped || resolving || hasContent) return;
|
|
29406
29265
|
resolving = true;
|
|
29407
29266
|
try {
|
|
29408
29267
|
const resolved = await resolve();
|
|
29409
29268
|
if (!resolved) {
|
|
29410
|
-
|
|
29269
|
+
if (unresolvedMeansEmpty) {
|
|
29270
|
+
if (!sessionFile && !announcedEmpty) {
|
|
29271
|
+
announcedEmpty = true;
|
|
29272
|
+
offer({
|
|
29273
|
+
kind: "messages",
|
|
29274
|
+
messages: [],
|
|
29275
|
+
workLog: [],
|
|
29276
|
+
streaming: false,
|
|
29277
|
+
snapshot: true
|
|
29278
|
+
});
|
|
29279
|
+
}
|
|
29280
|
+
return;
|
|
29281
|
+
}
|
|
29282
|
+
if (!sessionFile) offer({ kind: "discovering" });
|
|
29411
29283
|
return;
|
|
29412
29284
|
}
|
|
29413
|
-
sessionFile
|
|
29414
|
-
|
|
29415
|
-
|
|
29416
|
-
|
|
29417
|
-
|
|
29418
|
-
|
|
29419
|
-
|
|
29420
|
-
|
|
29421
|
-
|
|
29422
|
-
|
|
29423
|
-
|
|
29424
|
-
emit();
|
|
29425
|
-
}, 300);
|
|
29426
|
-
});
|
|
29427
|
-
} catch {}
|
|
29285
|
+
if (resolved !== sessionFile) {
|
|
29286
|
+
if (watcher) {
|
|
29287
|
+
try {
|
|
29288
|
+
watcher.close();
|
|
29289
|
+
} catch {}
|
|
29290
|
+
watcher = null;
|
|
29291
|
+
}
|
|
29292
|
+
sessionFile = resolved;
|
|
29293
|
+
await emit();
|
|
29294
|
+
if (!stopped) watchFile(resolved);
|
|
29295
|
+
} else await emit();
|
|
29428
29296
|
} finally {
|
|
29429
29297
|
resolving = false;
|
|
29430
29298
|
}
|
|
29431
29299
|
};
|
|
29432
29300
|
await tryResolve();
|
|
29433
|
-
if (!
|
|
29301
|
+
if (!hasContent) discoveryTimer = setInterval(() => {
|
|
29434
29302
|
tryResolve();
|
|
29435
29303
|
}, 2e3);
|
|
29436
29304
|
return { stop: () => {
|
|
@@ -29808,13 +29676,13 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
|
|
|
29808
29676
|
const conv = getConversationByName(input.conversationName);
|
|
29809
29677
|
if (!conv && /^(agent-|planning-|specialist-)/.test(input.conversationName)) {
|
|
29810
29678
|
const harness = yield* Effect.promise(() => resolveAgentHarness(input.conversationName));
|
|
29811
|
-
if (harness === "
|
|
29679
|
+
if (harness === "ohmypi") return streamResolvedFullParseSnapshots(() => resolvePiSessionPath(input.conversationName), parseOhmypiConversationMessages, null);
|
|
29812
29680
|
if (harness === "codex") return streamResolvedFullParseSnapshots(() => resolveCodexRolloutPath(input.conversationName), parseCodexConversationMessages, null);
|
|
29813
29681
|
return conversationDiscoveringStream();
|
|
29814
29682
|
}
|
|
29815
29683
|
if (!conv) return conversationDiscoveringStream();
|
|
29816
|
-
if (conv.harness === "
|
|
29817
|
-
if (conv.harness === "codex") return streamResolvedFullParseSnapshots(() => resolveCodexRolloutPath(conv.tmuxSession), parseCodexConversationMessages, conv.model ?? null);
|
|
29684
|
+
if (conv.harness === "ohmypi") return streamResolvedFullParseSnapshots(() => resolvePiSessionPath(conv.tmuxSession), parseOhmypiConversationMessages, conv.model ?? null, true);
|
|
29685
|
+
if (conv.harness === "codex") return streamResolvedFullParseSnapshots(() => resolveCodexRolloutPath(conv.tmuxSession), parseCodexConversationMessages, conv.model ?? null, true);
|
|
29818
29686
|
if (conv.harness !== "claude-code" && conv.harness != null) return conversationDiscoveringStream();
|
|
29819
29687
|
const launcherTmuxSession = conv.tmuxSession;
|
|
29820
29688
|
const resolvedSessionId = (launcherTmuxSession ? yield* Effect.promise(() => readLauncherPinnedSessionId(launcherTmuxSession)) : null) ?? conv.claudeSessionId;
|
|
@@ -30077,6 +29945,32 @@ const websocketRpcRouteLayer = Layer.unwrap(Effect.gen(function* () {
|
|
|
30077
29945
|
}));
|
|
30078
29946
|
//#endregion
|
|
30079
29947
|
//#region routes/costs.ts
|
|
29948
|
+
init_types();
|
|
29949
|
+
init_specs();
|
|
29950
|
+
init_io();
|
|
29951
|
+
init_pan_dir();
|
|
29952
|
+
init_docker_stats();
|
|
29953
|
+
init_review_status$1();
|
|
29954
|
+
init_dashboard_auth();
|
|
29955
|
+
init_reconciler();
|
|
29956
|
+
init_issue_cost_resolver();
|
|
29957
|
+
init_running_agents_cache();
|
|
29958
|
+
init_config$1();
|
|
29959
|
+
init_health();
|
|
29960
|
+
init_runtimes();
|
|
29961
|
+
init_specialists();
|
|
29962
|
+
init_concurrency();
|
|
29963
|
+
init_no_resume_mode();
|
|
29964
|
+
init_concurrency$1();
|
|
29965
|
+
init_deacon();
|
|
29966
|
+
init_service();
|
|
29967
|
+
init_system_health_service();
|
|
29968
|
+
init_git_info();
|
|
29969
|
+
init_agent_projection();
|
|
29970
|
+
init_agents();
|
|
29971
|
+
init_remote_agents();
|
|
29972
|
+
init_resource_discovery();
|
|
29973
|
+
init_issues();
|
|
30080
29974
|
/**
|
|
30081
29975
|
* Costs route module — Effect HttpRouter.Layer (PAN-428 B10)
|
|
30082
29976
|
*
|
|
@@ -30093,7 +29987,11 @@ const websocketRpcRouteLayer = Layer.unwrap(Effect.gen(function* () {
|
|
|
30093
29987
|
* POST /api/costs/sync-wal
|
|
30094
29988
|
* POST /api/costs/reconcile
|
|
30095
29989
|
*/
|
|
29990
|
+
init_http_helpers();
|
|
29991
|
+
init_costs();
|
|
30096
29992
|
init_cost_sync();
|
|
29993
|
+
init_sync_wal();
|
|
29994
|
+
init_http_handler();
|
|
30097
29995
|
const getCostsSummaryRoute = HttpRouter.add("GET", "/api/costs/summary", httpHandler(Effect.gen(function* () {
|
|
30098
29996
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
30099
29997
|
const urlOpt = HttpServerRequest.toURL(request);
|
|
@@ -30298,7 +30196,7 @@ const postCostsSyncWalRoute = HttpRouter.add("POST", "/api/costs/sync-wal", http
|
|
|
30298
30196
|
})));
|
|
30299
30197
|
const postCostsReconcileRoute = HttpRouter.add("POST", "/api/costs/reconcile", httpHandler(Effect.gen(function* () {
|
|
30300
30198
|
const result = yield* Effect.tryPromise({
|
|
30301
|
-
try: () => reconcile(),
|
|
30199
|
+
try: () => Effect.runPromise(reconcile()),
|
|
30302
30200
|
catch: (err) => new Error(err instanceof Error ? err.message : String(err))
|
|
30303
30201
|
});
|
|
30304
30202
|
console.log(`[reconciler] Sweep complete: ${result.eventsImported ?? 0} imported`);
|
|
@@ -30338,7 +30236,8 @@ const costsRouteLayer = Layer.mergeAll(getCostsSummaryRoute, getCostsByIssueRout
|
|
|
30338
30236
|
* PUT /api/cloister/config
|
|
30339
30237
|
* GET /api/cloister/agents/health
|
|
30340
30238
|
*/
|
|
30341
|
-
|
|
30239
|
+
init_http_helpers();
|
|
30240
|
+
init_http_handler();
|
|
30342
30241
|
const readJsonBody$11 = Effect.gen(function* () {
|
|
30343
30242
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
30344
30243
|
try {
|
|
@@ -30475,8 +30374,10 @@ const cloisterRouteLayer = Layer.mergeAll(getCloisterStatusRoute, postCloisterSt
|
|
|
30475
30374
|
* DELETE /api/resources/docker/volume/:name
|
|
30476
30375
|
* POST /api/resources/docker/prune-volumes
|
|
30477
30376
|
*/
|
|
30478
|
-
|
|
30479
|
-
|
|
30377
|
+
init_http_helpers();
|
|
30378
|
+
init_domain_services();
|
|
30379
|
+
init_http_handler();
|
|
30380
|
+
init_agents$2();
|
|
30480
30381
|
init_tmux();
|
|
30481
30382
|
const execAsync$6 = promisify(exec);
|
|
30482
30383
|
function formatUptime(startedAt) {
|
|
@@ -30729,6 +30630,7 @@ async function deriveSessionPresence(agentId, rtState, tmuxSessionNames) {
|
|
|
30729
30630
|
}
|
|
30730
30631
|
//#endregion
|
|
30731
30632
|
//#region ../../lib/settings-api.ts
|
|
30633
|
+
init_prd_locations();
|
|
30732
30634
|
/**
|
|
30733
30635
|
* Settings API Adapter
|
|
30734
30636
|
*
|
|
@@ -30790,19 +30692,7 @@ function sanitizeApiTtsConfig(tts) {
|
|
|
30790
30692
|
function getDefaultConversationModelApi() {
|
|
30791
30693
|
const { config } = loadConfigSync();
|
|
30792
30694
|
if (config.defaultConversationModel) return resolveModelIdSync(config.defaultConversationModel);
|
|
30793
|
-
|
|
30794
|
-
if (config.enabledProviders.has("minimax")) return resolveModelIdSync("minimax-m2.7-highspeed");
|
|
30795
|
-
if (config.enabledProviders.has("google")) return resolveModelIdSync("gemini-3.1-pro-preview");
|
|
30796
|
-
if (config.enabledProviders.has("kimi")) return resolveModelIdSync("kimi-k2.5");
|
|
30797
|
-
if (config.enabledProviders.has("zai")) return resolveModelIdSync("glm-5.2");
|
|
30798
|
-
if (config.enabledProviders.has("mimo")) return resolveModelIdSync("mimo-v2.5-pro");
|
|
30799
|
-
if (config.enabledProviders.has("nous")) return resolveModelIdSync("qwen/qwen3.6-plus");
|
|
30800
|
-
if (config.enabledProviders.has("dashscope")) return resolveModelIdSync("qwen3-coder-plus");
|
|
30801
|
-
if (config.enabledProviders.has("openrouter")) {
|
|
30802
|
-
const fav = config.openrouterFavorites[0];
|
|
30803
|
-
if (fav) return resolveModelIdSync(fav);
|
|
30804
|
-
}
|
|
30805
|
-
return resolveModelIdSync("claude-sonnet-4-6");
|
|
30695
|
+
throw new Error("No default model configured — set models.default_conversation_model");
|
|
30806
30696
|
}
|
|
30807
30697
|
const ROLE_NAMES = [
|
|
30808
30698
|
"plan",
|
|
@@ -30957,7 +30847,7 @@ function validateModelRef(fieldPath, ref, effectiveWorkhorses, errors, warnings,
|
|
|
30957
30847
|
}
|
|
30958
30848
|
function validateRoleFields(fieldPath, roleConfig, errors) {
|
|
30959
30849
|
const harness = roleConfig.harness;
|
|
30960
|
-
if (harness !== void 0 && harness !== null && harness !== "" && harness !== "claude-code" && harness !== "
|
|
30850
|
+
if (harness !== void 0 && harness !== null && harness !== "" && harness !== "claude-code" && harness !== "ohmypi" && harness !== "codex") errors.push(`${fieldPath}.harness must be claude-code, ohmypi, codex, null, or empty string`);
|
|
30961
30851
|
const effort = roleConfig.effort;
|
|
30962
30852
|
if (effort !== void 0 && !ROLE_EFFORTS.includes(effort)) errors.push(`${fieldPath}.effort must be one of ${ROLE_EFFORTS.join(", ")}`);
|
|
30963
30853
|
const maxAgents = roleConfig.maxAgents;
|
|
@@ -31392,7 +31282,7 @@ function validateSettingsApi(settings) {
|
|
|
31392
31282
|
errors.push(`Unknown provider harness entry "${provider}"`);
|
|
31393
31283
|
continue;
|
|
31394
31284
|
}
|
|
31395
|
-
if (harness !== void 0 && harness !== "" && harness !== "claude-code" && harness !== "
|
|
31285
|
+
if (harness !== void 0 && harness !== "" && harness !== "claude-code" && harness !== "ohmypi" && harness !== "codex") errors.push(`models.provider_harnesses.${provider} must be claude-code, ohmypi, codex, or empty string`);
|
|
31396
31286
|
}
|
|
31397
31287
|
if (settings.models?.overrides) {
|
|
31398
31288
|
const validModelIds = Object.keys(MODEL_CAPABILITIES);
|
|
@@ -31631,14 +31521,6 @@ const saveOpenRouterFavorites = (favorites) => Effect.tryPromise({
|
|
|
31631
31521
|
});
|
|
31632
31522
|
//#endregion
|
|
31633
31523
|
//#region services/agent-status.ts
|
|
31634
|
-
init_tracker_config();
|
|
31635
|
-
init_cache_service();
|
|
31636
|
-
init_internal_token();
|
|
31637
|
-
init_pipeline_notifier();
|
|
31638
|
-
init_review_status_sync();
|
|
31639
|
-
init_review_status();
|
|
31640
|
-
init_types();
|
|
31641
|
-
init_issue_service_singleton();
|
|
31642
31524
|
init_review_agent();
|
|
31643
31525
|
function normalizeAgentStatus(status) {
|
|
31644
31526
|
switch (status) {
|
|
@@ -31681,8 +31563,8 @@ function normalizeAgentStatus(status) {
|
|
|
31681
31563
|
*
|
|
31682
31564
|
* Async-only (fs/promises); safe to call from the dashboard server.
|
|
31683
31565
|
*/
|
|
31684
|
-
init_agents$
|
|
31685
|
-
|
|
31566
|
+
init_agents$2();
|
|
31567
|
+
init_jsonl_resolver();
|
|
31686
31568
|
init_tmux();
|
|
31687
31569
|
const CONVOY_REVIEWER_ROLES = [
|
|
31688
31570
|
"correctness",
|
|
@@ -31878,11 +31760,16 @@ async function buildReviewerNodes(opts) {
|
|
|
31878
31760
|
* POST /api/command-deck/planning/:issueId/init
|
|
31879
31761
|
* GET /api/command-deck/projects
|
|
31880
31762
|
*/
|
|
31763
|
+
init_http_helpers();
|
|
31881
31764
|
init_child_env();
|
|
31882
|
-
|
|
31765
|
+
init_domain_services();
|
|
31766
|
+
init_read_model();
|
|
31767
|
+
init_agents$2();
|
|
31768
|
+
init_costs();
|
|
31883
31769
|
init_tmux();
|
|
31884
31770
|
init_projects();
|
|
31885
|
-
|
|
31771
|
+
init_http_handler();
|
|
31772
|
+
init_jsonl_resolver();
|
|
31886
31773
|
const execAsync$5 = promisify(exec);
|
|
31887
31774
|
const execFileAsync$4 = promisify(execFile);
|
|
31888
31775
|
function getIssueDataService$2() {
|
|
@@ -32610,8 +32497,8 @@ Be specific: reference actual file names, function names, requirement text, disc
|
|
|
32610
32497
|
const { command: cliCmd, args: cliArgs } = getAgentCommandSync(statusModelId);
|
|
32611
32498
|
const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
|
|
32612
32499
|
const promptFile = join$1(planningDir, ".status-review-prompt.tmp");
|
|
32613
|
-
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-
|
|
32614
|
-
const { loadConfigSync: loadYamlConfig } = await import("./config-yaml-
|
|
32500
|
+
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-WToYbUwa.js");
|
|
32501
|
+
const { loadConfigSync: loadYamlConfig } = await import("./config-yaml-DR4CnMG4.js");
|
|
32615
32502
|
let providerEnvStr = "";
|
|
32616
32503
|
let providerEnv = {};
|
|
32617
32504
|
const statusProvider = getProviderForModelSync(statusModelId);
|
|
@@ -32906,7 +32793,6 @@ async function fetchProjectTree() {
|
|
|
32906
32793
|
const commandDeckRouteLayer = Layer.mergeAll(getMissionControlActivityRoute, getMissionControlPlanningRoute, postMissionControlStatusReviewRoute, postMissionControlUploadRoute, postMissionControlSyncDiscussionsRoute, postMissionControlPlanningInitRoute, getMissionControlProjectsRoute);
|
|
32907
32794
|
//#endregion
|
|
32908
32795
|
//#region routes/remote.ts
|
|
32909
|
-
init_specs();
|
|
32910
32796
|
/**
|
|
32911
32797
|
* Remote route module — Effect HttpRouter.Layer (PAN-428 B14)
|
|
32912
32798
|
*
|
|
@@ -32921,7 +32807,11 @@ init_specs();
|
|
|
32921
32807
|
* GET /api/remote/workspaces/:issueId/agent/output
|
|
32922
32808
|
* POST /api/remote/workspaces/:issueId/agent/tell
|
|
32923
32809
|
*/
|
|
32810
|
+
init_http_helpers();
|
|
32811
|
+
init_remote();
|
|
32924
32812
|
init_config();
|
|
32813
|
+
init_domain_services();
|
|
32814
|
+
init_http_handler();
|
|
32925
32815
|
async function loadRemoteWorkspaceMetadata(issueId) {
|
|
32926
32816
|
const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
32927
32817
|
const content = await readFile(join$1(homedir$1(), ".overdeck", "workspaces", `${normalizedId}.yaml`), "utf-8").catch(() => null);
|
|
@@ -36920,8 +36810,10 @@ function isAbortError(error) {
|
|
|
36920
36810
|
* POST /api/settings/validate-api-key
|
|
36921
36811
|
* PUT /api/settings
|
|
36922
36812
|
*/
|
|
36813
|
+
init_http_helpers();
|
|
36923
36814
|
init_providers();
|
|
36924
|
-
|
|
36815
|
+
init_http_handler();
|
|
36816
|
+
init_agents$2();
|
|
36925
36817
|
init_config_yaml();
|
|
36926
36818
|
const REINDEX_CONFIRM_THRESHOLD_USD = 1;
|
|
36927
36819
|
const REINDEX_CONFIRM_TTL_MS = 600 * 1e3;
|
|
@@ -37727,6 +37619,9 @@ const getProviderEnvConflictsRoute = HttpRouter.add("GET", "/api/settings/provid
|
|
|
37727
37619
|
const settingsRouteLayer = Layer.mergeAll(getSettingsRoute, getAvailableModelsRoute, getOptimalDefaultsRoute, getMiniMaxDefaultsRoute, getClaudeAuthRoute, getOpenAIAuthRoute, postTestApiKeyRoute, postValidateApiKeyRoute, getConversationSearchStatusRoute, getConversationSearchReindexEstimateRoute, postConversationSearchReindexRoute, getConversationSearchReindexProgressRoute, putSettingsRoute, putUiThemeRoute, getOpenRouterModelsRoute, putOpenRouterFavoritesRoute, putOpenRouterApiKeyRoute, postOpenRouterTestKeyRoute, getHarnessPolicyRoute, getProviderEnvConflictsRoute);
|
|
37728
37620
|
//#endregion
|
|
37729
37621
|
//#region routes/autopreso.ts
|
|
37622
|
+
init_http_helpers();
|
|
37623
|
+
init_http_handler();
|
|
37624
|
+
init_origin_validation();
|
|
37730
37625
|
const readJsonBody$7 = Effect.gen(function* () {
|
|
37731
37626
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
37732
37627
|
const contentLength = Number(request.headers["content-length"] ?? 0);
|
|
@@ -37790,7 +37685,12 @@ const autopresoRouteLayer = Layer.mergeAll(startRoute, backToStagingRoute, reset
|
|
|
37790
37685
|
* GET /api/activity
|
|
37791
37686
|
* GET /api/activity/:id
|
|
37792
37687
|
*/
|
|
37793
|
-
|
|
37688
|
+
init_http_helpers();
|
|
37689
|
+
init_domain_services();
|
|
37690
|
+
init_service();
|
|
37691
|
+
init_agents$2();
|
|
37692
|
+
init_git_activity();
|
|
37693
|
+
init_http_handler();
|
|
37794
37694
|
let _cachedReviewStatuses = null;
|
|
37795
37695
|
let _cachedReviewStatusesAt = 0;
|
|
37796
37696
|
const REVIEW_STATUS_CACHE_TTL_MS = 5e3;
|
|
@@ -37951,6 +37851,7 @@ const metricsRouteLayer = Layer.mergeAll(getMetricsSummaryRoute, getMetricsCosts
|
|
|
37951
37851
|
* Health filtering logic for dashboard health API
|
|
37952
37852
|
* Determines which agents should be visible in health checks
|
|
37953
37853
|
*/
|
|
37854
|
+
init_config$1();
|
|
37954
37855
|
init_tmux();
|
|
37955
37856
|
const KICKOFF_STALL_GRACE_MS = 300 * 1e3;
|
|
37956
37857
|
/**
|
|
@@ -38071,6 +37972,8 @@ const determineHealthStatus = (agentId, stateFile, liveSessions) => Effect.gen(f
|
|
|
38071
37972
|
* POST /api/dev/rebuild
|
|
38072
37973
|
* POST /api/system/restart-dashboard
|
|
38073
37974
|
*/
|
|
37975
|
+
init_http_helpers();
|
|
37976
|
+
init_service();
|
|
38074
37977
|
init_tmux();
|
|
38075
37978
|
init_projects();
|
|
38076
37979
|
init_tracker_config();
|
|
@@ -38078,9 +37981,11 @@ init_config_yaml();
|
|
|
38078
37981
|
init_config();
|
|
38079
37982
|
init_issue_id();
|
|
38080
37983
|
init_io();
|
|
37984
|
+
init_domain_services();
|
|
37985
|
+
init_read_model();
|
|
37986
|
+
init_http_handler();
|
|
38081
37987
|
init_types();
|
|
38082
|
-
init_agents$
|
|
38083
|
-
init_remote_agents();
|
|
37988
|
+
init_agents$2();
|
|
38084
37989
|
const execAsync$4 = promisify(exec);
|
|
38085
37990
|
async function readPackageVersion() {
|
|
38086
37991
|
let dir = dirname$1(fileURLToPath(import.meta.url));
|
|
@@ -38467,6 +38372,33 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
|
|
|
38467
38372
|
});
|
|
38468
38373
|
}));
|
|
38469
38374
|
const getNoResumeModeRoute = HttpRouter.add("GET", "/api/no-resume-mode", Effect.sync(() => jsonResponse(getNoResumeMode())));
|
|
38375
|
+
/**
|
|
38376
|
+
* Operator "Resume all" — the call-to-action behind the no-resume banner.
|
|
38377
|
+
* PAN-1963 makes agent auto-resume OFF by default at every boot, so after the
|
|
38378
|
+
* dashboard loads, stopped agents wait for the operator to put them back to
|
|
38379
|
+
* work. This clears no-resume mode for the running process (so the Deacon's
|
|
38380
|
+
* patrols and lifecycle-event handlers resume agents again) and immediately
|
|
38381
|
+
* sweeps the stopped work agents rather than waiting for the next patrol tick.
|
|
38382
|
+
*/
|
|
38383
|
+
const postResumeAllRoute = HttpRouter.add("POST", "/api/resume-all", Effect.promise(async () => {
|
|
38384
|
+
try {
|
|
38385
|
+
disableNoResumeMode();
|
|
38386
|
+
const resumed = await autoResumeStoppedWorkAgents();
|
|
38387
|
+
console.log(`[resume-all] No-resume mode cleared; resumed ${resumed.length} work agent(s)${resumed.length ? `: ${resumed.join(", ")}` : ""}`);
|
|
38388
|
+
return jsonResponse({
|
|
38389
|
+
ok: true,
|
|
38390
|
+
resumed,
|
|
38391
|
+
count: resumed.length
|
|
38392
|
+
});
|
|
38393
|
+
} catch (error) {
|
|
38394
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
38395
|
+
console.error("Error resuming all agents:", error);
|
|
38396
|
+
return jsonResponse({
|
|
38397
|
+
ok: false,
|
|
38398
|
+
error: "Failed to resume agents: " + msg
|
|
38399
|
+
}, { status: 500 });
|
|
38400
|
+
}
|
|
38401
|
+
}));
|
|
38470
38402
|
const getDeaconStatusRoute = HttpRouter.add("GET", "/api/deacon/status", Effect.try({
|
|
38471
38403
|
try: () => {
|
|
38472
38404
|
const service = getCloisterService();
|
|
@@ -38537,7 +38469,7 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
|
|
|
38537
38469
|
const version = await getOverdeckVersion();
|
|
38538
38470
|
let supervisorUrl = null;
|
|
38539
38471
|
try {
|
|
38540
|
-
const { getSupervisorUrlSync } = await import("./supervisor-
|
|
38472
|
+
const { getSupervisorUrlSync } = await import("./supervisor-DHuyC90H.js");
|
|
38541
38473
|
supervisorUrl = getSupervisorUrlSync();
|
|
38542
38474
|
} catch {}
|
|
38543
38475
|
return jsonResponse({
|
|
@@ -38633,7 +38565,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
|
|
|
38633
38565
|
const remoteState = loadRemoteAgentState(sessionName);
|
|
38634
38566
|
const isRemote = !!remoteState;
|
|
38635
38567
|
const vmName = remoteState?.vmName ?? "";
|
|
38636
|
-
const { getAgentStateSync } = await import("./agents-
|
|
38568
|
+
const { getAgentStateSync } = await import("./agents-DdvrDsH42.js");
|
|
38637
38569
|
const agentStarting = getAgentStateSync(sessionName)?.status === "starting";
|
|
38638
38570
|
let tmuxSessionAlive = false;
|
|
38639
38571
|
if (!isRemote) try {
|
|
@@ -38776,10 +38708,10 @@ Continue the PLANNING session. Do NOT implement anything.
|
|
|
38776
38708
|
`);
|
|
38777
38709
|
const agentCwd = workspacePath;
|
|
38778
38710
|
if (existsSync$1(outputFile)) await rename(outputFile, join$1(planningDir, `output-${Date.now()}.jsonl`));
|
|
38779
|
-
const { getAgentCommandSync } = await import("./settings-
|
|
38711
|
+
const { getAgentCommandSync } = await import("./settings-2rcV0DoQ.js");
|
|
38780
38712
|
let msgPlanningModel = "claude-sonnet-4-6";
|
|
38781
38713
|
try {
|
|
38782
|
-
const { loadConfigSync, resolveModel } = await import("./config-yaml-
|
|
38714
|
+
const { loadConfigSync, resolveModel } = await import("./config-yaml-DR4CnMG4.js");
|
|
38783
38715
|
msgPlanningModel = resolveModel("plan", void 0, loadConfigSync().config);
|
|
38784
38716
|
} catch {}
|
|
38785
38717
|
const msgAgentCmd = getAgentCommandSync(msgPlanningModel);
|
|
@@ -39043,7 +38975,7 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
|
|
|
39043
38975
|
const projectPath = await getProjectPath(issuePrefix);
|
|
39044
38976
|
const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
|
|
39045
38977
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
39046
|
-
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-
|
|
38978
|
+
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-DcZh0oHj.js");
|
|
39047
38979
|
const config = {
|
|
39048
38980
|
issueId,
|
|
39049
38981
|
workspacePath,
|
|
@@ -39073,7 +39005,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
|
|
|
39073
39005
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
39074
39006
|
const ghConfig = getGitHubConfig();
|
|
39075
39007
|
if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
|
|
39076
|
-
const { runObserverCycle } = await import("./shadow-engineering-
|
|
39008
|
+
const { runObserverCycle } = await import("./shadow-engineering-DcZh0oHj.js");
|
|
39077
39009
|
const firstRepo = ghConfig.repos[0];
|
|
39078
39010
|
const config = {
|
|
39079
39011
|
issueId,
|
|
@@ -39137,7 +39069,7 @@ const postRestartDashboardRoute = HttpRouter.add("POST", "/api/system/restart-da
|
|
|
39137
39069
|
return jsonResponse({ error: "Restart failed: " + (error instanceof Error ? error.message : String(error)) }, { status: 500 });
|
|
39138
39070
|
}
|
|
39139
39071
|
}));
|
|
39140
|
-
const miscRouteLayer = Layer.mergeAll(postTrackersRefreshRoute, getProjectMappingsRoute, putProjectMappingsRoute, postProjectMappingsRoute, getSystemHealthRoute, getGodviewSystemHealthRoute, getHealthAgentsRoute, postHealthAgentPingRoute, getTrackerStatusRoute, postRallyValidateRoute, getNoResumeModeRoute, getDeaconStatusRoute, getDeaconLogsRoute, postDeaconPatrolRoute, getDeaconPauseRoute, postDeaconPauseRoute, getVersionRoute, getRegisteredProjectsRoute, getConfirmationsRoute, postConfirmationRespondRoute, getSkillsRoute, getPlanningStatusRoute, postPlanningMessageRoute, deletePlanningSessionRoute, getTldrStatusRoute, postTldrStartRoute, postTldrStopRoute, postTldrReloadRoute, getCacheStatusRoute, clearCacheRoute, getMetricsRuntimesRoute, getMetricsTasksRoute, postShadowMonitorRoute, postShadowObserveRoute, postDevRebuildRoute, postRestartDashboardRoute);
|
|
39072
|
+
const miscRouteLayer = Layer.mergeAll(postTrackersRefreshRoute, getProjectMappingsRoute, putProjectMappingsRoute, postProjectMappingsRoute, getSystemHealthRoute, getGodviewSystemHealthRoute, getHealthAgentsRoute, postHealthAgentPingRoute, getTrackerStatusRoute, postRallyValidateRoute, getNoResumeModeRoute, postResumeAllRoute, getDeaconStatusRoute, getDeaconLogsRoute, postDeaconPatrolRoute, getDeaconPauseRoute, postDeaconPauseRoute, getVersionRoute, getRegisteredProjectsRoute, getConfirmationsRoute, postConfirmationRespondRoute, getSkillsRoute, getPlanningStatusRoute, postPlanningMessageRoute, deletePlanningSessionRoute, getTldrStatusRoute, postTldrStartRoute, postTldrStopRoute, postTldrReloadRoute, getCacheStatusRoute, clearCacheRoute, getMetricsRuntimesRoute, getMetricsTasksRoute, postShadowMonitorRoute, postShadowObserveRoute, postDevRebuildRoute, postRestartDashboardRoute);
|
|
39141
39073
|
//#endregion
|
|
39142
39074
|
//#region ../../lib/conversation-search/ranker.ts
|
|
39143
39075
|
init_fts_db();
|
|
@@ -39315,8 +39247,11 @@ async function searchConversationChunks(input) {
|
|
|
39315
39247
|
* own embedding pipeline and config (see linked GitHub issue at end of
|
|
39316
39248
|
* commit).
|
|
39317
39249
|
*/
|
|
39250
|
+
init_http_helpers();
|
|
39318
39251
|
init_projects();
|
|
39319
39252
|
init_conversations();
|
|
39253
|
+
init_dashboard_auth();
|
|
39254
|
+
init_origin_validation();
|
|
39320
39255
|
const PAN_COMMANDS = [
|
|
39321
39256
|
{
|
|
39322
39257
|
name: "pan up",
|
|
@@ -39891,66 +39826,32 @@ const getPaletteSearchRoute = HttpRouter.add("GET", "/api/palette/search", Effec
|
|
|
39891
39826
|
}));
|
|
39892
39827
|
const paletteRouteLayer = Layer.mergeAll(getPaletteCommandsRoute, getPaletteSearchRoute);
|
|
39893
39828
|
//#endregion
|
|
39894
|
-
//#region ../../lib/
|
|
39895
|
-
init_model_capabilities();
|
|
39896
|
-
const EXTENDED_CONTEXT_WINDOW_FLOOR = 1e6;
|
|
39897
|
-
function getEffectiveTargetWindow({ registryWindow, currentObservedCeiling, cliproxyRouted, providerRoutingChanged }) {
|
|
39898
|
-
if (cliproxyRouted) return CLIPROXY_CODEX_CONTEXT_WINDOW;
|
|
39899
|
-
if (!providerRoutingChanged && currentObservedCeiling > registryWindow) return Math.max(EXTENDED_CONTEXT_WINDOW_FLOOR, registryWindow);
|
|
39900
|
-
return registryWindow;
|
|
39901
|
-
}
|
|
39902
|
-
function decideSwitchStrategy({ harnessChanged, providerRoutingChanged, contextTokens, effectiveTargetWindow }) {
|
|
39903
|
-
if (harnessChanged) return {
|
|
39904
|
-
tier: 4,
|
|
39905
|
-
compact: false,
|
|
39906
|
-
useModelCommand: false
|
|
39907
|
-
};
|
|
39908
|
-
if (contextTokens > effectiveTargetWindow * .8) return {
|
|
39909
|
-
tier: 3,
|
|
39910
|
-
compact: true,
|
|
39911
|
-
useModelCommand: false
|
|
39912
|
-
};
|
|
39913
|
-
if (!providerRoutingChanged) return {
|
|
39914
|
-
tier: 1,
|
|
39915
|
-
compact: false,
|
|
39916
|
-
useModelCommand: true
|
|
39917
|
-
};
|
|
39918
|
-
return {
|
|
39919
|
-
tier: 2,
|
|
39920
|
-
compact: false,
|
|
39921
|
-
useModelCommand: false
|
|
39922
|
-
};
|
|
39923
|
-
}
|
|
39924
|
-
//#endregion
|
|
39925
|
-
//#region ../../lib/pi-codex-auth.ts
|
|
39829
|
+
//#region ../../lib/ohmypi-codex-auth.ts
|
|
39926
39830
|
init_features();
|
|
39927
39831
|
/**
|
|
39928
|
-
*
|
|
39832
|
+
* oh-my-pi (omp) OAuth helpers for the openai-codex (ChatGPT subscription) provider.
|
|
39833
|
+
* Forked from pi-codex-auth.ts (PAN-1520) for the omp migration (PAN-1989).
|
|
39929
39834
|
*
|
|
39930
|
-
*
|
|
39931
|
-
*
|
|
39932
|
-
*
|
|
39933
|
-
*
|
|
39934
|
-
* "No API key for provider: openai-codex".
|
|
39835
|
+
* omp stores its general credentials in ~/.omp/agent/agent.db (SQLite). The
|
|
39836
|
+
* openai-codex OAuth credential is persisted separately at ~/.omp/agent/auth.json
|
|
39837
|
+
* (same JSON format as Pi's ~/.pi/agent/auth.json) so that this helper's
|
|
39838
|
+
* read/write logic is unchanged from the Pi side.
|
|
39935
39839
|
*
|
|
39936
39840
|
* This module:
|
|
39937
|
-
* - reads/writes
|
|
39841
|
+
* - reads/writes the openai-codex credential under ~/.omp/agent/auth.json,
|
|
39938
39842
|
* - reports auth status (for `pan doctor` and the conversation spawn gate),
|
|
39939
39843
|
* - refreshes an expired-but-recoverable token, and
|
|
39940
|
-
* - drives
|
|
39844
|
+
* - drives omp's headless device-code login to re-authenticate.
|
|
39941
39845
|
*
|
|
39942
|
-
*
|
|
39943
|
-
*
|
|
39944
|
-
* imports no provider SDKs), so the credential format and OAuth endpoints
|
|
39945
|
-
* never drift from whatever the installed Pi expects. Every reuse is wrapped
|
|
39946
|
-
* so a missing/relocated Pi degrades gracefully rather than throwing.
|
|
39846
|
+
* The OAuth module is loaded from the installed `omp` package dynamically.
|
|
39847
|
+
* A missing or relocated omp OAuth module degrades to 'unavailable' — never throws.
|
|
39947
39848
|
*/
|
|
39948
39849
|
const PI_CODEX_PROVIDER = "openai-codex";
|
|
39949
|
-
function
|
|
39950
|
-
return join$1(homedir$1(), ".
|
|
39850
|
+
function getOhmypiAuthPath() {
|
|
39851
|
+
return join$1(homedir$1(), ".omp", "agent", "auth.json");
|
|
39951
39852
|
}
|
|
39952
39853
|
function readAuthFile() {
|
|
39953
|
-
const path =
|
|
39854
|
+
const path = getOhmypiAuthPath();
|
|
39954
39855
|
if (!existsSync$1(path)) return {};
|
|
39955
39856
|
try {
|
|
39956
39857
|
const parsed = JSON.parse(readFileSync$1(path, "utf-8"));
|
|
@@ -39959,14 +39860,14 @@ function readAuthFile() {
|
|
|
39959
39860
|
return {};
|
|
39960
39861
|
}
|
|
39961
39862
|
}
|
|
39962
|
-
function
|
|
39863
|
+
function readOhmypiCodexCredential() {
|
|
39963
39864
|
const cred = readAuthFile()[PI_CODEX_PROVIDER];
|
|
39964
39865
|
if (cred && typeof cred === "object" && typeof cred["access"] === "string" && typeof cred["refresh"] === "string") return cred;
|
|
39965
39866
|
return null;
|
|
39966
39867
|
}
|
|
39967
39868
|
/** Atomically merge a fresh codex credential into auth.json (mode 0600). */
|
|
39968
|
-
function
|
|
39969
|
-
const path =
|
|
39869
|
+
function writeOhmypiCodexCredential(tokens) {
|
|
39870
|
+
const path = getOhmypiAuthPath();
|
|
39970
39871
|
mkdirSync$1(dirname$1(path), { recursive: true });
|
|
39971
39872
|
const auth = readAuthFile();
|
|
39972
39873
|
const stored = {
|
|
@@ -39982,27 +39883,26 @@ function writePiCodexCredential(tokens) {
|
|
|
39982
39883
|
renameSync$1(tmp, path);
|
|
39983
39884
|
return stored;
|
|
39984
39885
|
}
|
|
39985
|
-
/** Locate the `
|
|
39986
|
-
function
|
|
39886
|
+
/** Locate the `omp` executable on PATH (no subprocess — event-loop safe). */
|
|
39887
|
+
function findOmpBinary() {
|
|
39987
39888
|
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
39988
39889
|
if (!dir) continue;
|
|
39989
|
-
const candidate = join$1(dir, "
|
|
39890
|
+
const candidate = join$1(dir, "omp");
|
|
39990
39891
|
if (existsSync$1(candidate)) return candidate;
|
|
39991
39892
|
}
|
|
39992
39893
|
return null;
|
|
39993
39894
|
}
|
|
39994
|
-
/** pi-
|
|
39995
|
-
const
|
|
39895
|
+
/** omp is @oh-my-pi/pi-coding-agent; the oauth submodule path mirrors pi-ai's layout. */
|
|
39896
|
+
const OMP_AI_OAUTH_SUBPATH = join$1("@oh-my-pi", "pi-ai", "dist", "utils", "oauth", "openai-codex.js");
|
|
39996
39897
|
/**
|
|
39997
|
-
* Resolve
|
|
39998
|
-
* from the real
|
|
39999
|
-
*
|
|
40000
|
-
* which can't resolve pi-ai's ESM-only `exports` map.
|
|
39898
|
+
* Resolve omp's openai-codex OAuth submodule by walking node_modules upward
|
|
39899
|
+
* from the real omp binary. Returns null when not found — the caller degrades
|
|
39900
|
+
* gracefully to 'unavailable' status.
|
|
40001
39901
|
*/
|
|
40002
|
-
function
|
|
40003
|
-
let dir = dirname$1(realpathSync$1(
|
|
39902
|
+
function resolveOmpCodexOAuthFile(ompBin) {
|
|
39903
|
+
let dir = dirname$1(realpathSync$1(ompBin));
|
|
40004
39904
|
for (let i = 0; i < 10; i++) {
|
|
40005
|
-
const candidate = join$1(dir, "node_modules",
|
|
39905
|
+
const candidate = join$1(dir, "node_modules", OMP_AI_OAUTH_SUBPATH);
|
|
40006
39906
|
if (existsSync$1(candidate)) return candidate;
|
|
40007
39907
|
const parent = dirname$1(dir);
|
|
40008
39908
|
if (parent === dir) break;
|
|
@@ -40012,18 +39912,16 @@ function resolvePiCodexOAuthFile(piBin) {
|
|
|
40012
39912
|
}
|
|
40013
39913
|
let cachedModule = null;
|
|
40014
39914
|
/**
|
|
40015
|
-
* Dynamically load
|
|
40016
|
-
* package.
|
|
40017
|
-
* polling), never the heavy provider SDKs. Returns null on any failure so
|
|
40018
|
-
* callers can degrade gracefully.
|
|
39915
|
+
* Dynamically load omp's openai-codex OAuth submodule from the installed `omp`
|
|
39916
|
+
* package. Returns null on any failure so callers can degrade gracefully.
|
|
40019
39917
|
*/
|
|
40020
|
-
async function
|
|
39918
|
+
async function loadOhmypiCodexOAuth() {
|
|
40021
39919
|
if (cachedModule) return cachedModule;
|
|
40022
39920
|
cachedModule = (async () => {
|
|
40023
39921
|
try {
|
|
40024
|
-
const
|
|
40025
|
-
if (!
|
|
40026
|
-
const oauthFile =
|
|
39922
|
+
const ompBin = findOmpBinary();
|
|
39923
|
+
if (!ompBin) return null;
|
|
39924
|
+
const oauthFile = resolveOmpCodexOAuthFile(ompBin);
|
|
40027
39925
|
if (!oauthFile) return null;
|
|
40028
39926
|
const mod = await import(pathToFileURL(oauthFile).href);
|
|
40029
39927
|
if (typeof mod.refreshOpenAICodexToken !== "function" || typeof mod.loginOpenAICodexDeviceCode !== "function") return null;
|
|
@@ -40034,22 +39932,16 @@ async function loadPiCodexOAuth() {
|
|
|
40034
39932
|
})();
|
|
40035
39933
|
return cachedModule;
|
|
40036
39934
|
}
|
|
40037
|
-
/** Treat a token expiring within this window as already expired. */
|
|
40038
39935
|
const EXPIRY_MARGIN_MS = 6e4;
|
|
40039
|
-
|
|
40040
|
-
|
|
40041
|
-
* token triggers one refresh attempt (writing the renewed token back on
|
|
40042
|
-
* success) so the caller learns whether the credential is actually dead.
|
|
40043
|
-
*/
|
|
40044
|
-
async function getPiCodexAuthStatus(opts) {
|
|
40045
|
-
const cred = readPiCodexCredential();
|
|
39936
|
+
async function getOhmypiCodexAuthStatus(opts) {
|
|
39937
|
+
const cred = readOhmypiCodexCredential();
|
|
40046
39938
|
if (!cred) return { status: "missing" };
|
|
40047
39939
|
if (cred.expires > Date.now() + EXPIRY_MARGIN_MS) return {
|
|
40048
39940
|
status: "ok",
|
|
40049
39941
|
expiresAt: cred.expires
|
|
40050
39942
|
};
|
|
40051
39943
|
if (opts?.refreshIfExpired) {
|
|
40052
|
-
const refreshed = await
|
|
39944
|
+
const refreshed = await refreshOhmypiCodexAuth();
|
|
40053
39945
|
if (refreshed) return {
|
|
40054
39946
|
status: "ok",
|
|
40055
39947
|
expiresAt: refreshed.expires
|
|
@@ -40066,19 +39958,13 @@ async function getPiCodexAuthStatus(opts) {
|
|
|
40066
39958
|
refreshFailed: false
|
|
40067
39959
|
};
|
|
40068
39960
|
}
|
|
40069
|
-
|
|
40070
|
-
|
|
40071
|
-
* returns the renewed credential on success, or null if there is no refresh
|
|
40072
|
-
* token, Pi's OAuth module is unavailable, or the refresh was rejected (the
|
|
40073
|
-
* refresh token itself is dead → a full re-login is required).
|
|
40074
|
-
*/
|
|
40075
|
-
async function refreshPiCodexAuth() {
|
|
40076
|
-
const cred = readPiCodexCredential();
|
|
39961
|
+
async function refreshOhmypiCodexAuth() {
|
|
39962
|
+
const cred = readOhmypiCodexCredential();
|
|
40077
39963
|
if (!cred?.refresh) return null;
|
|
40078
|
-
const mod = await
|
|
39964
|
+
const mod = await loadOhmypiCodexOAuth();
|
|
40079
39965
|
if (!mod) return null;
|
|
40080
39966
|
try {
|
|
40081
|
-
return
|
|
39967
|
+
return writeOhmypiCodexCredential(await mod.refreshOpenAICodexToken(cred.refresh));
|
|
40082
39968
|
} catch {
|
|
40083
39969
|
return null;
|
|
40084
39970
|
}
|
|
@@ -40155,7 +40041,7 @@ function isNonEmptyJsonlLine(buffer) {
|
|
|
40155
40041
|
}
|
|
40156
40042
|
//#endregion
|
|
40157
40043
|
//#region services/conversation-eaten-message-watcher.ts
|
|
40158
|
-
init_agents$
|
|
40044
|
+
init_agents$2();
|
|
40159
40045
|
const WATCH_TIMEOUT_MS = 5 * 6e4;
|
|
40160
40046
|
const WATCH_INTERVAL_MS = 3e3;
|
|
40161
40047
|
const REDELIVERY_GRACE_MS = 1e4;
|
|
@@ -40191,299 +40077,11 @@ async function watchForEatenConversationMessage(args) {
|
|
|
40191
40077
|
return "unverified";
|
|
40192
40078
|
}
|
|
40193
40079
|
//#endregion
|
|
40194
|
-
//#region ../../lib/
|
|
40080
|
+
//#region ../../lib/conversations/transcript-summary.ts
|
|
40195
40081
|
init_transcript_adapter();
|
|
40196
40082
|
init_summary_fork();
|
|
40197
40083
|
init_conversation_compaction();
|
|
40198
40084
|
/**
|
|
40199
|
-
* Session-format converter (P0, 2026-05-14).
|
|
40200
|
-
*
|
|
40201
|
-
* When a conversation's harness changes (Claude Code <-> Pi Agent), the two
|
|
40202
|
-
* runtimes store transcripts in incompatible JSONL formats and in different
|
|
40203
|
-
* locations:
|
|
40204
|
-
*
|
|
40205
|
-
* - Claude Code: ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl
|
|
40206
|
-
* - Pi Agent: ~/.overdeck/agents/<tmux-session>/sessions/<iso>_<id>.jsonl
|
|
40207
|
-
*
|
|
40208
|
-
* Historically the orchestrator would silently flip the harness and leave the
|
|
40209
|
-
* old transcript orphaned (the DB kept pointing at a session id with no file),
|
|
40210
|
-
* and the compaction path would even append Claude-format records into a Pi
|
|
40211
|
-
* JSONL. The chosen fix is to *convert* on an explicit harness change rather
|
|
40212
|
-
* than guard against it or build a multi-format reader.
|
|
40213
|
-
*
|
|
40214
|
-
* The conversion is deliberately lossless-of-content but lossy-of-structure:
|
|
40215
|
-
* we extract a readable transcript from the source format and seed a fresh
|
|
40216
|
-
* session in the target format with that transcript carried in as a single
|
|
40217
|
-
* continuation/summary message — the same "faux compaction boundary" mechanism
|
|
40218
|
-
* Overdeck already uses for native compaction. Tool-call structure, thinking
|
|
40219
|
-
* blocks, and per-message token accounting do not round-trip; the conversation
|
|
40220
|
-
* *content* does. This keeps the converter robust as both harness formats
|
|
40221
|
-
* continue to evolve.
|
|
40222
|
-
*/
|
|
40223
|
-
init_paths();
|
|
40224
|
-
/** Pull plain text out of a Claude/Pi `message.content` (string or block array). */
|
|
40225
|
-
function extractContentText(content) {
|
|
40226
|
-
if (typeof content === "string") return content;
|
|
40227
|
-
if (!Array.isArray(content)) return "";
|
|
40228
|
-
const parts = [];
|
|
40229
|
-
for (const block of content) {
|
|
40230
|
-
if (!block || typeof block !== "object") continue;
|
|
40231
|
-
const b = block;
|
|
40232
|
-
if (typeof b["text"] === "string") parts.push(b["text"]);
|
|
40233
|
-
else if (typeof b["thinking"] === "string") parts.push(`[thinking] ${b["thinking"]}`);
|
|
40234
|
-
else if ((b["type"] === "tool_use" || b["type"] === "toolCall") && typeof b["name"] === "string") parts.push(`[tool_use: ${b["name"]}]`);
|
|
40235
|
-
else if (b["type"] === "tool_result" || b["type"] === "toolResult") {
|
|
40236
|
-
const inner = extractContentText(b["content"]);
|
|
40237
|
-
if (inner) parts.push(`[tool_result] ${inner}`);
|
|
40238
|
-
}
|
|
40239
|
-
}
|
|
40240
|
-
return parts.join("\n").trim();
|
|
40241
|
-
}
|
|
40242
|
-
/** Read a Claude Code JSONL transcript into ordered role/text turns. */
|
|
40243
|
-
function extractClaudeTranscript(raw) {
|
|
40244
|
-
const turns = [];
|
|
40245
|
-
for (const line of raw.split("\n")) {
|
|
40246
|
-
const trimmed = line.trim();
|
|
40247
|
-
if (!trimmed) continue;
|
|
40248
|
-
let entry;
|
|
40249
|
-
try {
|
|
40250
|
-
entry = JSON.parse(trimmed);
|
|
40251
|
-
} catch {
|
|
40252
|
-
continue;
|
|
40253
|
-
}
|
|
40254
|
-
const type = entry["type"];
|
|
40255
|
-
if (type !== "user" && type !== "assistant") continue;
|
|
40256
|
-
const message = entry["message"];
|
|
40257
|
-
if (!message || typeof message !== "object") continue;
|
|
40258
|
-
const m = message;
|
|
40259
|
-
const role = typeof m["role"] === "string" ? m["role"] : type;
|
|
40260
|
-
const text = extractContentText(m["content"]);
|
|
40261
|
-
if (text) turns.push({
|
|
40262
|
-
role,
|
|
40263
|
-
text
|
|
40264
|
-
});
|
|
40265
|
-
}
|
|
40266
|
-
return turns;
|
|
40267
|
-
}
|
|
40268
|
-
/** Read a Pi Agent JSONL transcript into ordered role/text turns. */
|
|
40269
|
-
function extractPiTranscript(raw) {
|
|
40270
|
-
const turns = [];
|
|
40271
|
-
for (const line of raw.split("\n")) {
|
|
40272
|
-
const trimmed = line.trim();
|
|
40273
|
-
if (!trimmed) continue;
|
|
40274
|
-
let entry;
|
|
40275
|
-
try {
|
|
40276
|
-
entry = JSON.parse(trimmed);
|
|
40277
|
-
} catch {
|
|
40278
|
-
continue;
|
|
40279
|
-
}
|
|
40280
|
-
if (entry["type"] !== "message") continue;
|
|
40281
|
-
const message = entry["message"];
|
|
40282
|
-
if (!message || typeof message !== "object") continue;
|
|
40283
|
-
const m = message;
|
|
40284
|
-
const role = typeof m["role"] === "string" ? m["role"] : "assistant";
|
|
40285
|
-
const text = extractContentText(m["content"]);
|
|
40286
|
-
if (text) turns.push({
|
|
40287
|
-
role,
|
|
40288
|
-
text
|
|
40289
|
-
});
|
|
40290
|
-
}
|
|
40291
|
-
return turns;
|
|
40292
|
-
}
|
|
40293
|
-
/**
|
|
40294
|
-
* Read a Codex rollout JSONL transcript into ordered role/text turns.
|
|
40295
|
-
*
|
|
40296
|
-
* Rollout files use a different schema from --json stdout:
|
|
40297
|
-
* - task_started: the initial task (user role)
|
|
40298
|
-
* - agent_message: a model turn (assistant role)
|
|
40299
|
-
* - token_count: metadata — skipped
|
|
40300
|
-
*
|
|
40301
|
-
* We extract task_started as the user prompt and agent_message events as
|
|
40302
|
-
* assistant turns to produce a readable transcript.
|
|
40303
|
-
*/
|
|
40304
|
-
function extractCodexTranscript(raw) {
|
|
40305
|
-
const turns = [];
|
|
40306
|
-
for (const line of raw.split("\n")) {
|
|
40307
|
-
const trimmed = line.trim();
|
|
40308
|
-
if (!trimmed) continue;
|
|
40309
|
-
let entry;
|
|
40310
|
-
try {
|
|
40311
|
-
entry = JSON.parse(trimmed);
|
|
40312
|
-
} catch {
|
|
40313
|
-
continue;
|
|
40314
|
-
}
|
|
40315
|
-
const type = entry["type"];
|
|
40316
|
-
if (type === "task_started") {
|
|
40317
|
-
const task = typeof entry["task"] === "string" ? entry["task"] : "";
|
|
40318
|
-
if (task) turns.push({
|
|
40319
|
-
role: "user",
|
|
40320
|
-
text: task
|
|
40321
|
-
});
|
|
40322
|
-
} else if (type === "agent_message") {
|
|
40323
|
-
const content = typeof entry["content"] === "string" ? entry["content"] : extractContentText(entry["content"]);
|
|
40324
|
-
if (content) turns.push({
|
|
40325
|
-
role: "assistant",
|
|
40326
|
-
text: content
|
|
40327
|
-
});
|
|
40328
|
-
}
|
|
40329
|
-
}
|
|
40330
|
-
return turns;
|
|
40331
|
-
}
|
|
40332
|
-
/** Render ordered turns into a single readable transcript block. */
|
|
40333
|
-
function renderTranscript(turns) {
|
|
40334
|
-
return turns.map((t) => `### ${t.role}\n${t.text}`).join("\n\n");
|
|
40335
|
-
}
|
|
40336
|
-
function buildContinuation(fromHarness, transcript) {
|
|
40337
|
-
return [
|
|
40338
|
-
`This session is being continued from a previous conversation that ran under the ${fromHarness} harness.`,
|
|
40339
|
-
"The runtime was switched, so the transcript below is carried forward as context rather than as a native session.",
|
|
40340
|
-
"Continue from this history without redoing already-completed work.",
|
|
40341
|
-
"",
|
|
40342
|
-
"--- PRIOR TRANSCRIPT ---",
|
|
40343
|
-
transcript || "(the prior transcript was empty)",
|
|
40344
|
-
"--- END PRIOR TRANSCRIPT ---"
|
|
40345
|
-
].join("\n");
|
|
40346
|
-
}
|
|
40347
|
-
/** Short opaque id in Pi's `<8-hex>` style. */
|
|
40348
|
-
function shortId() {
|
|
40349
|
-
return randomBytes$1(4).toString("hex");
|
|
40350
|
-
}
|
|
40351
|
-
async function convertConversationTranscriptPromise(opts) {
|
|
40352
|
-
if (opts.fromHarness === opts.toHarness) throw new Error(`convertConversationTranscript called with no harness change (${opts.fromHarness})`);
|
|
40353
|
-
const raw = await readFile(opts.sourceSessionFile, "utf-8");
|
|
40354
|
-
let turns;
|
|
40355
|
-
switch (opts.fromHarness) {
|
|
40356
|
-
case "pi":
|
|
40357
|
-
turns = extractPiTranscript(raw);
|
|
40358
|
-
break;
|
|
40359
|
-
case "codex":
|
|
40360
|
-
turns = extractCodexTranscript(raw);
|
|
40361
|
-
break;
|
|
40362
|
-
default: turns = extractClaudeTranscript(raw);
|
|
40363
|
-
}
|
|
40364
|
-
const continuation = buildContinuation(opts.fromHarness, renderTranscript(turns));
|
|
40365
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
40366
|
-
if (opts.toHarness === "codex") {
|
|
40367
|
-
const threadId = randomUUID$1().replace(/-/g, "").slice(0, 16);
|
|
40368
|
-
const codexAgentDir = join$1(homedir$1(), ".overdeck", "agents", opts.tmuxSession, "codex-home");
|
|
40369
|
-
const sessionDate = /* @__PURE__ */ new Date();
|
|
40370
|
-
const sessionsDir = join$1(codexAgentDir, "sessions", [
|
|
40371
|
-
sessionDate.getFullYear().toString(),
|
|
40372
|
-
String(sessionDate.getMonth() + 1).padStart(2, "0"),
|
|
40373
|
-
String(sessionDate.getDate()).padStart(2, "0")
|
|
40374
|
-
].join("/"));
|
|
40375
|
-
await mkdir(sessionsDir, {
|
|
40376
|
-
recursive: true,
|
|
40377
|
-
mode: 448
|
|
40378
|
-
});
|
|
40379
|
-
const targetSessionFile = join$1(sessionsDir, `rollout-${randomUUID$1()}-${threadId}.jsonl`);
|
|
40380
|
-
await writeFile(targetSessionFile, `${[JSON.stringify({
|
|
40381
|
-
type: "task_started",
|
|
40382
|
-
model: "codex",
|
|
40383
|
-
task: continuation,
|
|
40384
|
-
thread_id: threadId,
|
|
40385
|
-
timestamp
|
|
40386
|
-
})].join("\n")}\n`, "utf-8");
|
|
40387
|
-
await mkdir(join$1(homedir$1(), ".overdeck", "agents", opts.tmuxSession), {
|
|
40388
|
-
recursive: true,
|
|
40389
|
-
mode: 448
|
|
40390
|
-
});
|
|
40391
|
-
writeThreadId(opts.tmuxSession, threadId);
|
|
40392
|
-
return {
|
|
40393
|
-
sessionId: threadId,
|
|
40394
|
-
targetSessionFile
|
|
40395
|
-
};
|
|
40396
|
-
}
|
|
40397
|
-
if (opts.toHarness === "pi") {
|
|
40398
|
-
const sessionId = randomUUID$1();
|
|
40399
|
-
const agentDir = join$1(homedir$1(), ".overdeck", "agents", opts.tmuxSession);
|
|
40400
|
-
const sessionDir = join$1(agentDir, "sessions");
|
|
40401
|
-
await mkdir(sessionDir, {
|
|
40402
|
-
recursive: true,
|
|
40403
|
-
mode: 448
|
|
40404
|
-
});
|
|
40405
|
-
const targetSessionFile = join$1(sessionDir, `${timestamp.replace(/[:.]/g, "-")}_${sessionId}.jsonl`);
|
|
40406
|
-
await writeFile(targetSessionFile, `${[JSON.stringify({
|
|
40407
|
-
type: "session",
|
|
40408
|
-
version: 3,
|
|
40409
|
-
id: sessionId,
|
|
40410
|
-
timestamp,
|
|
40411
|
-
cwd: opts.cwd
|
|
40412
|
-
}), JSON.stringify({
|
|
40413
|
-
type: "message",
|
|
40414
|
-
id: shortId(),
|
|
40415
|
-
parentId: null,
|
|
40416
|
-
timestamp,
|
|
40417
|
-
message: {
|
|
40418
|
-
role: "user",
|
|
40419
|
-
content: [{
|
|
40420
|
-
type: "text",
|
|
40421
|
-
text: continuation
|
|
40422
|
-
}]
|
|
40423
|
-
}
|
|
40424
|
-
})].join("\n")}\n`, "utf-8");
|
|
40425
|
-
await writeFile(join$1(agentDir, "session.id"), `${sessionId}\n`, "utf-8");
|
|
40426
|
-
return {
|
|
40427
|
-
sessionId,
|
|
40428
|
-
targetSessionFile
|
|
40429
|
-
};
|
|
40430
|
-
}
|
|
40431
|
-
const sessionId = randomUUID$1();
|
|
40432
|
-
const targetSessionFile = sessionFilePath(opts.cwd, sessionId);
|
|
40433
|
-
await mkdir(join$1(targetSessionFile, ".."), { recursive: true });
|
|
40434
|
-
const boundaryUuid = randomUUID$1();
|
|
40435
|
-
await writeFile(targetSessionFile, `${[JSON.stringify({
|
|
40436
|
-
parentUuid: null,
|
|
40437
|
-
isSidechain: false,
|
|
40438
|
-
type: "system",
|
|
40439
|
-
subtype: "compact_boundary",
|
|
40440
|
-
content: `Conversation runtime switched from ${opts.fromHarness} to claude-code`,
|
|
40441
|
-
isMeta: false,
|
|
40442
|
-
timestamp,
|
|
40443
|
-
uuid: boundaryUuid,
|
|
40444
|
-
sessionId,
|
|
40445
|
-
cwd: opts.cwd,
|
|
40446
|
-
level: "info",
|
|
40447
|
-
compactMetadata: {
|
|
40448
|
-
trigger: "overdeck-harness-switch",
|
|
40449
|
-
preTokens: 0
|
|
40450
|
-
}
|
|
40451
|
-
}), JSON.stringify({
|
|
40452
|
-
parentUuid: boundaryUuid,
|
|
40453
|
-
isSidechain: false,
|
|
40454
|
-
type: "user",
|
|
40455
|
-
message: {
|
|
40456
|
-
role: "user",
|
|
40457
|
-
content: continuation
|
|
40458
|
-
},
|
|
40459
|
-
isVisibleInTranscriptOnly: true,
|
|
40460
|
-
isCompactSummary: true,
|
|
40461
|
-
uuid: randomUUID$1(),
|
|
40462
|
-
sessionId,
|
|
40463
|
-
cwd: opts.cwd,
|
|
40464
|
-
timestamp
|
|
40465
|
-
})].join("\n")}\n`, "utf-8");
|
|
40466
|
-
return {
|
|
40467
|
-
sessionId,
|
|
40468
|
-
targetSessionFile
|
|
40469
|
-
};
|
|
40470
|
-
}
|
|
40471
|
-
/** Tagged error for session-format-converter Effect variants. */
|
|
40472
|
-
var SessionConvertError = class extends Data.TaggedError("SessionConvertError") {};
|
|
40473
|
-
/** Effect variant of `convertConversationTranscript`. */
|
|
40474
|
-
const convertConversationTranscript = (opts) => Effect.tryPromise({
|
|
40475
|
-
try: () => convertConversationTranscriptPromise(opts),
|
|
40476
|
-
catch: (cause) => new SessionConvertError({
|
|
40477
|
-
fromHarness: opts.fromHarness,
|
|
40478
|
-
toHarness: opts.toHarness,
|
|
40479
|
-
sourceSessionFile: opts.sourceSessionFile,
|
|
40480
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
40481
|
-
cause
|
|
40482
|
-
})
|
|
40483
|
-
});
|
|
40484
|
-
//#endregion
|
|
40485
|
-
//#region ../../lib/conversations/transcript-summary.ts
|
|
40486
|
-
/**
|
|
40487
40085
|
* Conversation transcript summarization.
|
|
40488
40086
|
*
|
|
40489
40087
|
* Shared helpers for turning a conversation's parsed messages into LLM-generated
|
|
@@ -40506,8 +40104,8 @@ const convertConversationTranscript = (opts) => Effect.tryPromise({
|
|
|
40506
40104
|
* layering inversion.
|
|
40507
40105
|
*/
|
|
40508
40106
|
init_child_env();
|
|
40509
|
-
init_agents$
|
|
40510
|
-
init_cost();
|
|
40107
|
+
init_agents$2();
|
|
40108
|
+
init_cost$1();
|
|
40511
40109
|
/** Haiku — fast/cheap, used for every conversation title and about-summary. */
|
|
40512
40110
|
const CONVERSATION_TITLE_MODEL = "claude-haiku-4-5-20251001";
|
|
40513
40111
|
/** Total transcript characters allowed into a single prompt. */
|
|
@@ -40553,6 +40151,17 @@ function sanitizeTitle(raw) {
|
|
|
40553
40151
|
return raw.trim().split(/\r?\n/)[0]?.trim().replace(/^['"`]+|['"`]+$/g, "").trim().replace(/\s+/g, " ") ?? "";
|
|
40554
40152
|
}
|
|
40555
40153
|
/**
|
|
40154
|
+
* Generate a deterministic title from a serialized transcript when the model
|
|
40155
|
+
* path is unavailable. Prefer the latest user request because explicit retitle
|
|
40156
|
+
* should describe where the conversation currently landed.
|
|
40157
|
+
*/
|
|
40158
|
+
function fallbackTranscriptTitle(transcript) {
|
|
40159
|
+
const lines = transcript.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("[…"));
|
|
40160
|
+
const compact = (lines.filter((line) => line.startsWith("User:")).map((line) => line.slice(5).trim()).filter(Boolean).at(-1) ?? lines[0]?.replace(/^(User|Assistant):\s*/i, "").trim() ?? "").replace(/```[\s\S]*?```/g, " ").replace(/`([^`]+)`/g, "$1").replace(/\b(?:please|can you|could you|would you)\b/gi, " ").replace(/\b(?:i need you to|i want you to|help me|let's|lets)\b/gi, " ").replace(/https?:\/\/\S+/gi, " ").replace(/[^\p{L}\p{N}#/_+.-]+/gu, " ").replace(/\s+/g, " ").trim();
|
|
40161
|
+
if (!compact) return "";
|
|
40162
|
+
return sanitizeTitle(compact.split(/\s+/).slice(0, 8).join(" ").replace(/\s+(?:and|or|to|for|with)$/i, "").replace(/[.,:;!?]+$/g, ""));
|
|
40163
|
+
}
|
|
40164
|
+
/**
|
|
40556
40165
|
* Invoke `claude -p` with a JSON schema and return the structured output.
|
|
40557
40166
|
* Throws on non-zero exit, timeout, spawn error, or unparseable output.
|
|
40558
40167
|
*/
|
|
@@ -40736,7 +40345,7 @@ async function cleanupConversationAttachments(name) {
|
|
|
40736
40345
|
* sessions that the lifecycle poller missed. */
|
|
40737
40346
|
async function cleanupOrphanedConversationAttachments() {
|
|
40738
40347
|
try {
|
|
40739
|
-
const { listConversations } = await import("./conversations-
|
|
40348
|
+
const { listConversations } = await import("./conversations-BC6lrn4U.js");
|
|
40740
40349
|
const convNames = new Set(listConversations().map((c) => c.name));
|
|
40741
40350
|
const root = getConversationAttachmentsRoot();
|
|
40742
40351
|
await runInBatches((await readdir(root, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !convNames.has(entry.name)).map((entry) => join$1(root, entry.name)), 10, (path) => rm(path, {
|
|
@@ -40931,22 +40540,27 @@ async function removeConversationAttachment(name, attachmentPath) {
|
|
|
40931
40540
|
*
|
|
40932
40541
|
* Conversations are NEVER deleted from the database, and JSONL transcript files are never removed.
|
|
40933
40542
|
*/
|
|
40543
|
+
init_http_helpers();
|
|
40934
40544
|
init_child_env();
|
|
40935
40545
|
init_claude_permissions();
|
|
40546
|
+
init_jsonl_resolver();
|
|
40547
|
+
init_origin_validation();
|
|
40936
40548
|
init_projects();
|
|
40937
40549
|
init_model_capabilities();
|
|
40938
40550
|
init_conversations();
|
|
40939
40551
|
init_tmux();
|
|
40940
|
-
init_agents$
|
|
40552
|
+
init_agents$2();
|
|
40941
40553
|
init_config_yaml();
|
|
40942
40554
|
init_harness_policy();
|
|
40943
40555
|
init_providers();
|
|
40556
|
+
init_agent_input_detection();
|
|
40944
40557
|
init_launcher_generator();
|
|
40945
40558
|
init_layers();
|
|
40946
40559
|
init_briefing_freshness();
|
|
40947
40560
|
init_conversation_service();
|
|
40948
40561
|
init_transcript_landing();
|
|
40949
40562
|
init_pi_conversation_parser();
|
|
40563
|
+
init_ohmypi_conversation_parser();
|
|
40950
40564
|
init_codex_conversation_parser();
|
|
40951
40565
|
init_paths();
|
|
40952
40566
|
init_event_store();
|
|
@@ -41055,66 +40669,11 @@ function shellQuote(str) {
|
|
|
41055
40669
|
return "'" + str.replace(/'/g, "'\"'\"'") + "'";
|
|
41056
40670
|
}
|
|
41057
40671
|
const SAFE_MODEL_PATTERN = /^[a-zA-Z0-9_.:\/-]+$/;
|
|
41058
|
-
const DEFAULT_SWITCH_MODEL_CONTEXT_WINDOW = 2e5;
|
|
41059
|
-
const SWITCH_MODEL_STATUSLINE_TIMEOUT_MS = 5e3;
|
|
41060
|
-
const SWITCH_MODEL_STATUSLINE_POLL_MS = 250;
|
|
41061
40672
|
const SAFE_EFFORT_PATTERN = /^(low|medium|high)$/;
|
|
41062
|
-
function modelCapabilityForModel(model) {
|
|
41063
|
-
if (!model) return void 0;
|
|
41064
|
-
const resolvedModel = resolveModelIdSync(model);
|
|
41065
|
-
return Object.prototype.hasOwnProperty.call(MODEL_CAPABILITIES, resolvedModel) ? MODEL_CAPABILITIES[resolvedModel] : void 0;
|
|
41066
|
-
}
|
|
41067
|
-
function registryContextWindowForModel(model) {
|
|
41068
|
-
return modelCapabilityForModel(model)?.contextWindow ?? DEFAULT_SWITCH_MODEL_CONTEXT_WINDOW;
|
|
41069
|
-
}
|
|
41070
|
-
function displayNameForModel(model) {
|
|
41071
|
-
return modelCapabilityForModel(model)?.displayName ?? model;
|
|
41072
|
-
}
|
|
41073
|
-
async function isCliproxyRoutedModel(model) {
|
|
41074
|
-
if (!model) return false;
|
|
41075
|
-
return getProviderForModelSync(model).name === "openai" && await getProviderAuthMode(model) === "subscription";
|
|
41076
|
-
}
|
|
41077
|
-
function providerRoutingSignature(exports) {
|
|
41078
|
-
return exports.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("unset ")).join("\n");
|
|
41079
|
-
}
|
|
41080
|
-
async function hasProviderRoutingChanged(currentModel, targetModel) {
|
|
41081
|
-
if (!targetModel || currentModel === targetModel) return false;
|
|
41082
|
-
const targetSignature = providerRoutingSignature(await getProviderExportsForModel(targetModel));
|
|
41083
|
-
if (!currentModel) return targetSignature !== "";
|
|
41084
|
-
return providerRoutingSignature(await getProviderExportsForModel(currentModel)) !== targetSignature;
|
|
41085
|
-
}
|
|
41086
|
-
const ANSI_ESCAPE_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
41087
|
-
function normalizePaneLine(line) {
|
|
41088
|
-
return line.replace(ANSI_ESCAPE_PATTERN, "").trim().toLowerCase();
|
|
41089
|
-
}
|
|
41090
|
-
function modelStatuslinePrefix(line) {
|
|
41091
|
-
return line.startsWith("statusline:") ? line.slice(11).trimStart() : line;
|
|
41092
|
-
}
|
|
41093
|
-
function hasStatuslineModelConfirmation(pane, targetModel) {
|
|
41094
|
-
const targetDisplayName = displayNameForModel(targetModel).toLowerCase();
|
|
41095
|
-
const targetModelId = targetModel.toLowerCase();
|
|
41096
|
-
const expectedWithId = `${targetDisplayName} (${targetModelId})`;
|
|
41097
|
-
for (const rawLine of pane.split(/\r?\n/)) {
|
|
41098
|
-
const line = normalizePaneLine(rawLine);
|
|
41099
|
-
if (!line || line.includes("/model")) continue;
|
|
41100
|
-
const modelLine = modelStatuslinePrefix(line);
|
|
41101
|
-
if (modelLine === targetModelId || modelLine.startsWith(`${targetModelId} `)) return true;
|
|
41102
|
-
if (modelLine === expectedWithId || modelLine.startsWith(`${expectedWithId} `)) return true;
|
|
41103
|
-
}
|
|
41104
|
-
return false;
|
|
41105
|
-
}
|
|
41106
|
-
async function waitForModelStatusline(tmuxSession, targetModel) {
|
|
41107
|
-
const start = Date.now();
|
|
41108
|
-
while (Date.now() - start < SWITCH_MODEL_STATUSLINE_TIMEOUT_MS) {
|
|
41109
|
-
if (hasStatuslineModelConfirmation(await Effect.runPromise(capturePane(tmuxSession, 10).pipe(Effect.catch(() => Effect.succeed("")))), targetModel)) return true;
|
|
41110
|
-
await new Promise((r) => setTimeout(r, SWITCH_MODEL_STATUSLINE_POLL_MS));
|
|
41111
|
-
}
|
|
41112
|
-
return false;
|
|
41113
|
-
}
|
|
41114
40673
|
const SAFE_ISSUE_ID_PATTERN = /^[A-Z0-9]+-[0-9]+$/;
|
|
41115
40674
|
async function resolveAllowedHarness(requested, model) {
|
|
41116
40675
|
if (!model) return "claude-code";
|
|
41117
|
-
const explicit = requested === "
|
|
40676
|
+
const explicit = requested === "ohmypi" || requested === "claude-code" || requested === "codex" ? requested : void 0;
|
|
41118
40677
|
try {
|
|
41119
40678
|
return await resolveHarness({
|
|
41120
40679
|
model,
|
|
@@ -41178,6 +40737,7 @@ async function getCachedMessages(sessionFile, isSpecialist) {
|
|
|
41178
40737
|
if (cached && cached.mtimeMs === fileStats.mtimeMs && cached.size === fileStats.size && cached.byteOffset >= fileStats.size) return cached.result;
|
|
41179
40738
|
let result;
|
|
41180
40739
|
if (isCodexSessionFile(sessionFile)) result = await parseCodexConversationMessages(sessionFile);
|
|
40740
|
+
else if (isOhmypiSessionFile(sessionFile)) result = await parseOhmypiConversationMessages(sessionFile);
|
|
41181
40741
|
else if (isPiSessionFile(sessionFile)) result = await parsePiConversationMessages(sessionFile);
|
|
41182
40742
|
else if (isSpecialist) result = await parseFromLastCompactBoundary(sessionFile);
|
|
41183
40743
|
else if (cached && cached.parseState && cached.byteOffset <= fileStats.size && cached.size <= fileStats.size) {
|
|
@@ -41332,8 +40892,14 @@ async function waitForPiTuiReady(tmuxSession, timeoutMs = 3e4) {
|
|
|
41332
40892
|
return false;
|
|
41333
40893
|
}
|
|
41334
40894
|
async function resolveSessionFile(conv) {
|
|
41335
|
-
if (conv.harness === "
|
|
41336
|
-
|
|
40895
|
+
if (conv.harness === "ohmypi") {
|
|
40896
|
+
const piPath = await resolvePiSessionPath(conv.tmuxSession);
|
|
40897
|
+
if (piPath) return piPath;
|
|
40898
|
+
}
|
|
40899
|
+
if (conv.harness === "codex") {
|
|
40900
|
+
const codexPath = await resolveCodexRolloutPath(conv.tmuxSession);
|
|
40901
|
+
if (codexPath) return codexPath;
|
|
40902
|
+
}
|
|
41337
40903
|
const sessionId = await readLauncherPinnedSessionId(conv.tmuxSession) ?? conv.claudeSessionId;
|
|
41338
40904
|
if (sessionId) return sessionFilePath(conv.cwd, sessionId);
|
|
41339
40905
|
console.error(`[conversations] UNRESOLVED claude-code session for conversation '${conv.name}' (tmux=${conv.tmuxSession}, status=${conv.status}, cwd=${conv.cwd}): no --session-id pinned in launcher.sh and no recorded claudeSessionId. The transcript panel cannot be trusted.`);
|
|
@@ -41524,7 +41090,7 @@ async function handleConversationMessage(name, body) {
|
|
|
41524
41090
|
if (!outboundMessage) return jsonResponse({ error: `${conv.model ?? "This model"} can't read images. Switch to a vision-capable model (e.g. mimo-v2.5) to send images.` }, { status: 422 });
|
|
41525
41091
|
}
|
|
41526
41092
|
let deliveredMessage = transformMessageForHarness(outboundMessage, harness, effectiveAttachmentPaths);
|
|
41527
|
-
if (harness === "
|
|
41093
|
+
if (harness === "ohmypi") deliveredMessage = await injectPiConversationMemory({
|
|
41528
41094
|
cwd: conv.cwd,
|
|
41529
41095
|
issueId: conv.issueId,
|
|
41530
41096
|
conversationName: conv.name
|
|
@@ -41585,7 +41151,7 @@ function shouldUseSupervisorForConversation(harness) {
|
|
|
41585
41151
|
}
|
|
41586
41152
|
function resolveConversationDeliveryMethod(conv) {
|
|
41587
41153
|
const harness = conv.harness ?? "claude-code";
|
|
41588
|
-
return conv.deliveryMethod ?? (harness === "
|
|
41154
|
+
return conv.deliveryMethod ?? (harness === "ohmypi" ? "tmux" : "auto");
|
|
41589
41155
|
}
|
|
41590
41156
|
/** Synthetic toolUseId prefix marking a Codex pane-detected approval (PAN-1690). */
|
|
41591
41157
|
const CODEX_APPROVAL_TOOL_PREFIX = "codex-approval:";
|
|
@@ -41801,10 +41367,10 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41801
41367
|
if (!runtimeCommand.includes("--permission-mode")) runtimeCommand = `${runtimeCommand} --permission-mode ${mode === "auto" ? "auto" : BYPASS_PERMISSION_MODE}`;
|
|
41802
41368
|
providerExportsStr = (await getProviderExportsForModel(model)).trim();
|
|
41803
41369
|
await getProviderEnvForModel(model);
|
|
41804
|
-
if (harness === "
|
|
41370
|
+
if (harness === "ohmypi") {
|
|
41805
41371
|
if (getProviderForModelSync(model).name === "openai") {
|
|
41806
|
-
const auth = await
|
|
41807
|
-
if (auth.status === "missing" || auth.status === "expired") throw new Error("
|
|
41372
|
+
const auth = await getOhmypiCodexAuthStatus({ refreshIfExpired: true });
|
|
41373
|
+
if (auth.status === "missing" || auth.status === "expired") throw new Error("ohmypi ChatGPT/Codex login (openai-codex) has expired and could not be refreshed. Re-authenticate with `pan pi-auth login`, then retry.");
|
|
41808
41374
|
}
|
|
41809
41375
|
const paths = piFifoPaths(tmuxSession);
|
|
41810
41376
|
const piSessionDir = join$1(paths.agentDir, "sessions");
|
|
@@ -41818,9 +41384,9 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41818
41384
|
});
|
|
41819
41385
|
const storedPiSessionId = resume ? await readFile(join$1(paths.agentDir, "session.id"), "utf-8").then((s) => s.trim()).catch(() => void 0) : void 0;
|
|
41820
41386
|
piFields = {
|
|
41821
|
-
harness: "
|
|
41387
|
+
harness: "ohmypi",
|
|
41822
41388
|
piMode: "tui",
|
|
41823
|
-
piExtensionPath: resolve$1(process.cwd(), "packages/
|
|
41389
|
+
piExtensionPath: resolveOhmypiExtensionPath() ?? resolve$1(process.cwd(), "packages/ohmypi-extension/dist/index.js"),
|
|
41824
41390
|
piSessionDir,
|
|
41825
41391
|
resumeSessionId: storedPiSessionId || void 0
|
|
41826
41392
|
};
|
|
@@ -41830,7 +41396,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41830
41396
|
const codexApprovalPolicy = codexPermMode === "full-access" ? "never" : "on-request";
|
|
41831
41397
|
const codexSandboxMode = codexPermMode === "full-access" ? "danger-full-access" : codexPermMode === "read-only" ? "read-only" : "workspace-write";
|
|
41832
41398
|
const codexApprovalsReviewer = codexPermMode === "auto-review" ? "auto_review" : void 0;
|
|
41833
|
-
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-
|
|
41399
|
+
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-Bt9WjVrk.js");
|
|
41834
41400
|
initCodexHome(codexHome, {
|
|
41835
41401
|
trustedDir: cwd,
|
|
41836
41402
|
approvalPolicy: codexApprovalPolicy,
|
|
@@ -41848,7 +41414,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41848
41414
|
}
|
|
41849
41415
|
}
|
|
41850
41416
|
let launcherModel = model;
|
|
41851
|
-
if (harness === "
|
|
41417
|
+
if (harness === "ohmypi" && model) {
|
|
41852
41418
|
const piProvider = piProviderForModel(model);
|
|
41853
41419
|
if (piProvider) launcherModel = `${piProvider}/${model}`;
|
|
41854
41420
|
}
|
|
@@ -41900,7 +41466,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41900
41466
|
} catch {}
|
|
41901
41467
|
console.log(`[claude-invoke] purpose=conversation-session | model=${model || "default"} | source=conversations.ts:spawnConversationSession | session=${tmuxSession} | resume=${resume} | command="${runtimeCommand}"`);
|
|
41902
41468
|
try {
|
|
41903
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
41469
|
+
const { preTrustDirectory } = await import("./workspace-manager-C1Ocyoqn.js");
|
|
41904
41470
|
preTrustDirectory(cwd);
|
|
41905
41471
|
} catch {}
|
|
41906
41472
|
try {
|
|
@@ -41917,7 +41483,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41917
41483
|
const codexHomeDir = codexFields.codexHome;
|
|
41918
41484
|
(async () => {
|
|
41919
41485
|
try {
|
|
41920
|
-
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-
|
|
41486
|
+
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-Bt9WjVrk.js");
|
|
41921
41487
|
const rollout = await waitForCodexRollout(codexHomeDir, 12e4);
|
|
41922
41488
|
if (rollout) {
|
|
41923
41489
|
const threadId = extractThreadIdFromRollout(rollout);
|
|
@@ -42051,6 +41617,9 @@ function scheduleTitleRefinement(conversationName) {
|
|
|
42051
41617
|
/** Conversations with a retitle currently running — guards against double-clicks. */
|
|
42052
41618
|
const retitleInFlight = /* @__PURE__ */ new Set();
|
|
42053
41619
|
const EXPLICIT_RETITLE_TIMEOUT_MS = 9e4;
|
|
41620
|
+
function isClaudeInvocationTimeout(error) {
|
|
41621
|
+
return error instanceof Error && /claude invocation timed out after \d+ms/.test(error.message);
|
|
41622
|
+
}
|
|
42054
41623
|
/** transcript-size-keyed cache so re-opening the About drawer doesn't re-summarize. */
|
|
42055
41624
|
const aboutSummaryCache = /* @__PURE__ */ new Map();
|
|
42056
41625
|
const ABOUT_SUMMARY_CACHE_MAX = 100;
|
|
@@ -42452,7 +42021,7 @@ const postConversationRoute = HttpRouter.add("POST", "/api/conversations", Effec
|
|
|
42452
42021
|
try {
|
|
42453
42022
|
await spawnConversationSession(tmuxSession, cwd, claudeSessionId, model, effort, issueId, false, harness);
|
|
42454
42023
|
console.log(`[conversations] tmux session ${tmuxSession} spawned, sessionId: ${claudeSessionId}`);
|
|
42455
|
-
if (harness === "
|
|
42024
|
+
if (harness === "ohmypi") await waitForPiTuiReady(tmuxSession);
|
|
42456
42025
|
else if (harness !== "codex") {
|
|
42457
42026
|
await waitForClaudeReady(tmuxSession);
|
|
42458
42027
|
console.log(`[conversations] Claude ready in ${tmuxSession}`);
|
|
@@ -42461,6 +42030,7 @@ const postConversationRoute = HttpRouter.add("POST", "/api/conversations", Effec
|
|
|
42461
42030
|
} catch (spawnErr) {
|
|
42462
42031
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
42463
42032
|
console.error(`[conversations] background spawn failed for ${tmuxSession}: ${msg}`);
|
|
42033
|
+
updateSpawnError(name, msg);
|
|
42464
42034
|
getEventStore().emitOnly({
|
|
42465
42035
|
type: "conversation.created",
|
|
42466
42036
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -42546,7 +42116,7 @@ const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:
|
|
|
42546
42116
|
try {
|
|
42547
42117
|
await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), model, effort, conv.issueId ?? void 0, canResume, harness);
|
|
42548
42118
|
await waitForTmuxSession(conv.tmuxSession);
|
|
42549
|
-
if (harness === "
|
|
42119
|
+
if (harness === "ohmypi") await waitForPiTuiReady(conv.tmuxSession);
|
|
42550
42120
|
else if (harness !== "codex") await waitForReadySignal(conv.tmuxSession, 30);
|
|
42551
42121
|
markConversationActive(name);
|
|
42552
42122
|
return jsonResponse({
|
|
@@ -42576,11 +42146,12 @@ const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
42576
42146
|
try {
|
|
42577
42147
|
const conv = getConversationByName(name);
|
|
42578
42148
|
if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
|
|
42149
|
+
if (conv.claudeSessionId) return jsonResponse({ error: "Conversation model is locked once a conversation has started" }, { status: 409 });
|
|
42579
42150
|
const model = typeof body["model"] === "string" && body["model"].trim() ? body["model"].trim() : conv.model ?? void 0;
|
|
42580
42151
|
const currentHarness = conv.harness ?? "claude-code";
|
|
42581
42152
|
const requestedHarness = body["harness"];
|
|
42582
42153
|
let harness = currentHarness;
|
|
42583
|
-
if (requestedHarness === "
|
|
42154
|
+
if (requestedHarness === "ohmypi" || requestedHarness === "claude-code" || requestedHarness === "codex") {
|
|
42584
42155
|
if (requestedHarness !== currentHarness) {
|
|
42585
42156
|
const policyModel = model ?? conv.model ?? "";
|
|
42586
42157
|
const decision = canUseHarnessSync(requestedHarness, policyModel, await getProviderAuthMode(policyModel));
|
|
@@ -42591,101 +42162,15 @@ const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
42591
42162
|
const harnessChanged = harness !== currentHarness;
|
|
42592
42163
|
if (!await validateCwdContainment(conv.cwd)) return jsonResponse({ error: "Invalid cwd" }, { status: 400 });
|
|
42593
42164
|
if (model && !SAFE_MODEL_PATTERN.test(model)) return jsonResponse({ error: "Invalid model" }, { status: 400 });
|
|
42594
|
-
|
|
42595
|
-
|
|
42596
|
-
const
|
|
42597
|
-
|
|
42598
|
-
|
|
42599
|
-
|
|
42600
|
-
|
|
42601
|
-
|
|
42602
|
-
const contextUsage = sessionFile && existsSync$1(sessionFile) ? await computeContextUsage(sessionFile, conv.model ?? targetModel ?? null) : null;
|
|
42603
|
-
const contextTokens = contextUsage?.estimatedTokens ?? 0;
|
|
42604
|
-
const currentObservedCeiling = Math.max(contextUsage?.maxObservedInputTokens ?? 0, contextTokens);
|
|
42605
|
-
const switchStrategy = decideSwitchStrategy({
|
|
42606
|
-
harnessChanged,
|
|
42607
|
-
providerRoutingChanged,
|
|
42608
|
-
contextTokens,
|
|
42609
|
-
effectiveTargetWindow: getEffectiveTargetWindow({
|
|
42610
|
-
registryWindow: registryContextWindowForModel(targetModel),
|
|
42611
|
-
currentObservedCeiling,
|
|
42612
|
-
cliproxyRouted: await isCliproxyRoutedModel(targetModel),
|
|
42613
|
-
providerRoutingChanged
|
|
42614
|
-
})
|
|
42165
|
+
if (model) setConversationModel(name, model);
|
|
42166
|
+
if (harnessChanged) setConversationHarness(name, harness);
|
|
42167
|
+
const updated = getConversationByName(name) ?? conv;
|
|
42168
|
+
return jsonResponse({
|
|
42169
|
+
...updated,
|
|
42170
|
+
model: model ?? updated.model,
|
|
42171
|
+
harness,
|
|
42172
|
+
sessionAlive: false
|
|
42615
42173
|
});
|
|
42616
|
-
if (harness === "claude-code" && switchStrategy.useModelCommand && targetModel) {
|
|
42617
|
-
if (model) setConversationModel(name, model);
|
|
42618
|
-
try {
|
|
42619
|
-
await deliverAgentMessage(tmuxSession, `/model ${targetModel}`, "conversation-switch-model", resolveConversationDeliveryMethod(conv));
|
|
42620
|
-
if (await waitForModelStatusline(tmuxSession, targetModel)) {
|
|
42621
|
-
markConversationActive(name);
|
|
42622
|
-
return jsonResponse({
|
|
42623
|
-
...conv,
|
|
42624
|
-
status: "active",
|
|
42625
|
-
model: targetModel,
|
|
42626
|
-
harness,
|
|
42627
|
-
reattached: false,
|
|
42628
|
-
sessionAlive: true
|
|
42629
|
-
});
|
|
42630
|
-
}
|
|
42631
|
-
console.warn(`[conversations] switch-model Tier 1 statusline verification timed out for ${name}; falling back to respawn`);
|
|
42632
|
-
} catch (deliveryErr) {
|
|
42633
|
-
const msg = deliveryErr instanceof Error ? deliveryErr.message : String(deliveryErr);
|
|
42634
|
-
console.warn(`[conversations] switch-model Tier 1 delivery failed for ${name}; falling back to respawn: ${msg}`);
|
|
42635
|
-
}
|
|
42636
|
-
}
|
|
42637
|
-
const respawn = markRespawnPending(tmuxSession);
|
|
42638
|
-
try {
|
|
42639
|
-
await Effect.runPromise(killSession(tmuxSession).pipe(Effect.catch(() => Effect.succeed(void 0))));
|
|
42640
|
-
if (model) setConversationModel(name, model);
|
|
42641
|
-
if (harnessChanged) setConversationHarness(name, harness);
|
|
42642
|
-
let resumeSessionId = oldSessionId ?? randomUUID$1();
|
|
42643
|
-
let canResume = !!oldSessionId && !!sessionFile && existsSync$1(sessionFile);
|
|
42644
|
-
if (oldSessionId && !canResume) console.error(`[conversations] SESSION-LOST ${name} harness=${currentHarness} claudeSessionId=${oldSessionId} resolved=${sessionFile ?? "null"} — switch-model will start a fresh session`);
|
|
42645
|
-
if (harnessChanged) if (canResume && sessionFile) try {
|
|
42646
|
-
const result = await Effect.runPromise(convertConversationTranscript({
|
|
42647
|
-
fromHarness: currentHarness,
|
|
42648
|
-
toHarness: harness,
|
|
42649
|
-
sourceSessionFile: sessionFile,
|
|
42650
|
-
cwd,
|
|
42651
|
-
tmuxSession
|
|
42652
|
-
}));
|
|
42653
|
-
resumeSessionId = result.sessionId;
|
|
42654
|
-
canResume = true;
|
|
42655
|
-
if (harness === "claude-code") setConversationClaudeSessionId(name, result.sessionId);
|
|
42656
|
-
} catch (convErr) {
|
|
42657
|
-
const cm = convErr instanceof Error ? convErr.message : String(convErr);
|
|
42658
|
-
console.error(`[conversations] SESSION-CONVERT-FAILED ${name} ${currentHarness}->${harness}: ${cm}`);
|
|
42659
|
-
canResume = false;
|
|
42660
|
-
}
|
|
42661
|
-
else canResume = false;
|
|
42662
|
-
else if (harness === "claude-code") {
|
|
42663
|
-
const compactionFork = await maybeCompactBeforeRespawn({
|
|
42664
|
-
sessionFile,
|
|
42665
|
-
cwd,
|
|
42666
|
-
shouldCompact: switchStrategy.compact
|
|
42667
|
-
});
|
|
42668
|
-
if (compactionFork) {
|
|
42669
|
-
resumeSessionId = compactionFork.forkedSessionId;
|
|
42670
|
-
setConversationClaudeSessionId(name, compactionFork.forkedSessionId);
|
|
42671
|
-
}
|
|
42672
|
-
}
|
|
42673
|
-
await spawnConversationSession(tmuxSession, cwd, resumeSessionId, model, effort, issueId, canResume, harness);
|
|
42674
|
-
await waitForTmuxSession(tmuxSession);
|
|
42675
|
-
if (harness === "pi") await waitForPiTuiReady(tmuxSession);
|
|
42676
|
-
else if (harness !== "codex") await waitForReadySignal(tmuxSession, 30);
|
|
42677
|
-
markConversationActive(name);
|
|
42678
|
-
return jsonResponse({
|
|
42679
|
-
...conv,
|
|
42680
|
-
status: "active",
|
|
42681
|
-
model,
|
|
42682
|
-
harness,
|
|
42683
|
-
reattached: false,
|
|
42684
|
-
sessionAlive: true
|
|
42685
|
-
});
|
|
42686
|
-
} finally {
|
|
42687
|
-
respawn.done();
|
|
42688
|
-
}
|
|
42689
42174
|
} catch (error) {
|
|
42690
42175
|
const msg = error instanceof Error ? error.message : String(error);
|
|
42691
42176
|
console.error("[conversations] switch model failed:", msg);
|
|
@@ -42735,7 +42220,7 @@ const getConversationMessagesRoute = HttpRouter.add("GET", "/api/conversations/:
|
|
|
42735
42220
|
sessionFile = rollout;
|
|
42736
42221
|
setSpecialistSessionCache(name, rollout);
|
|
42737
42222
|
}
|
|
42738
|
-
} else if (agentHarness === "
|
|
42223
|
+
} else if (agentHarness === "ohmypi") {
|
|
42739
42224
|
const piSession = await resolvePiSessionPath(name);
|
|
42740
42225
|
if (piSession) {
|
|
42741
42226
|
sessionFile = piSession;
|
|
@@ -43238,7 +42723,7 @@ async function ensureForkSessionReady(conv, sessionId, resume, plainFork = false
|
|
|
43238
42723
|
async function injectForkSummary(conv, summary, caller) {
|
|
43239
42724
|
updateForkStatus(conv.name, "injecting");
|
|
43240
42725
|
const method = resolveConversationDeliveryMethod(conv);
|
|
43241
|
-
if (conv.harness === "
|
|
42726
|
+
if (conv.harness === "ohmypi") {
|
|
43242
42727
|
await waitForPiTuiReady(conv.tmuxSession, 6e4);
|
|
43243
42728
|
await deliverAgentMessage(conv.tmuxSession, summary, caller, method);
|
|
43244
42729
|
return;
|
|
@@ -43268,7 +42753,7 @@ async function runForkPipeline(convName, parentConv, sessionId, summaryModel, fo
|
|
|
43268
42753
|
const parentSessionFile = await resolveForkSourceSessionFile(parentConv);
|
|
43269
42754
|
if (!parentSessionFile) throw new Error(`Parent has no session file`);
|
|
43270
42755
|
if (forkMode === "plain") {
|
|
43271
|
-
if (conv.harness === "
|
|
42756
|
+
if (conv.harness === "ohmypi" || conv.harness === "codex") throw new Error(`Plain forks cannot launch under the ${conv.harness} harness — it cannot consume Claude session history.`);
|
|
43272
42757
|
if (!(await forkSessionExists(conv.tmuxSession) && await forkHarnessProcessAlive(conv.tmuxSession))) {
|
|
43273
42758
|
const forkSessionFile = await resolveSessionFile(conv);
|
|
43274
42759
|
if (!forkSessionFile) throw new Error(`Fork conversation ${convName} has no session file`);
|
|
@@ -43485,7 +42970,7 @@ const postConversationSummaryForkRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
43485
42970
|
const launchHarness = await resolveAllowedHarness(body["harness"], launchModel);
|
|
43486
42971
|
const summaryHarness = await resolveAllowedHarness(body["summaryHarness"], effectiveSummaryModel);
|
|
43487
42972
|
const handoffAuthorHarness = body["handoffAuthorHarness"] !== void 0 ? await resolveAllowedHarness(body["handoffAuthorHarness"], handoffAuthorModel || effectiveSummaryModel) : void 0;
|
|
43488
|
-
if (forkMode === "plain" && (launchHarness === "
|
|
42973
|
+
if (forkMode === "plain" && (launchHarness === "ohmypi" || launchHarness === "codex")) return jsonResponse({ error: `Plain forks cannot launch under ${launchHarness} — it cannot consume Claude session history. Use a summary fork instead.` }, { status: 400 });
|
|
43489
42974
|
const defaultTitle = forkMode === "plain" ? `Fork: ${conv.title || conv.name}` : forkMode === "handoff" ? handoffTitleFromFocus(handoffFocus, conv.title || conv.name) : `Summary Fork: ${conv.title || conv.name}`;
|
|
43490
42975
|
const newConv = createConversation({
|
|
43491
42976
|
name: newName,
|
|
@@ -43818,7 +43303,15 @@ const postConversationRetitleRoute = HttpRouter.add("POST", "/api/conversations/
|
|
|
43818
43303
|
try {
|
|
43819
43304
|
const model = configuredTitleModel();
|
|
43820
43305
|
console.log(`[claude-invoke] purpose=conversation-retitle | model=${model} | conversation=${name} | transcriptChars=${transcript.length}`);
|
|
43821
|
-
|
|
43306
|
+
let title;
|
|
43307
|
+
try {
|
|
43308
|
+
title = await summarizeTranscriptTitle(transcript, model, EXPLICIT_RETITLE_TIMEOUT_MS);
|
|
43309
|
+
} catch (error) {
|
|
43310
|
+
if (!isClaudeInvocationTimeout(error)) throw error;
|
|
43311
|
+
title = fallbackTranscriptTitle(transcript);
|
|
43312
|
+
if (!title) throw error;
|
|
43313
|
+
console.warn(`[conversations] retitle timed out for "${name}"; using deterministic fallback title "${title}"`);
|
|
43314
|
+
}
|
|
43822
43315
|
if (!title) return jsonResponse({ error: "Title model returned an empty result" }, { status: 502 });
|
|
43823
43316
|
updateConversationTitle(name, title, "ai");
|
|
43824
43317
|
console.log(`[claude-invoke] SUCCESS purpose=conversation-retitle | conversation=${name} | title="${title}"`);
|
|
@@ -43914,6 +43407,8 @@ const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, getConvers
|
|
|
43914
43407
|
* contract. Internal events are not exposed on this route.
|
|
43915
43408
|
*/
|
|
43916
43409
|
init_event_store();
|
|
43410
|
+
init_http_helpers();
|
|
43411
|
+
init_http_handler();
|
|
43917
43412
|
const PUBLIC_CATALOG = [
|
|
43918
43413
|
"activity.entry",
|
|
43919
43414
|
"activity.detailed",
|
|
@@ -44070,6 +43565,8 @@ const eventsRouteLayer = Layer.mergeAll(getEventStreamRoute, getEventVersionRout
|
|
|
44070
43565
|
* GET /api/show/:issueId/shadow — shadow state details
|
|
44071
43566
|
* GET /api/show/:issueId/health — health + heartbeat only
|
|
44072
43567
|
*/
|
|
43568
|
+
init_http_helpers();
|
|
43569
|
+
init_http_handler();
|
|
44073
43570
|
init_shadow_state();
|
|
44074
43571
|
const getShowRoute = HttpRouter.add("GET", "/api/show/:issueId", httpHandler(Effect.gen(function* () {
|
|
44075
43572
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
@@ -44168,7 +43665,7 @@ async function registerProjectFromPath(opts) {
|
|
|
44168
43665
|
registerProjectSync(key, projectConfig);
|
|
44169
43666
|
const seededContextLayer = ensureProjectLayer(fullPath);
|
|
44170
43667
|
try {
|
|
44171
|
-
const { preTrustDirectorySync } = await import("./workspace-manager-
|
|
43668
|
+
const { preTrustDirectorySync } = await import("./workspace-manager-C1Ocyoqn.js");
|
|
44172
43669
|
preTrustDirectorySync(fullPath);
|
|
44173
43670
|
} catch {}
|
|
44174
43671
|
let hooksInstalled = 0;
|
|
@@ -44183,7 +43680,6 @@ async function registerProjectFromPath(opts) {
|
|
|
44183
43680
|
}
|
|
44184
43681
|
//#endregion
|
|
44185
43682
|
//#region ../../lib/overdeck/specs.ts
|
|
44186
|
-
init_pan_dir();
|
|
44187
43683
|
init_harness();
|
|
44188
43684
|
init_render();
|
|
44189
43685
|
const findSpecByIssueThroughOverdeck = findSpecByIssue;
|
|
@@ -44195,14 +43691,22 @@ const findSpecByIssueThroughOverdeck = findSpecByIssue;
|
|
|
44195
43691
|
* Implements:
|
|
44196
43692
|
* GET /api/projects/:projectKey/session-tree
|
|
44197
43693
|
*/
|
|
43694
|
+
init_http_helpers();
|
|
43695
|
+
init_http_handler();
|
|
44198
43696
|
init_projects();
|
|
43697
|
+
init_dashboard_auth();
|
|
44199
43698
|
init_issue_id();
|
|
44200
43699
|
init_tmux();
|
|
44201
|
-
|
|
43700
|
+
init_concurrency$1();
|
|
43701
|
+
init_read_model();
|
|
43702
|
+
init_agents$2();
|
|
43703
|
+
init_agent_input_detection();
|
|
43704
|
+
init_review_status$1();
|
|
43705
|
+
init_jsonl_resolver();
|
|
44202
43706
|
init_paths();
|
|
44203
43707
|
const execAsync$2 = promisify(exec);
|
|
44204
43708
|
async function getIssueDataService() {
|
|
44205
|
-
const { getSharedIssueService } = await import("./issue-service-singleton-
|
|
43709
|
+
const { getSharedIssueService } = await import("./issue-service-singleton-p8pVr1YM.js");
|
|
44206
43710
|
return getSharedIssueService();
|
|
44207
43711
|
}
|
|
44208
43712
|
/** Returns true if the path exists (any type). */
|
|
@@ -44715,12 +44219,16 @@ const postProjectsRoute = HttpRouter.add("POST", "/api/projects", httpHandler(Ef
|
|
|
44715
44219
|
const projectsRouteLayer = Layer.mergeAll(getProjectSessionTreeRoute, getAllSessionTreesRoute, getProjectAutoMergeDefaultRoute, postProjectAutoMergeDefaultRoute, postProjectsRoute);
|
|
44716
44220
|
//#endregion
|
|
44717
44221
|
//#region routes/context.ts
|
|
44222
|
+
init_src();
|
|
44718
44223
|
init_layers();
|
|
44719
44224
|
init_paths();
|
|
44720
44225
|
init_projects();
|
|
44226
|
+
init_http_helpers();
|
|
44227
|
+
init_domain_services();
|
|
44228
|
+
init_http_handler();
|
|
44721
44229
|
const PREVIEW_HARNESSES = [
|
|
44722
44230
|
"claude-code",
|
|
44723
|
-
"
|
|
44231
|
+
"ohmypi",
|
|
44724
44232
|
"codex"
|
|
44725
44233
|
];
|
|
44726
44234
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
@@ -44979,9 +44487,9 @@ function fullPromptPreview(previews) {
|
|
|
44979
44487
|
"",
|
|
44980
44488
|
previews["claude-code"] || "(no rendered context)",
|
|
44981
44489
|
"",
|
|
44982
|
-
"## Overdeck-controlled
|
|
44490
|
+
"## Overdeck-controlled oh-my-pi bundle",
|
|
44983
44491
|
"",
|
|
44984
|
-
previews.
|
|
44492
|
+
previews.ohmypi || "(no rendered context)",
|
|
44985
44493
|
"",
|
|
44986
44494
|
"## Overdeck-controlled Codex bundle",
|
|
44987
44495
|
"",
|
|
@@ -45022,7 +44530,7 @@ async function previewContextLayers(projects, requestOrSelectedLayer, maybeDraft
|
|
|
45022
44530
|
operation: "preview",
|
|
45023
44531
|
previews: {
|
|
45024
44532
|
"claude-code": previews["claude-code"],
|
|
45025
|
-
|
|
44533
|
+
ohmypi: previews.ohmypi,
|
|
45026
44534
|
codex: previews.codex,
|
|
45027
44535
|
fullPrompt: fullPromptPreview(previews)
|
|
45028
44536
|
},
|
|
@@ -45155,6 +44663,8 @@ const contextRouteLayer = Layer.mergeAll(getContextLayersRoute, postContextPrevi
|
|
|
45155
44663
|
* Implements /api/admin/* endpoints mirroring the `pan admin` CLI namespace:
|
|
45156
44664
|
* GET /api/admin/tldr/:issueId — TLDR daemon status for a workspace
|
|
45157
44665
|
*/
|
|
44666
|
+
init_http_helpers();
|
|
44667
|
+
init_http_handler();
|
|
45158
44668
|
init_tldr_daemon();
|
|
45159
44669
|
init_projects();
|
|
45160
44670
|
const getAdminTldrRoute = HttpRouter.add("GET", "/api/admin/tldr/:issueId", httpHandler(Effect.gen(function* () {
|
|
@@ -45335,6 +44845,8 @@ async function installOx() {
|
|
|
45335
44845
|
* GET /api/prereqs/:feature — check which tools are missing for a feature
|
|
45336
44846
|
* POST /api/prereqs/install — install a specific tool by name
|
|
45337
44847
|
*/
|
|
44848
|
+
init_http_helpers();
|
|
44849
|
+
init_http_handler();
|
|
45338
44850
|
const readJsonBody$3 = Effect.gen(function* () {
|
|
45339
44851
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
45340
44852
|
try {
|
|
@@ -45381,6 +44893,8 @@ const installToolRoute = HttpRouter.add("POST", "/api/prereqs/install", httpHand
|
|
|
45381
44893
|
const prereqsRouteLayer = Layer.mergeAll(listPrereqsRoute, checkFeatureRoute, installToolRoute);
|
|
45382
44894
|
//#endregion
|
|
45383
44895
|
//#region routes/cliproxy.ts
|
|
44896
|
+
init_http_helpers();
|
|
44897
|
+
init_http_handler();
|
|
45384
44898
|
init_cliproxy();
|
|
45385
44899
|
let lastStatus = null;
|
|
45386
44900
|
async function refreshStatus() {
|
|
@@ -45452,6 +44966,10 @@ const postCliproxyRestartRoute = HttpRouter.add("POST", "/api/cliproxy/restart",
|
|
|
45452
44966
|
});
|
|
45453
44967
|
})));
|
|
45454
44968
|
const cliproxyRouteLayer = Layer.mergeAll(getCliproxyStatusRoute, postCliproxyRestartRoute);
|
|
44969
|
+
//#endregion
|
|
44970
|
+
//#region routes/tts.ts
|
|
44971
|
+
init_origin_validation();
|
|
44972
|
+
init_http_helpers();
|
|
45455
44973
|
const TTS_ROUTE_BODY_MAX_BYTES = 64 * 1024;
|
|
45456
44974
|
async function checkTtsHealth(options = {}) {
|
|
45457
44975
|
const runtimeConfig = getTtsRuntimeConfig();
|
|
@@ -45780,7 +45298,7 @@ const ttsRouteLayer = Layer.mergeAll(getTtsHealthRoute, postTtsStartRoute, getTt
|
|
|
45780
45298
|
* - Diff's the PR's failing check names against main's current failing set so
|
|
45781
45299
|
* inherited main-red failures are labelled as such.
|
|
45782
45300
|
*/
|
|
45783
|
-
init_agents$
|
|
45301
|
+
init_agents$2();
|
|
45784
45302
|
init_projects();
|
|
45785
45303
|
init_feedback_writer();
|
|
45786
45304
|
function execFilePromise(file, args, options) {
|
|
@@ -46090,6 +45608,7 @@ async function refreshMergeStateFromGitHub(issueId, repo, prNumber) {
|
|
|
46090
45608
|
encoding: "utf-8",
|
|
46091
45609
|
timeout: 15e3
|
|
46092
45610
|
});
|
|
45611
|
+
if (!stdout.trim()) return;
|
|
46093
45612
|
const pr = JSON.parse(stdout);
|
|
46094
45613
|
const status = await Effect.runPromise(getReviewStatus(issueId));
|
|
46095
45614
|
if (!status) return;
|
|
@@ -46203,8 +45722,8 @@ async function handlePullRequestPromise(payload) {
|
|
|
46203
45722
|
if (!issueId) return;
|
|
46204
45723
|
const repo = payload.repository.full_name;
|
|
46205
45724
|
if (payload.action === "closed" && pr.merged === true) try {
|
|
46206
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
46207
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
45725
|
+
const { postMergeLifecycle } = await import("./merge-agent-Dhw22tcB.js");
|
|
45726
|
+
const { resolveProjectFromIssueSync } = await import("./projects-LkdoL5F9.js");
|
|
46208
45727
|
const project = resolveProjectFromIssueSync(issueId);
|
|
46209
45728
|
if (project) {
|
|
46210
45729
|
const branchName = pr.head.ref;
|
|
@@ -46472,6 +45991,8 @@ async function reconcileStaleGitHubBlockers() {
|
|
|
46472
45991
|
* Verifies X-Hub-Signature-256 HMAC-SHA256 signature.
|
|
46473
45992
|
* Dispatches to per-event-type handlers.
|
|
46474
45993
|
*/
|
|
45994
|
+
init_http_helpers();
|
|
45995
|
+
init_http_handler();
|
|
46475
45996
|
const WEBHOOK_SECRET_PATH = join$1(homedir$1(), ".overdeck", "github-app", "webhook-secret");
|
|
46476
45997
|
let _cachedWebhookSecret = void 0;
|
|
46477
45998
|
let _secretLoadPromise = null;
|
|
@@ -46584,6 +46105,7 @@ const webhooksRouteLayer = HttpRouter.add("POST", "/api/webhooks/github", httpHa
|
|
|
46584
46105
|
//#region ../../lib/compliance/advisory-warning.ts
|
|
46585
46106
|
init_config_yaml();
|
|
46586
46107
|
init_paths$2();
|
|
46108
|
+
init_rollup();
|
|
46587
46109
|
const COMPLIANCE_ADVISORY_WARNING = "Last turn included a memory-first trigger but the search wasn't called. Try pan memory search first next time.";
|
|
46588
46110
|
async function resolveComplianceAdvisoryWarning(input) {
|
|
46589
46111
|
if (await (input.loadComplianceMode ?? loadComplianceMode)() === "off") return null;
|
|
@@ -46625,8 +46147,9 @@ function isCurrentSessionMiss(observation, identity) {
|
|
|
46625
46147
|
//#endregion
|
|
46626
46148
|
//#region ../../lib/memory/checkpoint-client.ts
|
|
46627
46149
|
init_settings();
|
|
46628
|
-
init_health();
|
|
46150
|
+
init_health$1();
|
|
46629
46151
|
init_providers$1();
|
|
46152
|
+
init_pending();
|
|
46630
46153
|
init_query_expansion();
|
|
46631
46154
|
init_injection();
|
|
46632
46155
|
let worker = null;
|
|
@@ -46661,7 +46184,7 @@ function getCheckpointWorker() {
|
|
|
46661
46184
|
return worker;
|
|
46662
46185
|
}
|
|
46663
46186
|
async function runInline(operation, payload) {
|
|
46664
|
-
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-
|
|
46187
|
+
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-xdJ_1zqi.js");
|
|
46665
46188
|
switch (operation) {
|
|
46666
46189
|
case "claimTranscriptRange": return claimTranscriptRange(payload);
|
|
46667
46190
|
case "commitTranscriptRange": return commitTranscriptRange(payload);
|
|
@@ -46711,6 +46234,92 @@ const getTranscriptCheckpoint = (sessionId) => Effect.tryPromise({
|
|
|
46711
46234
|
catch: toError
|
|
46712
46235
|
});
|
|
46713
46236
|
//#endregion
|
|
46237
|
+
//#region ../../lib/session-format-converter.ts
|
|
46238
|
+
init_paths();
|
|
46239
|
+
/** Pull plain text out of a Claude/Pi `message.content` (string or block array). */
|
|
46240
|
+
function extractContentText(content) {
|
|
46241
|
+
if (typeof content === "string") return content;
|
|
46242
|
+
if (!Array.isArray(content)) return "";
|
|
46243
|
+
const parts = [];
|
|
46244
|
+
for (const block of content) {
|
|
46245
|
+
if (!block || typeof block !== "object") continue;
|
|
46246
|
+
const b = block;
|
|
46247
|
+
if (typeof b["text"] === "string") parts.push(b["text"]);
|
|
46248
|
+
else if (typeof b["thinking"] === "string") parts.push(`[thinking] ${b["thinking"]}`);
|
|
46249
|
+
else if ((b["type"] === "tool_use" || b["type"] === "toolCall") && typeof b["name"] === "string") parts.push(`[tool_use: ${b["name"]}]`);
|
|
46250
|
+
else if (b["type"] === "tool_result" || b["type"] === "toolResult") {
|
|
46251
|
+
const inner = extractContentText(b["content"]);
|
|
46252
|
+
if (inner) parts.push(`[tool_result] ${inner}`);
|
|
46253
|
+
}
|
|
46254
|
+
}
|
|
46255
|
+
return parts.join("\n").trim();
|
|
46256
|
+
}
|
|
46257
|
+
/** Read a Pi Agent JSONL transcript into ordered role/text turns. */
|
|
46258
|
+
function extractPiTranscript(raw) {
|
|
46259
|
+
const turns = [];
|
|
46260
|
+
for (const line of raw.split("\n")) {
|
|
46261
|
+
const trimmed = line.trim();
|
|
46262
|
+
if (!trimmed) continue;
|
|
46263
|
+
let entry;
|
|
46264
|
+
try {
|
|
46265
|
+
entry = JSON.parse(trimmed);
|
|
46266
|
+
} catch {
|
|
46267
|
+
continue;
|
|
46268
|
+
}
|
|
46269
|
+
if (entry["type"] !== "message") continue;
|
|
46270
|
+
const message = entry["message"];
|
|
46271
|
+
if (!message || typeof message !== "object") continue;
|
|
46272
|
+
const m = message;
|
|
46273
|
+
const role = typeof m["role"] === "string" ? m["role"] : "assistant";
|
|
46274
|
+
const text = extractContentText(m["content"]);
|
|
46275
|
+
if (text) turns.push({
|
|
46276
|
+
role,
|
|
46277
|
+
text
|
|
46278
|
+
});
|
|
46279
|
+
}
|
|
46280
|
+
return turns;
|
|
46281
|
+
}
|
|
46282
|
+
/**
|
|
46283
|
+
* Read a Codex rollout JSONL transcript into ordered role/text turns.
|
|
46284
|
+
*
|
|
46285
|
+
* Rollout files use a different schema from --json stdout:
|
|
46286
|
+
* - task_started: the initial task (user role)
|
|
46287
|
+
* - agent_message: a model turn (assistant role)
|
|
46288
|
+
* - token_count: metadata — skipped
|
|
46289
|
+
*
|
|
46290
|
+
* We extract task_started as the user prompt and agent_message events as
|
|
46291
|
+
* assistant turns to produce a readable transcript.
|
|
46292
|
+
*/
|
|
46293
|
+
function extractCodexTranscript(raw) {
|
|
46294
|
+
const turns = [];
|
|
46295
|
+
for (const line of raw.split("\n")) {
|
|
46296
|
+
const trimmed = line.trim();
|
|
46297
|
+
if (!trimmed) continue;
|
|
46298
|
+
let entry;
|
|
46299
|
+
try {
|
|
46300
|
+
entry = JSON.parse(trimmed);
|
|
46301
|
+
} catch {
|
|
46302
|
+
continue;
|
|
46303
|
+
}
|
|
46304
|
+
const type = entry["type"];
|
|
46305
|
+
if (type === "task_started") {
|
|
46306
|
+
const task = typeof entry["task"] === "string" ? entry["task"] : "";
|
|
46307
|
+
if (task) turns.push({
|
|
46308
|
+
role: "user",
|
|
46309
|
+
text: task
|
|
46310
|
+
});
|
|
46311
|
+
} else if (type === "agent_message") {
|
|
46312
|
+
const content = typeof entry["content"] === "string" ? entry["content"] : extractContentText(entry["content"]);
|
|
46313
|
+
if (content) turns.push({
|
|
46314
|
+
role: "assistant",
|
|
46315
|
+
text: content
|
|
46316
|
+
});
|
|
46317
|
+
}
|
|
46318
|
+
}
|
|
46319
|
+
return turns;
|
|
46320
|
+
}
|
|
46321
|
+
Data.TaggedError("SessionConvertError");
|
|
46322
|
+
//#endregion
|
|
46714
46323
|
//#region ../../lib/memory/compress.ts
|
|
46715
46324
|
const MAX_USER_CHARS = 4e4;
|
|
46716
46325
|
const MAX_TRANSCRIPT_DELTA_BYTES = 1024 * 1024;
|
|
@@ -46830,7 +46439,7 @@ function isRecord$1(value) {
|
|
|
46830
46439
|
}
|
|
46831
46440
|
//#endregion
|
|
46832
46441
|
//#region ../../lib/memory/transcript-source.ts
|
|
46833
|
-
init_agents$
|
|
46442
|
+
init_agents$2();
|
|
46834
46443
|
init_paths();
|
|
46835
46444
|
init_codex();
|
|
46836
46445
|
var ClaudeCodeTranscriptSource = class {
|
|
@@ -46883,7 +46492,7 @@ var ClaudeCodeTranscriptSource = class {
|
|
|
46883
46492
|
}
|
|
46884
46493
|
};
|
|
46885
46494
|
var PiTranscriptSource = class {
|
|
46886
|
-
harness = "
|
|
46495
|
+
harness = "ohmypi";
|
|
46887
46496
|
listAgents;
|
|
46888
46497
|
readSessionId;
|
|
46889
46498
|
resolveTranscriptPath;
|
|
@@ -46896,7 +46505,7 @@ var PiTranscriptSource = class {
|
|
|
46896
46505
|
}
|
|
46897
46506
|
async getActiveTranscripts() {
|
|
46898
46507
|
const agents = await this.listAgents();
|
|
46899
|
-
return (await Promise.all(agents.filter((agent) => agent.tmuxActive && agent.status === "running" && agent.role === "work" && agent.harness === "
|
|
46508
|
+
return (await Promise.all(agents.filter((agent) => agent.tmuxActive && agent.status === "running" && agent.role === "work" && agent.harness === "ohmypi").map((agent) => this.resolveAgentTranscript(agent)))).filter((entry) => entry !== null);
|
|
46900
46509
|
}
|
|
46901
46510
|
parseDelta(buffer, fromOffset = 0) {
|
|
46902
46511
|
const text = Buffer.isBuffer(buffer) ? buffer.toString("utf8") : buffer;
|
|
@@ -46927,7 +46536,7 @@ var PiTranscriptSource = class {
|
|
|
46927
46536
|
sessionId,
|
|
46928
46537
|
transcriptPath,
|
|
46929
46538
|
identity: buildMemoryIdentity(agent, sessionId),
|
|
46930
|
-
harness: "
|
|
46539
|
+
harness: "ohmypi",
|
|
46931
46540
|
size: fileStat.size,
|
|
46932
46541
|
mtimeMs: fileStat.mtimeMs
|
|
46933
46542
|
};
|
|
@@ -47064,6 +46673,7 @@ async function readCodexThreadId(agent) {
|
|
|
47064
46673
|
}
|
|
47065
46674
|
//#endregion
|
|
47066
46675
|
//#region ../../lib/memory/extract.ts
|
|
46676
|
+
init_src();
|
|
47067
46677
|
const MEMORY_DOMAIN_TAGS = [
|
|
47068
46678
|
"review-blocker",
|
|
47069
46679
|
"test-failure",
|
|
@@ -47377,7 +46987,7 @@ function isRecord(value) {
|
|
|
47377
46987
|
}
|
|
47378
46988
|
//#endregion
|
|
47379
46989
|
//#region ../../lib/memory/pipeline.ts
|
|
47380
|
-
init_health();
|
|
46990
|
+
init_health$1();
|
|
47381
46991
|
async function extractFromTranscriptDelta(input) {
|
|
47382
46992
|
if (isSubagentHookPayload(input.hookPayload)) return {
|
|
47383
46993
|
status: "noop",
|
|
@@ -47728,7 +47338,7 @@ function buildPendingTurn(input, fromOffset, toOffset, compressed) {
|
|
|
47728
47338
|
};
|
|
47729
47339
|
}
|
|
47730
47340
|
async function emitMemoryObservationCreated(observation, timestamp) {
|
|
47731
|
-
const { initEventStore } = await import("./event-store-
|
|
47341
|
+
const { initEventStore } = await import("./event-store-CltcAmHd.js");
|
|
47732
47342
|
await (await initEventStore()).appendAsync({
|
|
47733
47343
|
type: "memory.observation_created",
|
|
47734
47344
|
timestamp,
|
|
@@ -47737,7 +47347,7 @@ async function emitMemoryObservationCreated(observation, timestamp) {
|
|
|
47737
47347
|
}
|
|
47738
47348
|
//#endregion
|
|
47739
47349
|
//#region ../../lib/memory/worker-pool.ts
|
|
47740
|
-
init_health();
|
|
47350
|
+
init_health$1();
|
|
47741
47351
|
init_providers$1();
|
|
47742
47352
|
function normalizeQueueLimit(value) {
|
|
47743
47353
|
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : 500;
|
|
@@ -48231,10 +47841,14 @@ function countCompleteLines(text) {
|
|
|
48231
47841
|
* `hook_event_name`. We look up the conversation by claude_session_id and
|
|
48232
47842
|
* emit an in-memory-only event via emitOnly().
|
|
48233
47843
|
*/
|
|
47844
|
+
init_http_helpers();
|
|
47845
|
+
init_http_handler();
|
|
48234
47846
|
init_event_store();
|
|
48235
|
-
init_agents$
|
|
47847
|
+
init_agents$2();
|
|
48236
47848
|
init_paths();
|
|
48237
47849
|
init_paths$2();
|
|
47850
|
+
init_dashboard_auth();
|
|
47851
|
+
init_read_model();
|
|
48238
47852
|
init_conversations();
|
|
48239
47853
|
init_briefing_freshness();
|
|
48240
47854
|
init_settings();
|
|
@@ -48593,7 +48207,10 @@ function isRole(value) {
|
|
|
48593
48207
|
* GET /api/agents/:agentId/diffs/:turnId — unified diff for a specific turn
|
|
48594
48208
|
* GET /api/agents/:agentId/diffs/full — full thread diff (all turns combined)
|
|
48595
48209
|
*/
|
|
48210
|
+
init_http_helpers();
|
|
48211
|
+
init_read_model();
|
|
48596
48212
|
init_event_store();
|
|
48213
|
+
init_checkpoint_manager();
|
|
48597
48214
|
function validateOrigin(request) {
|
|
48598
48215
|
const origin = request.headers["origin"];
|
|
48599
48216
|
if (origin && typeof origin === "string" && !origin.includes("localhost") && !origin.includes("127.0.0.1")) return {
|
|
@@ -48789,7 +48406,11 @@ const diffsRouteLayer = Layer.mergeAll(getDiffsRoute, getTurnDiffRoute, getFullD
|
|
|
48789
48406
|
* t3code's `terminal.*` contracts, this create/kill pair is the seam that gets
|
|
48790
48407
|
* folded into that RPC surface.
|
|
48791
48408
|
*/
|
|
48409
|
+
init_http_helpers();
|
|
48410
|
+
init_http_handler();
|
|
48792
48411
|
init_tmux();
|
|
48412
|
+
init_origin_validation();
|
|
48413
|
+
init_dashboard_auth();
|
|
48793
48414
|
const readJsonBody$2 = Effect.gen(function* () {
|
|
48794
48415
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
48795
48416
|
return text ? JSON.parse(text) : {};
|
|
@@ -48850,7 +48471,12 @@ const terminalsRouteLayer = Layer.mergeAll(postTerminalRoute, deleteTerminalRout
|
|
|
48850
48471
|
*
|
|
48851
48472
|
* Zero sync FS calls — lib functions use fs/promises; SQLite work stays in the existing sync DB layer.
|
|
48852
48473
|
*/
|
|
48474
|
+
init_domain_services();
|
|
48475
|
+
init_http_helpers();
|
|
48476
|
+
init_http_handler();
|
|
48853
48477
|
init_config_yaml();
|
|
48478
|
+
init_origin_validation();
|
|
48479
|
+
init_dashboard_auth();
|
|
48854
48480
|
function getRequestHeader(request, name) {
|
|
48855
48481
|
const value = request.headers[name];
|
|
48856
48482
|
if (Array.isArray(value)) return value[0];
|
|
@@ -50143,7 +49769,9 @@ const AUTO_MERGE_COOLDOWN_MS = 3e5;
|
|
|
50143
49769
|
//#endregion
|
|
50144
49770
|
//#region ../../lib/cloister/auto-merge-eligibility.ts
|
|
50145
49771
|
init_github_app();
|
|
49772
|
+
init_forge();
|
|
50146
49773
|
init_review_status();
|
|
49774
|
+
init_tracker_utils();
|
|
50147
49775
|
const execFileAsync = promisify(execFile);
|
|
50148
49776
|
const BLOCKER_LABELS = [
|
|
50149
49777
|
"needs-design",
|
|
@@ -50324,8 +49952,15 @@ function getProjectAutoMergeDefault(issueId) {
|
|
|
50324
49952
|
}
|
|
50325
49953
|
//#endregion
|
|
50326
49954
|
//#region routes/flywheel.ts
|
|
49955
|
+
init_http_helpers();
|
|
49956
|
+
init_src();
|
|
49957
|
+
init_http_handler();
|
|
49958
|
+
init_origin_validation();
|
|
49959
|
+
init_flywheel_run_state();
|
|
49960
|
+
init_dashboard_auth();
|
|
50327
49961
|
init_tmux();
|
|
50328
49962
|
init_control_settings();
|
|
49963
|
+
init_forge();
|
|
50329
49964
|
init_review_status();
|
|
50330
49965
|
init_projects();
|
|
50331
49966
|
init_merge_sync();
|
|
@@ -50631,7 +50266,7 @@ async function getFlywheelConversationPayload() {
|
|
|
50631
50266
|
};
|
|
50632
50267
|
}
|
|
50633
50268
|
async function postFlywheelReportPayload() {
|
|
50634
|
-
const { flywheelReportCommand } = await import("./flywheel-
|
|
50269
|
+
const { flywheelReportCommand } = await import("./flywheel-B600poCU.js");
|
|
50635
50270
|
await flywheelReportCommand({ cwd: process.cwd() });
|
|
50636
50271
|
return {
|
|
50637
50272
|
status: 200,
|
|
@@ -50820,11 +50455,11 @@ const getMergeBlockersRoute = HttpRouter.add("GET", "/api/flywheel/merge-blocker
|
|
|
50820
50455
|
async function defaultGetOrderedIssueIds() {
|
|
50821
50456
|
const status = await readCurrentFlywheelStatusForDashboard();
|
|
50822
50457
|
if (!status) return [];
|
|
50823
|
-
const { computeMergeQueue } = await import("./flywheel-merge-order-
|
|
50458
|
+
const { computeMergeQueue } = await import("./flywheel-merge-order-CxtnH0iT.js");
|
|
50824
50459
|
return (await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd()).pipe(Effect.provide(layer)))).map((i) => i.issueId);
|
|
50825
50460
|
}
|
|
50826
50461
|
async function defaultMergeOne(issueId) {
|
|
50827
|
-
const { triggerMerge } = await import("./workspaces-
|
|
50462
|
+
const { triggerMerge } = await import("./workspaces-u5uok4gi.js");
|
|
50828
50463
|
const r = await triggerMerge(issueId);
|
|
50829
50464
|
return r.success ? { ok: true } : {
|
|
50830
50465
|
ok: false,
|
|
@@ -51001,7 +50636,7 @@ const getFlywheelMergeQueueRoute = HttpRouter.add("GET", "/api/flywheel/merge-qu
|
|
|
51001
50636
|
return yield* Effect.promise(async () => {
|
|
51002
50637
|
const status = await readCurrentFlywheelStatusForDashboard();
|
|
51003
50638
|
if (!status) return jsonResponse([]);
|
|
51004
|
-
const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-
|
|
50639
|
+
const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-CxtnH0iT.js");
|
|
51005
50640
|
return jsonResponse(await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd(), { getPrUrl: resolveMergeQueuePrUrl }).pipe(Effect.provide(layer))));
|
|
51006
50641
|
});
|
|
51007
50642
|
})));
|
|
@@ -51015,14 +50650,14 @@ function uatGenerationNameFromParam(param) {
|
|
|
51015
50650
|
return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
|
|
51016
50651
|
}
|
|
51017
50652
|
const getUatGenerationsRoute = HttpRouter.add("GET", "/api/flywheel/uat-generations", httpHandler(Effect.gen(function* () {
|
|
51018
|
-
const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-
|
|
50653
|
+
const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-BlWjkHk7.js"));
|
|
51019
50654
|
return jsonResponse(yield* Effect.promise(() => getUatGenerationsPayload()));
|
|
51020
50655
|
})));
|
|
51021
50656
|
const postUatGenerationStackRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/stack", httpHandler(Effect.gen(function* () {
|
|
51022
50657
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51023
50658
|
if (authError) return authError;
|
|
51024
50659
|
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
51025
|
-
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-
|
|
50660
|
+
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-BlWjkHk7.js"));
|
|
51026
50661
|
const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
|
|
51027
50662
|
if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
|
|
51028
50663
|
return jsonResponse({
|
|
@@ -51034,8 +50669,8 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
|
|
|
51034
50669
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51035
50670
|
if (authError) return authError;
|
|
51036
50671
|
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
51037
|
-
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-
|
|
51038
|
-
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-
|
|
50672
|
+
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-BlWjkHk7.js"));
|
|
50673
|
+
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-OyXhszCe.js"));
|
|
51039
50674
|
const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
|
|
51040
50675
|
if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
|
|
51041
50676
|
return jsonResponse(result);
|
|
@@ -51048,7 +50683,7 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
|
|
|
51048
50683
|
const postFlywheelAssembleUatRoute = HttpRouter.add("POST", "/api/flywheel/assemble-uat", httpHandler(Effect.gen(function* () {
|
|
51049
50684
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51050
50685
|
if (authError) return authError;
|
|
51051
|
-
const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-
|
|
50686
|
+
const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-BlWjkHk7.js"));
|
|
51052
50687
|
return jsonResponse(yield* Effect.promise(() => runUatTrainReconcile({ force: true })));
|
|
51053
50688
|
})));
|
|
51054
50689
|
const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
|
|
@@ -51156,6 +50791,9 @@ function escapeXml(value) {
|
|
|
51156
50791
|
//#endregion
|
|
51157
50792
|
//#region routes/artifacts.ts
|
|
51158
50793
|
init_paths();
|
|
50794
|
+
init_http_helpers();
|
|
50795
|
+
init_dashboard_auth();
|
|
50796
|
+
init_http_handler();
|
|
51159
50797
|
const ARTIFACT_SLUG_PATTERN = /^[A-Za-z0-9_-]{8}$/;
|
|
51160
50798
|
const WORKSPACE_ARTIFACT_SELECTOR_PATTERN = /^[A-Za-z0-9._:-]+$/;
|
|
51161
50799
|
const RAW_ARTIFACT_CSP = [
|
|
@@ -51469,6 +51107,9 @@ const postArtifactUnshareRoute = HttpRouter.add("POST", "/api/artifacts/:slug/un
|
|
|
51469
51107
|
const artifactsRouteLayer = Layer.mergeAll(getRawArtifactRoute, getArtifactDetailRoute, getWorkspaceArtifactsRoute, getArtifactThumbnailRoute, postArtifactUnshareRoute);
|
|
51470
51108
|
//#endregion
|
|
51471
51109
|
//#region ../../lib/backlog/label-ops.ts
|
|
51110
|
+
init_sequence_io();
|
|
51111
|
+
init_tracker_utils();
|
|
51112
|
+
init_pickup();
|
|
51472
51113
|
const execAsync = promisify(exec);
|
|
51473
51114
|
/**
|
|
51474
51115
|
* Add or remove a GitHub label on an issue. Non-GitHub issues are silently
|
|
@@ -51492,6 +51133,7 @@ const applyIssueReadyLabel = (id) => addIssueLabel(id, READY_LABEL);
|
|
|
51492
51133
|
const removeIssueReadyLabel = (id) => removeIssueLabel(id, READY_LABEL);
|
|
51493
51134
|
//#endregion
|
|
51494
51135
|
//#region ../../lib/database/agent-mappers.ts
|
|
51136
|
+
init_lookups();
|
|
51495
51137
|
function agentStateToDbAgent(state) {
|
|
51496
51138
|
return {
|
|
51497
51139
|
id: state.id,
|
|
@@ -52440,7 +52082,7 @@ function initSchema(db) {
|
|
|
52440
52082
|
*/
|
|
52441
52083
|
function runMigrations(db, dbPath) {
|
|
52442
52084
|
const currentVersion = db.pragma("user_version", { simple: true });
|
|
52443
|
-
if (currentVersion
|
|
52085
|
+
if (currentVersion >= 57) return;
|
|
52444
52086
|
if (currentVersion === 0) {
|
|
52445
52087
|
initSchema(db);
|
|
52446
52088
|
return;
|
|
@@ -53264,6 +52906,11 @@ function upsertBacklogSequence(projectKey, doc) {
|
|
|
53264
52906
|
`);
|
|
53265
52907
|
db.transaction((nodes) => {
|
|
53266
52908
|
for (const node of nodes) stmt.run(projectKey, node.issue, node.rank, node.size, node.importance, node.score, node.condition, JSON.stringify(node.dependsOn), node.why, node.gate, node.planning, doc.generatedAt);
|
|
52909
|
+
const keep = nodes.map((n) => n.issue);
|
|
52910
|
+
if (keep.length > 0) {
|
|
52911
|
+
const placeholders = keep.map(() => "?").join(",");
|
|
52912
|
+
db.prepare(`DELETE FROM backlog_sequence WHERE project_key = ? AND issue_id NOT IN (${placeholders})`).run(projectKey, ...keep);
|
|
52913
|
+
} else db.prepare("DELETE FROM backlog_sequence WHERE project_key = ?").run(projectKey);
|
|
53267
52914
|
})(doc.nodes);
|
|
53268
52915
|
}
|
|
53269
52916
|
function clearBacklogSequence(projectKey) {
|
|
@@ -53313,8 +52960,14 @@ function getBacklogSequence(projectKey) {
|
|
|
53313
52960
|
}
|
|
53314
52961
|
//#endregion
|
|
53315
52962
|
//#region routes/backlog.ts
|
|
52963
|
+
init_http_handler();
|
|
52964
|
+
init_http_helpers();
|
|
52965
|
+
init_dashboard_auth();
|
|
52966
|
+
init_sequence_io();
|
|
52967
|
+
init_pickup();
|
|
53316
52968
|
init_review_status();
|
|
53317
|
-
|
|
52969
|
+
init_sequencer_agent();
|
|
52970
|
+
init_jsonl_resolver();
|
|
53318
52971
|
const readJsonBody = Effect.gen(function* () {
|
|
53319
52972
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53320
52973
|
try {
|
|
@@ -53408,6 +53061,7 @@ const postBacklogRegenerateRoute = HttpRouter.add("POST", "/api/backlog/sequence
|
|
|
53408
53061
|
const { getSharedIssueService } = (init_issue_service_singleton(), __toCommonJS(issue_service_singleton_exports));
|
|
53409
53062
|
const issues = getSharedIssueService().getIssues();
|
|
53410
53063
|
try {
|
|
53064
|
+
await clearFinishedSequencerRun(projectRoot);
|
|
53411
53065
|
return jsonResponse({
|
|
53412
53066
|
status: "spawned",
|
|
53413
53067
|
agentId: (await spawnSequencerAgent(pass, {
|
|
@@ -53603,14 +53257,7 @@ const postBacklogClearRoute = HttpRouter.add("POST", "/api/backlog/sequence/clea
|
|
|
53603
53257
|
const getSequencerStatusRoute = HttpRouter.add("GET", "/api/backlog/sequencer-status", httpHandler(Effect.gen(function* () {
|
|
53604
53258
|
return yield* Effect.promise(async () => {
|
|
53605
53259
|
const projectRoot = process.cwd();
|
|
53606
|
-
const
|
|
53607
|
-
const startedAt = alive ? getAgentStateSync("sequencer-runner")?.startedAt ?? null : null;
|
|
53608
|
-
const seqPath = join$1(projectRoot, ".pan", "backlog", "sequence.md");
|
|
53609
|
-
let freshSequence = false;
|
|
53610
|
-
if (alive && startedAt && existsSync$1(seqPath)) try {
|
|
53611
|
-
freshSequence = statSync$1(seqPath).mtimeMs >= new Date(startedAt).getTime();
|
|
53612
|
-
} catch {}
|
|
53613
|
-
const running = alive && !freshSequence;
|
|
53260
|
+
const { running, startedAt } = getSequencerRunStatus(projectRoot);
|
|
53614
53261
|
let total = 0;
|
|
53615
53262
|
const manifestPath = join$1(projectRoot, ".pan", "backlog", "manifest.json");
|
|
53616
53263
|
if (existsSync$1(manifestPath)) try {
|
|
@@ -53652,6 +53299,8 @@ function listFeatureRegistryForDashboard(filter = {}) {
|
|
|
53652
53299
|
}
|
|
53653
53300
|
//#endregion
|
|
53654
53301
|
//#region routes/feature-registry.ts
|
|
53302
|
+
init_http_helpers();
|
|
53303
|
+
init_http_handler();
|
|
53655
53304
|
async function getFeatureRegistryListPayload(options = {}) {
|
|
53656
53305
|
return { entries: await (options.listEntries ?? listFeatureRegistryForDashboard)({ limit: 100 }) };
|
|
53657
53306
|
}
|
|
@@ -53666,6 +53315,9 @@ const featureRegistryRouteLayer = Layer.provideMerge(listFeatureRegistryRoute, L
|
|
|
53666
53315
|
*
|
|
53667
53316
|
* GET /api/fs/list-dirs?path=<abs> — list immediate subdirectories, home-clamped + auth-gated
|
|
53668
53317
|
*/
|
|
53318
|
+
init_http_helpers();
|
|
53319
|
+
init_http_handler();
|
|
53320
|
+
init_dashboard_auth();
|
|
53669
53321
|
const listDirsRoute = HttpRouter.add("GET", "/api/fs/list-dirs", httpHandler(Effect.gen(function* () {
|
|
53670
53322
|
const req = yield* HttpServerRequest.HttpServerRequest;
|
|
53671
53323
|
const authError = rejectUnauthorizedDashboardRequest(req);
|
|
@@ -53716,7 +53368,14 @@ const fsRouteLayer = Layer.mergeAll(listDirsRoute);
|
|
|
53716
53368
|
* GET /ws/terminal → Raw WebSocket terminal (bypasses Effect RPC)
|
|
53717
53369
|
* GET * → static files from OVERDECK_FRONTEND_DIR
|
|
53718
53370
|
*/
|
|
53371
|
+
init_http_helpers();
|
|
53372
|
+
init_domain_services();
|
|
53373
|
+
init_read_model();
|
|
53374
|
+
init_cost();
|
|
53719
53375
|
init_infra();
|
|
53376
|
+
init_linear_client();
|
|
53377
|
+
init_dashboard_auth();
|
|
53378
|
+
init_origin_validation();
|
|
53720
53379
|
init_activity_logger();
|
|
53721
53380
|
const HttpServerLive = Layer.unwrap(Effect.gen(function* () {
|
|
53722
53381
|
const config = yield* ServerConfig;
|
|
@@ -53853,10 +53512,14 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
53853
53512
|
* These fields were dropped in the Effect server migration (PAN-428) and are
|
|
53854
53513
|
* restored here via the event-driven projection pipeline.
|
|
53855
53514
|
*/
|
|
53856
|
-
init_agents$
|
|
53515
|
+
init_agents$2();
|
|
53516
|
+
init_agent_enrichment();
|
|
53857
53517
|
init_review_status();
|
|
53518
|
+
init_concurrency$1();
|
|
53858
53519
|
init_event_store();
|
|
53520
|
+
init_agent_projection();
|
|
53859
53521
|
init_activity_logger();
|
|
53522
|
+
init_read_model();
|
|
53860
53523
|
function enrichmentChanged(prev, next) {
|
|
53861
53524
|
if (!prev) return true;
|
|
53862
53525
|
return prev.role !== next.role || prev.hasPendingQuestion !== next.hasPendingQuestion || prev.pendingQuestionCount !== next.pendingQuestionCount || prev.pendingQuestionPrompt !== next.pendingQuestionPrompt || prev.pendingQuestionReason !== next.pendingQuestionReason || prev.pendingInputCount !== next.pendingInputCount || prev.pendingInputKinds.join(",") !== next.pendingInputKinds.join(",") || prev.pendingAskUserQuestion?.toolUseId !== next.pendingAskUserQuestion?.toolUseId || prev.resolution !== next.resolution || prev.resolutionCount !== next.resolutionCount;
|
|
@@ -54135,8 +53798,9 @@ function drainRefreshQueue(state) {
|
|
|
54135
53798
|
* expects — the reducer and WebSocket subscription already exist, but no
|
|
54136
53799
|
* server code was emitting the events.
|
|
54137
53800
|
*/
|
|
54138
|
-
init_agents$
|
|
53801
|
+
init_agents$2();
|
|
54139
53802
|
init_tmux();
|
|
53803
|
+
init_concurrency$1();
|
|
54140
53804
|
init_event_store();
|
|
54141
53805
|
function splitLines(text) {
|
|
54142
53806
|
const lines = text.split("\n");
|
|
@@ -54174,7 +53838,7 @@ async function pollOnce(state) {
|
|
|
54174
53838
|
try {
|
|
54175
53839
|
const remoteState = await readFile(join$1(homedir$1(), ".overdeck", "agents", agentId, "remote-state.json"), "utf-8").then((text) => JSON.parse(text)).catch(() => null);
|
|
54176
53840
|
if (remoteState?.location === "remote" && remoteState?.vmName) {
|
|
54177
|
-
const { getRemoteAgentOutput } = await import("./remote-agents-
|
|
53841
|
+
const { getRemoteAgentOutput } = await import("./remote-agents-B_xysqhd.js");
|
|
54178
53842
|
stdout = await getRemoteAgentOutput(agentId, remoteState.vmName, 50);
|
|
54179
53843
|
} else stdout = await Effect.runPromise(capturePane(agentId, 50));
|
|
54180
53844
|
} catch {
|
|
@@ -54377,7 +54041,7 @@ async function detectOrphanedClaudeCodeSessions(activeConvs) {
|
|
|
54377
54041
|
for (const conv of activeConvs) {
|
|
54378
54042
|
if (!conv.cwd) continue;
|
|
54379
54043
|
if (!conv.claudeSessionId) continue;
|
|
54380
|
-
if (conv.harness === "
|
|
54044
|
+
if (conv.harness === "ohmypi" || conv.harness === "codex") continue;
|
|
54381
54045
|
const list = cwdGroups.get(conv.cwd) ?? [];
|
|
54382
54046
|
list.push(conv);
|
|
54383
54047
|
cwdGroups.set(conv.cwd, list);
|
|
@@ -54698,7 +54362,7 @@ async function announceNewRestart(deps = {}) {
|
|
|
54698
54362
|
setLastAnnounced(status.ts);
|
|
54699
54363
|
return true;
|
|
54700
54364
|
}
|
|
54701
|
-
let timer$
|
|
54365
|
+
let timer$2 = null;
|
|
54702
54366
|
let running = false;
|
|
54703
54367
|
let runToken = 0;
|
|
54704
54368
|
function startRestartAnnouncer(deps = {}) {
|
|
@@ -54708,8 +54372,8 @@ function startRestartAnnouncer(deps = {}) {
|
|
|
54708
54372
|
let remainingBootstrapPolls = BOOTSTRAP_FAST_POLL_COUNT;
|
|
54709
54373
|
const schedule = (delayMs) => {
|
|
54710
54374
|
if (!running || token !== runToken) return;
|
|
54711
|
-
timer$
|
|
54712
|
-
timer$
|
|
54375
|
+
timer$2 = setTimeout(pass, delayMs);
|
|
54376
|
+
timer$2.unref?.();
|
|
54713
54377
|
};
|
|
54714
54378
|
const nextDelay = (emitted) => {
|
|
54715
54379
|
if (emitted) return POLL_MS;
|
|
@@ -54727,8 +54391,8 @@ function startRestartAnnouncer(deps = {}) {
|
|
|
54727
54391
|
function stopRestartAnnouncer() {
|
|
54728
54392
|
running = false;
|
|
54729
54393
|
runToken += 1;
|
|
54730
|
-
if (timer$
|
|
54731
|
-
timer$
|
|
54394
|
+
if (timer$2) clearTimeout(timer$2);
|
|
54395
|
+
timer$2 = null;
|
|
54732
54396
|
}
|
|
54733
54397
|
//#endregion
|
|
54734
54398
|
//#region services/substrate-bug-poller.ts
|
|
@@ -54957,7 +54621,7 @@ init_config_yaml();
|
|
|
54957
54621
|
init_event_store();
|
|
54958
54622
|
init_activity_logger();
|
|
54959
54623
|
init_features();
|
|
54960
|
-
init_cost();
|
|
54624
|
+
init_cost$1();
|
|
54961
54625
|
const SYSTEM_PROMPT = `You are a concise voice narrator for a software development dashboard.
|
|
54962
54626
|
Your job: review recent activity and produce a SINGLE brief utterance suitable for text-to-speech.
|
|
54963
54627
|
|
|
@@ -55123,7 +54787,7 @@ const RESTART_MARKER = join(homedir(), ".overdeck", "dashboard-restarting.json")
|
|
|
55123
54787
|
* loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
|
|
55124
54788
|
*/
|
|
55125
54789
|
async function defaultLifecycleRunner(pending) {
|
|
55126
|
-
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-
|
|
54790
|
+
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-Dhw22tcB.js");
|
|
55127
54791
|
await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
|
|
55128
54792
|
if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
|
|
55129
54793
|
}
|
|
@@ -55191,7 +54855,7 @@ async function processPendingLifecycle(options) {
|
|
|
55191
54855
|
}
|
|
55192
54856
|
//#endregion
|
|
55193
54857
|
//#region ../../lib/memory/reconciliation.ts
|
|
55194
|
-
init_agents$
|
|
54858
|
+
init_agents$2();
|
|
55195
54859
|
async function reconcileStaleTranscriptCheckpoints(options = {}) {
|
|
55196
54860
|
const limit = options.limit ?? 100;
|
|
55197
54861
|
const checkpoints = (options.listCheckpoints ?? listTranscriptCheckpoints)(limit);
|
|
@@ -55255,7 +54919,7 @@ function checkpointIdentity(checkpoint) {
|
|
|
55255
54919
|
};
|
|
55256
54920
|
}
|
|
55257
54921
|
function inferCheckpointHarness(transcriptPath) {
|
|
55258
|
-
if (transcriptPath.includes("/.overdeck/agents/") && transcriptPath.includes("/sessions/")) return "
|
|
54922
|
+
if (transcriptPath.includes("/.overdeck/agents/") && transcriptPath.includes("/sessions/")) return "ohmypi";
|
|
55259
54923
|
if (transcriptPath.includes("/codex-home/sessions/") && transcriptPath.includes("rollout-")) return "codex";
|
|
55260
54924
|
return "claude-code";
|
|
55261
54925
|
}
|
|
@@ -55291,7 +54955,7 @@ init_paths();
|
|
|
55291
54955
|
init_tmux();
|
|
55292
54956
|
init_issue_id();
|
|
55293
54957
|
init_errors();
|
|
55294
|
-
init_agents$
|
|
54958
|
+
init_agents$2();
|
|
55295
54959
|
function getAgentDirectoryIssueId(name) {
|
|
55296
54960
|
const match = name.match(/^(?:agent|planning)-(.+)$/);
|
|
55297
54961
|
if (!match) return null;
|
|
@@ -55434,7 +55098,7 @@ init_activity_logger();
|
|
|
55434
55098
|
init_merge_sync();
|
|
55435
55099
|
const AUTO_MERGE_EXECUTOR_INTERVAL_MS = 3e4;
|
|
55436
55100
|
const REQUEUE_BACKOFF_MS = 6e4;
|
|
55437
|
-
let timer = null;
|
|
55101
|
+
let timer$1 = null;
|
|
55438
55102
|
let activeTick = null;
|
|
55439
55103
|
function errorMessage(error) {
|
|
55440
55104
|
if (error instanceof Error && error.message) return error.message;
|
|
@@ -55444,7 +55108,7 @@ function failureReason(result) {
|
|
|
55444
55108
|
return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
|
|
55445
55109
|
}
|
|
55446
55110
|
async function defaultMergeIssue(issueId) {
|
|
55447
|
-
const { triggerMerge } = await import("./workspaces-
|
|
55111
|
+
const { triggerMerge } = await import("./workspaces-u5uok4gi.js");
|
|
55448
55112
|
return triggerMerge(issueId);
|
|
55449
55113
|
}
|
|
55450
55114
|
function defaultAnnounceFailure(issueId, reason) {
|
|
@@ -55514,14 +55178,48 @@ function runTick(deps) {
|
|
|
55514
55178
|
}
|
|
55515
55179
|
function startAutoMergeExecutor(deps = {}) {
|
|
55516
55180
|
if (process.env.OVERDECK_DISABLE_AUTO_MERGE === "1") return false;
|
|
55517
|
-
if (timer) return false;
|
|
55518
|
-
timer = setInterval(() => runTick(deps), AUTO_MERGE_EXECUTOR_INTERVAL_MS);
|
|
55181
|
+
if (timer$1) return false;
|
|
55182
|
+
timer$1 = setInterval(() => runTick(deps), AUTO_MERGE_EXECUTOR_INTERVAL_MS);
|
|
55519
55183
|
return true;
|
|
55520
55184
|
}
|
|
55521
55185
|
function stopAutoMergeExecutor() {
|
|
55522
|
-
if (!timer) return;
|
|
55523
|
-
clearInterval(timer);
|
|
55524
|
-
timer = null;
|
|
55186
|
+
if (!timer$1) return;
|
|
55187
|
+
clearInterval(timer$1);
|
|
55188
|
+
timer$1 = null;
|
|
55189
|
+
}
|
|
55190
|
+
//#endregion
|
|
55191
|
+
//#region services/cost-reconcile-service.ts
|
|
55192
|
+
const RECONCILE_INTERVAL_MS = 5 * 6e4;
|
|
55193
|
+
let timer = null;
|
|
55194
|
+
let inFlight = null;
|
|
55195
|
+
async function runCostReconcileOnce(reason) {
|
|
55196
|
+
if (inFlight) return inFlight;
|
|
55197
|
+
inFlight = (async () => {
|
|
55198
|
+
const result = await reconcilePiTranscripts();
|
|
55199
|
+
if (result.eventsImported > 0 || result.errors.length > 0) console.log(`[cost-reconciler] ${reason} sweep: ${result.eventsImported} imported, ${result.duplicatesSkipped} duplicate(s), ${result.errors.length} error(s)`);
|
|
55200
|
+
if (result.errors.length > 0) for (const err of result.errors.slice(0, 5)) console.warn(`[cost-reconciler] ${err.path}: ${err.error}`);
|
|
55201
|
+
})().finally(() => {
|
|
55202
|
+
inFlight = null;
|
|
55203
|
+
});
|
|
55204
|
+
return inFlight;
|
|
55205
|
+
}
|
|
55206
|
+
function startCostReconcileService() {
|
|
55207
|
+
if (timer) return;
|
|
55208
|
+
timer = setInterval(() => {
|
|
55209
|
+
runCostReconcileOnce("interval").catch((err) => {
|
|
55210
|
+
console.warn("[cost-reconciler] interval sweep failed:", err instanceof Error ? err.message : err);
|
|
55211
|
+
});
|
|
55212
|
+
}, RECONCILE_INTERVAL_MS);
|
|
55213
|
+
timer.unref?.();
|
|
55214
|
+
runCostReconcileOnce("startup").catch((err) => {
|
|
55215
|
+
console.warn("[cost-reconciler] startup sweep failed:", err instanceof Error ? err.message : err);
|
|
55216
|
+
});
|
|
55217
|
+
}
|
|
55218
|
+
function stopCostReconcileService() {
|
|
55219
|
+
if (timer) {
|
|
55220
|
+
clearInterval(timer);
|
|
55221
|
+
timer = null;
|
|
55222
|
+
}
|
|
55525
55223
|
}
|
|
55526
55224
|
//#endregion
|
|
55527
55225
|
//#region ../../lib/boot-gates.ts
|
|
@@ -55617,14 +55315,14 @@ function createOverdeckDatabase(options = {}) {
|
|
|
55617
55315
|
try {
|
|
55618
55316
|
applyMigration(db, migrationPath);
|
|
55619
55317
|
const tables = userTableNames(db);
|
|
55620
|
-
if (tables.length !==
|
|
55318
|
+
if (tables.length !== 30) throw new Error(`Expected 30 overdeck tables, found ${tables.length}: ${tables.join(", ")}`);
|
|
55621
55319
|
assertEmptyTables(db, tables);
|
|
55622
55320
|
} finally {
|
|
55623
55321
|
db.close();
|
|
55624
55322
|
}
|
|
55625
55323
|
return {
|
|
55626
55324
|
dbPath,
|
|
55627
|
-
tableCount:
|
|
55325
|
+
tableCount: 30
|
|
55628
55326
|
};
|
|
55629
55327
|
}
|
|
55630
55328
|
//#endregion
|
|
@@ -55640,7 +55338,11 @@ init_tracker_config();
|
|
|
55640
55338
|
init_review_status();
|
|
55641
55339
|
init_event_store();
|
|
55642
55340
|
init_activity_logger();
|
|
55643
|
-
|
|
55341
|
+
init_service();
|
|
55342
|
+
init_config$1();
|
|
55343
|
+
init_deacon();
|
|
55344
|
+
init_agents$2();
|
|
55345
|
+
init_agent_projection();
|
|
55644
55346
|
init_paths();
|
|
55645
55347
|
init_tmux();
|
|
55646
55348
|
init_fts_db();
|
|
@@ -55916,6 +55618,8 @@ syncTranscriptPollerRegistry().catch((err) => console.warn("[memory-poller] init
|
|
|
55916
55618
|
reconcileStaleTranscriptCheckpoints({ log: (message) => console.log(message) }).catch((err) => console.warn("[memory-reconciliation] startup sweep failed:", err?.message ?? err));
|
|
55917
55619
|
startTranscriptPoller();
|
|
55918
55620
|
console.log("[overdeck] Memory transcript poller started");
|
|
55621
|
+
startCostReconcileService();
|
|
55622
|
+
console.log("[overdeck] Cost reconciler started");
|
|
55919
55623
|
const conversationSearchWatcher = startConversationSearchWatcher();
|
|
55920
55624
|
console.log(conversationSearchWatcher ? "[overdeck] Conversation search watcher started" : "[overdeck] Conversation search watcher skipped (conversationSearch.enabled=false)");
|
|
55921
55625
|
(async () => {
|
|
@@ -55965,6 +55669,7 @@ const handleShutdownSignal = async (signal) => {
|
|
|
55965
55669
|
stopTtsPlayback();
|
|
55966
55670
|
stopAutoMergeExecutor();
|
|
55967
55671
|
stopTranscriptPoller();
|
|
55672
|
+
stopCostReconcileService();
|
|
55968
55673
|
stopRestartAnnouncer();
|
|
55969
55674
|
await stopConversationSearchWatcher().catch((err) => console.warn("[conversation-search] watcher shutdown failed:", err));
|
|
55970
55675
|
closeConversationSearchService();
|
|
@@ -56014,7 +55719,7 @@ reconcileStaleGitHubBlockers().then((n) => {
|
|
|
56014
55719
|
}
|
|
56015
55720
|
}).catch((err) => console.warn(`[overdeck] Startup blocker reconciliation failed: ${err.message}`));
|
|
56016
55721
|
try {
|
|
56017
|
-
const { resetProcessingToQueued } = await import("./merge-sync-
|
|
55722
|
+
const { resetProcessingToQueued } = await import("./merge-sync-N6oGrZi7.js");
|
|
56018
55723
|
const resetCount = resetProcessingToQueued();
|
|
56019
55724
|
if (resetCount > 0) {
|
|
56020
55725
|
console.log(`[overdeck] Reset ${resetCount} stuck merge queue entries to queued`);
|