@overdeck/desktop 0.30.2 → 0.40.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-D647WvzH.js → chunk-BO2N2NFS-CW1ZdFdY.js} +4 -4
- package/server/public/assets/{diagram-OG6HWLK6-D94iJ8UD.js → diagram-OG6HWLK6-Cw_BgPPR.js} +1 -1
- package/server/public/assets/{dist-D-Is2vOq.js → dist-913yenhq.js} +1 -1
- package/server/public/assets/{dist-DJs-blp3.js → dist-CGMAxsiA.js} +3 -3
- package/server/public/assets/{ganttDiagram-6RSMTGT7-BCO0lQgo.js → ganttDiagram-6RSMTGT7-CUPZhXKC.js} +1 -1
- package/server/public/assets/{highlighted-body-OFNGDK62-Hms9Zx_K.js → highlighted-body-OFNGDK62-PZCZRTma.js} +1 -1
- package/server/public/assets/index-2sJIy1Mo.js +805 -0
- package/server/public/assets/index-D_duUQjN.css +1 -0
- package/server/public/assets/{linear-X3dJyawe.js → linear-CaWsupFC.js} +1 -1
- package/server/public/assets/mermaid-GHXKKRXX-CD7SbVD6.js +1 -0
- package/server/public/assets/{pieDiagram-4H26LBE5-BYZIa_Gs.js → pieDiagram-4H26LBE5-BhU2fIWh.js} +1 -1
- package/server/public/assets/{prod-De0nXELP.js → prod-Dk-iWRhQ.js} +4 -4
- package/server/public/assets/{quadrantDiagram-W4KKPZXB-CWvcQZvc.js → quadrantDiagram-W4KKPZXB-DGOsJ_nS.js} +1 -1
- package/server/public/assets/{sankeyDiagram-5OEKKPKP-CXmvKnWY.js → sankeyDiagram-5OEKKPKP-CzirInk6.js} +1 -1
- package/server/public/assets/{xychartDiagram-2RQKCTM6-BypSwt-2.js → xychartDiagram-2RQKCTM6-CG8FHgaF.js} +1 -1
- package/server/public/index.html +2 -2
- package/server/server.js +818 -1024
- package/server/public/assets/index-7_dXwqNm.css +0 -1
- package/server/public/assets/index-DnfNk7ij.js +0 -801
- package/server/public/assets/mermaid-GHXKKRXX-D7b6S76i.js +0 -1
package/server/server.js
CHANGED
|
@@ -1,93 +1,90 @@
|
|
|
1
|
-
import { a as __toCommonJS, i as __require, o as __toESM, t as __commonJSMin } from "./
|
|
2
|
-
import { C as isDevMode, S as init_paths, T as
|
|
3
|
-
import {
|
|
4
|
-
import { A as
|
|
5
|
-
import { a as init_activity_logger, i as emitDashboardLifecycleSync, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-
|
|
6
|
-
import { A as
|
|
7
|
-
import { n as openDatabase, t as init_driver } from "./driver-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { a as
|
|
15
|
-
import {
|
|
16
|
-
import { i as
|
|
17
|
-
import {
|
|
18
|
-
import { n as
|
|
19
|
-
import { i as
|
|
20
|
-
import { n as
|
|
21
|
-
import {
|
|
22
|
-
import { a as
|
|
23
|
-
import { n as
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { r as
|
|
29
|
-
import {
|
|
30
|
-
import { a as
|
|
31
|
-
import { i as
|
|
32
|
-
import { a as
|
|
33
|
-
import { c as
|
|
34
|
-
import {
|
|
35
|
-
import { C as
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import { C as
|
|
39
|
-
import { f as
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import { n as
|
|
48
|
-
import {
|
|
49
|
-
import { t as
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import { a as
|
|
57
|
-
import {
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
60
|
-
import {
|
|
61
|
-
import {
|
|
62
|
-
import {
|
|
63
|
-
import {
|
|
64
|
-
import {
|
|
65
|
-
import {
|
|
66
|
-
import {
|
|
67
|
-
import {
|
|
68
|
-
import { t as
|
|
69
|
-
import {
|
|
70
|
-
import { a as
|
|
71
|
-
import {
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
import {
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
77
|
-
import {
|
|
78
|
-
import { r as
|
|
79
|
-
import { t as
|
|
80
|
-
import { n as
|
|
81
|
-
import { r as
|
|
82
|
-
import { n as
|
|
83
|
-
import { a as
|
|
84
|
-
import {
|
|
85
|
-
import {
|
|
86
|
-
import { a as
|
|
87
|
-
import {
|
|
88
|
-
import { r as parseArtifactRef } from "./forge-i30UYoWv.js";
|
|
89
|
-
import { n as spawnSequencerAgent, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-nsW6G44K.js";
|
|
90
|
-
import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-BpQ8wIW1.js";
|
|
1
|
+
import { a as __toCommonJS, i as __require, o as __toESM, t as __commonJSMin } from "./rolldown-runtime-DNCzzKnI.js";
|
|
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-jZvjmiV6.js";
|
|
3
|
+
import { A as init_model_capabilities, B as FsError, C as defaultBackgroundAiFeatures, E as MODEL_DEPRECATIONS, F as require_dist$1, H as GitHubApiError, J as TrackerError, K as ProcessSpawnError, M as resolveModelIdSync, N as init_js_yaml, O as getModelEffortLevelsSync, P as jsYaml, S as updateConversationsConfig, T as MODEL_CAPABILITIES, X as init_errors, _ as loadConfigNoMigration, a as ROLE_EFFORTS, b as mergeTtsDaemonConfigs, c as getConversationSearchConfigSync, d as getDefaultTtsDaemonConfig, f as getGlobalConfigPath, g as isTldrEnabledSync, i as PARENT_MODEL_REF, j as modelSupportsImagesSync, k as hasModelCapabilitySync, l as getConversationsConfig, m as isClaudeCodeChannelsEnabled, n as DEFAULT_ROLES, o as clearConfigCache, p as init_config_yaml, r as DEFAULT_WORKHORSES, s as computeModelOrigin, t as COMPLIANCE_MODES, v as loadConfigSync, w as init_registry, x as resolveModel, y as mergeConfigs } from "./config-yaml-DKmldcyb.js";
|
|
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-L3yA6mO7.js";
|
|
5
|
+
import { a as init_activity_logger, i as emitDashboardLifecycleSync, n as emitActivityEntrySync, r as emitActivityTtsSync } from "./activity-logger-DW1XjyNu.js";
|
|
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-V576nNrp.js";
|
|
7
|
+
import { n as openDatabase, t as init_driver } from "./driver-CYPr28GN.js";
|
|
8
|
+
import { a as parseIssueIdSync, n as extractPrefixSync, r as init_issue_id } from "./issue-id-9iS2dwrp.js";
|
|
9
|
+
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-BpstKN1Q.js";
|
|
10
|
+
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-DuzZlrCh.js";
|
|
11
|
+
import { a as init_event_store, i as initEventStore, n as getEventStore, r as getSharedDb } from "./event-store-hdZZ-JnB.js";
|
|
12
|
+
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-wyzx0Z0w.js";
|
|
13
|
+
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-D_w3kLBb.js";
|
|
14
|
+
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-D4DcNPZ-.js";
|
|
15
|
+
import { n as AgentsResolverLive, o as init_agents$1 } from "./agents-BOX5w2kT.js";
|
|
16
|
+
import { i as init_paths$2, l as resolveObservationsFile, r as ensureParentDir, s as resolveIssueMemoryRoot, t as assertMemorySafeSegment } from "./paths-zPOV7_VB.js";
|
|
17
|
+
import { i as recordBriefingSessionStart, n as ensureSessionContextBriefingFile, r as init_briefing_freshness, t as appendFreshBriefingUpdate } from "./briefing-freshness--_mHhmzI.js";
|
|
18
|
+
import { n as listFeatureRegistryEntries, t as init_feature_registry_storage } from "./feature-registry-storage-5mIu-zwl.js";
|
|
19
|
+
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-B8USYP2J.js";
|
|
20
|
+
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-CoFoCGgg.js";
|
|
21
|
+
import { i as init_agent_state_service, n as AgentStateServiceLive } from "./agent-state-service-CoVk44dM.js";
|
|
22
|
+
import { a as init_tracker_config, i as initTrackerConfigCache, n as getLinearApiKey, r as getRallyConfig, t as getGitHubConfig } from "./tracker-config-Clt5yfo6.js";
|
|
23
|
+
import { d as init_typed_errors, l as WorkspaceCreateError, n as AgentStartError, r as BeadsNotInitialized, t as AgentAlreadyRunning, u as WorkspaceNotFound } from "./typed-errors-BRDFMoss.js";
|
|
24
|
+
import { i as init_linear_client, r as LinearClientOptionalLive, t as LinearClient } from "./linear-client-DCCtUBEM.js";
|
|
25
|
+
import { i as init_github_client, r as GitHubClientOptionalLive } from "./github-client-Dxt2nXAf.js";
|
|
26
|
+
import { i as init_rally_client, r as RallyClientOptionalLive } from "./rally-client-CFxmPAi2.js";
|
|
27
|
+
import { i as resolveGitHubIssueSync, n as init_tracker_utils } from "./tracker-utils-k1WKm_mu.js";
|
|
28
|
+
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-0AVb8ADy.js";
|
|
29
|
+
import { i as ensureInternalTokenSync, s as init_internal_token } from "./internal-token-R4gY8z44.js";
|
|
30
|
+
import { a as setPipelineHandlerSync, t as init_pipeline_notifier } from "./pipeline-notifier-C5ZCbH9K.js";
|
|
31
|
+
import { c as init_review_status_sync, i as getMergeBlockerReconcileCandidates, r as getAllReviewStatusesFromDb } from "./review-status-sync-DGaMxP95.js";
|
|
32
|
+
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-CI1Gfwnb.js";
|
|
33
|
+
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-CKUHrPQl.js";
|
|
34
|
+
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-cnr9mD4B.js";
|
|
35
|
+
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-O755gANb.js";
|
|
36
|
+
import { f as init_config, m as loadConfigSync$1, s as getDashboardApiUrlSync } from "./config-B8QT8B9M.js";
|
|
37
|
+
import { n as require_auth_errors, r as require_token_error, t as require_token_util } from "./token-util-CROoF5ic.js";
|
|
38
|
+
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-_HbvcXw1.js";
|
|
39
|
+
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-CJimCSkV.js";
|
|
40
|
+
import { i as getClaudePermissionFlagsStringSync, o as init_claude_permissions, s as resolvePermissionModeSync, t as BYPASS_PERMISSION_MODE } from "./claude-permissions-BqmkURDk.js";
|
|
41
|
+
import { l as init_codex, s as findRolloutPath } from "./codex-B8fyHBID.js";
|
|
42
|
+
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, Xt as init_agent_record_sync, Z as messageAgent, Zt as readAgentHarnessModelRecordSync, 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-qDfx6gda.js";
|
|
43
|
+
import { a as getBuiltInDefaultHarness, c as getProviderForModelSync, l as init_providers, o as getKimiAnthropicBaseUrl, u as piProviderForModel } from "./providers-Cju7HorZ.js";
|
|
44
|
+
import { n as isBackgroundFeatureEnabled, t as init_features } from "./features-BsiM65ZI.js";
|
|
45
|
+
import { i as init_settings, r as getMemoryWorkerConcurrency, t as areMemoryObservationsEnabled } from "./settings-s_9BJkQW.js";
|
|
46
|
+
import { t as init_pan_dir } from "./pan-dir-BfyAUgin.js";
|
|
47
|
+
import { n as init_launcher_generator, t as generateLauncherScriptSync } from "./launcher-generator-CZaEkOZW.js";
|
|
48
|
+
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-CoMbLSYY.js";
|
|
49
|
+
import { i as init_harness_policy, n as resolveHarness, r as canUseHarnessSync, t as init_harness_resolve } from "./harness-resolve-CMrgPv1e.js";
|
|
50
|
+
import { c as init_docker_stats } from "./stack-health-KI4ZA4dt.js";
|
|
51
|
+
import { i as updateMemoryHealth, n as extractWithProviderPolicy, r as init_health$1, t as init_providers$1 } from "./providers-0791nfjR.js";
|
|
52
|
+
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-BaPQ0U5p.js";
|
|
53
|
+
import { a as parseRelativeTime, n as CostThresholdError, s as embed } from "./scanner-DYR1QDik.js";
|
|
54
|
+
import { n as deduplicateEventsSync, o as readEventsSync, s as tailEventsSync } from "./events-C0JbknXU.js";
|
|
55
|
+
import { n as recordBackgroundAiCost, t as init_cost$1 } from "./cost-CBa8loyG.js";
|
|
56
|
+
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-BF905HkK.js";
|
|
57
|
+
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-rQwXVZR5.js";
|
|
58
|
+
import { f as workspacesRouteLayer, g as getWorkspacePathForIssue, h as processPendingFeedbackDeliveries, m as resumeQueuedMerges, p as enrichReviewStatus } from "./workspaces-CvQySqp3.js";
|
|
59
|
+
import { _ as init_platform, g as detectPlatform } from "./workspace-manager-oMP5s9VY.js";
|
|
60
|
+
import { a as getShadowState, s as init_shadow_state } from "./shadow-state-xPxOHguz.js";
|
|
61
|
+
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-D909CPHX.js";
|
|
62
|
+
import { a as loadCloisterConfigSync, i as loadCloisterConfig, o as saveCloisterConfigSync, r as init_config$1, s as shouldAutoStart } from "./config-wf_W38L3.js";
|
|
63
|
+
import { O as init_specialists, b as getReviewerSessionName } from "./specialists-C5uBTD_g.js";
|
|
64
|
+
import { H as init_deacon, _t as emergencyBrake, ct as setAgentStoppedNotifier, gt as withConcurrencyLimit, ht as init_concurrency$1, i as autoResumeStoppedWorkAgents, lt as setMergeReadyNotifier, rt as resetPatrolHeartbeatForStartup, st as setAgentStatusChangedNotifier, vt as init_concurrency } from "./deacon-BJOrAeJn.js";
|
|
65
|
+
import { n as getNoResumeMode, r as init_no_resume_mode, t as disableNoResumeMode } from "./no-resume-mode-DlMPigWY.js";
|
|
66
|
+
import { c as init_prd_locations, s as findPrdAtStatusSync } from "./archive-planning-O-QKXVWX.js";
|
|
67
|
+
import { a as writeFeedbackFile, i as init_feedback_writer } from "./feedback-writer-D5GpgTWq.js";
|
|
68
|
+
import { n as parseSequenceMd, r as writeSequenceMd, t as init_sequence_io } from "./sequence-io-CMiS9KMK.js";
|
|
69
|
+
import { _ as computeStats, b as normalizeGate, c as BLOCKS_MAIN_LABEL, d as READY_LABEL, f as RELEASED_LABEL, g as computeLanes, h as computeCohort, l as OBJECTION_LABEL, m as classifyIssue, p as VETOED_LABEL, u as PARKED_LABEL, v as computeWaves, y as init_pickup } from "./flywheel-merge-order-bSoDRUVw.js";
|
|
70
|
+
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-DQRd2At2.js";
|
|
71
|
+
import { _ as init_git_activity, v as listGitOperationsSync } from "./merge-agent-BsELKm49.js";
|
|
72
|
+
import { n as getTldrDaemonServiceSync, r as init_tldr_daemon } from "./tldr-daemon-C4f0Cv5Z.js";
|
|
73
|
+
import { i as runMemoryFtsTransaction, n as init_fts_db, r as runMemoryFtsStatement, t as closeMemoryFtsDatabases } from "./fts-db-DH6pFiOa.js";
|
|
74
|
+
import { c as init_pending, l as maybeTriggerStatusRollup, o as readRecentObservations, r as init_rollup, u as writePendingTurn } from "./rollup-_dL7JXdO.js";
|
|
75
|
+
import { r as specialistsRouteLayer } from "./specialists-DFDg83jj.js";
|
|
76
|
+
import { t as getAgentCommandSync } from "./settings-DVFIQrHs.js";
|
|
77
|
+
import { n as init_review_agent, r as isExtendedReviewEnabled } from "./review-agent-GjWZBuhW.js";
|
|
78
|
+
import { i as isRemoteAvailable, r as init_remote, t as createFlyProviderFromConfig } from "./remote-br-7Zy2V.js";
|
|
79
|
+
import { n as init_claude_settings_overlay, t as detectProviderEnvConflicts } from "./claude-settings-overlay-Ck8qNezZ.js";
|
|
80
|
+
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-CcJERZro.js";
|
|
81
|
+
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-znoS388v.js";
|
|
82
|
+
import { a as init_conversation_compaction, c as shouldInterceptManualCompact, n as compactConversationNative, o as isCompacting } from "./conversation-compaction-DfmqrfYi.js";
|
|
83
|
+
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-CIMR-y8_.js";
|
|
84
|
+
import { c as init_github_app, s as getPullRequestState } from "./github-app-DgISqJqI.js";
|
|
85
|
+
import { i as parseArtifactRef, r as init_forge } from "./forge-mcRx-ba-.js";
|
|
86
|
+
import { a as spawnSequencerAgent, i as init_sequencer_agent, n as clearFinishedSequencerRun, r as getSequencerRunStatus, t as SEQUENCER_AGENT_ID } from "./sequencer-agent-CFrrqU0M.js";
|
|
87
|
+
import { i as listTranscriptCheckpoints, r as getTranscriptCheckpoint$1 } from "./checkpoints-9h0pTZ5k.js";
|
|
91
88
|
import { createRequire } from "node:module";
|
|
92
89
|
import { Cause, Context, Data, Effect, Exit, Fiber, FileSystem, Layer, Option, Path, Queue, Result, Schedule, Schema, Stream } from "effect";
|
|
93
90
|
import { createReadStream, createWriteStream, existsSync, fstatSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
@@ -102,7 +99,7 @@ import { createHash, randomUUID } from "crypto";
|
|
|
102
99
|
import * as sp from "node:path";
|
|
103
100
|
import { basename as basename$1, delimiter, dirname as dirname$1, extname as extname$1, isAbsolute as isAbsolute$1, join as join$1, normalize, relative as relative$1, resolve as resolve$1, sep as sep$1 } from "node:path";
|
|
104
101
|
import { chmod as chmod$1, mkdir as mkdir$1, open as open$1, readFile as readFile$1, readdir as readdir$1, rename as rename$1, stat as stat$2, unlink as unlink$1, writeFile as writeFile$1 } from "fs/promises";
|
|
105
|
-
import { createHmac, randomBytes
|
|
102
|
+
import { createHmac, randomBytes, randomUUID as randomUUID$1, timingSafeEqual } from "node:crypto";
|
|
106
103
|
import { exec, execFile, execFileSync, execSync, spawn } from "node:child_process";
|
|
107
104
|
import { promisify } from "node:util";
|
|
108
105
|
import * as pty from "@homebridge/node-pty-prebuilt-multiarch";
|
|
@@ -303,6 +300,8 @@ const ServerConfigLayer = Layer.effect(ServerConfig, Effect.sync(() => {
|
|
|
303
300
|
}));
|
|
304
301
|
//#endregion
|
|
305
302
|
//#region services/terminal-service.ts
|
|
303
|
+
init_http_helpers();
|
|
304
|
+
init_activity_logger();
|
|
306
305
|
init_paths$1();
|
|
307
306
|
init_driver();
|
|
308
307
|
var import_dist = /* @__PURE__ */ __toESM(require_dist$1(), 1);
|
|
@@ -312,7 +311,13 @@ init_registry();
|
|
|
312
311
|
init_config_yaml();
|
|
313
312
|
init_ui_theme();
|
|
314
313
|
init_infra();
|
|
315
|
-
|
|
314
|
+
init_event_store();
|
|
315
|
+
init_agents$1();
|
|
316
|
+
init_read_model();
|
|
317
|
+
init_checkpoint_manager();
|
|
318
|
+
init_domain_services();
|
|
319
|
+
init_cost();
|
|
320
|
+
init_agent_state_service();
|
|
316
321
|
/**
|
|
317
322
|
* TerminalService — dual-runtime PTY terminal streaming (PAN-428 B20)
|
|
318
323
|
*
|
|
@@ -325,6 +330,7 @@ init_agents();
|
|
|
325
330
|
* toggle dimensions to force SIGWINCH + full repaint.
|
|
326
331
|
* - On stream/close: do NOT kill the PTY — just remove from tracking.
|
|
327
332
|
*/
|
|
333
|
+
init_src();
|
|
328
334
|
init_tmux();
|
|
329
335
|
init_child_env();
|
|
330
336
|
function isBun() {
|
|
@@ -592,12 +598,23 @@ const TerminalServiceLive = Layer.effect(TerminalService, Effect.sync(() => {
|
|
|
592
598
|
}));
|
|
593
599
|
//#endregion
|
|
594
600
|
//#region services/agent-spawner.ts
|
|
601
|
+
init_issue_id();
|
|
602
|
+
init_projects();
|
|
603
|
+
init_tracker_config();
|
|
604
|
+
init_linear_client();
|
|
605
|
+
init_github_client();
|
|
606
|
+
init_rally_client();
|
|
607
|
+
init_tracker_utils();
|
|
608
|
+
init_cache_service();
|
|
609
|
+
init_issue_service_singleton();
|
|
610
|
+
init_issue_lifecycle();
|
|
595
611
|
/**
|
|
596
612
|
* AgentSpawner Effect service (PAN-449)
|
|
597
613
|
*
|
|
598
614
|
* Wraps agents.ts in an Effect service with typed errors.
|
|
599
615
|
* Route handlers use this instead of importing from lib/agents.ts directly.
|
|
600
616
|
*/
|
|
617
|
+
init_typed_errors();
|
|
601
618
|
var AgentSpawner = class extends Context.Service()("overdeck/dashboard/AgentSpawner") {};
|
|
602
619
|
const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
603
620
|
startWork: (issueId, opts) => Effect.tryPromise({
|
|
@@ -611,7 +628,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
611
628
|
const beadsDir = join$1(workspacePath, ".beads");
|
|
612
629
|
const projectBeadsDir = join$1(workspacePath, "..", "..", ".beads");
|
|
613
630
|
if (!(existsSync$1(beadsDir) || existsSync$1(projectBeadsDir))) throw new BeadsNotInitialized({ workspace: workspacePath });
|
|
614
|
-
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-
|
|
631
|
+
const { getAgentState, spawnAgent, normalizeAgentId } = await import("./agents-DsFz3A8y.js");
|
|
615
632
|
const normalizedId = normalizeAgentId(issueId);
|
|
616
633
|
if ((await Effect.runPromise(getAgentState(normalizedId)))?.status === "running") throw new AgentAlreadyRunning({ id: issueId });
|
|
617
634
|
return {
|
|
@@ -642,7 +659,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
642
659
|
const { workspacePath, projectPath, issue } = opts;
|
|
643
660
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
644
661
|
const sessionName = opts.sessionName ?? `planning-${issueId.toLowerCase()}`;
|
|
645
|
-
const { spawnPlanningSession } = await import("./spawn-planning-session-
|
|
662
|
+
const { spawnPlanningSession } = await import("./spawn-planning-session-DnUv0hSH.js");
|
|
646
663
|
const result = await spawnPlanningSession({
|
|
647
664
|
issue: {
|
|
648
665
|
id: issue.id,
|
|
@@ -675,14 +692,14 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
675
692
|
}),
|
|
676
693
|
kill: (agentId) => Effect.tryPromise({
|
|
677
694
|
try: async () => {
|
|
678
|
-
const { stopAgent } = await import("./agents-
|
|
695
|
+
const { stopAgent } = await import("./agents-DsFz3A8y.js");
|
|
679
696
|
await Effect.runPromise(stopAgent(agentId));
|
|
680
697
|
},
|
|
681
698
|
catch: () => void 0
|
|
682
699
|
}).pipe(Effect.ignore),
|
|
683
700
|
message: (agentId, msg) => Effect.tryPromise({
|
|
684
701
|
try: async () => {
|
|
685
|
-
const { messageAgent } = await import("./agents-
|
|
702
|
+
const { messageAgent } = await import("./agents-DsFz3A8y.js");
|
|
686
703
|
await messageAgent(agentId, msg);
|
|
687
704
|
},
|
|
688
705
|
catch: (err) => new AgentStartError({
|
|
@@ -693,8 +710,8 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
693
710
|
}),
|
|
694
711
|
deepWipe: (issueId, opts) => Effect.tryPromise({
|
|
695
712
|
try: async () => {
|
|
696
|
-
const { deepWipe } = await import("./workflows-
|
|
697
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
713
|
+
const { deepWipe } = await import("./workflows-LNUGDzVu.js");
|
|
714
|
+
const { resolveProjectFromIssueSync } = await import("./projects-DWBDcB6V.js");
|
|
698
715
|
const project = resolveProjectFromIssueSync(issueId);
|
|
699
716
|
const projectPath = project?.projectPath ?? process.cwd();
|
|
700
717
|
await Effect.runPromise(deepWipe({
|
|
@@ -722,7 +739,7 @@ const AgentSpawnerLive = Layer.effect(AgentSpawner, Effect.sync(() => ({
|
|
|
722
739
|
* Wraps workspace-manager.ts in an Effect service with typed errors.
|
|
723
740
|
* Route handlers and AgentSpawner use this instead of calling workspace-manager directly.
|
|
724
741
|
*/
|
|
725
|
-
|
|
742
|
+
init_typed_errors();
|
|
726
743
|
const execAsync$8 = promisify(exec);
|
|
727
744
|
var WorkspaceService = class extends Context.Service()("overdeck/dashboard/WorkspaceService") {};
|
|
728
745
|
const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
@@ -750,8 +767,8 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
750
767
|
const { workspacePath, branch } = getWorkspacePath(issueId);
|
|
751
768
|
const issueLower = issueId.toLowerCase();
|
|
752
769
|
if (existsSync$1(workspacePath)) return workspacePath;
|
|
753
|
-
const { createWorkspace } = await import("./workspace-manager-
|
|
754
|
-
const { loadProjectsConfigSync } = await import("./projects-
|
|
770
|
+
const { createWorkspace } = await import("./workspace-manager-XDNuCCXG.js");
|
|
771
|
+
const { loadProjectsConfigSync } = await import("./projects-DWBDcB6V.js");
|
|
755
772
|
const { projects } = loadProjectsConfigSync();
|
|
756
773
|
const project = resolveProjectFromIssueSync(issueId);
|
|
757
774
|
if (!project) throw new WorkspaceCreateError({
|
|
@@ -786,7 +803,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
786
803
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
787
804
|
const issueLower = issueId.toLowerCase();
|
|
788
805
|
if (!existsSync$1(workspacePath)) throw new WorkspaceNotFound({ id: issueId });
|
|
789
|
-
const { removeWorkspace } = await import("./workspace-manager-
|
|
806
|
+
const { removeWorkspace } = await import("./workspace-manager-XDNuCCXG.js");
|
|
790
807
|
const project = resolveProjectFromIssueSync(issueId);
|
|
791
808
|
if (!project) throw new WorkspaceCreateError({
|
|
792
809
|
id: issueId,
|
|
@@ -817,7 +834,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
817
834
|
try: async () => {
|
|
818
835
|
const { workspacePath } = getWorkspacePath(issueId);
|
|
819
836
|
const issueLower = issueId.toLowerCase();
|
|
820
|
-
const { stopWorkspaceDocker } = await import("./workspace-manager-
|
|
837
|
+
const { stopWorkspaceDocker } = await import("./workspace-manager-XDNuCCXG.js");
|
|
821
838
|
await Effect.runPromise(stopWorkspaceDocker(workspacePath, issueLower));
|
|
822
839
|
},
|
|
823
840
|
catch: () => void 0
|
|
@@ -886,7 +903,7 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
886
903
|
join$1(workspacePath, ".devcontainer", "docker-compose.devcontainer.yml")
|
|
887
904
|
];
|
|
888
905
|
if (!composePaths.find((p) => existsSync$1(p))) {
|
|
889
|
-
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-
|
|
906
|
+
const { ensureDevcontainerSync } = await import("./ensure-devcontainer-Uu-fGqwo.js");
|
|
890
907
|
const ensure = ensureDevcontainerSync({
|
|
891
908
|
workspacePath,
|
|
892
909
|
issueId
|
|
@@ -915,7 +932,6 @@ const WorkspaceServiceLive = Layer.effect(WorkspaceService, Effect.sync(() => {
|
|
|
915
932
|
}));
|
|
916
933
|
//#endregion
|
|
917
934
|
//#region services/openrouter-service.ts
|
|
918
|
-
init_issue_id();
|
|
919
935
|
/**
|
|
920
936
|
* OpenRouter Service
|
|
921
937
|
*
|
|
@@ -1060,6 +1076,7 @@ function getDefaultCwd() {
|
|
|
1060
1076
|
}
|
|
1061
1077
|
//#endregion
|
|
1062
1078
|
//#region services/open.ts
|
|
1079
|
+
init_src();
|
|
1063
1080
|
const execAsync$7 = promisify(exec);
|
|
1064
1081
|
function getFileManagerCommand() {
|
|
1065
1082
|
switch (process.platform) {
|
|
@@ -3156,7 +3173,7 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
3156
3173
|
const http$1 = __require("http");
|
|
3157
3174
|
const net = __require("net");
|
|
3158
3175
|
const tls = __require("tls");
|
|
3159
|
-
const { randomBytes: randomBytes$
|
|
3176
|
+
const { randomBytes: randomBytes$1, createHash: createHash$3 } = __require("crypto");
|
|
3160
3177
|
const { Duplex: Duplex$2, Readable: Readable$1 } = __require("stream");
|
|
3161
3178
|
const { URL: URL$1 } = __require("url");
|
|
3162
3179
|
const PerMessageDeflate = require_permessage_deflate();
|
|
@@ -3711,7 +3728,7 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
3711
3728
|
}
|
|
3712
3729
|
}
|
|
3713
3730
|
const defaultPort = isSecure ? 443 : 80;
|
|
3714
|
-
const key = randomBytes$
|
|
3731
|
+
const key = randomBytes$1(16).toString("base64");
|
|
3715
3732
|
const request = isSecure ? https.request : http$1.request;
|
|
3716
3733
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
3717
3734
|
let perMessageDeflate;
|
|
@@ -4766,9 +4783,12 @@ function removeClientFromHub(hubs, sessionName, ws) {
|
|
|
4766
4783
|
}
|
|
4767
4784
|
//#endregion
|
|
4768
4785
|
//#region routes/codex-auth.ts
|
|
4786
|
+
init_http_handler();
|
|
4787
|
+
init_codex_auth();
|
|
4769
4788
|
init_cliproxy();
|
|
4770
4789
|
init_tmux();
|
|
4771
4790
|
init_config();
|
|
4791
|
+
init_origin_validation();
|
|
4772
4792
|
const reauthSessions = /* @__PURE__ */ new Map();
|
|
4773
4793
|
const SESSION_MAX_AGE_MS = 3600 * 1e3;
|
|
4774
4794
|
const readJsonBody$13 = Effect.gen(function* () {
|
|
@@ -4973,6 +4993,7 @@ async function waitForSessionRespawn(sessionName, timeoutMs) {
|
|
|
4973
4993
|
//#endregion
|
|
4974
4994
|
//#region ws-terminal.ts
|
|
4975
4995
|
init_tmux();
|
|
4996
|
+
init_origin_validation();
|
|
4976
4997
|
init_child_env();
|
|
4977
4998
|
const RESPAWN_WAIT_MS = 35e3;
|
|
4978
4999
|
const ATTACH_TIMEOUT_MS = 5e3;
|
|
@@ -15904,7 +15925,7 @@ var require_get_vercel_oidc_token = /* @__PURE__ */ __commonJSMin(((exports, mod
|
|
|
15904
15925
|
err = error;
|
|
15905
15926
|
}
|
|
15906
15927
|
try {
|
|
15907
|
-
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-
|
|
15928
|
+
const [{ getTokenPayload, isExpired }, { refreshToken }] = await Promise.all([await import("./token-util-xNaV-00f.js").then((m) => /* @__PURE__ */ __toESM(m.default)), await import("./token-mVJcOeCq.js").then((m) => /* @__PURE__ */ __toESM(m.default))]);
|
|
15908
15929
|
if (!token || isExpired(getTokenPayload(token), options?.expirationBufferMs)) {
|
|
15909
15930
|
await refreshToken(options);
|
|
15910
15931
|
token = getVercelOidcTokenSync();
|
|
@@ -28221,7 +28242,7 @@ var GoogleCloudTranscription = class {
|
|
|
28221
28242
|
}
|
|
28222
28243
|
async start(apiKey, model) {
|
|
28223
28244
|
try {
|
|
28224
|
-
const { SpeechClient } = await import("./src-
|
|
28245
|
+
const { SpeechClient } = await import("./src-BuEHMMFm.js").then((m) => /* @__PURE__ */ __toESM(m.default, 1)).then((module) => module.v1p1beta1 ?? module.v1);
|
|
28225
28246
|
if (this.closed) return;
|
|
28226
28247
|
const stream = new SpeechClient({ apiKey }).streamingRecognize({
|
|
28227
28248
|
config: {
|
|
@@ -28470,6 +28491,9 @@ function createTurnQueue(emitter, onTurn) {
|
|
|
28470
28491
|
//#endregion
|
|
28471
28492
|
//#region routes/voice.ts
|
|
28472
28493
|
init_paths();
|
|
28494
|
+
init_http_helpers();
|
|
28495
|
+
init_http_handler();
|
|
28496
|
+
init_origin_validation();
|
|
28473
28497
|
const MAX_VOICE_SETTINGS_BODY_BYTES = 16384;
|
|
28474
28498
|
const DEFAULT_VOICE_SETTINGS = {
|
|
28475
28499
|
stt: {
|
|
@@ -28621,6 +28645,7 @@ const putVoiceSettingsRoute = HttpRouter.add("PUT", "/api/voice/settings", httpH
|
|
|
28621
28645
|
const voiceRouteLayer = Layer.mergeAll(getVoiceSettingsRoute, putVoiceSettingsRoute);
|
|
28622
28646
|
//#endregion
|
|
28623
28647
|
//#region ws-voice.ts
|
|
28648
|
+
init_origin_validation();
|
|
28624
28649
|
function sendJson$1(ws, payload) {
|
|
28625
28650
|
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(payload));
|
|
28626
28651
|
}
|
|
@@ -28836,6 +28861,7 @@ function boundedAutoPresoElements(elements) {
|
|
|
28836
28861
|
}
|
|
28837
28862
|
//#endregion
|
|
28838
28863
|
//#region ws-autopreso.ts
|
|
28864
|
+
init_origin_validation();
|
|
28839
28865
|
function sendJson(ws, payload) {
|
|
28840
28866
|
if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(payload));
|
|
28841
28867
|
}
|
|
@@ -28886,226 +28912,24 @@ function setupAutoPresoWebSocket(server) {
|
|
|
28886
28912
|
});
|
|
28887
28913
|
}
|
|
28888
28914
|
//#endregion
|
|
28889
|
-
//#region
|
|
28915
|
+
//#region services/read-workspace-file.ts
|
|
28916
|
+
init_briefing_freshness();
|
|
28917
|
+
init_internal_token();
|
|
28918
|
+
init_pipeline_notifier();
|
|
28919
|
+
init_review_status_sync();
|
|
28920
|
+
init_review_status();
|
|
28890
28921
|
init_conversations();
|
|
28891
28922
|
init_codex_conversation_parser();
|
|
28892
28923
|
init_pi_conversation_parser();
|
|
28924
|
+
init_ohmypi_conversation_parser();
|
|
28893
28925
|
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
28926
|
init_claude_permissions();
|
|
29104
28927
|
init_codex();
|
|
29105
28928
|
init_providers();
|
|
29106
28929
|
init_openai_auth();
|
|
29107
28930
|
init_claude_auth();
|
|
29108
28931
|
init_launcher_generator();
|
|
28932
|
+
init_agent_record_sync();
|
|
29109
28933
|
init_layers();
|
|
29110
28934
|
init_bridge_token();
|
|
29111
28935
|
init_pty_token();
|
|
@@ -29115,6 +28939,12 @@ init_pi_fifo();
|
|
|
29115
28939
|
init_control_settings();
|
|
29116
28940
|
init_operator_interventions();
|
|
29117
28941
|
init_transcript_landing();
|
|
28942
|
+
init_agents$2();
|
|
28943
|
+
init_agent_input_detection();
|
|
28944
|
+
init_agent_enrichment();
|
|
28945
|
+
init_jsonl_resolver();
|
|
28946
|
+
init_flywheel_run_state();
|
|
28947
|
+
init_src();
|
|
29118
28948
|
init_projects();
|
|
29119
28949
|
const MAX_WORKSPACE_FILE_BYTES = 256 * 1024;
|
|
29120
28950
|
const DEFAULT_CONTEXT_LINES = 10;
|
|
@@ -29283,6 +29113,7 @@ function readWorkspaceFileEffect(input) {
|
|
|
29283
29113
|
* out of cwd is no broader than what the caller could query directly
|
|
29284
29114
|
* with an absolute path.
|
|
29285
29115
|
*/
|
|
29116
|
+
init_src();
|
|
29286
29117
|
const MAX_PATH_LENGTH = 4096;
|
|
29287
29118
|
async function resolveFilePathExists(input) {
|
|
29288
29119
|
const { cwd, path } = input;
|
|
@@ -29334,9 +29165,12 @@ function resolveFilePathExistsEffect(input) {
|
|
|
29334
29165
|
* Terminal RPC methods (subscribeTerminal, terminalOpen/Write/Resize/Close)
|
|
29335
29166
|
* are implemented via TerminalService (dual-runtime PTY, B20).
|
|
29336
29167
|
*/
|
|
29168
|
+
init_src();
|
|
29337
29169
|
init_paths();
|
|
29338
29170
|
init_tmux();
|
|
29339
29171
|
init_projects();
|
|
29172
|
+
init_origin_validation();
|
|
29173
|
+
init_http_helpers();
|
|
29340
29174
|
function storedToDomainEvent(stored) {
|
|
29341
29175
|
return {
|
|
29342
29176
|
type: stored.type,
|
|
@@ -29359,7 +29193,7 @@ function normalizedIssueId(value) {
|
|
|
29359
29193
|
function conversationDiscoveringStream() {
|
|
29360
29194
|
return Stream.succeed({ kind: "discovering" }).pipe(Stream.repeat(Schedule.fixed("2 seconds")));
|
|
29361
29195
|
}
|
|
29362
|
-
function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
29196
|
+
function streamResolvedFullParseSnapshots(resolve, parse, model, unresolvedMeansEmpty = false) {
|
|
29363
29197
|
return Stream.callback((queue) => Effect.acquireRelease(Effect.promise(async () => {
|
|
29364
29198
|
let stopped = false;
|
|
29365
29199
|
let resolving = false;
|
|
@@ -29369,6 +29203,14 @@ function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
|
29369
29203
|
let parsing = false;
|
|
29370
29204
|
let pendingReparse = false;
|
|
29371
29205
|
let sessionFile = null;
|
|
29206
|
+
let announcedEmpty = false;
|
|
29207
|
+
let hasContent = false;
|
|
29208
|
+
const stopDiscovery = () => {
|
|
29209
|
+
if (discoveryTimer) {
|
|
29210
|
+
clearInterval(discoveryTimer);
|
|
29211
|
+
discoveryTimer = null;
|
|
29212
|
+
}
|
|
29213
|
+
};
|
|
29372
29214
|
const offer = (event) => {
|
|
29373
29215
|
try {
|
|
29374
29216
|
Queue.offerUnsafe(queue, event);
|
|
@@ -29383,6 +29225,10 @@ function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
|
29383
29225
|
parsing = true;
|
|
29384
29226
|
try {
|
|
29385
29227
|
const result = await parse(sessionFile);
|
|
29228
|
+
if (result.messages.length > 0 && !hasContent) {
|
|
29229
|
+
hasContent = true;
|
|
29230
|
+
stopDiscovery();
|
|
29231
|
+
}
|
|
29386
29232
|
offer({
|
|
29387
29233
|
kind: "messages",
|
|
29388
29234
|
messages: result.messages,
|
|
@@ -29401,36 +29247,56 @@ function streamResolvedFullParseSnapshots(resolve, parse, model) {
|
|
|
29401
29247
|
}
|
|
29402
29248
|
}
|
|
29403
29249
|
};
|
|
29250
|
+
const watchFile = (file) => {
|
|
29251
|
+
try {
|
|
29252
|
+
watcher = watch(file, () => {
|
|
29253
|
+
if (debounce) return;
|
|
29254
|
+
debounce = setTimeout(() => {
|
|
29255
|
+
debounce = null;
|
|
29256
|
+
emit();
|
|
29257
|
+
}, 300);
|
|
29258
|
+
});
|
|
29259
|
+
} catch {}
|
|
29260
|
+
};
|
|
29404
29261
|
const tryResolve = async () => {
|
|
29405
|
-
if (stopped || resolving ||
|
|
29262
|
+
if (stopped || resolving || hasContent) return;
|
|
29406
29263
|
resolving = true;
|
|
29407
29264
|
try {
|
|
29408
29265
|
const resolved = await resolve();
|
|
29409
29266
|
if (!resolved) {
|
|
29410
|
-
|
|
29267
|
+
if (unresolvedMeansEmpty) {
|
|
29268
|
+
if (!sessionFile && !announcedEmpty) {
|
|
29269
|
+
announcedEmpty = true;
|
|
29270
|
+
offer({
|
|
29271
|
+
kind: "messages",
|
|
29272
|
+
messages: [],
|
|
29273
|
+
workLog: [],
|
|
29274
|
+
streaming: false,
|
|
29275
|
+
snapshot: true
|
|
29276
|
+
});
|
|
29277
|
+
}
|
|
29278
|
+
return;
|
|
29279
|
+
}
|
|
29280
|
+
if (!sessionFile) offer({ kind: "discovering" });
|
|
29411
29281
|
return;
|
|
29412
29282
|
}
|
|
29413
|
-
sessionFile
|
|
29414
|
-
|
|
29415
|
-
|
|
29416
|
-
|
|
29417
|
-
|
|
29418
|
-
|
|
29419
|
-
|
|
29420
|
-
|
|
29421
|
-
|
|
29422
|
-
|
|
29423
|
-
|
|
29424
|
-
emit();
|
|
29425
|
-
}, 300);
|
|
29426
|
-
});
|
|
29427
|
-
} catch {}
|
|
29283
|
+
if (resolved !== sessionFile) {
|
|
29284
|
+
if (watcher) {
|
|
29285
|
+
try {
|
|
29286
|
+
watcher.close();
|
|
29287
|
+
} catch {}
|
|
29288
|
+
watcher = null;
|
|
29289
|
+
}
|
|
29290
|
+
sessionFile = resolved;
|
|
29291
|
+
await emit();
|
|
29292
|
+
if (!stopped) watchFile(resolved);
|
|
29293
|
+
} else await emit();
|
|
29428
29294
|
} finally {
|
|
29429
29295
|
resolving = false;
|
|
29430
29296
|
}
|
|
29431
29297
|
};
|
|
29432
29298
|
await tryResolve();
|
|
29433
|
-
if (!
|
|
29299
|
+
if (!hasContent) discoveryTimer = setInterval(() => {
|
|
29434
29300
|
tryResolve();
|
|
29435
29301
|
}, 2e3);
|
|
29436
29302
|
return { stop: () => {
|
|
@@ -29808,13 +29674,15 @@ const PanRpcLayer = PanRpcGroup.toLayer(Effect.gen(function* () {
|
|
|
29808
29674
|
const conv = getConversationByName(input.conversationName);
|
|
29809
29675
|
if (!conv && /^(agent-|planning-|specialist-)/.test(input.conversationName)) {
|
|
29810
29676
|
const harness = yield* Effect.promise(() => resolveAgentHarness(input.conversationName));
|
|
29677
|
+
if (harness === "ohmypi") return streamResolvedFullParseSnapshots(() => resolvePiSessionPath(input.conversationName), parseOhmypiConversationMessages, null);
|
|
29811
29678
|
if (harness === "pi") return streamResolvedFullParseSnapshots(() => resolvePiSessionPath(input.conversationName), parsePiConversationMessages, null);
|
|
29812
29679
|
if (harness === "codex") return streamResolvedFullParseSnapshots(() => resolveCodexRolloutPath(input.conversationName), parseCodexConversationMessages, null);
|
|
29813
29680
|
return conversationDiscoveringStream();
|
|
29814
29681
|
}
|
|
29815
29682
|
if (!conv) return conversationDiscoveringStream();
|
|
29816
|
-
if (conv.harness === "
|
|
29817
|
-
if (conv.harness === "
|
|
29683
|
+
if (conv.harness === "ohmypi") return streamResolvedFullParseSnapshots(() => resolvePiSessionPath(conv.tmuxSession), parseOhmypiConversationMessages, conv.model ?? null, true);
|
|
29684
|
+
if (conv.harness === "pi") return streamResolvedFullParseSnapshots(() => resolvePiSessionPath(conv.tmuxSession), parsePiConversationMessages, 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) {
|
|
@@ -30708,6 +30609,47 @@ const getContainerLogsRoute = HttpRouter.add("GET", "/api/resources/docker/conta
|
|
|
30708
30609
|
})));
|
|
30709
30610
|
const resourcesRouteLayer = Layer.mergeAll(getResourcesRoute, getContainerHistoryRoute, getContainerDetailsRoute, deleteDockerContainerRoute, postPruneContainersRoute, deleteDockerNetworkRoute, deleteDockerVolumeRoute, postPruneVolumesRoute, postRestartContainerRoute, postStartContainerRoute, getContainerLogsRoute);
|
|
30710
30611
|
//#endregion
|
|
30612
|
+
//#region services/model-origin-enrich.ts
|
|
30613
|
+
init_agents$2();
|
|
30614
|
+
init_config_yaml();
|
|
30615
|
+
/**
|
|
30616
|
+
* Map a session-node type to the pipeline Role whose model distribution it draws
|
|
30617
|
+
* from. Returns null for types that never sample a top-level weighted role
|
|
30618
|
+
* distribution: 'reviewer' (sub-role convoy — resolves via a sub-role scalar),
|
|
30619
|
+
* 'legacy', and anything unrecognized.
|
|
30620
|
+
*/
|
|
30621
|
+
function sessionTypeToModelRole(type) {
|
|
30622
|
+
switch (type) {
|
|
30623
|
+
case "work": return "work";
|
|
30624
|
+
case "review": return "review";
|
|
30625
|
+
case "test": return "test";
|
|
30626
|
+
case "ship":
|
|
30627
|
+
case "merge": return "ship";
|
|
30628
|
+
case "planning": return "plan";
|
|
30629
|
+
case "strike": return "strike";
|
|
30630
|
+
default: return null;
|
|
30631
|
+
}
|
|
30632
|
+
}
|
|
30633
|
+
/**
|
|
30634
|
+
* Mutate `sections` in place, attaching `modelOrigin` to each node whose role uses
|
|
30635
|
+
* a weighted distribution. Scalar roles are left untouched (the client renders the
|
|
30636
|
+
* resolved model with no bars/hash). Reconstructs the spawn key from the agent's
|
|
30637
|
+
* persisted `modelSpawnKey` (exact) or, for pre-PAN-2053 agents, `${role}:${issueId}`.
|
|
30638
|
+
* Wrapped so a config/state error can never break the tree.
|
|
30639
|
+
*/
|
|
30640
|
+
function enrichSessionsWithModelOrigin(sections, fallbackIssueId) {
|
|
30641
|
+
try {
|
|
30642
|
+
const { config } = loadConfigSync();
|
|
30643
|
+
for (const section of sections) {
|
|
30644
|
+
const role = sessionTypeToModelRole(section.type);
|
|
30645
|
+
if (!role) continue;
|
|
30646
|
+
const state = getAgentStateSync(section.sessionId);
|
|
30647
|
+
const origin = computeModelOrigin(role, state?.modelSpawnKey ?? `${role}:${state?.issueId ?? fallbackIssueId}`, config);
|
|
30648
|
+
if (origin) section.modelOrigin = origin;
|
|
30649
|
+
}
|
|
30650
|
+
} catch {}
|
|
30651
|
+
}
|
|
30652
|
+
//#endregion
|
|
30711
30653
|
//#region services/session-presence.ts
|
|
30712
30654
|
/**
|
|
30713
30655
|
* Derive session presence from runtime state, tmux session existence, and recent activity.
|
|
@@ -30729,6 +30671,7 @@ async function deriveSessionPresence(agentId, rtState, tmuxSessionNames) {
|
|
|
30729
30671
|
}
|
|
30730
30672
|
//#endregion
|
|
30731
30673
|
//#region ../../lib/settings-api.ts
|
|
30674
|
+
init_prd_locations();
|
|
30732
30675
|
/**
|
|
30733
30676
|
* Settings API Adapter
|
|
30734
30677
|
*
|
|
@@ -30790,19 +30733,7 @@ function sanitizeApiTtsConfig(tts) {
|
|
|
30790
30733
|
function getDefaultConversationModelApi() {
|
|
30791
30734
|
const { config } = loadConfigSync();
|
|
30792
30735
|
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");
|
|
30736
|
+
throw new Error("No default model configured — set models.default_conversation_model");
|
|
30806
30737
|
}
|
|
30807
30738
|
const ROLE_NAMES = [
|
|
30808
30739
|
"plan",
|
|
@@ -30927,7 +30858,27 @@ function normalizeRolesConfig(roles) {
|
|
|
30927
30858
|
for (const [role, roleConfig] of Object.entries(roles)) normalized[role] = normalizeRoleConfig(roleConfig);
|
|
30928
30859
|
return normalized;
|
|
30929
30860
|
}
|
|
30930
|
-
function validateModelRef(fieldPath, ref, effectiveWorkhorses, errors, warnings, allowWorkhorseRef, allowParentRef = false) {
|
|
30861
|
+
function validateModelRef(fieldPath, ref, effectiveWorkhorses, errors, warnings, allowWorkhorseRef, allowParentRef = false, allowDistribution = false) {
|
|
30862
|
+
if (Array.isArray(ref)) {
|
|
30863
|
+
if (!allowDistribution) {
|
|
30864
|
+
errors.push(`${fieldPath} distribution not allowed here; must be a scalar model reference`);
|
|
30865
|
+
return;
|
|
30866
|
+
}
|
|
30867
|
+
if (ref.length === 0) {
|
|
30868
|
+
errors.push(`${fieldPath} distribution must be a non-empty array`);
|
|
30869
|
+
return;
|
|
30870
|
+
}
|
|
30871
|
+
for (let i = 0; i < ref.length; i++) {
|
|
30872
|
+
const entry = ref[i];
|
|
30873
|
+
if (!isRecord$3(entry)) {
|
|
30874
|
+
errors.push(`${fieldPath}[${i}] must be an object with model and weight`);
|
|
30875
|
+
continue;
|
|
30876
|
+
}
|
|
30877
|
+
if (!Number.isInteger(entry.weight) || entry.weight <= 0) errors.push(`${fieldPath}[${i}].weight must be a positive integer`);
|
|
30878
|
+
validateModelRef(`${fieldPath}[${i}].model`, entry.model, effectiveWorkhorses, errors, warnings, allowWorkhorseRef);
|
|
30879
|
+
}
|
|
30880
|
+
return;
|
|
30881
|
+
}
|
|
30931
30882
|
if (typeof ref !== "string" || ref.trim() === "") {
|
|
30932
30883
|
errors.push(`${fieldPath} must be a non-empty model reference`);
|
|
30933
30884
|
return;
|
|
@@ -30957,7 +30908,7 @@ function validateModelRef(fieldPath, ref, effectiveWorkhorses, errors, warnings,
|
|
|
30957
30908
|
}
|
|
30958
30909
|
function validateRoleFields(fieldPath, roleConfig, errors) {
|
|
30959
30910
|
const harness = roleConfig.harness;
|
|
30960
|
-
if (harness !== void 0 && harness !== null && harness !== "" && harness !== "claude-code" && harness !== "
|
|
30911
|
+
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
30912
|
const effort = roleConfig.effort;
|
|
30962
30913
|
if (effort !== void 0 && !ROLE_EFFORTS.includes(effort)) errors.push(`${fieldPath}.effort must be one of ${ROLE_EFFORTS.join(", ")}`);
|
|
30963
30914
|
const maxAgents = roleConfig.maxAgents;
|
|
@@ -30997,14 +30948,24 @@ function validateWorkhorsesAndRoles(settings, errors, warnings) {
|
|
|
30997
30948
|
errors.push(`roles.${role}.model must be a non-empty model reference`);
|
|
30998
30949
|
continue;
|
|
30999
30950
|
}
|
|
31000
|
-
validateModelRef(`roles.${role}.model`, rawRoleConfig.model, effectiveWorkhorses, errors, warnings, true);
|
|
30951
|
+
validateModelRef(`roles.${role}.model`, rawRoleConfig.model, effectiveWorkhorses, errors, warnings, true, false, true);
|
|
31001
30952
|
validateRoleFields(`roles.${role}`, rawRoleConfig, errors);
|
|
31002
30953
|
const effort = rawRoleConfig.effort;
|
|
31003
30954
|
if (typeof effort === "string" && ROLE_EFFORTS.includes(effort)) {
|
|
31004
|
-
const
|
|
31005
|
-
if (
|
|
31006
|
-
const
|
|
31007
|
-
if (
|
|
30955
|
+
const modelRef = rawRoleConfig.model ?? DEFAULT_ROLES[role]?.model;
|
|
30956
|
+
if (Array.isArray(modelRef)) for (const entry of modelRef) {
|
|
30957
|
+
const resolvedModel = resolveModelRefToId(entry.model, effectiveWorkhorses);
|
|
30958
|
+
if (resolvedModel) {
|
|
30959
|
+
const supported = getModelEffortLevelsSync(resolvedModel);
|
|
30960
|
+
if (supported !== void 0 && !supported.includes(effort)) errors.push(`roles.${role}.effort '${effort}' is not supported by ${resolvedModel} (supported: ${supported.join(", ")})`);
|
|
30961
|
+
}
|
|
30962
|
+
}
|
|
30963
|
+
else {
|
|
30964
|
+
const resolvedModel = resolveModelRefToId(modelRef, effectiveWorkhorses);
|
|
30965
|
+
if (resolvedModel) {
|
|
30966
|
+
const supported = getModelEffortLevelsSync(resolvedModel);
|
|
30967
|
+
if (supported !== void 0 && !supported.includes(effort)) errors.push(`roles.${role}.effort '${effort}' is not supported by ${resolvedModel} (supported: ${supported.join(", ")})`);
|
|
30968
|
+
}
|
|
31008
30969
|
}
|
|
31009
30970
|
}
|
|
31010
30971
|
if (rawRoleConfig.sub !== void 0) if (!isRecord$3(rawRoleConfig.sub)) errors.push(`roles.${role}.sub must be an object`);
|
|
@@ -31392,7 +31353,7 @@ function validateSettingsApi(settings) {
|
|
|
31392
31353
|
errors.push(`Unknown provider harness entry "${provider}"`);
|
|
31393
31354
|
continue;
|
|
31394
31355
|
}
|
|
31395
|
-
if (harness !== void 0 && harness !== "" && harness !== "claude-code" && harness !== "
|
|
31356
|
+
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
31357
|
}
|
|
31397
31358
|
if (settings.models?.overrides) {
|
|
31398
31359
|
const validModelIds = Object.keys(MODEL_CAPABILITIES);
|
|
@@ -31631,14 +31592,6 @@ const saveOpenRouterFavorites = (favorites) => Effect.tryPromise({
|
|
|
31631
31592
|
});
|
|
31632
31593
|
//#endregion
|
|
31633
31594
|
//#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
31595
|
init_review_agent();
|
|
31643
31596
|
function normalizeAgentStatus(status) {
|
|
31644
31597
|
switch (status) {
|
|
@@ -31681,8 +31634,8 @@ function normalizeAgentStatus(status) {
|
|
|
31681
31634
|
*
|
|
31682
31635
|
* Async-only (fs/promises); safe to call from the dashboard server.
|
|
31683
31636
|
*/
|
|
31684
|
-
init_agents$
|
|
31685
|
-
|
|
31637
|
+
init_agents$2();
|
|
31638
|
+
init_jsonl_resolver();
|
|
31686
31639
|
init_tmux();
|
|
31687
31640
|
const CONVOY_REVIEWER_ROLES = [
|
|
31688
31641
|
"correctness",
|
|
@@ -31878,11 +31831,17 @@ async function buildReviewerNodes(opts) {
|
|
|
31878
31831
|
* POST /api/command-deck/planning/:issueId/init
|
|
31879
31832
|
* GET /api/command-deck/projects
|
|
31880
31833
|
*/
|
|
31834
|
+
init_http_helpers();
|
|
31881
31835
|
init_child_env();
|
|
31882
|
-
|
|
31836
|
+
init_domain_services();
|
|
31837
|
+
init_read_model();
|
|
31838
|
+
init_agents$2();
|
|
31839
|
+
init_costs();
|
|
31883
31840
|
init_tmux();
|
|
31884
31841
|
init_projects();
|
|
31885
|
-
|
|
31842
|
+
init_config_yaml();
|
|
31843
|
+
init_http_handler();
|
|
31844
|
+
init_jsonl_resolver();
|
|
31886
31845
|
const execAsync$5 = promisify(exec);
|
|
31887
31846
|
const execFileAsync$4 = promisify(execFile);
|
|
31888
31847
|
function getIssueDataService$2() {
|
|
@@ -32217,6 +32176,7 @@ async function fetchActivityDataWithContext(issueId, context = {}) {
|
|
|
32217
32176
|
if (!b.startedAt) return -1;
|
|
32218
32177
|
return a.startedAt.localeCompare(b.startedAt);
|
|
32219
32178
|
});
|
|
32179
|
+
enrichSessionsWithModelOrigin(sections, issueId);
|
|
32220
32180
|
let costByStage = {};
|
|
32221
32181
|
let totalCost = null;
|
|
32222
32182
|
try {
|
|
@@ -32610,13 +32570,12 @@ Be specific: reference actual file names, function names, requirement text, disc
|
|
|
32610
32570
|
const { command: cliCmd, args: cliArgs } = getAgentCommandSync(statusModelId);
|
|
32611
32571
|
const modelFlag = cliArgs.length > 0 ? ` ${cliArgs.join(" ")}` : "";
|
|
32612
32572
|
const promptFile = join$1(planningDir, ".status-review-prompt.tmp");
|
|
32613
|
-
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-
|
|
32614
|
-
const { loadConfigSync: loadYamlConfig } = await import("./config-yaml-BPbPSBp2.js");
|
|
32573
|
+
const { getProviderForModelSync, getProviderEnvSync } = await import("./providers-Dre9thog.js");
|
|
32615
32574
|
let providerEnvStr = "";
|
|
32616
32575
|
let providerEnv = {};
|
|
32617
32576
|
const statusProvider = getProviderForModelSync(statusModelId);
|
|
32618
32577
|
if (statusProvider.name !== "anthropic") {
|
|
32619
|
-
const { config } =
|
|
32578
|
+
const { config } = loadConfigSync();
|
|
32620
32579
|
const apiKey = config.apiKeys[statusProvider.name];
|
|
32621
32580
|
if (apiKey) {
|
|
32622
32581
|
providerEnv = getProviderEnvSync(statusProvider, apiKey);
|
|
@@ -32694,7 +32653,7 @@ const postMissionControlUploadRoute = HttpRouter.add("POST", "/api/command-deck/
|
|
|
32694
32653
|
let safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "-");
|
|
32695
32654
|
let processedContent = content;
|
|
32696
32655
|
if (safeName.endsWith(".vtt")) {
|
|
32697
|
-
const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-
|
|
32656
|
+
const { vttToMarkdown } = yield* Effect.promise(() => import("./vtt-parser-Dik5Bh9h.js"));
|
|
32698
32657
|
processedContent = vttToMarkdown(content);
|
|
32699
32658
|
safeName = safeName.replace(/\.vtt$/, ".md");
|
|
32700
32659
|
}
|
|
@@ -32906,7 +32865,6 @@ async function fetchProjectTree() {
|
|
|
32906
32865
|
const commandDeckRouteLayer = Layer.mergeAll(getMissionControlActivityRoute, getMissionControlPlanningRoute, postMissionControlStatusReviewRoute, postMissionControlUploadRoute, postMissionControlSyncDiscussionsRoute, postMissionControlPlanningInitRoute, getMissionControlProjectsRoute);
|
|
32907
32866
|
//#endregion
|
|
32908
32867
|
//#region routes/remote.ts
|
|
32909
|
-
init_specs();
|
|
32910
32868
|
/**
|
|
32911
32869
|
* Remote route module — Effect HttpRouter.Layer (PAN-428 B14)
|
|
32912
32870
|
*
|
|
@@ -32921,7 +32879,11 @@ init_specs();
|
|
|
32921
32879
|
* GET /api/remote/workspaces/:issueId/agent/output
|
|
32922
32880
|
* POST /api/remote/workspaces/:issueId/agent/tell
|
|
32923
32881
|
*/
|
|
32882
|
+
init_http_helpers();
|
|
32883
|
+
init_remote();
|
|
32924
32884
|
init_config();
|
|
32885
|
+
init_domain_services();
|
|
32886
|
+
init_http_handler();
|
|
32925
32887
|
async function loadRemoteWorkspaceMetadata(issueId) {
|
|
32926
32888
|
const normalizedId = issueId.toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
32927
32889
|
const content = await readFile(join$1(homedir$1(), ".overdeck", "workspaces", `${normalizedId}.yaml`), "utf-8").catch(() => null);
|
|
@@ -33285,7 +33247,7 @@ async function getTtsDaemonAuthTokenPromise() {
|
|
|
33285
33247
|
return existing;
|
|
33286
33248
|
}
|
|
33287
33249
|
} catch {}
|
|
33288
|
-
const token = randomBytes
|
|
33250
|
+
const token = randomBytes(32).toString("base64url");
|
|
33289
33251
|
await mkdir(dirname$1(QWEN_TTS_AUTH_TOKEN_PATH), {
|
|
33290
33252
|
recursive: true,
|
|
33291
33253
|
mode: 448
|
|
@@ -36920,8 +36882,10 @@ function isAbortError(error) {
|
|
|
36920
36882
|
* POST /api/settings/validate-api-key
|
|
36921
36883
|
* PUT /api/settings
|
|
36922
36884
|
*/
|
|
36885
|
+
init_http_helpers();
|
|
36923
36886
|
init_providers();
|
|
36924
|
-
|
|
36887
|
+
init_http_handler();
|
|
36888
|
+
init_agents$2();
|
|
36925
36889
|
init_config_yaml();
|
|
36926
36890
|
const REINDEX_CONFIRM_THRESHOLD_USD = 1;
|
|
36927
36891
|
const REINDEX_CONFIRM_TTL_MS = 600 * 1e3;
|
|
@@ -36934,7 +36898,7 @@ let conversationReindexProgress = {
|
|
|
36934
36898
|
chunksIndexed: 0
|
|
36935
36899
|
};
|
|
36936
36900
|
function createReindexConfirmationNonce(estimatedUsd) {
|
|
36937
|
-
const nonce = randomBytes
|
|
36901
|
+
const nonce = randomBytes(24).toString("base64url");
|
|
36938
36902
|
const now = Date.now();
|
|
36939
36903
|
for (const [key, entry] of reindexConfirmationNonces) if (entry.expiresAt <= now) reindexConfirmationNonces.delete(key);
|
|
36940
36904
|
reindexConfirmationNonces.set(nonce, {
|
|
@@ -37727,6 +37691,9 @@ const getProviderEnvConflictsRoute = HttpRouter.add("GET", "/api/settings/provid
|
|
|
37727
37691
|
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
37692
|
//#endregion
|
|
37729
37693
|
//#region routes/autopreso.ts
|
|
37694
|
+
init_http_helpers();
|
|
37695
|
+
init_http_handler();
|
|
37696
|
+
init_origin_validation();
|
|
37730
37697
|
const readJsonBody$7 = Effect.gen(function* () {
|
|
37731
37698
|
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
37732
37699
|
const contentLength = Number(request.headers["content-length"] ?? 0);
|
|
@@ -37790,7 +37757,12 @@ const autopresoRouteLayer = Layer.mergeAll(startRoute, backToStagingRoute, reset
|
|
|
37790
37757
|
* GET /api/activity
|
|
37791
37758
|
* GET /api/activity/:id
|
|
37792
37759
|
*/
|
|
37793
|
-
|
|
37760
|
+
init_http_helpers();
|
|
37761
|
+
init_domain_services();
|
|
37762
|
+
init_service();
|
|
37763
|
+
init_agents$2();
|
|
37764
|
+
init_git_activity();
|
|
37765
|
+
init_http_handler();
|
|
37794
37766
|
let _cachedReviewStatuses = null;
|
|
37795
37767
|
let _cachedReviewStatusesAt = 0;
|
|
37796
37768
|
const REVIEW_STATUS_CACHE_TTL_MS = 5e3;
|
|
@@ -37951,6 +37923,7 @@ const metricsRouteLayer = Layer.mergeAll(getMetricsSummaryRoute, getMetricsCosts
|
|
|
37951
37923
|
* Health filtering logic for dashboard health API
|
|
37952
37924
|
* Determines which agents should be visible in health checks
|
|
37953
37925
|
*/
|
|
37926
|
+
init_config$1();
|
|
37954
37927
|
init_tmux();
|
|
37955
37928
|
const KICKOFF_STALL_GRACE_MS = 300 * 1e3;
|
|
37956
37929
|
/**
|
|
@@ -38071,6 +38044,8 @@ const determineHealthStatus = (agentId, stateFile, liveSessions) => Effect.gen(f
|
|
|
38071
38044
|
* POST /api/dev/rebuild
|
|
38072
38045
|
* POST /api/system/restart-dashboard
|
|
38073
38046
|
*/
|
|
38047
|
+
init_http_helpers();
|
|
38048
|
+
init_service();
|
|
38074
38049
|
init_tmux();
|
|
38075
38050
|
init_projects();
|
|
38076
38051
|
init_tracker_config();
|
|
@@ -38078,9 +38053,11 @@ init_config_yaml();
|
|
|
38078
38053
|
init_config();
|
|
38079
38054
|
init_issue_id();
|
|
38080
38055
|
init_io();
|
|
38056
|
+
init_domain_services();
|
|
38057
|
+
init_read_model();
|
|
38058
|
+
init_http_handler();
|
|
38081
38059
|
init_types();
|
|
38082
|
-
init_agents$
|
|
38083
|
-
init_remote_agents();
|
|
38060
|
+
init_agents$2();
|
|
38084
38061
|
const execAsync$4 = promisify(exec);
|
|
38085
38062
|
async function readPackageVersion() {
|
|
38086
38063
|
let dir = dirname$1(fileURLToPath(import.meta.url));
|
|
@@ -38437,7 +38414,7 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
|
|
|
38437
38414
|
}, { status: 400 });
|
|
38438
38415
|
return yield* Effect.promise(async () => {
|
|
38439
38416
|
try {
|
|
38440
|
-
const { RallyRestApi } = await import("./rally-api-
|
|
38417
|
+
const { RallyRestApi } = await import("./rally-api-CKayMhOp.js");
|
|
38441
38418
|
const api = new RallyRestApi({
|
|
38442
38419
|
apiKey,
|
|
38443
38420
|
server: server || "https://rally1.rallydev.com"
|
|
@@ -38467,6 +38444,33 @@ const postRallyValidateRoute = HttpRouter.add("POST", "/api/rally/validate", Eff
|
|
|
38467
38444
|
});
|
|
38468
38445
|
}));
|
|
38469
38446
|
const getNoResumeModeRoute = HttpRouter.add("GET", "/api/no-resume-mode", Effect.sync(() => jsonResponse(getNoResumeMode())));
|
|
38447
|
+
/**
|
|
38448
|
+
* Operator "Resume all" — the call-to-action behind the no-resume banner.
|
|
38449
|
+
* PAN-1963 makes agent auto-resume OFF by default at every boot, so after the
|
|
38450
|
+
* dashboard loads, stopped agents wait for the operator to put them back to
|
|
38451
|
+
* work. This clears no-resume mode for the running process (so the Deacon's
|
|
38452
|
+
* patrols and lifecycle-event handlers resume agents again) and immediately
|
|
38453
|
+
* sweeps the stopped work agents rather than waiting for the next patrol tick.
|
|
38454
|
+
*/
|
|
38455
|
+
const postResumeAllRoute = HttpRouter.add("POST", "/api/resume-all", Effect.promise(async () => {
|
|
38456
|
+
try {
|
|
38457
|
+
disableNoResumeMode();
|
|
38458
|
+
const resumed = await autoResumeStoppedWorkAgents();
|
|
38459
|
+
console.log(`[resume-all] No-resume mode cleared; resumed ${resumed.length} work agent(s)${resumed.length ? `: ${resumed.join(", ")}` : ""}`);
|
|
38460
|
+
return jsonResponse({
|
|
38461
|
+
ok: true,
|
|
38462
|
+
resumed,
|
|
38463
|
+
count: resumed.length
|
|
38464
|
+
});
|
|
38465
|
+
} catch (error) {
|
|
38466
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
38467
|
+
console.error("Error resuming all agents:", error);
|
|
38468
|
+
return jsonResponse({
|
|
38469
|
+
ok: false,
|
|
38470
|
+
error: "Failed to resume agents: " + msg
|
|
38471
|
+
}, { status: 500 });
|
|
38472
|
+
}
|
|
38473
|
+
}));
|
|
38470
38474
|
const getDeaconStatusRoute = HttpRouter.add("GET", "/api/deacon/status", Effect.try({
|
|
38471
38475
|
try: () => {
|
|
38472
38476
|
const service = getCloisterService();
|
|
@@ -38537,7 +38541,7 @@ const getVersionRoute = HttpRouter.add("GET", "/api/version", Effect.promise(asy
|
|
|
38537
38541
|
const version = await getOverdeckVersion();
|
|
38538
38542
|
let supervisorUrl = null;
|
|
38539
38543
|
try {
|
|
38540
|
-
const { getSupervisorUrlSync } = await import("./supervisor-
|
|
38544
|
+
const { getSupervisorUrlSync } = await import("./supervisor-ti-xrTNH.js");
|
|
38541
38545
|
supervisorUrl = getSupervisorUrlSync();
|
|
38542
38546
|
} catch {}
|
|
38543
38547
|
return jsonResponse({
|
|
@@ -38633,7 +38637,7 @@ const getPlanningStatusRoute = HttpRouter.add("GET", "/api/planning/:issueId/sta
|
|
|
38633
38637
|
const remoteState = loadRemoteAgentState(sessionName);
|
|
38634
38638
|
const isRemote = !!remoteState;
|
|
38635
38639
|
const vmName = remoteState?.vmName ?? "";
|
|
38636
|
-
const { getAgentStateSync } = await import("./agents-
|
|
38640
|
+
const { getAgentStateSync } = await import("./agents-DsFz3A8y.js");
|
|
38637
38641
|
const agentStarting = getAgentStateSync(sessionName)?.status === "starting";
|
|
38638
38642
|
let tmuxSessionAlive = false;
|
|
38639
38643
|
if (!isRemote) try {
|
|
@@ -38776,10 +38780,9 @@ Continue the PLANNING session. Do NOT implement anything.
|
|
|
38776
38780
|
`);
|
|
38777
38781
|
const agentCwd = workspacePath;
|
|
38778
38782
|
if (existsSync$1(outputFile)) await rename(outputFile, join$1(planningDir, `output-${Date.now()}.jsonl`));
|
|
38779
|
-
const { getAgentCommandSync } = await import("./settings-
|
|
38783
|
+
const { getAgentCommandSync } = await import("./settings-oOlkt2wY.js");
|
|
38780
38784
|
let msgPlanningModel = "claude-sonnet-4-6";
|
|
38781
38785
|
try {
|
|
38782
|
-
const { loadConfigSync, resolveModel } = await import("./config-yaml-BPbPSBp2.js");
|
|
38783
38786
|
msgPlanningModel = resolveModel("plan", void 0, loadConfigSync().config);
|
|
38784
38787
|
} catch {}
|
|
38785
38788
|
const msgAgentCmd = getAgentCommandSync(msgPlanningModel);
|
|
@@ -38839,7 +38842,7 @@ const deletePlanningSessionRoute = HttpRouter.add("DELETE", "/api/planning/:issu
|
|
|
38839
38842
|
}));
|
|
38840
38843
|
const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Effect.promise(async () => {
|
|
38841
38844
|
try {
|
|
38842
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
38845
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CdfMe3Oe.js");
|
|
38843
38846
|
const projectRoot = process.cwd();
|
|
38844
38847
|
const venvPath = join$1(projectRoot, ".venv");
|
|
38845
38848
|
const results = [];
|
|
@@ -38884,7 +38887,7 @@ const getTldrStatusRoute = HttpRouter.add("GET", "/api/services/tldr/status", Ef
|
|
|
38884
38887
|
}));
|
|
38885
38888
|
const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Effect.promise(async () => {
|
|
38886
38889
|
try {
|
|
38887
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
38890
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CdfMe3Oe.js");
|
|
38888
38891
|
const projectRoot = process.cwd();
|
|
38889
38892
|
const venvPath = join$1(projectRoot, ".venv");
|
|
38890
38893
|
if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
|
|
@@ -38901,7 +38904,7 @@ const postTldrStartRoute = HttpRouter.add("POST", "/api/services/tldr/start", Ef
|
|
|
38901
38904
|
}));
|
|
38902
38905
|
const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effect.promise(async () => {
|
|
38903
38906
|
try {
|
|
38904
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
38907
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CdfMe3Oe.js");
|
|
38905
38908
|
const projectRoot = process.cwd();
|
|
38906
38909
|
const venvPath = join$1(projectRoot, ".venv");
|
|
38907
38910
|
if (!existsSync$1(venvPath)) return jsonResponse({ error: "No .venv found in project root" }, { status: 404 });
|
|
@@ -38918,7 +38921,7 @@ const postTldrStopRoute = HttpRouter.add("POST", "/api/services/tldr/stop", Effe
|
|
|
38918
38921
|
}));
|
|
38919
38922
|
const postTldrReloadRoute = HttpRouter.add("POST", "/api/services/tldr/reload", Effect.promise(async () => {
|
|
38920
38923
|
try {
|
|
38921
|
-
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-
|
|
38924
|
+
const { getTldrDaemonServiceSync } = await import("./tldr-daemon-CdfMe3Oe.js");
|
|
38922
38925
|
const enabled = isTldrEnabledSync();
|
|
38923
38926
|
const projectRoot = process.cwd();
|
|
38924
38927
|
const targets = [];
|
|
@@ -39043,7 +39046,7 @@ const postShadowMonitorRoute = HttpRouter.add("POST", "/api/shadow/:issueId/moni
|
|
|
39043
39046
|
const projectPath = await getProjectPath(issuePrefix);
|
|
39044
39047
|
const workspacePath = join$1(projectPath, "workspaces", `feature-${issueLower}`);
|
|
39045
39048
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
39046
|
-
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-
|
|
39049
|
+
const { gatherArtifacts, generateBasicInference, updateInferenceDocumentSync } = await import("./shadow-engineering-eRFcHl7F.js");
|
|
39047
39050
|
const config = {
|
|
39048
39051
|
issueId,
|
|
39049
39052
|
workspacePath,
|
|
@@ -39073,7 +39076,7 @@ const postShadowObserveRoute = HttpRouter.add("POST", "/api/shadow/:issueId/obse
|
|
|
39073
39076
|
if (!existsSync$1(workspacePath)) return jsonResponse({ error: "Workspace not found" }, { status: 404 });
|
|
39074
39077
|
const ghConfig = getGitHubConfig();
|
|
39075
39078
|
if (!ghConfig) return jsonResponse({ error: "GitHub not configured - Observer requires GitHub" }, { status: 400 });
|
|
39076
|
-
const { runObserverCycle } = await import("./shadow-engineering-
|
|
39079
|
+
const { runObserverCycle } = await import("./shadow-engineering-eRFcHl7F.js");
|
|
39077
39080
|
const firstRepo = ghConfig.repos[0];
|
|
39078
39081
|
const config = {
|
|
39079
39082
|
issueId,
|
|
@@ -39137,7 +39140,7 @@ const postRestartDashboardRoute = HttpRouter.add("POST", "/api/system/restart-da
|
|
|
39137
39140
|
return jsonResponse({ error: "Restart failed: " + (error instanceof Error ? error.message : String(error)) }, { status: 500 });
|
|
39138
39141
|
}
|
|
39139
39142
|
}));
|
|
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);
|
|
39143
|
+
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
39144
|
//#endregion
|
|
39142
39145
|
//#region ../../lib/conversation-search/ranker.ts
|
|
39143
39146
|
init_fts_db();
|
|
@@ -39315,8 +39318,11 @@ async function searchConversationChunks(input) {
|
|
|
39315
39318
|
* own embedding pipeline and config (see linked GitHub issue at end of
|
|
39316
39319
|
* commit).
|
|
39317
39320
|
*/
|
|
39321
|
+
init_http_helpers();
|
|
39318
39322
|
init_projects();
|
|
39319
39323
|
init_conversations();
|
|
39324
|
+
init_dashboard_auth();
|
|
39325
|
+
init_origin_validation();
|
|
39320
39326
|
const PAN_COMMANDS = [
|
|
39321
39327
|
{
|
|
39322
39328
|
name: "pan up",
|
|
@@ -39891,66 +39897,32 @@ const getPaletteSearchRoute = HttpRouter.add("GET", "/api/palette/search", Effec
|
|
|
39891
39897
|
}));
|
|
39892
39898
|
const paletteRouteLayer = Layer.mergeAll(getPaletteCommandsRoute, getPaletteSearchRoute);
|
|
39893
39899
|
//#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
|
|
39900
|
+
//#region ../../lib/ohmypi-codex-auth.ts
|
|
39926
39901
|
init_features();
|
|
39927
39902
|
/**
|
|
39928
|
-
*
|
|
39903
|
+
* oh-my-pi (omp) OAuth helpers for the openai-codex (ChatGPT subscription) provider.
|
|
39904
|
+
* Forked from pi-codex-auth.ts (PAN-1520) for the omp migration (PAN-1989).
|
|
39929
39905
|
*
|
|
39930
|
-
*
|
|
39931
|
-
*
|
|
39932
|
-
*
|
|
39933
|
-
*
|
|
39934
|
-
* "No API key for provider: openai-codex".
|
|
39906
|
+
* omp stores its general credentials in ~/.omp/agent/agent.db (SQLite). The
|
|
39907
|
+
* openai-codex OAuth credential is persisted separately at ~/.omp/agent/auth.json
|
|
39908
|
+
* (same JSON format as Pi's ~/.pi/agent/auth.json) so that this helper's
|
|
39909
|
+
* read/write logic is unchanged from the Pi side.
|
|
39935
39910
|
*
|
|
39936
39911
|
* This module:
|
|
39937
|
-
* - reads/writes
|
|
39912
|
+
* - reads/writes the openai-codex credential under ~/.omp/agent/auth.json,
|
|
39938
39913
|
* - reports auth status (for `pan doctor` and the conversation spawn gate),
|
|
39939
39914
|
* - refreshes an expired-but-recoverable token, and
|
|
39940
|
-
* - drives
|
|
39915
|
+
* - drives omp's headless device-code login to re-authenticate.
|
|
39941
39916
|
*
|
|
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.
|
|
39917
|
+
* The OAuth module is loaded from the installed `omp` package dynamically.
|
|
39918
|
+
* A missing or relocated omp OAuth module degrades to 'unavailable' — never throws.
|
|
39947
39919
|
*/
|
|
39948
39920
|
const PI_CODEX_PROVIDER = "openai-codex";
|
|
39949
|
-
function
|
|
39950
|
-
return join$1(homedir$1(), ".
|
|
39921
|
+
function getOhmypiAuthPath() {
|
|
39922
|
+
return join$1(homedir$1(), ".omp", "agent", "auth.json");
|
|
39951
39923
|
}
|
|
39952
39924
|
function readAuthFile() {
|
|
39953
|
-
const path =
|
|
39925
|
+
const path = getOhmypiAuthPath();
|
|
39954
39926
|
if (!existsSync$1(path)) return {};
|
|
39955
39927
|
try {
|
|
39956
39928
|
const parsed = JSON.parse(readFileSync$1(path, "utf-8"));
|
|
@@ -39959,14 +39931,14 @@ function readAuthFile() {
|
|
|
39959
39931
|
return {};
|
|
39960
39932
|
}
|
|
39961
39933
|
}
|
|
39962
|
-
function
|
|
39934
|
+
function readOhmypiCodexCredential() {
|
|
39963
39935
|
const cred = readAuthFile()[PI_CODEX_PROVIDER];
|
|
39964
39936
|
if (cred && typeof cred === "object" && typeof cred["access"] === "string" && typeof cred["refresh"] === "string") return cred;
|
|
39965
39937
|
return null;
|
|
39966
39938
|
}
|
|
39967
39939
|
/** Atomically merge a fresh codex credential into auth.json (mode 0600). */
|
|
39968
|
-
function
|
|
39969
|
-
const path =
|
|
39940
|
+
function writeOhmypiCodexCredential(tokens) {
|
|
39941
|
+
const path = getOhmypiAuthPath();
|
|
39970
39942
|
mkdirSync$1(dirname$1(path), { recursive: true });
|
|
39971
39943
|
const auth = readAuthFile();
|
|
39972
39944
|
const stored = {
|
|
@@ -39982,27 +39954,26 @@ function writePiCodexCredential(tokens) {
|
|
|
39982
39954
|
renameSync$1(tmp, path);
|
|
39983
39955
|
return stored;
|
|
39984
39956
|
}
|
|
39985
|
-
/** Locate the `
|
|
39986
|
-
function
|
|
39957
|
+
/** Locate the `omp` executable on PATH (no subprocess — event-loop safe). */
|
|
39958
|
+
function findOmpBinary() {
|
|
39987
39959
|
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
39988
39960
|
if (!dir) continue;
|
|
39989
|
-
const candidate = join$1(dir, "
|
|
39961
|
+
const candidate = join$1(dir, "omp");
|
|
39990
39962
|
if (existsSync$1(candidate)) return candidate;
|
|
39991
39963
|
}
|
|
39992
39964
|
return null;
|
|
39993
39965
|
}
|
|
39994
|
-
/** pi-
|
|
39995
|
-
const
|
|
39966
|
+
/** omp is @oh-my-pi/pi-coding-agent; the oauth submodule path mirrors pi-ai's layout. */
|
|
39967
|
+
const OMP_AI_OAUTH_SUBPATH = join$1("@oh-my-pi", "pi-ai", "dist", "utils", "oauth", "openai-codex.js");
|
|
39996
39968
|
/**
|
|
39997
|
-
* Resolve
|
|
39998
|
-
* from the real
|
|
39999
|
-
*
|
|
40000
|
-
* which can't resolve pi-ai's ESM-only `exports` map.
|
|
39969
|
+
* Resolve omp's openai-codex OAuth submodule by walking node_modules upward
|
|
39970
|
+
* from the real omp binary. Returns null when not found — the caller degrades
|
|
39971
|
+
* gracefully to 'unavailable' status.
|
|
40001
39972
|
*/
|
|
40002
|
-
function
|
|
40003
|
-
let dir = dirname$1(realpathSync$1(
|
|
39973
|
+
function resolveOmpCodexOAuthFile(ompBin) {
|
|
39974
|
+
let dir = dirname$1(realpathSync$1(ompBin));
|
|
40004
39975
|
for (let i = 0; i < 10; i++) {
|
|
40005
|
-
const candidate = join$1(dir, "node_modules",
|
|
39976
|
+
const candidate = join$1(dir, "node_modules", OMP_AI_OAUTH_SUBPATH);
|
|
40006
39977
|
if (existsSync$1(candidate)) return candidate;
|
|
40007
39978
|
const parent = dirname$1(dir);
|
|
40008
39979
|
if (parent === dir) break;
|
|
@@ -40012,18 +39983,16 @@ function resolvePiCodexOAuthFile(piBin) {
|
|
|
40012
39983
|
}
|
|
40013
39984
|
let cachedModule = null;
|
|
40014
39985
|
/**
|
|
40015
|
-
* Dynamically load
|
|
40016
|
-
* package.
|
|
40017
|
-
* polling), never the heavy provider SDKs. Returns null on any failure so
|
|
40018
|
-
* callers can degrade gracefully.
|
|
39986
|
+
* Dynamically load omp's openai-codex OAuth submodule from the installed `omp`
|
|
39987
|
+
* package. Returns null on any failure so callers can degrade gracefully.
|
|
40019
39988
|
*/
|
|
40020
|
-
async function
|
|
39989
|
+
async function loadOhmypiCodexOAuth() {
|
|
40021
39990
|
if (cachedModule) return cachedModule;
|
|
40022
39991
|
cachedModule = (async () => {
|
|
40023
39992
|
try {
|
|
40024
|
-
const
|
|
40025
|
-
if (!
|
|
40026
|
-
const oauthFile =
|
|
39993
|
+
const ompBin = findOmpBinary();
|
|
39994
|
+
if (!ompBin) return null;
|
|
39995
|
+
const oauthFile = resolveOmpCodexOAuthFile(ompBin);
|
|
40027
39996
|
if (!oauthFile) return null;
|
|
40028
39997
|
const mod = await import(pathToFileURL(oauthFile).href);
|
|
40029
39998
|
if (typeof mod.refreshOpenAICodexToken !== "function" || typeof mod.loginOpenAICodexDeviceCode !== "function") return null;
|
|
@@ -40034,22 +40003,16 @@ async function loadPiCodexOAuth() {
|
|
|
40034
40003
|
})();
|
|
40035
40004
|
return cachedModule;
|
|
40036
40005
|
}
|
|
40037
|
-
/** Treat a token expiring within this window as already expired. */
|
|
40038
40006
|
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();
|
|
40007
|
+
async function getOhmypiCodexAuthStatus(opts) {
|
|
40008
|
+
const cred = readOhmypiCodexCredential();
|
|
40046
40009
|
if (!cred) return { status: "missing" };
|
|
40047
40010
|
if (cred.expires > Date.now() + EXPIRY_MARGIN_MS) return {
|
|
40048
40011
|
status: "ok",
|
|
40049
40012
|
expiresAt: cred.expires
|
|
40050
40013
|
};
|
|
40051
40014
|
if (opts?.refreshIfExpired) {
|
|
40052
|
-
const refreshed = await
|
|
40015
|
+
const refreshed = await refreshOhmypiCodexAuth();
|
|
40053
40016
|
if (refreshed) return {
|
|
40054
40017
|
status: "ok",
|
|
40055
40018
|
expiresAt: refreshed.expires
|
|
@@ -40066,19 +40029,13 @@ async function getPiCodexAuthStatus(opts) {
|
|
|
40066
40029
|
refreshFailed: false
|
|
40067
40030
|
};
|
|
40068
40031
|
}
|
|
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();
|
|
40032
|
+
async function refreshOhmypiCodexAuth() {
|
|
40033
|
+
const cred = readOhmypiCodexCredential();
|
|
40077
40034
|
if (!cred?.refresh) return null;
|
|
40078
|
-
const mod = await
|
|
40035
|
+
const mod = await loadOhmypiCodexOAuth();
|
|
40079
40036
|
if (!mod) return null;
|
|
40080
40037
|
try {
|
|
40081
|
-
return
|
|
40038
|
+
return writeOhmypiCodexCredential(await mod.refreshOpenAICodexToken(cred.refresh));
|
|
40082
40039
|
} catch {
|
|
40083
40040
|
return null;
|
|
40084
40041
|
}
|
|
@@ -40155,7 +40112,7 @@ function isNonEmptyJsonlLine(buffer) {
|
|
|
40155
40112
|
}
|
|
40156
40113
|
//#endregion
|
|
40157
40114
|
//#region services/conversation-eaten-message-watcher.ts
|
|
40158
|
-
init_agents$
|
|
40115
|
+
init_agents$2();
|
|
40159
40116
|
const WATCH_TIMEOUT_MS = 5 * 6e4;
|
|
40160
40117
|
const WATCH_INTERVAL_MS = 3e3;
|
|
40161
40118
|
const REDELIVERY_GRACE_MS = 1e4;
|
|
@@ -40191,299 +40148,11 @@ async function watchForEatenConversationMessage(args) {
|
|
|
40191
40148
|
return "unverified";
|
|
40192
40149
|
}
|
|
40193
40150
|
//#endregion
|
|
40194
|
-
//#region ../../lib/
|
|
40151
|
+
//#region ../../lib/conversations/transcript-summary.ts
|
|
40195
40152
|
init_transcript_adapter();
|
|
40196
40153
|
init_summary_fork();
|
|
40197
40154
|
init_conversation_compaction();
|
|
40198
40155
|
/**
|
|
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
40156
|
* Conversation transcript summarization.
|
|
40488
40157
|
*
|
|
40489
40158
|
* Shared helpers for turning a conversation's parsed messages into LLM-generated
|
|
@@ -40506,8 +40175,8 @@ const convertConversationTranscript = (opts) => Effect.tryPromise({
|
|
|
40506
40175
|
* layering inversion.
|
|
40507
40176
|
*/
|
|
40508
40177
|
init_child_env();
|
|
40509
|
-
init_agents$
|
|
40510
|
-
init_cost();
|
|
40178
|
+
init_agents$2();
|
|
40179
|
+
init_cost$1();
|
|
40511
40180
|
/** Haiku — fast/cheap, used for every conversation title and about-summary. */
|
|
40512
40181
|
const CONVERSATION_TITLE_MODEL = "claude-haiku-4-5-20251001";
|
|
40513
40182
|
/** Total transcript characters allowed into a single prompt. */
|
|
@@ -40553,6 +40222,17 @@ function sanitizeTitle(raw) {
|
|
|
40553
40222
|
return raw.trim().split(/\r?\n/)[0]?.trim().replace(/^['"`]+|['"`]+$/g, "").trim().replace(/\s+/g, " ") ?? "";
|
|
40554
40223
|
}
|
|
40555
40224
|
/**
|
|
40225
|
+
* Generate a deterministic title from a serialized transcript when the model
|
|
40226
|
+
* path is unavailable. Prefer the latest user request because explicit retitle
|
|
40227
|
+
* should describe where the conversation currently landed.
|
|
40228
|
+
*/
|
|
40229
|
+
function fallbackTranscriptTitle(transcript) {
|
|
40230
|
+
const lines = transcript.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("[…"));
|
|
40231
|
+
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();
|
|
40232
|
+
if (!compact) return "";
|
|
40233
|
+
return sanitizeTitle(compact.split(/\s+/).slice(0, 8).join(" ").replace(/\s+(?:and|or|to|for|with)$/i, "").replace(/[.,:;!?]+$/g, ""));
|
|
40234
|
+
}
|
|
40235
|
+
/**
|
|
40556
40236
|
* Invoke `claude -p` with a JSON schema and return the structured output.
|
|
40557
40237
|
* Throws on non-zero exit, timeout, spawn error, or unparseable output.
|
|
40558
40238
|
*/
|
|
@@ -40736,7 +40416,7 @@ async function cleanupConversationAttachments(name) {
|
|
|
40736
40416
|
* sessions that the lifecycle poller missed. */
|
|
40737
40417
|
async function cleanupOrphanedConversationAttachments() {
|
|
40738
40418
|
try {
|
|
40739
|
-
const { listConversations } = await import("./conversations-
|
|
40419
|
+
const { listConversations } = await import("./conversations-BtRONkWR.js");
|
|
40740
40420
|
const convNames = new Set(listConversations().map((c) => c.name));
|
|
40741
40421
|
const root = getConversationAttachmentsRoot();
|
|
40742
40422
|
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 +40611,27 @@ async function removeConversationAttachment(name, attachmentPath) {
|
|
|
40931
40611
|
*
|
|
40932
40612
|
* Conversations are NEVER deleted from the database, and JSONL transcript files are never removed.
|
|
40933
40613
|
*/
|
|
40614
|
+
init_http_helpers();
|
|
40934
40615
|
init_child_env();
|
|
40935
40616
|
init_claude_permissions();
|
|
40617
|
+
init_jsonl_resolver();
|
|
40618
|
+
init_origin_validation();
|
|
40936
40619
|
init_projects();
|
|
40937
40620
|
init_model_capabilities();
|
|
40938
40621
|
init_conversations();
|
|
40939
40622
|
init_tmux();
|
|
40940
|
-
init_agents$
|
|
40623
|
+
init_agents$2();
|
|
40941
40624
|
init_config_yaml();
|
|
40942
40625
|
init_harness_policy();
|
|
40943
40626
|
init_providers();
|
|
40627
|
+
init_agent_input_detection();
|
|
40944
40628
|
init_launcher_generator();
|
|
40945
40629
|
init_layers();
|
|
40946
40630
|
init_briefing_freshness();
|
|
40947
40631
|
init_conversation_service();
|
|
40948
40632
|
init_transcript_landing();
|
|
40949
40633
|
init_pi_conversation_parser();
|
|
40634
|
+
init_ohmypi_conversation_parser();
|
|
40950
40635
|
init_codex_conversation_parser();
|
|
40951
40636
|
init_paths();
|
|
40952
40637
|
init_event_store();
|
|
@@ -41055,66 +40740,11 @@ function shellQuote(str) {
|
|
|
41055
40740
|
return "'" + str.replace(/'/g, "'\"'\"'") + "'";
|
|
41056
40741
|
}
|
|
41057
40742
|
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
40743
|
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
40744
|
const SAFE_ISSUE_ID_PATTERN = /^[A-Z0-9]+-[0-9]+$/;
|
|
41115
40745
|
async function resolveAllowedHarness(requested, model) {
|
|
41116
40746
|
if (!model) return "claude-code";
|
|
41117
|
-
const explicit = requested === "
|
|
40747
|
+
const explicit = requested === "ohmypi" || requested === "claude-code" || requested === "codex" ? requested : void 0;
|
|
41118
40748
|
try {
|
|
41119
40749
|
return await resolveHarness({
|
|
41120
40750
|
model,
|
|
@@ -41178,6 +40808,7 @@ async function getCachedMessages(sessionFile, isSpecialist) {
|
|
|
41178
40808
|
if (cached && cached.mtimeMs === fileStats.mtimeMs && cached.size === fileStats.size && cached.byteOffset >= fileStats.size) return cached.result;
|
|
41179
40809
|
let result;
|
|
41180
40810
|
if (isCodexSessionFile(sessionFile)) result = await parseCodexConversationMessages(sessionFile);
|
|
40811
|
+
else if (isOhmypiSessionFile(sessionFile)) result = await parseOhmypiConversationMessages(sessionFile);
|
|
41181
40812
|
else if (isPiSessionFile(sessionFile)) result = await parsePiConversationMessages(sessionFile);
|
|
41182
40813
|
else if (isSpecialist) result = await parseFromLastCompactBoundary(sessionFile);
|
|
41183
40814
|
else if (cached && cached.parseState && cached.byteOffset <= fileStats.size && cached.size <= fileStats.size) {
|
|
@@ -41332,8 +40963,14 @@ async function waitForPiTuiReady(tmuxSession, timeoutMs = 3e4) {
|
|
|
41332
40963
|
return false;
|
|
41333
40964
|
}
|
|
41334
40965
|
async function resolveSessionFile(conv) {
|
|
41335
|
-
if (conv.harness === "
|
|
41336
|
-
|
|
40966
|
+
if (conv.harness === "ohmypi" || conv.harness === "pi") {
|
|
40967
|
+
const piPath = await resolvePiSessionPath(conv.tmuxSession);
|
|
40968
|
+
if (piPath) return piPath;
|
|
40969
|
+
}
|
|
40970
|
+
if (conv.harness === "codex") {
|
|
40971
|
+
const codexPath = await resolveCodexRolloutPath(conv.tmuxSession);
|
|
40972
|
+
if (codexPath) return codexPath;
|
|
40973
|
+
}
|
|
41337
40974
|
const sessionId = await readLauncherPinnedSessionId(conv.tmuxSession) ?? conv.claudeSessionId;
|
|
41338
40975
|
if (sessionId) return sessionFilePath(conv.cwd, sessionId);
|
|
41339
40976
|
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.`);
|
|
@@ -41483,6 +41120,7 @@ async function handleConversationImageUpload(name, filename, bytes, mimeType) {
|
|
|
41483
41120
|
async function handleConversationMessage(name, body) {
|
|
41484
41121
|
const conv = getConversationByName(name);
|
|
41485
41122
|
if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
|
|
41123
|
+
if (conv.status === "ended") return jsonResponse({ error: "Session has ended — start a new run to interact" }, { status: 422 });
|
|
41486
41124
|
const message = typeof body["message"] === "string" ? body["message"].trim() : "";
|
|
41487
41125
|
if (!message) return jsonResponse({ error: "Message is required" }, { status: 400 });
|
|
41488
41126
|
if (message.length > MAX_MESSAGE_LENGTH) return jsonResponse({ error: `Message exceeds maximum length of ${MAX_MESSAGE_LENGTH} characters` }, { status: 400 });
|
|
@@ -41524,7 +41162,7 @@ async function handleConversationMessage(name, body) {
|
|
|
41524
41162
|
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
41163
|
}
|
|
41526
41164
|
let deliveredMessage = transformMessageForHarness(outboundMessage, harness, effectiveAttachmentPaths);
|
|
41527
|
-
if (harness === "
|
|
41165
|
+
if (harness === "ohmypi") deliveredMessage = await injectPiConversationMemory({
|
|
41528
41166
|
cwd: conv.cwd,
|
|
41529
41167
|
issueId: conv.issueId,
|
|
41530
41168
|
conversationName: conv.name
|
|
@@ -41585,7 +41223,7 @@ function shouldUseSupervisorForConversation(harness) {
|
|
|
41585
41223
|
}
|
|
41586
41224
|
function resolveConversationDeliveryMethod(conv) {
|
|
41587
41225
|
const harness = conv.harness ?? "claude-code";
|
|
41588
|
-
return conv.deliveryMethod ?? (harness === "
|
|
41226
|
+
return conv.deliveryMethod ?? (harness === "ohmypi" ? "tmux" : "auto");
|
|
41589
41227
|
}
|
|
41590
41228
|
/** Synthetic toolUseId prefix marking a Codex pane-detected approval (PAN-1690). */
|
|
41591
41229
|
const CODEX_APPROVAL_TOOL_PREFIX = "codex-approval:";
|
|
@@ -41801,10 +41439,10 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41801
41439
|
if (!runtimeCommand.includes("--permission-mode")) runtimeCommand = `${runtimeCommand} --permission-mode ${mode === "auto" ? "auto" : BYPASS_PERMISSION_MODE}`;
|
|
41802
41440
|
providerExportsStr = (await getProviderExportsForModel(model)).trim();
|
|
41803
41441
|
await getProviderEnvForModel(model);
|
|
41804
|
-
if (harness === "
|
|
41442
|
+
if (harness === "ohmypi") {
|
|
41805
41443
|
if (getProviderForModelSync(model).name === "openai") {
|
|
41806
|
-
const auth = await
|
|
41807
|
-
if (auth.status === "missing" || auth.status === "expired") throw new Error("
|
|
41444
|
+
const auth = await getOhmypiCodexAuthStatus({ refreshIfExpired: true });
|
|
41445
|
+
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
41446
|
}
|
|
41809
41447
|
const paths = piFifoPaths(tmuxSession);
|
|
41810
41448
|
const piSessionDir = join$1(paths.agentDir, "sessions");
|
|
@@ -41818,9 +41456,9 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41818
41456
|
});
|
|
41819
41457
|
const storedPiSessionId = resume ? await readFile(join$1(paths.agentDir, "session.id"), "utf-8").then((s) => s.trim()).catch(() => void 0) : void 0;
|
|
41820
41458
|
piFields = {
|
|
41821
|
-
harness: "
|
|
41459
|
+
harness: "ohmypi",
|
|
41822
41460
|
piMode: "tui",
|
|
41823
|
-
piExtensionPath: resolve$1(process.cwd(), "packages/
|
|
41461
|
+
piExtensionPath: resolveOhmypiExtensionPath() ?? resolve$1(process.cwd(), "packages/ohmypi-extension/dist/index.js"),
|
|
41824
41462
|
piSessionDir,
|
|
41825
41463
|
resumeSessionId: storedPiSessionId || void 0
|
|
41826
41464
|
};
|
|
@@ -41830,7 +41468,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41830
41468
|
const codexApprovalPolicy = codexPermMode === "full-access" ? "never" : "on-request";
|
|
41831
41469
|
const codexSandboxMode = codexPermMode === "full-access" ? "danger-full-access" : codexPermMode === "read-only" ? "read-only" : "workspace-write";
|
|
41832
41470
|
const codexApprovalsReviewer = codexPermMode === "auto-review" ? "auto_review" : void 0;
|
|
41833
|
-
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-
|
|
41471
|
+
const { initCodexHome, extractThreadIdFromRollout } = await import("./codex-sd8uk-U3.js");
|
|
41834
41472
|
initCodexHome(codexHome, {
|
|
41835
41473
|
trustedDir: cwd,
|
|
41836
41474
|
approvalPolicy: codexApprovalPolicy,
|
|
@@ -41848,7 +41486,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41848
41486
|
}
|
|
41849
41487
|
}
|
|
41850
41488
|
let launcherModel = model;
|
|
41851
|
-
if (harness === "
|
|
41489
|
+
if (harness === "ohmypi" && model) {
|
|
41852
41490
|
const piProvider = piProviderForModel(model);
|
|
41853
41491
|
if (piProvider) launcherModel = `${piProvider}/${model}`;
|
|
41854
41492
|
}
|
|
@@ -41900,7 +41538,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41900
41538
|
} catch {}
|
|
41901
41539
|
console.log(`[claude-invoke] purpose=conversation-session | model=${model || "default"} | source=conversations.ts:spawnConversationSession | session=${tmuxSession} | resume=${resume} | command="${runtimeCommand}"`);
|
|
41902
41540
|
try {
|
|
41903
|
-
const { preTrustDirectory } = await import("./workspace-manager-
|
|
41541
|
+
const { preTrustDirectory } = await import("./workspace-manager-XDNuCCXG.js");
|
|
41904
41542
|
preTrustDirectory(cwd);
|
|
41905
41543
|
} catch {}
|
|
41906
41544
|
try {
|
|
@@ -41917,7 +41555,7 @@ async function spawnConversationSession(tmuxSession, cwd, claudeSessionId, model
|
|
|
41917
41555
|
const codexHomeDir = codexFields.codexHome;
|
|
41918
41556
|
(async () => {
|
|
41919
41557
|
try {
|
|
41920
|
-
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-
|
|
41558
|
+
const { waitForCodexRollout, extractThreadIdFromRollout, writeThreadId } = await import("./codex-sd8uk-U3.js");
|
|
41921
41559
|
const rollout = await waitForCodexRollout(codexHomeDir, 12e4);
|
|
41922
41560
|
if (rollout) {
|
|
41923
41561
|
const threadId = extractThreadIdFromRollout(rollout);
|
|
@@ -42051,6 +41689,9 @@ function scheduleTitleRefinement(conversationName) {
|
|
|
42051
41689
|
/** Conversations with a retitle currently running — guards against double-clicks. */
|
|
42052
41690
|
const retitleInFlight = /* @__PURE__ */ new Set();
|
|
42053
41691
|
const EXPLICIT_RETITLE_TIMEOUT_MS = 9e4;
|
|
41692
|
+
function isClaudeInvocationTimeout(error) {
|
|
41693
|
+
return error instanceof Error && /claude invocation timed out after \d+ms/.test(error.message);
|
|
41694
|
+
}
|
|
42054
41695
|
/** transcript-size-keyed cache so re-opening the About drawer doesn't re-summarize. */
|
|
42055
41696
|
const aboutSummaryCache = /* @__PURE__ */ new Map();
|
|
42056
41697
|
const ABOUT_SUMMARY_CACHE_MAX = 100;
|
|
@@ -42452,7 +42093,7 @@ const postConversationRoute = HttpRouter.add("POST", "/api/conversations", Effec
|
|
|
42452
42093
|
try {
|
|
42453
42094
|
await spawnConversationSession(tmuxSession, cwd, claudeSessionId, model, effort, issueId, false, harness);
|
|
42454
42095
|
console.log(`[conversations] tmux session ${tmuxSession} spawned, sessionId: ${claudeSessionId}`);
|
|
42455
|
-
if (harness === "
|
|
42096
|
+
if (harness === "ohmypi") await waitForPiTuiReady(tmuxSession);
|
|
42456
42097
|
else if (harness !== "codex") {
|
|
42457
42098
|
await waitForClaudeReady(tmuxSession);
|
|
42458
42099
|
console.log(`[conversations] Claude ready in ${tmuxSession}`);
|
|
@@ -42461,6 +42102,7 @@ const postConversationRoute = HttpRouter.add("POST", "/api/conversations", Effec
|
|
|
42461
42102
|
} catch (spawnErr) {
|
|
42462
42103
|
const msg = spawnErr instanceof Error ? spawnErr.message : String(spawnErr);
|
|
42463
42104
|
console.error(`[conversations] background spawn failed for ${tmuxSession}: ${msg}`);
|
|
42105
|
+
updateSpawnError(name, msg);
|
|
42464
42106
|
getEventStore().emitOnly({
|
|
42465
42107
|
type: "conversation.created",
|
|
42466
42108
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -42546,7 +42188,7 @@ const postConversationResumeRoute = HttpRouter.add("POST", "/api/conversations/:
|
|
|
42546
42188
|
try {
|
|
42547
42189
|
await spawnConversationSession(conv.tmuxSession, conv.cwd, oldSessionId ?? randomUUID$1(), model, effort, conv.issueId ?? void 0, canResume, harness);
|
|
42548
42190
|
await waitForTmuxSession(conv.tmuxSession);
|
|
42549
|
-
if (harness === "
|
|
42191
|
+
if (harness === "ohmypi") await waitForPiTuiReady(conv.tmuxSession);
|
|
42550
42192
|
else if (harness !== "codex") await waitForReadySignal(conv.tmuxSession, 30);
|
|
42551
42193
|
markConversationActive(name);
|
|
42552
42194
|
return jsonResponse({
|
|
@@ -42576,11 +42218,12 @@ const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
42576
42218
|
try {
|
|
42577
42219
|
const conv = getConversationByName(name);
|
|
42578
42220
|
if (!conv) return jsonResponse({ error: "Conversation not found" }, { status: 404 });
|
|
42221
|
+
if (conv.claudeSessionId) return jsonResponse({ error: "Conversation model is locked once a conversation has started" }, { status: 409 });
|
|
42579
42222
|
const model = typeof body["model"] === "string" && body["model"].trim() ? body["model"].trim() : conv.model ?? void 0;
|
|
42580
42223
|
const currentHarness = conv.harness ?? "claude-code";
|
|
42581
42224
|
const requestedHarness = body["harness"];
|
|
42582
42225
|
let harness = currentHarness;
|
|
42583
|
-
if (requestedHarness === "
|
|
42226
|
+
if (requestedHarness === "ohmypi" || requestedHarness === "claude-code" || requestedHarness === "codex") {
|
|
42584
42227
|
if (requestedHarness !== currentHarness) {
|
|
42585
42228
|
const policyModel = model ?? conv.model ?? "";
|
|
42586
42229
|
const decision = canUseHarnessSync(requestedHarness, policyModel, await getProviderAuthMode(policyModel));
|
|
@@ -42591,101 +42234,15 @@ const postConversationSwitchModelRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
42591
42234
|
const harnessChanged = harness !== currentHarness;
|
|
42592
42235
|
if (!await validateCwdContainment(conv.cwd)) return jsonResponse({ error: "Invalid cwd" }, { status: 400 });
|
|
42593
42236
|
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
|
-
})
|
|
42237
|
+
if (model) setConversationModel(name, model);
|
|
42238
|
+
if (harnessChanged) setConversationHarness(name, harness);
|
|
42239
|
+
const updated = getConversationByName(name) ?? conv;
|
|
42240
|
+
return jsonResponse({
|
|
42241
|
+
...updated,
|
|
42242
|
+
model: model ?? updated.model,
|
|
42243
|
+
harness,
|
|
42244
|
+
sessionAlive: false
|
|
42615
42245
|
});
|
|
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
42246
|
} catch (error) {
|
|
42690
42247
|
const msg = error instanceof Error ? error.message : String(error);
|
|
42691
42248
|
console.error("[conversations] switch model failed:", msg);
|
|
@@ -42735,7 +42292,7 @@ const getConversationMessagesRoute = HttpRouter.add("GET", "/api/conversations/:
|
|
|
42735
42292
|
sessionFile = rollout;
|
|
42736
42293
|
setSpecialistSessionCache(name, rollout);
|
|
42737
42294
|
}
|
|
42738
|
-
} else if (agentHarness === "
|
|
42295
|
+
} else if (agentHarness === "ohmypi") {
|
|
42739
42296
|
const piSession = await resolvePiSessionPath(name);
|
|
42740
42297
|
if (piSession) {
|
|
42741
42298
|
sessionFile = piSession;
|
|
@@ -43238,7 +42795,7 @@ async function ensureForkSessionReady(conv, sessionId, resume, plainFork = false
|
|
|
43238
42795
|
async function injectForkSummary(conv, summary, caller) {
|
|
43239
42796
|
updateForkStatus(conv.name, "injecting");
|
|
43240
42797
|
const method = resolveConversationDeliveryMethod(conv);
|
|
43241
|
-
if (conv.harness === "
|
|
42798
|
+
if (conv.harness === "ohmypi") {
|
|
43242
42799
|
await waitForPiTuiReady(conv.tmuxSession, 6e4);
|
|
43243
42800
|
await deliverAgentMessage(conv.tmuxSession, summary, caller, method);
|
|
43244
42801
|
return;
|
|
@@ -43268,7 +42825,7 @@ async function runForkPipeline(convName, parentConv, sessionId, summaryModel, fo
|
|
|
43268
42825
|
const parentSessionFile = await resolveForkSourceSessionFile(parentConv);
|
|
43269
42826
|
if (!parentSessionFile) throw new Error(`Parent has no session file`);
|
|
43270
42827
|
if (forkMode === "plain") {
|
|
43271
|
-
if (conv.harness === "
|
|
42828
|
+
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
42829
|
if (!(await forkSessionExists(conv.tmuxSession) && await forkHarnessProcessAlive(conv.tmuxSession))) {
|
|
43273
42830
|
const forkSessionFile = await resolveSessionFile(conv);
|
|
43274
42831
|
if (!forkSessionFile) throw new Error(`Fork conversation ${convName} has no session file`);
|
|
@@ -43485,7 +43042,7 @@ const postConversationSummaryForkRoute = HttpRouter.add("POST", "/api/conversati
|
|
|
43485
43042
|
const launchHarness = await resolveAllowedHarness(body["harness"], launchModel);
|
|
43486
43043
|
const summaryHarness = await resolveAllowedHarness(body["summaryHarness"], effectiveSummaryModel);
|
|
43487
43044
|
const handoffAuthorHarness = body["handoffAuthorHarness"] !== void 0 ? await resolveAllowedHarness(body["handoffAuthorHarness"], handoffAuthorModel || effectiveSummaryModel) : void 0;
|
|
43488
|
-
if (forkMode === "plain" && (launchHarness === "
|
|
43045
|
+
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
43046
|
const defaultTitle = forkMode === "plain" ? `Fork: ${conv.title || conv.name}` : forkMode === "handoff" ? handoffTitleFromFocus(handoffFocus, conv.title || conv.name) : `Summary Fork: ${conv.title || conv.name}`;
|
|
43490
43047
|
const newConv = createConversation({
|
|
43491
43048
|
name: newName,
|
|
@@ -43818,7 +43375,15 @@ const postConversationRetitleRoute = HttpRouter.add("POST", "/api/conversations/
|
|
|
43818
43375
|
try {
|
|
43819
43376
|
const model = configuredTitleModel();
|
|
43820
43377
|
console.log(`[claude-invoke] purpose=conversation-retitle | model=${model} | conversation=${name} | transcriptChars=${transcript.length}`);
|
|
43821
|
-
|
|
43378
|
+
let title;
|
|
43379
|
+
try {
|
|
43380
|
+
title = await summarizeTranscriptTitle(transcript, model, EXPLICIT_RETITLE_TIMEOUT_MS);
|
|
43381
|
+
} catch (error) {
|
|
43382
|
+
if (!isClaudeInvocationTimeout(error)) throw error;
|
|
43383
|
+
title = fallbackTranscriptTitle(transcript);
|
|
43384
|
+
if (!title) throw error;
|
|
43385
|
+
console.warn(`[conversations] retitle timed out for "${name}"; using deterministic fallback title "${title}"`);
|
|
43386
|
+
}
|
|
43822
43387
|
if (!title) return jsonResponse({ error: "Title model returned an empty result" }, { status: 502 });
|
|
43823
43388
|
updateConversationTitle(name, title, "ai");
|
|
43824
43389
|
console.log(`[claude-invoke] SUCCESS purpose=conversation-retitle | conversation=${name} | title="${title}"`);
|
|
@@ -43914,6 +43479,8 @@ const conversationsRouteLayer = Layer.mergeAll(getConversationsRoute, getConvers
|
|
|
43914
43479
|
* contract. Internal events are not exposed on this route.
|
|
43915
43480
|
*/
|
|
43916
43481
|
init_event_store();
|
|
43482
|
+
init_http_helpers();
|
|
43483
|
+
init_http_handler();
|
|
43917
43484
|
const PUBLIC_CATALOG = [
|
|
43918
43485
|
"activity.entry",
|
|
43919
43486
|
"activity.detailed",
|
|
@@ -44070,6 +43637,8 @@ const eventsRouteLayer = Layer.mergeAll(getEventStreamRoute, getEventVersionRout
|
|
|
44070
43637
|
* GET /api/show/:issueId/shadow — shadow state details
|
|
44071
43638
|
* GET /api/show/:issueId/health — health + heartbeat only
|
|
44072
43639
|
*/
|
|
43640
|
+
init_http_helpers();
|
|
43641
|
+
init_http_handler();
|
|
44073
43642
|
init_shadow_state();
|
|
44074
43643
|
const getShowRoute = HttpRouter.add("GET", "/api/show/:issueId", httpHandler(Effect.gen(function* () {
|
|
44075
43644
|
const issueId = (yield* HttpRouter.params)["issueId"] ?? "";
|
|
@@ -44168,7 +43737,7 @@ async function registerProjectFromPath(opts) {
|
|
|
44168
43737
|
registerProjectSync(key, projectConfig);
|
|
44169
43738
|
const seededContextLayer = ensureProjectLayer(fullPath);
|
|
44170
43739
|
try {
|
|
44171
|
-
const { preTrustDirectorySync } = await import("./workspace-manager-
|
|
43740
|
+
const { preTrustDirectorySync } = await import("./workspace-manager-XDNuCCXG.js");
|
|
44172
43741
|
preTrustDirectorySync(fullPath);
|
|
44173
43742
|
} catch {}
|
|
44174
43743
|
let hooksInstalled = 0;
|
|
@@ -44183,7 +43752,6 @@ async function registerProjectFromPath(opts) {
|
|
|
44183
43752
|
}
|
|
44184
43753
|
//#endregion
|
|
44185
43754
|
//#region ../../lib/overdeck/specs.ts
|
|
44186
|
-
init_pan_dir();
|
|
44187
43755
|
init_harness();
|
|
44188
43756
|
init_render();
|
|
44189
43757
|
const findSpecByIssueThroughOverdeck = findSpecByIssue;
|
|
@@ -44195,14 +43763,22 @@ const findSpecByIssueThroughOverdeck = findSpecByIssue;
|
|
|
44195
43763
|
* Implements:
|
|
44196
43764
|
* GET /api/projects/:projectKey/session-tree
|
|
44197
43765
|
*/
|
|
43766
|
+
init_http_helpers();
|
|
43767
|
+
init_http_handler();
|
|
44198
43768
|
init_projects();
|
|
43769
|
+
init_dashboard_auth();
|
|
44199
43770
|
init_issue_id();
|
|
44200
43771
|
init_tmux();
|
|
44201
|
-
|
|
43772
|
+
init_concurrency$1();
|
|
43773
|
+
init_read_model();
|
|
43774
|
+
init_agents$2();
|
|
43775
|
+
init_agent_input_detection();
|
|
43776
|
+
init_review_status$1();
|
|
43777
|
+
init_jsonl_resolver();
|
|
44202
43778
|
init_paths();
|
|
44203
43779
|
const execAsync$2 = promisify(exec);
|
|
44204
43780
|
async function getIssueDataService() {
|
|
44205
|
-
const { getSharedIssueService } = await import("./issue-service-singleton-
|
|
43781
|
+
const { getSharedIssueService } = await import("./issue-service-singleton-DfRSzdFO.js");
|
|
44206
43782
|
return getSharedIssueService();
|
|
44207
43783
|
}
|
|
44208
43784
|
/** Returns true if the path exists (any type). */
|
|
@@ -44452,6 +44028,7 @@ async function collectSessionTreeNodes(issueId, workspacePath, projectPath, cont
|
|
|
44452
44028
|
});
|
|
44453
44029
|
}
|
|
44454
44030
|
}
|
|
44031
|
+
enrichSessionsWithModelOrigin(sections, issueId);
|
|
44455
44032
|
return sections.filter((s) => !isStaleLegacySession(s));
|
|
44456
44033
|
}
|
|
44457
44034
|
async function resolveFeatureTitle(issueId, issueLower, issueTitles, project) {
|
|
@@ -44715,12 +44292,16 @@ const postProjectsRoute = HttpRouter.add("POST", "/api/projects", httpHandler(Ef
|
|
|
44715
44292
|
const projectsRouteLayer = Layer.mergeAll(getProjectSessionTreeRoute, getAllSessionTreesRoute, getProjectAutoMergeDefaultRoute, postProjectAutoMergeDefaultRoute, postProjectsRoute);
|
|
44716
44293
|
//#endregion
|
|
44717
44294
|
//#region routes/context.ts
|
|
44295
|
+
init_src();
|
|
44718
44296
|
init_layers();
|
|
44719
44297
|
init_paths();
|
|
44720
44298
|
init_projects();
|
|
44299
|
+
init_http_helpers();
|
|
44300
|
+
init_domain_services();
|
|
44301
|
+
init_http_handler();
|
|
44721
44302
|
const PREVIEW_HARNESSES = [
|
|
44722
44303
|
"claude-code",
|
|
44723
|
-
"
|
|
44304
|
+
"ohmypi",
|
|
44724
44305
|
"codex"
|
|
44725
44306
|
];
|
|
44726
44307
|
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
@@ -44979,9 +44560,9 @@ function fullPromptPreview(previews) {
|
|
|
44979
44560
|
"",
|
|
44980
44561
|
previews["claude-code"] || "(no rendered context)",
|
|
44981
44562
|
"",
|
|
44982
|
-
"## Overdeck-controlled
|
|
44563
|
+
"## Overdeck-controlled oh-my-pi bundle",
|
|
44983
44564
|
"",
|
|
44984
|
-
previews.
|
|
44565
|
+
previews.ohmypi || "(no rendered context)",
|
|
44985
44566
|
"",
|
|
44986
44567
|
"## Overdeck-controlled Codex bundle",
|
|
44987
44568
|
"",
|
|
@@ -45022,7 +44603,7 @@ async function previewContextLayers(projects, requestOrSelectedLayer, maybeDraft
|
|
|
45022
44603
|
operation: "preview",
|
|
45023
44604
|
previews: {
|
|
45024
44605
|
"claude-code": previews["claude-code"],
|
|
45025
|
-
|
|
44606
|
+
ohmypi: previews.ohmypi,
|
|
45026
44607
|
codex: previews.codex,
|
|
45027
44608
|
fullPrompt: fullPromptPreview(previews)
|
|
45028
44609
|
},
|
|
@@ -45155,6 +44736,8 @@ const contextRouteLayer = Layer.mergeAll(getContextLayersRoute, postContextPrevi
|
|
|
45155
44736
|
* Implements /api/admin/* endpoints mirroring the `pan admin` CLI namespace:
|
|
45156
44737
|
* GET /api/admin/tldr/:issueId — TLDR daemon status for a workspace
|
|
45157
44738
|
*/
|
|
44739
|
+
init_http_helpers();
|
|
44740
|
+
init_http_handler();
|
|
45158
44741
|
init_tldr_daemon();
|
|
45159
44742
|
init_projects();
|
|
45160
44743
|
const getAdminTldrRoute = HttpRouter.add("GET", "/api/admin/tldr/:issueId", httpHandler(Effect.gen(function* () {
|
|
@@ -45335,6 +44918,8 @@ async function installOx() {
|
|
|
45335
44918
|
* GET /api/prereqs/:feature — check which tools are missing for a feature
|
|
45336
44919
|
* POST /api/prereqs/install — install a specific tool by name
|
|
45337
44920
|
*/
|
|
44921
|
+
init_http_helpers();
|
|
44922
|
+
init_http_handler();
|
|
45338
44923
|
const readJsonBody$3 = Effect.gen(function* () {
|
|
45339
44924
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
45340
44925
|
try {
|
|
@@ -45381,6 +44966,8 @@ const installToolRoute = HttpRouter.add("POST", "/api/prereqs/install", httpHand
|
|
|
45381
44966
|
const prereqsRouteLayer = Layer.mergeAll(listPrereqsRoute, checkFeatureRoute, installToolRoute);
|
|
45382
44967
|
//#endregion
|
|
45383
44968
|
//#region routes/cliproxy.ts
|
|
44969
|
+
init_http_helpers();
|
|
44970
|
+
init_http_handler();
|
|
45384
44971
|
init_cliproxy();
|
|
45385
44972
|
let lastStatus = null;
|
|
45386
44973
|
async function refreshStatus() {
|
|
@@ -45452,6 +45039,10 @@ const postCliproxyRestartRoute = HttpRouter.add("POST", "/api/cliproxy/restart",
|
|
|
45452
45039
|
});
|
|
45453
45040
|
})));
|
|
45454
45041
|
const cliproxyRouteLayer = Layer.mergeAll(getCliproxyStatusRoute, postCliproxyRestartRoute);
|
|
45042
|
+
//#endregion
|
|
45043
|
+
//#region routes/tts.ts
|
|
45044
|
+
init_origin_validation();
|
|
45045
|
+
init_http_helpers();
|
|
45455
45046
|
const TTS_ROUTE_BODY_MAX_BYTES = 64 * 1024;
|
|
45456
45047
|
async function checkTtsHealth(options = {}) {
|
|
45457
45048
|
const runtimeConfig = getTtsRuntimeConfig();
|
|
@@ -45780,7 +45371,7 @@ const ttsRouteLayer = Layer.mergeAll(getTtsHealthRoute, postTtsStartRoute, getTt
|
|
|
45780
45371
|
* - Diff's the PR's failing check names against main's current failing set so
|
|
45781
45372
|
* inherited main-red failures are labelled as such.
|
|
45782
45373
|
*/
|
|
45783
|
-
init_agents$
|
|
45374
|
+
init_agents$2();
|
|
45784
45375
|
init_projects();
|
|
45785
45376
|
init_feedback_writer();
|
|
45786
45377
|
function execFilePromise(file, args, options) {
|
|
@@ -46090,6 +45681,7 @@ async function refreshMergeStateFromGitHub(issueId, repo, prNumber) {
|
|
|
46090
45681
|
encoding: "utf-8",
|
|
46091
45682
|
timeout: 15e3
|
|
46092
45683
|
});
|
|
45684
|
+
if (!stdout.trim()) return;
|
|
46093
45685
|
const pr = JSON.parse(stdout);
|
|
46094
45686
|
const status = await Effect.runPromise(getReviewStatus(issueId));
|
|
46095
45687
|
if (!status) return;
|
|
@@ -46203,8 +45795,8 @@ async function handlePullRequestPromise(payload) {
|
|
|
46203
45795
|
if (!issueId) return;
|
|
46204
45796
|
const repo = payload.repository.full_name;
|
|
46205
45797
|
if (payload.action === "closed" && pr.merged === true) try {
|
|
46206
|
-
const { postMergeLifecycle } = await import("./merge-agent-
|
|
46207
|
-
const { resolveProjectFromIssueSync } = await import("./projects-
|
|
45798
|
+
const { postMergeLifecycle } = await import("./merge-agent-CdxCcqFv.js");
|
|
45799
|
+
const { resolveProjectFromIssueSync } = await import("./projects-DWBDcB6V.js");
|
|
46208
45800
|
const project = resolveProjectFromIssueSync(issueId);
|
|
46209
45801
|
if (project) {
|
|
46210
45802
|
const branchName = pr.head.ref;
|
|
@@ -46472,6 +46064,8 @@ async function reconcileStaleGitHubBlockers() {
|
|
|
46472
46064
|
* Verifies X-Hub-Signature-256 HMAC-SHA256 signature.
|
|
46473
46065
|
* Dispatches to per-event-type handlers.
|
|
46474
46066
|
*/
|
|
46067
|
+
init_http_helpers();
|
|
46068
|
+
init_http_handler();
|
|
46475
46069
|
const WEBHOOK_SECRET_PATH = join$1(homedir$1(), ".overdeck", "github-app", "webhook-secret");
|
|
46476
46070
|
let _cachedWebhookSecret = void 0;
|
|
46477
46071
|
let _secretLoadPromise = null;
|
|
@@ -46584,6 +46178,7 @@ const webhooksRouteLayer = HttpRouter.add("POST", "/api/webhooks/github", httpHa
|
|
|
46584
46178
|
//#region ../../lib/compliance/advisory-warning.ts
|
|
46585
46179
|
init_config_yaml();
|
|
46586
46180
|
init_paths$2();
|
|
46181
|
+
init_rollup();
|
|
46587
46182
|
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
46183
|
async function resolveComplianceAdvisoryWarning(input) {
|
|
46589
46184
|
if (await (input.loadComplianceMode ?? loadComplianceMode)() === "off") return null;
|
|
@@ -46625,8 +46220,9 @@ function isCurrentSessionMiss(observation, identity) {
|
|
|
46625
46220
|
//#endregion
|
|
46626
46221
|
//#region ../../lib/memory/checkpoint-client.ts
|
|
46627
46222
|
init_settings();
|
|
46628
|
-
init_health();
|
|
46223
|
+
init_health$1();
|
|
46629
46224
|
init_providers$1();
|
|
46225
|
+
init_pending();
|
|
46630
46226
|
init_query_expansion();
|
|
46631
46227
|
init_injection();
|
|
46632
46228
|
let worker = null;
|
|
@@ -46661,7 +46257,7 @@ function getCheckpointWorker() {
|
|
|
46661
46257
|
return worker;
|
|
46662
46258
|
}
|
|
46663
46259
|
async function runInline(operation, payload) {
|
|
46664
|
-
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-
|
|
46260
|
+
const { claimTranscriptRange, commitTranscriptRange, releaseTranscriptRange, getTranscriptCheckpoint, listTranscriptCheckpoints } = await import("./checkpoints-BRNSJDyI.js");
|
|
46665
46261
|
switch (operation) {
|
|
46666
46262
|
case "claimTranscriptRange": return claimTranscriptRange(payload);
|
|
46667
46263
|
case "commitTranscriptRange": return commitTranscriptRange(payload);
|
|
@@ -46711,6 +46307,92 @@ const getTranscriptCheckpoint = (sessionId) => Effect.tryPromise({
|
|
|
46711
46307
|
catch: toError
|
|
46712
46308
|
});
|
|
46713
46309
|
//#endregion
|
|
46310
|
+
//#region ../../lib/session-format-converter.ts
|
|
46311
|
+
init_paths();
|
|
46312
|
+
/** Pull plain text out of a Claude/Pi `message.content` (string or block array). */
|
|
46313
|
+
function extractContentText(content) {
|
|
46314
|
+
if (typeof content === "string") return content;
|
|
46315
|
+
if (!Array.isArray(content)) return "";
|
|
46316
|
+
const parts = [];
|
|
46317
|
+
for (const block of content) {
|
|
46318
|
+
if (!block || typeof block !== "object") continue;
|
|
46319
|
+
const b = block;
|
|
46320
|
+
if (typeof b["text"] === "string") parts.push(b["text"]);
|
|
46321
|
+
else if (typeof b["thinking"] === "string") parts.push(`[thinking] ${b["thinking"]}`);
|
|
46322
|
+
else if ((b["type"] === "tool_use" || b["type"] === "toolCall") && typeof b["name"] === "string") parts.push(`[tool_use: ${b["name"]}]`);
|
|
46323
|
+
else if (b["type"] === "tool_result" || b["type"] === "toolResult") {
|
|
46324
|
+
const inner = extractContentText(b["content"]);
|
|
46325
|
+
if (inner) parts.push(`[tool_result] ${inner}`);
|
|
46326
|
+
}
|
|
46327
|
+
}
|
|
46328
|
+
return parts.join("\n").trim();
|
|
46329
|
+
}
|
|
46330
|
+
/** Read a Pi Agent JSONL transcript into ordered role/text turns. */
|
|
46331
|
+
function extractPiTranscript(raw) {
|
|
46332
|
+
const turns = [];
|
|
46333
|
+
for (const line of raw.split("\n")) {
|
|
46334
|
+
const trimmed = line.trim();
|
|
46335
|
+
if (!trimmed) continue;
|
|
46336
|
+
let entry;
|
|
46337
|
+
try {
|
|
46338
|
+
entry = JSON.parse(trimmed);
|
|
46339
|
+
} catch {
|
|
46340
|
+
continue;
|
|
46341
|
+
}
|
|
46342
|
+
if (entry["type"] !== "message") continue;
|
|
46343
|
+
const message = entry["message"];
|
|
46344
|
+
if (!message || typeof message !== "object") continue;
|
|
46345
|
+
const m = message;
|
|
46346
|
+
const role = typeof m["role"] === "string" ? m["role"] : "assistant";
|
|
46347
|
+
const text = extractContentText(m["content"]);
|
|
46348
|
+
if (text) turns.push({
|
|
46349
|
+
role,
|
|
46350
|
+
text
|
|
46351
|
+
});
|
|
46352
|
+
}
|
|
46353
|
+
return turns;
|
|
46354
|
+
}
|
|
46355
|
+
/**
|
|
46356
|
+
* Read a Codex rollout JSONL transcript into ordered role/text turns.
|
|
46357
|
+
*
|
|
46358
|
+
* Rollout files use a different schema from --json stdout:
|
|
46359
|
+
* - task_started: the initial task (user role)
|
|
46360
|
+
* - agent_message: a model turn (assistant role)
|
|
46361
|
+
* - token_count: metadata — skipped
|
|
46362
|
+
*
|
|
46363
|
+
* We extract task_started as the user prompt and agent_message events as
|
|
46364
|
+
* assistant turns to produce a readable transcript.
|
|
46365
|
+
*/
|
|
46366
|
+
function extractCodexTranscript(raw) {
|
|
46367
|
+
const turns = [];
|
|
46368
|
+
for (const line of raw.split("\n")) {
|
|
46369
|
+
const trimmed = line.trim();
|
|
46370
|
+
if (!trimmed) continue;
|
|
46371
|
+
let entry;
|
|
46372
|
+
try {
|
|
46373
|
+
entry = JSON.parse(trimmed);
|
|
46374
|
+
} catch {
|
|
46375
|
+
continue;
|
|
46376
|
+
}
|
|
46377
|
+
const type = entry["type"];
|
|
46378
|
+
if (type === "task_started") {
|
|
46379
|
+
const task = typeof entry["task"] === "string" ? entry["task"] : "";
|
|
46380
|
+
if (task) turns.push({
|
|
46381
|
+
role: "user",
|
|
46382
|
+
text: task
|
|
46383
|
+
});
|
|
46384
|
+
} else if (type === "agent_message") {
|
|
46385
|
+
const content = typeof entry["content"] === "string" ? entry["content"] : extractContentText(entry["content"]);
|
|
46386
|
+
if (content) turns.push({
|
|
46387
|
+
role: "assistant",
|
|
46388
|
+
text: content
|
|
46389
|
+
});
|
|
46390
|
+
}
|
|
46391
|
+
}
|
|
46392
|
+
return turns;
|
|
46393
|
+
}
|
|
46394
|
+
Data.TaggedError("SessionConvertError");
|
|
46395
|
+
//#endregion
|
|
46714
46396
|
//#region ../../lib/memory/compress.ts
|
|
46715
46397
|
const MAX_USER_CHARS = 4e4;
|
|
46716
46398
|
const MAX_TRANSCRIPT_DELTA_BYTES = 1024 * 1024;
|
|
@@ -46830,7 +46512,7 @@ function isRecord$1(value) {
|
|
|
46830
46512
|
}
|
|
46831
46513
|
//#endregion
|
|
46832
46514
|
//#region ../../lib/memory/transcript-source.ts
|
|
46833
|
-
init_agents$
|
|
46515
|
+
init_agents$2();
|
|
46834
46516
|
init_paths();
|
|
46835
46517
|
init_codex();
|
|
46836
46518
|
var ClaudeCodeTranscriptSource = class {
|
|
@@ -46883,7 +46565,7 @@ var ClaudeCodeTranscriptSource = class {
|
|
|
46883
46565
|
}
|
|
46884
46566
|
};
|
|
46885
46567
|
var PiTranscriptSource = class {
|
|
46886
|
-
harness = "
|
|
46568
|
+
harness = "ohmypi";
|
|
46887
46569
|
listAgents;
|
|
46888
46570
|
readSessionId;
|
|
46889
46571
|
resolveTranscriptPath;
|
|
@@ -46896,7 +46578,7 @@ var PiTranscriptSource = class {
|
|
|
46896
46578
|
}
|
|
46897
46579
|
async getActiveTranscripts() {
|
|
46898
46580
|
const agents = await this.listAgents();
|
|
46899
|
-
return (await Promise.all(agents.filter((agent) => agent.tmuxActive && agent.status === "running" && agent.role === "work" && agent.harness === "
|
|
46581
|
+
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
46582
|
}
|
|
46901
46583
|
parseDelta(buffer, fromOffset = 0) {
|
|
46902
46584
|
const text = Buffer.isBuffer(buffer) ? buffer.toString("utf8") : buffer;
|
|
@@ -46927,7 +46609,7 @@ var PiTranscriptSource = class {
|
|
|
46927
46609
|
sessionId,
|
|
46928
46610
|
transcriptPath,
|
|
46929
46611
|
identity: buildMemoryIdentity(agent, sessionId),
|
|
46930
|
-
harness: "
|
|
46612
|
+
harness: "ohmypi",
|
|
46931
46613
|
size: fileStat.size,
|
|
46932
46614
|
mtimeMs: fileStat.mtimeMs
|
|
46933
46615
|
};
|
|
@@ -47064,6 +46746,7 @@ async function readCodexThreadId(agent) {
|
|
|
47064
46746
|
}
|
|
47065
46747
|
//#endregion
|
|
47066
46748
|
//#region ../../lib/memory/extract.ts
|
|
46749
|
+
init_src();
|
|
47067
46750
|
const MEMORY_DOMAIN_TAGS = [
|
|
47068
46751
|
"review-blocker",
|
|
47069
46752
|
"test-failure",
|
|
@@ -47377,7 +47060,7 @@ function isRecord(value) {
|
|
|
47377
47060
|
}
|
|
47378
47061
|
//#endregion
|
|
47379
47062
|
//#region ../../lib/memory/pipeline.ts
|
|
47380
|
-
init_health();
|
|
47063
|
+
init_health$1();
|
|
47381
47064
|
async function extractFromTranscriptDelta(input) {
|
|
47382
47065
|
if (isSubagentHookPayload(input.hookPayload)) return {
|
|
47383
47066
|
status: "noop",
|
|
@@ -47728,7 +47411,7 @@ function buildPendingTurn(input, fromOffset, toOffset, compressed) {
|
|
|
47728
47411
|
};
|
|
47729
47412
|
}
|
|
47730
47413
|
async function emitMemoryObservationCreated(observation, timestamp) {
|
|
47731
|
-
const { initEventStore } = await import("./event-store-
|
|
47414
|
+
const { initEventStore } = await import("./event-store-D_9DeP8Y.js");
|
|
47732
47415
|
await (await initEventStore()).appendAsync({
|
|
47733
47416
|
type: "memory.observation_created",
|
|
47734
47417
|
timestamp,
|
|
@@ -47737,7 +47420,7 @@ async function emitMemoryObservationCreated(observation, timestamp) {
|
|
|
47737
47420
|
}
|
|
47738
47421
|
//#endregion
|
|
47739
47422
|
//#region ../../lib/memory/worker-pool.ts
|
|
47740
|
-
init_health();
|
|
47423
|
+
init_health$1();
|
|
47741
47424
|
init_providers$1();
|
|
47742
47425
|
function normalizeQueueLimit(value) {
|
|
47743
47426
|
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : 500;
|
|
@@ -48231,10 +47914,14 @@ function countCompleteLines(text) {
|
|
|
48231
47914
|
* `hook_event_name`. We look up the conversation by claude_session_id and
|
|
48232
47915
|
* emit an in-memory-only event via emitOnly().
|
|
48233
47916
|
*/
|
|
47917
|
+
init_http_helpers();
|
|
47918
|
+
init_http_handler();
|
|
48234
47919
|
init_event_store();
|
|
48235
|
-
init_agents$
|
|
47920
|
+
init_agents$2();
|
|
48236
47921
|
init_paths();
|
|
48237
47922
|
init_paths$2();
|
|
47923
|
+
init_dashboard_auth();
|
|
47924
|
+
init_read_model();
|
|
48238
47925
|
init_conversations();
|
|
48239
47926
|
init_briefing_freshness();
|
|
48240
47927
|
init_settings();
|
|
@@ -48593,7 +48280,10 @@ function isRole(value) {
|
|
|
48593
48280
|
* GET /api/agents/:agentId/diffs/:turnId — unified diff for a specific turn
|
|
48594
48281
|
* GET /api/agents/:agentId/diffs/full — full thread diff (all turns combined)
|
|
48595
48282
|
*/
|
|
48283
|
+
init_http_helpers();
|
|
48284
|
+
init_read_model();
|
|
48596
48285
|
init_event_store();
|
|
48286
|
+
init_checkpoint_manager();
|
|
48597
48287
|
function validateOrigin(request) {
|
|
48598
48288
|
const origin = request.headers["origin"];
|
|
48599
48289
|
if (origin && typeof origin === "string" && !origin.includes("localhost") && !origin.includes("127.0.0.1")) return {
|
|
@@ -48789,7 +48479,11 @@ const diffsRouteLayer = Layer.mergeAll(getDiffsRoute, getTurnDiffRoute, getFullD
|
|
|
48789
48479
|
* t3code's `terminal.*` contracts, this create/kill pair is the seam that gets
|
|
48790
48480
|
* folded into that RPC surface.
|
|
48791
48481
|
*/
|
|
48482
|
+
init_http_helpers();
|
|
48483
|
+
init_http_handler();
|
|
48792
48484
|
init_tmux();
|
|
48485
|
+
init_origin_validation();
|
|
48486
|
+
init_dashboard_auth();
|
|
48793
48487
|
const readJsonBody$2 = Effect.gen(function* () {
|
|
48794
48488
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
48795
48489
|
return text ? JSON.parse(text) : {};
|
|
@@ -48850,7 +48544,12 @@ const terminalsRouteLayer = Layer.mergeAll(postTerminalRoute, deleteTerminalRout
|
|
|
48850
48544
|
*
|
|
48851
48545
|
* Zero sync FS calls — lib functions use fs/promises; SQLite work stays in the existing sync DB layer.
|
|
48852
48546
|
*/
|
|
48547
|
+
init_domain_services();
|
|
48548
|
+
init_http_helpers();
|
|
48549
|
+
init_http_handler();
|
|
48853
48550
|
init_config_yaml();
|
|
48551
|
+
init_origin_validation();
|
|
48552
|
+
init_dashboard_auth();
|
|
48854
48553
|
function getRequestHeader(request, name) {
|
|
48855
48554
|
const value = request.headers[name];
|
|
48856
48555
|
if (Array.isArray(value)) return value[0];
|
|
@@ -50143,7 +49842,9 @@ const AUTO_MERGE_COOLDOWN_MS = 3e5;
|
|
|
50143
49842
|
//#endregion
|
|
50144
49843
|
//#region ../../lib/cloister/auto-merge-eligibility.ts
|
|
50145
49844
|
init_github_app();
|
|
49845
|
+
init_forge();
|
|
50146
49846
|
init_review_status();
|
|
49847
|
+
init_tracker_utils();
|
|
50147
49848
|
const execFileAsync = promisify(execFile);
|
|
50148
49849
|
const BLOCKER_LABELS = [
|
|
50149
49850
|
"needs-design",
|
|
@@ -50324,8 +50025,15 @@ function getProjectAutoMergeDefault(issueId) {
|
|
|
50324
50025
|
}
|
|
50325
50026
|
//#endregion
|
|
50326
50027
|
//#region routes/flywheel.ts
|
|
50028
|
+
init_http_helpers();
|
|
50029
|
+
init_src();
|
|
50030
|
+
init_http_handler();
|
|
50031
|
+
init_origin_validation();
|
|
50032
|
+
init_flywheel_run_state();
|
|
50033
|
+
init_dashboard_auth();
|
|
50327
50034
|
init_tmux();
|
|
50328
50035
|
init_control_settings();
|
|
50036
|
+
init_forge();
|
|
50329
50037
|
init_review_status();
|
|
50330
50038
|
init_projects();
|
|
50331
50039
|
init_merge_sync();
|
|
@@ -50631,7 +50339,7 @@ async function getFlywheelConversationPayload() {
|
|
|
50631
50339
|
};
|
|
50632
50340
|
}
|
|
50633
50341
|
async function postFlywheelReportPayload() {
|
|
50634
|
-
const { flywheelReportCommand } = await import("./flywheel-
|
|
50342
|
+
const { flywheelReportCommand } = await import("./flywheel-NZJyASRc.js");
|
|
50635
50343
|
await flywheelReportCommand({ cwd: process.cwd() });
|
|
50636
50344
|
return {
|
|
50637
50345
|
status: 200,
|
|
@@ -50820,11 +50528,11 @@ const getMergeBlockersRoute = HttpRouter.add("GET", "/api/flywheel/merge-blocker
|
|
|
50820
50528
|
async function defaultGetOrderedIssueIds() {
|
|
50821
50529
|
const status = await readCurrentFlywheelStatusForDashboard();
|
|
50822
50530
|
if (!status) return [];
|
|
50823
|
-
const { computeMergeQueue } = await import("./flywheel-merge-order-
|
|
50531
|
+
const { computeMergeQueue } = await import("./flywheel-merge-order-BkA6937p.js");
|
|
50824
50532
|
return (await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd()).pipe(Effect.provide(layer)))).map((i) => i.issueId);
|
|
50825
50533
|
}
|
|
50826
50534
|
async function defaultMergeOne(issueId) {
|
|
50827
|
-
const { triggerMerge } = await import("./workspaces-
|
|
50535
|
+
const { triggerMerge } = await import("./workspaces-DL8hfuDT.js");
|
|
50828
50536
|
const r = await triggerMerge(issueId);
|
|
50829
50537
|
return r.success ? { ok: true } : {
|
|
50830
50538
|
ok: false,
|
|
@@ -50844,7 +50552,7 @@ async function postFlywheelMergeNextPayload(payload, deps = {}) {
|
|
|
50844
50552
|
body: { error: "n must be a positive integer" }
|
|
50845
50553
|
};
|
|
50846
50554
|
const issueIds = (await (deps.getOrderedIssueIds ?? defaultGetOrderedIssueIds)()).slice(0, n);
|
|
50847
|
-
const { shipMergeBatch } = await import("./merge-batch-
|
|
50555
|
+
const { shipMergeBatch } = await import("./merge-batch-CaSP7OL6.js");
|
|
50848
50556
|
return {
|
|
50849
50557
|
status: 200,
|
|
50850
50558
|
body: { outcomes: await shipMergeBatch(issueIds, { merge: deps.merge ?? defaultMergeOne }) }
|
|
@@ -51001,7 +50709,7 @@ const getFlywheelMergeQueueRoute = HttpRouter.add("GET", "/api/flywheel/merge-qu
|
|
|
51001
50709
|
return yield* Effect.promise(async () => {
|
|
51002
50710
|
const status = await readCurrentFlywheelStatusForDashboard();
|
|
51003
50711
|
if (!status) return jsonResponse([]);
|
|
51004
|
-
const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-
|
|
50712
|
+
const { computeMergeQueue, resolveMergeQueuePrUrl } = await import("./flywheel-merge-order-BkA6937p.js");
|
|
51005
50713
|
return jsonResponse(await Effect.runPromise(computeMergeQueue(status.activePipeline, process.cwd(), { getPrUrl: resolveMergeQueuePrUrl }).pipe(Effect.provide(layer))));
|
|
51006
50714
|
});
|
|
51007
50715
|
})));
|
|
@@ -51015,14 +50723,14 @@ function uatGenerationNameFromParam(param) {
|
|
|
51015
50723
|
return decoded.startsWith("uat/") ? decoded : `uat/${decoded}`;
|
|
51016
50724
|
}
|
|
51017
50725
|
const getUatGenerationsRoute = HttpRouter.add("GET", "/api/flywheel/uat-generations", httpHandler(Effect.gen(function* () {
|
|
51018
|
-
const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-
|
|
50726
|
+
const { getUatGenerationsPayload } = yield* Effect.promise(() => import("./uat-train-C6_NdOfR.js"));
|
|
51019
50727
|
return jsonResponse(yield* Effect.promise(() => getUatGenerationsPayload()));
|
|
51020
50728
|
})));
|
|
51021
50729
|
const postUatGenerationStackRoute = HttpRouter.add("POST", "/api/flywheel/uat-generations/:name/stack", httpHandler(Effect.gen(function* () {
|
|
51022
50730
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51023
50731
|
if (authError) return authError;
|
|
51024
50732
|
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
51025
|
-
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-
|
|
50733
|
+
const { postUatGenerationStackPayload } = yield* Effect.promise(() => import("./uat-train-C6_NdOfR.js"));
|
|
51026
50734
|
const result = yield* Effect.promise(() => postUatGenerationStackPayload(name));
|
|
51027
50735
|
if (!result.ok) return jsonResponse({ error: result.error }, { status: result.status });
|
|
51028
50736
|
return jsonResponse({
|
|
@@ -51034,8 +50742,8 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
|
|
|
51034
50742
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51035
50743
|
if (authError) return authError;
|
|
51036
50744
|
const name = uatGenerationNameFromParam((yield* HttpRouter.params)["name"] ?? "");
|
|
51037
|
-
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-
|
|
51038
|
-
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-
|
|
50745
|
+
const { postUatGenerationPromotePayload } = yield* Effect.promise(() => import("./uat-train-C6_NdOfR.js"));
|
|
50746
|
+
const { firePostMergeLifecycle } = yield* Effect.promise(() => import("./specialists-Bbj7bCwh.js"));
|
|
51039
50747
|
const result = yield* Effect.promise(() => postUatGenerationPromotePayload(name, firePostMergeLifecycle));
|
|
51040
50748
|
if (!result.success) return jsonResponse(result, { status: result.reason === "not-found" ? 404 : result.reason === "merge-failed" ? 500 : 409 });
|
|
51041
50749
|
return jsonResponse(result);
|
|
@@ -51048,7 +50756,7 @@ const postUatGenerationPromoteRoute = HttpRouter.add("POST", "/api/flywheel/uat-
|
|
|
51048
50756
|
const postFlywheelAssembleUatRoute = HttpRouter.add("POST", "/api/flywheel/assemble-uat", httpHandler(Effect.gen(function* () {
|
|
51049
50757
|
const authError = rejectUnsafeDashboardMutationRequest(yield* HttpServerRequest.HttpServerRequest);
|
|
51050
50758
|
if (authError) return authError;
|
|
51051
|
-
const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-
|
|
50759
|
+
const { runUatTrainReconcile } = yield* Effect.promise(() => import("./uat-train-C6_NdOfR.js"));
|
|
51052
50760
|
return jsonResponse(yield* Effect.promise(() => runUatTrainReconcile({ force: true })));
|
|
51053
50761
|
})));
|
|
51054
50762
|
const getFlywheelStateRoute = HttpRouter.add("GET", "/api/flywheel/state", httpHandler(Effect.gen(function* () {
|
|
@@ -51156,6 +50864,9 @@ function escapeXml(value) {
|
|
|
51156
50864
|
//#endregion
|
|
51157
50865
|
//#region routes/artifacts.ts
|
|
51158
50866
|
init_paths();
|
|
50867
|
+
init_http_helpers();
|
|
50868
|
+
init_dashboard_auth();
|
|
50869
|
+
init_http_handler();
|
|
51159
50870
|
const ARTIFACT_SLUG_PATTERN = /^[A-Za-z0-9_-]{8}$/;
|
|
51160
50871
|
const WORKSPACE_ARTIFACT_SELECTOR_PATTERN = /^[A-Za-z0-9._:-]+$/;
|
|
51161
50872
|
const RAW_ARTIFACT_CSP = [
|
|
@@ -51469,6 +51180,9 @@ const postArtifactUnshareRoute = HttpRouter.add("POST", "/api/artifacts/:slug/un
|
|
|
51469
51180
|
const artifactsRouteLayer = Layer.mergeAll(getRawArtifactRoute, getArtifactDetailRoute, getWorkspaceArtifactsRoute, getArtifactThumbnailRoute, postArtifactUnshareRoute);
|
|
51470
51181
|
//#endregion
|
|
51471
51182
|
//#region ../../lib/backlog/label-ops.ts
|
|
51183
|
+
init_sequence_io();
|
|
51184
|
+
init_tracker_utils();
|
|
51185
|
+
init_pickup();
|
|
51472
51186
|
const execAsync = promisify(exec);
|
|
51473
51187
|
/**
|
|
51474
51188
|
* Add or remove a GitHub label on an issue. Non-GitHub issues are silently
|
|
@@ -51490,8 +51204,13 @@ const applyIssueBlocksMainLabel = (id) => addIssueLabel(id, BLOCKS_MAIN_LABEL);
|
|
|
51490
51204
|
const removeIssueBlocksMainLabel = (id) => removeIssueLabel(id, BLOCKS_MAIN_LABEL);
|
|
51491
51205
|
const applyIssueReadyLabel = (id) => addIssueLabel(id, READY_LABEL);
|
|
51492
51206
|
const removeIssueReadyLabel = (id) => removeIssueLabel(id, READY_LABEL);
|
|
51207
|
+
const applyIssueReleasedLabel = (id) => addIssueLabel(id, RELEASED_LABEL);
|
|
51208
|
+
const removeIssueReleasedLabel = (id) => removeIssueLabel(id, RELEASED_LABEL);
|
|
51209
|
+
const applyIssueObjectionLabel = (id) => addIssueLabel(id, OBJECTION_LABEL);
|
|
51210
|
+
const removeIssueObjectionLabel = (id) => removeIssueLabel(id, OBJECTION_LABEL);
|
|
51493
51211
|
//#endregion
|
|
51494
51212
|
//#region ../../lib/database/agent-mappers.ts
|
|
51213
|
+
init_lookups();
|
|
51495
51214
|
function agentStateToDbAgent(state) {
|
|
51496
51215
|
return {
|
|
51497
51216
|
id: state.id,
|
|
@@ -51666,6 +51385,7 @@ function buildNamedParams(row) {
|
|
|
51666
51385
|
function backfillAgentsFromStateJsonSync(db, options) {
|
|
51667
51386
|
const agentsDir = join$1(getOverdeckHome(), "agents");
|
|
51668
51387
|
const liveSessions = options?.listLiveSessions?.() ?? listLiveTmuxSessionNames();
|
|
51388
|
+
const readHarnessModel = options?.readHarnessModel ?? readAgentHarnessModelRecordSync;
|
|
51669
51389
|
let processed = 0;
|
|
51670
51390
|
let skipped = 0;
|
|
51671
51391
|
let markedStopped = 0;
|
|
@@ -51706,7 +51426,16 @@ function backfillAgentsFromStateJsonSync(db, options) {
|
|
|
51706
51426
|
}
|
|
51707
51427
|
const reconciled = reconcileAgentStatus(state, liveSessions);
|
|
51708
51428
|
if (reconciled.status === "stopped" && state.status !== "stopped") markedStopped++;
|
|
51709
|
-
|
|
51429
|
+
let effective = reconciled;
|
|
51430
|
+
if (reconciled.issueId) {
|
|
51431
|
+
const rec = readHarnessModel(reconciled.issueId);
|
|
51432
|
+
if (rec?.harness || rec?.model) {
|
|
51433
|
+
effective = { ...reconciled };
|
|
51434
|
+
if (rec.harness) effective.harness = rec.harness;
|
|
51435
|
+
if (rec.model) effective.model = rec.model;
|
|
51436
|
+
}
|
|
51437
|
+
}
|
|
51438
|
+
const row = agentStateToDbAgent(effective);
|
|
51710
51439
|
upsert.run(buildNamedParams(row));
|
|
51711
51440
|
processed++;
|
|
51712
51441
|
if (options?.verbose) console.log(`[backfill] ${row.id} -> ${row.status}`);
|
|
@@ -52440,7 +52169,7 @@ function initSchema(db) {
|
|
|
52440
52169
|
*/
|
|
52441
52170
|
function runMigrations(db, dbPath) {
|
|
52442
52171
|
const currentVersion = db.pragma("user_version", { simple: true });
|
|
52443
|
-
if (currentVersion
|
|
52172
|
+
if (currentVersion >= 57) return;
|
|
52444
52173
|
if (currentVersion === 0) {
|
|
52445
52174
|
initSchema(db);
|
|
52446
52175
|
return;
|
|
@@ -53318,8 +53047,14 @@ function getBacklogSequence(projectKey) {
|
|
|
53318
53047
|
}
|
|
53319
53048
|
//#endregion
|
|
53320
53049
|
//#region routes/backlog.ts
|
|
53050
|
+
init_http_handler();
|
|
53051
|
+
init_http_helpers();
|
|
53052
|
+
init_dashboard_auth();
|
|
53053
|
+
init_sequence_io();
|
|
53054
|
+
init_pickup();
|
|
53321
53055
|
init_review_status();
|
|
53322
|
-
|
|
53056
|
+
init_sequencer_agent();
|
|
53057
|
+
init_jsonl_resolver();
|
|
53323
53058
|
const readJsonBody = Effect.gen(function* () {
|
|
53324
53059
|
const text = yield* (yield* HttpServerRequest.HttpServerRequest).text;
|
|
53325
53060
|
try {
|
|
@@ -53413,6 +53148,7 @@ const postBacklogRegenerateRoute = HttpRouter.add("POST", "/api/backlog/sequence
|
|
|
53413
53148
|
const { getSharedIssueService } = (init_issue_service_singleton(), __toCommonJS(issue_service_singleton_exports));
|
|
53414
53149
|
const issues = getSharedIssueService().getIssues();
|
|
53415
53150
|
try {
|
|
53151
|
+
await clearFinishedSequencerRun(projectRoot);
|
|
53416
53152
|
return jsonResponse({
|
|
53417
53153
|
status: "spawned",
|
|
53418
53154
|
agentId: (await spawnSequencerAgent(pass, {
|
|
@@ -53580,6 +53316,8 @@ const postBacklogLabelsRoute = HttpRouter.add("POST", "/api/backlog/sequence/lab
|
|
|
53580
53316
|
if (typeof body["ready"] === "boolean") await (body["ready"] ? applyIssueReadyLabel : removeIssueReadyLabel)(issueId);
|
|
53581
53317
|
if (typeof body["parked"] === "boolean") await (body["parked"] ? applyIssueParkedLabel : removeIssueParkedLabel)(issueId);
|
|
53582
53318
|
if (typeof body["blocksMain"] === "boolean") await (body["blocksMain"] ? applyIssueBlocksMainLabel : removeIssueBlocksMainLabel)(issueId);
|
|
53319
|
+
if (typeof body["released"] === "boolean") await (body["released"] ? applyIssueReleasedLabel : removeIssueReleasedLabel)(issueId);
|
|
53320
|
+
if (typeof body["objection"] === "boolean") await (body["objection"] ? applyIssueObjectionLabel : removeIssueObjectionLabel)(issueId);
|
|
53583
53321
|
return jsonResponse({
|
|
53584
53322
|
status: "ok",
|
|
53585
53323
|
issueId
|
|
@@ -53608,14 +53346,7 @@ const postBacklogClearRoute = HttpRouter.add("POST", "/api/backlog/sequence/clea
|
|
|
53608
53346
|
const getSequencerStatusRoute = HttpRouter.add("GET", "/api/backlog/sequencer-status", httpHandler(Effect.gen(function* () {
|
|
53609
53347
|
return yield* Effect.promise(async () => {
|
|
53610
53348
|
const projectRoot = process.cwd();
|
|
53611
|
-
const
|
|
53612
|
-
const startedAt = alive ? getAgentStateSync("sequencer-runner")?.startedAt ?? null : null;
|
|
53613
|
-
const seqPath = join$1(projectRoot, ".pan", "backlog", "sequence.md");
|
|
53614
|
-
let freshSequence = false;
|
|
53615
|
-
if (alive && startedAt && existsSync$1(seqPath)) try {
|
|
53616
|
-
freshSequence = statSync$1(seqPath).mtimeMs >= new Date(startedAt).getTime();
|
|
53617
|
-
} catch {}
|
|
53618
|
-
const running = alive && !freshSequence;
|
|
53349
|
+
const { running, startedAt } = getSequencerRunStatus(projectRoot);
|
|
53619
53350
|
let total = 0;
|
|
53620
53351
|
const manifestPath = join$1(projectRoot, ".pan", "backlog", "manifest.json");
|
|
53621
53352
|
if (existsSync$1(manifestPath)) try {
|
|
@@ -53657,6 +53388,8 @@ function listFeatureRegistryForDashboard(filter = {}) {
|
|
|
53657
53388
|
}
|
|
53658
53389
|
//#endregion
|
|
53659
53390
|
//#region routes/feature-registry.ts
|
|
53391
|
+
init_http_helpers();
|
|
53392
|
+
init_http_handler();
|
|
53660
53393
|
async function getFeatureRegistryListPayload(options = {}) {
|
|
53661
53394
|
return { entries: await (options.listEntries ?? listFeatureRegistryForDashboard)({ limit: 100 }) };
|
|
53662
53395
|
}
|
|
@@ -53671,6 +53404,9 @@ const featureRegistryRouteLayer = Layer.provideMerge(listFeatureRegistryRoute, L
|
|
|
53671
53404
|
*
|
|
53672
53405
|
* GET /api/fs/list-dirs?path=<abs> — list immediate subdirectories, home-clamped + auth-gated
|
|
53673
53406
|
*/
|
|
53407
|
+
init_http_helpers();
|
|
53408
|
+
init_http_handler();
|
|
53409
|
+
init_dashboard_auth();
|
|
53674
53410
|
const listDirsRoute = HttpRouter.add("GET", "/api/fs/list-dirs", httpHandler(Effect.gen(function* () {
|
|
53675
53411
|
const req = yield* HttpServerRequest.HttpServerRequest;
|
|
53676
53412
|
const authError = rejectUnauthorizedDashboardRequest(req);
|
|
@@ -53721,7 +53457,14 @@ const fsRouteLayer = Layer.mergeAll(listDirsRoute);
|
|
|
53721
53457
|
* GET /ws/terminal → Raw WebSocket terminal (bypasses Effect RPC)
|
|
53722
53458
|
* GET * → static files from OVERDECK_FRONTEND_DIR
|
|
53723
53459
|
*/
|
|
53460
|
+
init_http_helpers();
|
|
53461
|
+
init_domain_services();
|
|
53462
|
+
init_read_model();
|
|
53463
|
+
init_cost();
|
|
53724
53464
|
init_infra();
|
|
53465
|
+
init_linear_client();
|
|
53466
|
+
init_dashboard_auth();
|
|
53467
|
+
init_origin_validation();
|
|
53725
53468
|
init_activity_logger();
|
|
53726
53469
|
const HttpServerLive = Layer.unwrap(Effect.gen(function* () {
|
|
53727
53470
|
const config = yield* ServerConfig;
|
|
@@ -53858,10 +53601,14 @@ const runServer = Layer.launch(makeServerLayer);
|
|
|
53858
53601
|
* These fields were dropped in the Effect server migration (PAN-428) and are
|
|
53859
53602
|
* restored here via the event-driven projection pipeline.
|
|
53860
53603
|
*/
|
|
53861
|
-
init_agents$
|
|
53604
|
+
init_agents$2();
|
|
53605
|
+
init_agent_enrichment();
|
|
53862
53606
|
init_review_status();
|
|
53607
|
+
init_concurrency$1();
|
|
53863
53608
|
init_event_store();
|
|
53609
|
+
init_agent_projection();
|
|
53864
53610
|
init_activity_logger();
|
|
53611
|
+
init_read_model();
|
|
53865
53612
|
function enrichmentChanged(prev, next) {
|
|
53866
53613
|
if (!prev) return true;
|
|
53867
53614
|
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;
|
|
@@ -54140,8 +53887,9 @@ function drainRefreshQueue(state) {
|
|
|
54140
53887
|
* expects — the reducer and WebSocket subscription already exist, but no
|
|
54141
53888
|
* server code was emitting the events.
|
|
54142
53889
|
*/
|
|
54143
|
-
init_agents$
|
|
53890
|
+
init_agents$2();
|
|
54144
53891
|
init_tmux();
|
|
53892
|
+
init_concurrency$1();
|
|
54145
53893
|
init_event_store();
|
|
54146
53894
|
function splitLines(text) {
|
|
54147
53895
|
const lines = text.split("\n");
|
|
@@ -54179,7 +53927,7 @@ async function pollOnce(state) {
|
|
|
54179
53927
|
try {
|
|
54180
53928
|
const remoteState = await readFile(join$1(homedir$1(), ".overdeck", "agents", agentId, "remote-state.json"), "utf-8").then((text) => JSON.parse(text)).catch(() => null);
|
|
54181
53929
|
if (remoteState?.location === "remote" && remoteState?.vmName) {
|
|
54182
|
-
const { getRemoteAgentOutput } = await import("./remote-agents-
|
|
53930
|
+
const { getRemoteAgentOutput } = await import("./remote-agents-DQ2gRI6m.js");
|
|
54183
53931
|
stdout = await getRemoteAgentOutput(agentId, remoteState.vmName, 50);
|
|
54184
53932
|
} else stdout = await Effect.runPromise(capturePane(agentId, 50));
|
|
54185
53933
|
} catch {
|
|
@@ -54382,7 +54130,7 @@ async function detectOrphanedClaudeCodeSessions(activeConvs) {
|
|
|
54382
54130
|
for (const conv of activeConvs) {
|
|
54383
54131
|
if (!conv.cwd) continue;
|
|
54384
54132
|
if (!conv.claudeSessionId) continue;
|
|
54385
|
-
if (conv.harness === "
|
|
54133
|
+
if (conv.harness === "ohmypi" || conv.harness === "codex") continue;
|
|
54386
54134
|
const list = cwdGroups.get(conv.cwd) ?? [];
|
|
54387
54135
|
list.push(conv);
|
|
54388
54136
|
cwdGroups.set(conv.cwd, list);
|
|
@@ -54703,7 +54451,7 @@ async function announceNewRestart(deps = {}) {
|
|
|
54703
54451
|
setLastAnnounced(status.ts);
|
|
54704
54452
|
return true;
|
|
54705
54453
|
}
|
|
54706
|
-
let timer$
|
|
54454
|
+
let timer$2 = null;
|
|
54707
54455
|
let running = false;
|
|
54708
54456
|
let runToken = 0;
|
|
54709
54457
|
function startRestartAnnouncer(deps = {}) {
|
|
@@ -54713,8 +54461,8 @@ function startRestartAnnouncer(deps = {}) {
|
|
|
54713
54461
|
let remainingBootstrapPolls = BOOTSTRAP_FAST_POLL_COUNT;
|
|
54714
54462
|
const schedule = (delayMs) => {
|
|
54715
54463
|
if (!running || token !== runToken) return;
|
|
54716
|
-
timer$
|
|
54717
|
-
timer$
|
|
54464
|
+
timer$2 = setTimeout(pass, delayMs);
|
|
54465
|
+
timer$2.unref?.();
|
|
54718
54466
|
};
|
|
54719
54467
|
const nextDelay = (emitted) => {
|
|
54720
54468
|
if (emitted) return POLL_MS;
|
|
@@ -54732,8 +54480,8 @@ function startRestartAnnouncer(deps = {}) {
|
|
|
54732
54480
|
function stopRestartAnnouncer() {
|
|
54733
54481
|
running = false;
|
|
54734
54482
|
runToken += 1;
|
|
54735
|
-
if (timer$
|
|
54736
|
-
timer$
|
|
54483
|
+
if (timer$2) clearTimeout(timer$2);
|
|
54484
|
+
timer$2 = null;
|
|
54737
54485
|
}
|
|
54738
54486
|
//#endregion
|
|
54739
54487
|
//#region services/substrate-bug-poller.ts
|
|
@@ -54845,7 +54593,7 @@ function createSubstrateBugPoller(options = {}) {
|
|
|
54845
54593
|
}
|
|
54846
54594
|
async function scanIssueCandidates(config, store) {
|
|
54847
54595
|
const since = isoLookback(now(), lookbackMs);
|
|
54848
|
-
for (const repo of config.repos) {
|
|
54596
|
+
for (const repo of config.repos) try {
|
|
54849
54597
|
const repoQualifier = `repo:${repo.owner}/${repo.repo}`;
|
|
54850
54598
|
const authorResults = await fetchSearch(config.token, searchQuery([
|
|
54851
54599
|
repoQualifier,
|
|
@@ -54882,11 +54630,13 @@ function createSubstrateBugPoller(options = {}) {
|
|
|
54882
54630
|
});
|
|
54883
54631
|
if (!existing) await appendSubstrateBugFiledEvent(store, bug);
|
|
54884
54632
|
}
|
|
54633
|
+
} catch (err) {
|
|
54634
|
+
log.warn(`[substrate-bug-poller] skipping ${repo.owner}/${repo.repo}:`, err instanceof Error ? err.message : err);
|
|
54885
54635
|
}
|
|
54886
54636
|
}
|
|
54887
54637
|
async function scanMergedPullRequests(config) {
|
|
54888
54638
|
const since = isoLookback(now(), lookbackMs);
|
|
54889
|
-
for (const repo of config.repos) {
|
|
54639
|
+
for (const repo of config.repos) try {
|
|
54890
54640
|
const repoQualifier = `repo:${repo.owner}/${repo.repo}`;
|
|
54891
54641
|
const pullResults = await fetchSearch(config.token, searchQuery([
|
|
54892
54642
|
repoQualifier,
|
|
@@ -54914,6 +54664,8 @@ function createSubstrateBugPoller(options = {}) {
|
|
|
54914
54664
|
repository.markFixed(issueId, commitSha, fixedAt);
|
|
54915
54665
|
}
|
|
54916
54666
|
}
|
|
54667
|
+
} catch (err) {
|
|
54668
|
+
log.warn(`[substrate-bug-poller] skipping ${repo.owner}/${repo.repo}:`, err instanceof Error ? err.message : err);
|
|
54917
54669
|
}
|
|
54918
54670
|
}
|
|
54919
54671
|
async function pollOnce() {
|
|
@@ -54962,7 +54714,7 @@ init_config_yaml();
|
|
|
54962
54714
|
init_event_store();
|
|
54963
54715
|
init_activity_logger();
|
|
54964
54716
|
init_features();
|
|
54965
|
-
init_cost();
|
|
54717
|
+
init_cost$1();
|
|
54966
54718
|
const SYSTEM_PROMPT = `You are a concise voice narrator for a software development dashboard.
|
|
54967
54719
|
Your job: review recent activity and produce a SINGLE brief utterance suitable for text-to-speech.
|
|
54968
54720
|
|
|
@@ -55128,7 +54880,7 @@ const RESTART_MARKER = join(homedir(), ".overdeck", "dashboard-restarting.json")
|
|
|
55128
54880
|
* loads new content-hashed chunk filenames (no ERR_MODULE_NOT_FOUND after rebuild).
|
|
55129
54881
|
*/
|
|
55130
54882
|
async function defaultLifecycleRunner(pending) {
|
|
55131
|
-
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-
|
|
54883
|
+
const { postMergeLifecycle, notifyTldrDaemon } = await import("./merge-agent-CdxCcqFv.js");
|
|
55132
54884
|
await postMergeLifecycle(pending.issueId, pending.projectPath, pending.sourceBranch, { skipDeploy: true });
|
|
55133
54885
|
if (pending.sourceBranch) await notifyTldrDaemon(pending.projectPath, pending.sourceBranch);
|
|
55134
54886
|
}
|
|
@@ -55196,7 +54948,7 @@ async function processPendingLifecycle(options) {
|
|
|
55196
54948
|
}
|
|
55197
54949
|
//#endregion
|
|
55198
54950
|
//#region ../../lib/memory/reconciliation.ts
|
|
55199
|
-
init_agents$
|
|
54951
|
+
init_agents$2();
|
|
55200
54952
|
async function reconcileStaleTranscriptCheckpoints(options = {}) {
|
|
55201
54953
|
const limit = options.limit ?? 100;
|
|
55202
54954
|
const checkpoints = (options.listCheckpoints ?? listTranscriptCheckpoints)(limit);
|
|
@@ -55260,7 +55012,7 @@ function checkpointIdentity(checkpoint) {
|
|
|
55260
55012
|
};
|
|
55261
55013
|
}
|
|
55262
55014
|
function inferCheckpointHarness(transcriptPath) {
|
|
55263
|
-
if (transcriptPath.includes("/.overdeck/agents/") && transcriptPath.includes("/sessions/")) return "
|
|
55015
|
+
if (transcriptPath.includes("/.overdeck/agents/") && transcriptPath.includes("/sessions/")) return "ohmypi";
|
|
55264
55016
|
if (transcriptPath.includes("/codex-home/sessions/") && transcriptPath.includes("rollout-")) return "codex";
|
|
55265
55017
|
return "claude-code";
|
|
55266
55018
|
}
|
|
@@ -55296,7 +55048,7 @@ init_paths();
|
|
|
55296
55048
|
init_tmux();
|
|
55297
55049
|
init_issue_id();
|
|
55298
55050
|
init_errors();
|
|
55299
|
-
init_agents$
|
|
55051
|
+
init_agents$2();
|
|
55300
55052
|
function getAgentDirectoryIssueId(name) {
|
|
55301
55053
|
const match = name.match(/^(?:agent|planning)-(.+)$/);
|
|
55302
55054
|
if (!match) return null;
|
|
@@ -55439,7 +55191,7 @@ init_activity_logger();
|
|
|
55439
55191
|
init_merge_sync();
|
|
55440
55192
|
const AUTO_MERGE_EXECUTOR_INTERVAL_MS = 3e4;
|
|
55441
55193
|
const REQUEUE_BACKOFF_MS = 6e4;
|
|
55442
|
-
let timer = null;
|
|
55194
|
+
let timer$1 = null;
|
|
55443
55195
|
let activeTick = null;
|
|
55444
55196
|
function errorMessage(error) {
|
|
55445
55197
|
if (error instanceof Error && error.message) return error.message;
|
|
@@ -55449,7 +55201,7 @@ function failureReason(result) {
|
|
|
55449
55201
|
return result.error ?? result.message ?? `merge returned status ${result.statusCode ?? "unknown"}`;
|
|
55450
55202
|
}
|
|
55451
55203
|
async function defaultMergeIssue(issueId) {
|
|
55452
|
-
const { triggerMerge } = await import("./workspaces-
|
|
55204
|
+
const { triggerMerge } = await import("./workspaces-DL8hfuDT.js");
|
|
55453
55205
|
return triggerMerge(issueId);
|
|
55454
55206
|
}
|
|
55455
55207
|
function defaultAnnounceFailure(issueId, reason) {
|
|
@@ -55519,14 +55271,48 @@ function runTick(deps) {
|
|
|
55519
55271
|
}
|
|
55520
55272
|
function startAutoMergeExecutor(deps = {}) {
|
|
55521
55273
|
if (process.env.OVERDECK_DISABLE_AUTO_MERGE === "1") return false;
|
|
55522
|
-
if (timer) return false;
|
|
55523
|
-
timer = setInterval(() => runTick(deps), AUTO_MERGE_EXECUTOR_INTERVAL_MS);
|
|
55274
|
+
if (timer$1) return false;
|
|
55275
|
+
timer$1 = setInterval(() => runTick(deps), AUTO_MERGE_EXECUTOR_INTERVAL_MS);
|
|
55524
55276
|
return true;
|
|
55525
55277
|
}
|
|
55526
55278
|
function stopAutoMergeExecutor() {
|
|
55527
|
-
if (!timer) return;
|
|
55528
|
-
clearInterval(timer);
|
|
55529
|
-
timer = null;
|
|
55279
|
+
if (!timer$1) return;
|
|
55280
|
+
clearInterval(timer$1);
|
|
55281
|
+
timer$1 = null;
|
|
55282
|
+
}
|
|
55283
|
+
//#endregion
|
|
55284
|
+
//#region services/cost-reconcile-service.ts
|
|
55285
|
+
const RECONCILE_INTERVAL_MS = 5 * 6e4;
|
|
55286
|
+
let timer = null;
|
|
55287
|
+
let inFlight = null;
|
|
55288
|
+
async function runCostReconcileOnce(reason) {
|
|
55289
|
+
if (inFlight) return inFlight;
|
|
55290
|
+
inFlight = (async () => {
|
|
55291
|
+
const result = await reconcilePiTranscripts();
|
|
55292
|
+
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)`);
|
|
55293
|
+
if (result.errors.length > 0) for (const err of result.errors.slice(0, 5)) console.warn(`[cost-reconciler] ${err.path}: ${err.error}`);
|
|
55294
|
+
})().finally(() => {
|
|
55295
|
+
inFlight = null;
|
|
55296
|
+
});
|
|
55297
|
+
return inFlight;
|
|
55298
|
+
}
|
|
55299
|
+
function startCostReconcileService() {
|
|
55300
|
+
if (timer) return;
|
|
55301
|
+
timer = setInterval(() => {
|
|
55302
|
+
runCostReconcileOnce("interval").catch((err) => {
|
|
55303
|
+
console.warn("[cost-reconciler] interval sweep failed:", err instanceof Error ? err.message : err);
|
|
55304
|
+
});
|
|
55305
|
+
}, RECONCILE_INTERVAL_MS);
|
|
55306
|
+
timer.unref?.();
|
|
55307
|
+
runCostReconcileOnce("startup").catch((err) => {
|
|
55308
|
+
console.warn("[cost-reconciler] startup sweep failed:", err instanceof Error ? err.message : err);
|
|
55309
|
+
});
|
|
55310
|
+
}
|
|
55311
|
+
function stopCostReconcileService() {
|
|
55312
|
+
if (timer) {
|
|
55313
|
+
clearInterval(timer);
|
|
55314
|
+
timer = null;
|
|
55315
|
+
}
|
|
55530
55316
|
}
|
|
55531
55317
|
//#endregion
|
|
55532
55318
|
//#region ../../lib/boot-gates.ts
|
|
@@ -55622,14 +55408,14 @@ function createOverdeckDatabase(options = {}) {
|
|
|
55622
55408
|
try {
|
|
55623
55409
|
applyMigration(db, migrationPath);
|
|
55624
55410
|
const tables = userTableNames(db);
|
|
55625
|
-
if (tables.length !==
|
|
55411
|
+
if (tables.length !== 30) throw new Error(`Expected 30 overdeck tables, found ${tables.length}: ${tables.join(", ")}`);
|
|
55626
55412
|
assertEmptyTables(db, tables);
|
|
55627
55413
|
} finally {
|
|
55628
55414
|
db.close();
|
|
55629
55415
|
}
|
|
55630
55416
|
return {
|
|
55631
55417
|
dbPath,
|
|
55632
|
-
tableCount:
|
|
55418
|
+
tableCount: 30
|
|
55633
55419
|
};
|
|
55634
55420
|
}
|
|
55635
55421
|
//#endregion
|
|
@@ -55645,7 +55431,11 @@ init_tracker_config();
|
|
|
55645
55431
|
init_review_status();
|
|
55646
55432
|
init_event_store();
|
|
55647
55433
|
init_activity_logger();
|
|
55648
|
-
|
|
55434
|
+
init_service();
|
|
55435
|
+
init_config$1();
|
|
55436
|
+
init_deacon();
|
|
55437
|
+
init_agents$2();
|
|
55438
|
+
init_agent_projection();
|
|
55649
55439
|
init_paths();
|
|
55650
55440
|
init_tmux();
|
|
55651
55441
|
init_fts_db();
|
|
@@ -55921,6 +55711,8 @@ syncTranscriptPollerRegistry().catch((err) => console.warn("[memory-poller] init
|
|
|
55921
55711
|
reconcileStaleTranscriptCheckpoints({ log: (message) => console.log(message) }).catch((err) => console.warn("[memory-reconciliation] startup sweep failed:", err?.message ?? err));
|
|
55922
55712
|
startTranscriptPoller();
|
|
55923
55713
|
console.log("[overdeck] Memory transcript poller started");
|
|
55714
|
+
startCostReconcileService();
|
|
55715
|
+
console.log("[overdeck] Cost reconciler started");
|
|
55924
55716
|
const conversationSearchWatcher = startConversationSearchWatcher();
|
|
55925
55717
|
console.log(conversationSearchWatcher ? "[overdeck] Conversation search watcher started" : "[overdeck] Conversation search watcher skipped (conversationSearch.enabled=false)");
|
|
55926
55718
|
(async () => {
|
|
@@ -55970,6 +55762,7 @@ const handleShutdownSignal = async (signal) => {
|
|
|
55970
55762
|
stopTtsPlayback();
|
|
55971
55763
|
stopAutoMergeExecutor();
|
|
55972
55764
|
stopTranscriptPoller();
|
|
55765
|
+
stopCostReconcileService();
|
|
55973
55766
|
stopRestartAnnouncer();
|
|
55974
55767
|
await stopConversationSearchWatcher().catch((err) => console.warn("[conversation-search] watcher shutdown failed:", err));
|
|
55975
55768
|
closeConversationSearchService();
|
|
@@ -56019,7 +55812,7 @@ reconcileStaleGitHubBlockers().then((n) => {
|
|
|
56019
55812
|
}
|
|
56020
55813
|
}).catch((err) => console.warn(`[overdeck] Startup blocker reconciliation failed: ${err.message}`));
|
|
56021
55814
|
try {
|
|
56022
|
-
const { resetProcessingToQueued } = await import("./merge-sync-
|
|
55815
|
+
const { resetProcessingToQueued } = await import("./merge-sync-CmpwVmNH.js");
|
|
56023
55816
|
const resetCount = resetProcessingToQueued();
|
|
56024
55817
|
if (resetCount > 0) {
|
|
56025
55818
|
console.log(`[overdeck] Reset ${resetCount} stuck merge queue entries to queued`);
|
|
@@ -56048,6 +55841,7 @@ if (process.env.OVERDECK_DISABLE_DEACON === "1") {
|
|
|
56048
55841
|
message: "Cloister auto-start skipped via OVERDECK_DISABLE_DEACON — deacon is not running"
|
|
56049
55842
|
});
|
|
56050
55843
|
} else if (shouldAutoStart()) {
|
|
55844
|
+
resetPatrolHeartbeatForStartup();
|
|
56051
55845
|
getCloisterService().start().catch((err) => {
|
|
56052
55846
|
console.error("[overdeck] Cloister auto-start failed:", err);
|
|
56053
55847
|
emitActivityEntrySync({
|