sneakoscope 7.3.0 → 7.6.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/README.md +129 -10
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/codex-app-command.js +1 -1
- package/dist/cli/command-manifest-lite.js +4 -1
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
- package/dist/cli/install-helpers-codex-lb-config.js +114 -9
- package/dist/cli/install-helpers-install-support.js +6 -16
- package/dist/cli/install-helpers.js +788 -600
- package/dist/cli/router.js +30 -2
- package/dist/commands/codex-app.js +37 -1
- package/dist/commands/codex-lb.js +491 -300
- package/dist/config/skills-manifest.json +57 -71
- package/dist/core/align/align-route.js +127 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
- package/dist/core/codex-app/codex-app-restart.js +83 -0
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
- package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
- package/dist/core/codex-app/menubar/constants.js +5 -0
- package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
- package/dist/core/codex-app/menubar/installer.js +18 -0
- package/dist/core/codex-app/multi-provider-router.js +22 -10
- package/dist/core/codex-app/openrouter-activate.js +26 -1
- package/dist/core/codex-app.js +118 -26
- package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
- package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
- package/dist/core/codex-control/codex-task-runner.js +2 -2
- package/dist/core/codex-lb/capability-runner.js +204 -0
- package/dist/core/codex-lb/capability-types.js +1 -0
- package/dist/core/codex-lb/codex-lb-env.js +9 -13
- package/dist/core/codex-lb/codex-lb-setup.js +45 -8
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
- package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
- package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
- package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
- package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
- package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
- package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
- package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
- package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
- package/dist/core/codex-lb/desktop-controller.js +1410 -0
- package/dist/core/codex-lb/desktop-mode.js +32 -0
- package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
- package/dist/core/codex-lb/desktop-service.js +613 -0
- package/dist/core/codex-lb/legacy-migration.js +575 -0
- package/dist/core/codex-lb/migration-receipt.js +246 -0
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
- package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
- package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
- package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
- package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
- package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
- package/dist/core/codex-native/core-skill-manifest.js +22 -6
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
- package/dist/core/commands/align-command.js +220 -0
- package/dist/core/commands/image-ux-review-command.js +280 -68
- package/dist/core/commands/naruto-command.js +257 -8
- package/dist/core/commands/ppt-command.js +2 -2
- package/dist/core/commands/telegram-command.js +402 -34
- package/dist/core/commands/triwiki-command.js +11 -1
- package/dist/core/commands/triwiki-graph-command.js +160 -0
- package/dist/core/commands/wiki-command.js +100 -20
- package/dist/core/doctor/skill-legacy-surface.js +1 -3
- package/dist/core/errors/message.js +3 -0
- package/dist/core/evidence/evidence-freshness.js +14 -0
- package/dist/core/feature-fixtures.js +9 -1
- package/dist/core/feature-registry.js +5 -3
- package/dist/core/fsx.js +7 -3
- package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
- package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
- package/dist/core/hooks-runtime/hook-context.js +15 -2
- package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
- package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +33 -89
- package/dist/core/image-ux-review/callout-extraction.js +6 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
- package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
- package/dist/core/image-ux-review.js +230 -12
- package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
- package/dist/core/imagegen/imagegen-capability.js +10 -4
- package/dist/core/imagegen/require-imagegen.js +29 -5
- package/dist/core/init/skills.js +25 -13
- package/dist/core/init.js +1 -1
- package/dist/core/install/installed-package-smoke.js +157 -4
- package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
- package/dist/core/managed-path-safety.js +8 -10
- package/dist/core/mcp-config/backup.js +2 -4
- package/dist/core/mcp-config/config-reader.js +2 -4
- package/dist/core/mcp-config/scope.js +3 -5
- package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
- package/dist/core/naruto/context-graph-advisor.js +0 -0
- package/dist/core/perf/release-latency-slo.js +12 -6
- package/dist/core/pipeline-internals/runtime-core.js +78 -0
- package/dist/core/pipeline-internals/runtime-gates.js +5 -2
- package/dist/core/policy/latest-version-guidance.js +113 -0
- package/dist/core/ppt.js +8 -8
- package/dist/core/preflight/parallel-preflight-engine.js +1 -1
- package/dist/core/proof/auto-finalize.js +98 -6
- package/dist/core/proof/route-proof-gate.js +12 -1
- package/dist/core/proof/route-proof-policy.js +8 -8
- package/dist/core/release/gate-manifest.js +32 -1
- package/dist/core/release/npm-stage-contract.js +21 -0
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/release-gate-contract.js +5 -0
- package/dist/core/release/release-proof-io.js +1 -3
- package/dist/core/release/release-real-contract.js +5 -4
- package/dist/core/release/release-stamp-proof.js +1 -3
- package/dist/core/release/stage-publish.js +27 -0
- package/dist/core/remote/audit-idempotency.js +50 -18
- package/dist/core/remote/codex-public-activity.js +283 -0
- package/dist/core/remote/index.js +1 -0
- package/dist/core/remote/ssh-worker-client.js +4 -1
- package/dist/core/remote/worker.js +206 -27
- package/dist/core/research/research-adversarial-review.js +1 -3
- package/dist/core/research/research-claim-synthesizer.js +1 -3
- package/dist/core/research/research-falsification-runner.js +1 -3
- package/dist/core/research/research-source-evidence.js +1 -3
- package/dist/core/responses-stream.js +65 -19
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/design-policy.js +7 -2
- package/dist/core/routes/dollar-manifest-lite.js +2 -4
- package/dist/core/routes/evidence.js +1 -1
- package/dist/core/routes.js +30 -10
- package/dist/core/safety/command-contract/contracts.js +2 -0
- package/dist/core/safety/command-contract/types.js +1 -1
- package/dist/core/search/context-graph-seeds.js +205 -0
- package/dist/core/search/context.js +0 -0
- package/dist/core/search/provider.js +2 -2
- package/dist/core/secret-redaction.js +6 -0
- package/dist/core/subagents/naruto-help-contract.js +2 -1
- package/dist/core/subagents/naruto-host-credentials.js +161 -0
- package/dist/core/subagents/official-subagent-preparation.js +4 -1
- package/dist/core/subagents/official-subagent-prompt.js +44 -2
- package/dist/core/subagents/official-subagent-runner.js +26 -8
- package/dist/core/subagents/triwiki-attention.js +135 -123
- package/dist/core/telegram/bot-api.js +85 -10
- package/dist/core/telegram/center-snapshot.js +718 -0
- package/dist/core/telegram/config.js +158 -31
- package/dist/core/telegram/hub.js +288 -33
- package/dist/core/telegram/index.js +2 -0
- package/dist/core/telegram/ingress-spool.js +419 -0
- package/dist/core/telegram/ledgers.js +188 -29
- package/dist/core/telegram/messages.js +26 -6
- package/dist/core/telegram/owner-lock.js +10 -7
- package/dist/core/telegram/runtime-projection.js +38 -3
- package/dist/core/telegram/runtime.js +298 -63
- package/dist/core/telegram/service.js +137 -8
- package/dist/core/telegram/setup.js +291 -73
- package/dist/core/text/strings.js +3 -0
- package/dist/core/triwiki/code-pack.js +12 -120
- package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
- package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
- package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
- package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
- package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
- package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
- package/dist/core/triwiki/context-graph/contracts.js +236 -0
- package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
- package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
- package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
- package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
- package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
- package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
- package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
- package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
- package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
- package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
- package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
- package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
- package/dist/core/triwiki/context-graph/graph-index.js +143 -0
- package/dist/core/triwiki/context-graph/ids.js +0 -0
- package/dist/core/triwiki/context-graph/lint/index.js +0 -0
- package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
- package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
- package/dist/core/triwiki/context-graph/paths.js +116 -0
- package/dist/core/triwiki/context-graph/profiles.js +78 -0
- package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
- package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
- package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
- package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
- package/dist/core/triwiki/context-graph/projections/index.js +7 -0
- package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
- package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
- package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
- package/dist/core/triwiki/context-graph/query/explain.js +0 -0
- package/dist/core/triwiki/context-graph/query/index.js +178 -0
- package/dist/core/triwiki/context-graph/query/load.js +116 -0
- package/dist/core/triwiki/context-graph/query/pack.js +117 -0
- package/dist/core/triwiki/context-graph/query/rank.js +142 -0
- package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
- package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
- package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
- package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
- package/dist/core/triwiki/context-graph/query-types.js +29 -0
- package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
- package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
- package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
- package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
- package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
- package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
- package/dist/core/verification/context-graph-affected.js +271 -0
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
- package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
- package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
- package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
- package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
- package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
- package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
- package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
- package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
- package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
- package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
- package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
- package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
- package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
- package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
- package/dist/scripts/context-graph-check.js +191 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
- package/dist/scripts/gate-policy-audit-check.js +1 -1
- package/dist/scripts/helper-dedup-check.js +0 -2
- package/dist/scripts/installed-package-smoke-check.js +4 -1
- package/dist/scripts/latest-version-guidance-check.js +74 -0
- package/dist/scripts/release-metadata-check.js +21 -4
- package/dist/scripts/release-real-check.js +7 -0
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
- package/package.json +8 -3
- package/release-gates.v2.json +176 -1
- package/runtime-required-scripts.json +30 -0
- package/schemas/triwiki/context-graph.schema.json +119 -0
- package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
- package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
- package/dist/core/triwiki/code-index-scanner.js +0 -309
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { asRecordOrNull as asRecord } from '../json/records.js';
|
|
3
|
+
import { redactString } from '../secret-redaction.js';
|
|
4
|
+
import { redactRemoteValue } from './audit-idempotency.js';
|
|
5
|
+
const PUBLIC_DETAIL_BYTES = 2 * 1024;
|
|
6
|
+
export function publicCodexActivityFromItem(value, projectRoot) {
|
|
7
|
+
const item = asRecord(value);
|
|
8
|
+
if (!item)
|
|
9
|
+
return null;
|
|
10
|
+
const type = String(item.type || '');
|
|
11
|
+
const status = publicStatus(item.status);
|
|
12
|
+
const duration = publicInteger(item.durationMs);
|
|
13
|
+
if (type === 'commandExecution') {
|
|
14
|
+
return {
|
|
15
|
+
kind: 'command',
|
|
16
|
+
status,
|
|
17
|
+
title: 'Command execution',
|
|
18
|
+
detail: publicCommandSummary(item.command),
|
|
19
|
+
duration_ms: duration,
|
|
20
|
+
exit_code: publicInteger(item.exitCode)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (type === 'fileChange') {
|
|
24
|
+
const changes = Array.isArray(item.changes) ? item.changes.map(asRecord).filter(Boolean) : [];
|
|
25
|
+
const paths = changes
|
|
26
|
+
.map((change) => publicProjectPath(change.path, projectRoot))
|
|
27
|
+
.filter((entry) => Boolean(entry))
|
|
28
|
+
.slice(0, 12);
|
|
29
|
+
const omitted = Math.max(0, changes.length - paths.length);
|
|
30
|
+
return {
|
|
31
|
+
kind: 'file_change',
|
|
32
|
+
status,
|
|
33
|
+
title: `${changes.length} file change${changes.length === 1 ? '' : 's'}`,
|
|
34
|
+
detail: paths.length
|
|
35
|
+
? `${paths.join(', ')}${omitted ? ` · +${omitted} more` : ''}`
|
|
36
|
+
: null,
|
|
37
|
+
duration_ms: null,
|
|
38
|
+
exit_code: null
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (type === 'mcpToolCall') {
|
|
42
|
+
const server = publicCodexText(item.server, 120);
|
|
43
|
+
const tool = publicCodexText(item.tool, 160);
|
|
44
|
+
return {
|
|
45
|
+
kind: 'mcp_tool',
|
|
46
|
+
status,
|
|
47
|
+
title: [server, tool].filter(Boolean).join('.') || 'MCP tool',
|
|
48
|
+
detail: asRecord(item.error) ? 'Tool reported an error.' : null,
|
|
49
|
+
duration_ms: duration,
|
|
50
|
+
exit_code: null
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (type === 'dynamicToolCall') {
|
|
54
|
+
const namespace = publicCodexText(item.namespace, 120);
|
|
55
|
+
const tool = publicCodexText(item.tool, 160);
|
|
56
|
+
return {
|
|
57
|
+
kind: 'dynamic_tool',
|
|
58
|
+
status,
|
|
59
|
+
title: [namespace, tool].filter(Boolean).join('.') || 'Dynamic tool',
|
|
60
|
+
detail: item.success === false ? 'Tool reported failure.' : null,
|
|
61
|
+
duration_ms: duration,
|
|
62
|
+
exit_code: null
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (type === 'collabAgentToolCall') {
|
|
66
|
+
const receivers = Array.isArray(item.receiverThreadIds) ? item.receiverThreadIds.length : 0;
|
|
67
|
+
return {
|
|
68
|
+
kind: 'subagent_tool',
|
|
69
|
+
status,
|
|
70
|
+
title: `Subagent ${publicCodexText(item.tool, 120) || 'activity'}`,
|
|
71
|
+
detail: receivers ? `${receivers} target${receivers === 1 ? '' : 's'}` : null,
|
|
72
|
+
duration_ms: null,
|
|
73
|
+
exit_code: null
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (type === 'subAgentActivity') {
|
|
77
|
+
return {
|
|
78
|
+
kind: 'subagent',
|
|
79
|
+
status: publicStatus(item.kind),
|
|
80
|
+
title: `Subagent ${publicCodexText(item.kind, 80) || 'activity'}`,
|
|
81
|
+
detail: null,
|
|
82
|
+
duration_ms: null,
|
|
83
|
+
exit_code: null
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (type === 'webSearch') {
|
|
87
|
+
const action = asRecord(item.action);
|
|
88
|
+
const queryCount = Array.isArray(action?.queries)
|
|
89
|
+
? action.queries.length
|
|
90
|
+
: item.query || action?.query
|
|
91
|
+
? 1
|
|
92
|
+
: 0;
|
|
93
|
+
return {
|
|
94
|
+
kind: 'web_search',
|
|
95
|
+
status,
|
|
96
|
+
title: 'Web search',
|
|
97
|
+
detail: queryCount > 0 ? `${queryCount} bounded search request${queryCount === 1 ? '' : 's'}` : null,
|
|
98
|
+
duration_ms: null,
|
|
99
|
+
exit_code: null
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (type === 'plan') {
|
|
103
|
+
return {
|
|
104
|
+
kind: 'plan',
|
|
105
|
+
status,
|
|
106
|
+
title: 'Plan updated',
|
|
107
|
+
detail: null,
|
|
108
|
+
duration_ms: null,
|
|
109
|
+
exit_code: null
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (type === 'contextCompaction') {
|
|
113
|
+
return {
|
|
114
|
+
kind: 'compaction',
|
|
115
|
+
status: 'completed',
|
|
116
|
+
title: 'Context compacted',
|
|
117
|
+
detail: null,
|
|
118
|
+
duration_ms: null,
|
|
119
|
+
exit_code: null
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (type === 'imageGeneration') {
|
|
123
|
+
return {
|
|
124
|
+
kind: 'image_generation',
|
|
125
|
+
status,
|
|
126
|
+
title: 'Image generation',
|
|
127
|
+
detail: null,
|
|
128
|
+
duration_ms: duration,
|
|
129
|
+
exit_code: null
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (type === 'imageView') {
|
|
133
|
+
return {
|
|
134
|
+
kind: 'image_view',
|
|
135
|
+
status,
|
|
136
|
+
title: 'Image inspected',
|
|
137
|
+
detail: null,
|
|
138
|
+
duration_ms: null,
|
|
139
|
+
exit_code: null
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
if (type === 'sleep') {
|
|
143
|
+
return {
|
|
144
|
+
kind: 'wait',
|
|
145
|
+
status,
|
|
146
|
+
title: 'Waiting',
|
|
147
|
+
detail: null,
|
|
148
|
+
duration_ms: duration,
|
|
149
|
+
exit_code: null
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (type === 'enteredReviewMode' || type === 'exitedReviewMode') {
|
|
153
|
+
return {
|
|
154
|
+
kind: 'review',
|
|
155
|
+
status,
|
|
156
|
+
title: type === 'enteredReviewMode' ? 'Review started' : 'Review completed',
|
|
157
|
+
detail: null,
|
|
158
|
+
duration_ms: null,
|
|
159
|
+
exit_code: null
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
export function publicCodexJournalEvent(value, expectedThreadId, projectRoot) {
|
|
165
|
+
const event = asRecord(value);
|
|
166
|
+
const method = String(event?.method || '');
|
|
167
|
+
if (!['turn/started', 'turn/completed', 'item/started', 'item/completed'].includes(method))
|
|
168
|
+
return null;
|
|
169
|
+
const params = asRecord(event?.params);
|
|
170
|
+
const threadId = publicIdentifier(params?.threadId, 200);
|
|
171
|
+
if (!threadId || !expectedThreadId || threadId !== expectedThreadId)
|
|
172
|
+
return null;
|
|
173
|
+
const turn = asRecord(params?.turn);
|
|
174
|
+
const turnId = publicIdentifier(params?.turnId ?? turn?.id, 200);
|
|
175
|
+
if (!turnId)
|
|
176
|
+
return null;
|
|
177
|
+
if (method === 'turn/started' || method === 'turn/completed') {
|
|
178
|
+
const lifecycle = method.endsWith('started') ? 'started' : 'completed';
|
|
179
|
+
const status = publicStatus(turn?.status || lifecycle);
|
|
180
|
+
return {
|
|
181
|
+
type: lifecycle === 'started' ? 'codex.turn.started' : 'codex.turn.completed',
|
|
182
|
+
dedupe_key: `turn:${turnId}:${lifecycle}`,
|
|
183
|
+
turn_id: turnId,
|
|
184
|
+
item_id: null,
|
|
185
|
+
summary: {
|
|
186
|
+
thread_id: threadId,
|
|
187
|
+
turn_id: turnId,
|
|
188
|
+
kind: 'turn',
|
|
189
|
+
status,
|
|
190
|
+
title: lifecycle === 'started' ? 'Codex turn started' : `Codex turn ${status}`,
|
|
191
|
+
detail: null,
|
|
192
|
+
duration_ms: publicInteger(turn?.durationMs),
|
|
193
|
+
exit_code: null
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const item = asRecord(params?.item);
|
|
198
|
+
const itemId = publicIdentifier(item?.id, 240);
|
|
199
|
+
const activity = publicCodexActivityFromItem(item, projectRoot);
|
|
200
|
+
if (!itemId || !activity)
|
|
201
|
+
return null;
|
|
202
|
+
const lifecycle = method.endsWith('started') ? 'started' : 'completed';
|
|
203
|
+
return {
|
|
204
|
+
type: lifecycle === 'started' ? 'codex.item.started' : 'codex.item.completed',
|
|
205
|
+
dedupe_key: `item:${itemId}:${lifecycle}`,
|
|
206
|
+
turn_id: turnId,
|
|
207
|
+
item_id: itemId,
|
|
208
|
+
summary: {
|
|
209
|
+
thread_id: threadId,
|
|
210
|
+
turn_id: turnId,
|
|
211
|
+
item_id: itemId,
|
|
212
|
+
item_type: String(item?.type || 'unknown').slice(0, 80),
|
|
213
|
+
...activity
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
export function publicCodexText(value, maxBytes = PUBLIC_DETAIL_BYTES) {
|
|
218
|
+
if (typeof value !== 'string')
|
|
219
|
+
return null;
|
|
220
|
+
let text = redactString(String(redactRemoteValue(value)))
|
|
221
|
+
.replace(/\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g, '[REDACTED]')
|
|
222
|
+
.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, '[REDACTED]')
|
|
223
|
+
.replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, '[REDACTED]')
|
|
224
|
+
.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}\b/gi, 'Bearer [REDACTED]')
|
|
225
|
+
.replace(/((?:api[_-]?key|token|secret|password|passwd|authorization)\s*[:=]\s*)[^\s"',}]+/gi, '$1[REDACTED]')
|
|
226
|
+
.replace(/([?&](?:api[_-]?key|token|secret|password)=)[^&#\s]+/gi, '$1[REDACTED]')
|
|
227
|
+
.replace(/(?:\/Users|\/home|\/private|\/Volumes|\/etc|\/root)\/[^\s"'`]+(?:\/[^\s"'`]*)?/g, '[path-redacted]')
|
|
228
|
+
.replace(/\b[A-Za-z]:\\(?:[^\\\s"'`]+\\)*[^\\\s"'`]*/g, '[path-redacted]')
|
|
229
|
+
.trim();
|
|
230
|
+
if (!text)
|
|
231
|
+
return null;
|
|
232
|
+
if (Buffer.byteLength(text, 'utf8') <= maxBytes)
|
|
233
|
+
return text;
|
|
234
|
+
const suffix = '…';
|
|
235
|
+
const budget = Math.max(0, maxBytes - Buffer.byteLength(suffix, 'utf8'));
|
|
236
|
+
text = Buffer.from(text, 'utf8').subarray(0, budget).toString('utf8').replace(/\uFFFD+$/g, '');
|
|
237
|
+
return `${text}${suffix}`;
|
|
238
|
+
}
|
|
239
|
+
function publicProjectPath(value, projectRoot) {
|
|
240
|
+
if (typeof value !== 'string' || !value.trim())
|
|
241
|
+
return null;
|
|
242
|
+
const absolute = path.isAbsolute(value) ? path.resolve(value) : path.resolve(projectRoot, value);
|
|
243
|
+
const relative = path.relative(path.resolve(projectRoot), absolute);
|
|
244
|
+
if (!relative || relative === '.')
|
|
245
|
+
return path.basename(projectRoot);
|
|
246
|
+
if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
|
|
247
|
+
return '[outside-project]';
|
|
248
|
+
return publicCodexText(relative.split(path.sep).join('/'), 480);
|
|
249
|
+
}
|
|
250
|
+
function publicCommandSummary(value) {
|
|
251
|
+
if (typeof value !== 'string')
|
|
252
|
+
return null;
|
|
253
|
+
const tokens = value.trim().split(/\s+/).filter(Boolean);
|
|
254
|
+
while (tokens[0] && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0]))
|
|
255
|
+
tokens.shift();
|
|
256
|
+
if (tokens[0] && path.basename(tokens[0]) === 'env') {
|
|
257
|
+
tokens.shift();
|
|
258
|
+
while (tokens[0] && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[0]))
|
|
259
|
+
tokens.shift();
|
|
260
|
+
}
|
|
261
|
+
const executable = tokens[0]
|
|
262
|
+
? path.basename(tokens[0]).replace(/[^A-Za-z0-9._+-]/g, '').slice(0, 80)
|
|
263
|
+
: '';
|
|
264
|
+
if (!executable)
|
|
265
|
+
return null;
|
|
266
|
+
const safeSubcommands = new Set([
|
|
267
|
+
'build', 'check', 'diff', 'install', 'lint', 'list', 'run', 'status',
|
|
268
|
+
'test', 'typecheck', 'verify', '--check', '--version', '-v'
|
|
269
|
+
]);
|
|
270
|
+
const subcommand = tokens.slice(1, 3).find((token) => safeSubcommands.has(token));
|
|
271
|
+
return `Executable: ${executable}${subcommand ? ` · ${subcommand}` : ''}`;
|
|
272
|
+
}
|
|
273
|
+
function publicStatus(value) {
|
|
274
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
275
|
+
return text && /^[A-Za-z][A-Za-z0-9._-]{0,63}$/.test(text) ? text : 'unknown';
|
|
276
|
+
}
|
|
277
|
+
function publicIdentifier(value, maxLength) {
|
|
278
|
+
const text = typeof value === 'string' ? value.trim() : '';
|
|
279
|
+
return text && text.length <= maxLength && /^[A-Za-z0-9][A-Za-z0-9._:/-]*$/.test(text) ? text : null;
|
|
280
|
+
}
|
|
281
|
+
function publicInteger(value) {
|
|
282
|
+
return typeof value === 'number' && Number.isSafeInteger(value) ? value : null;
|
|
283
|
+
}
|
|
@@ -7,6 +7,7 @@ export * from './owner-proof.js';
|
|
|
7
7
|
export * from './protocol.js';
|
|
8
8
|
export * from './session-snapshot.js';
|
|
9
9
|
export * from './session-binding.js';
|
|
10
|
+
export * from './codex-public-activity.js';
|
|
10
11
|
export * from './worker.js';
|
|
11
12
|
export * from './ssh-worker-client.js';
|
|
12
13
|
export * from './local-worker-client.js';
|
|
@@ -22,6 +22,7 @@ export class RemoteSshWorkerClient {
|
|
|
22
22
|
projectId;
|
|
23
23
|
sshCommand;
|
|
24
24
|
requestTimeoutMs;
|
|
25
|
+
commandRequestTimeoutMs;
|
|
25
26
|
maxResponseLineBytes;
|
|
26
27
|
maxConnectionOutputBytes;
|
|
27
28
|
reconnectAttempts;
|
|
@@ -46,6 +47,8 @@ export class RemoteSshWorkerClient {
|
|
|
46
47
|
this.projectId = options.projectId;
|
|
47
48
|
this.sshCommand = options.sshCommand ?? 'ssh';
|
|
48
49
|
this.requestTimeoutMs = Math.max(1_000, options.requestTimeoutMs ?? 30_000);
|
|
50
|
+
this.commandRequestTimeoutMs = Math.max(1_000, options.commandRequestTimeoutMs
|
|
51
|
+
?? (options.requestTimeoutMs === undefined ? 31 * 60_000 : options.requestTimeoutMs));
|
|
49
52
|
this.maxResponseLineBytes = Math.max(4_096, options.maxResponseLineBytes ?? 512 * 1024);
|
|
50
53
|
this.maxConnectionOutputBytes = Math.max(this.maxResponseLineBytes, options.maxConnectionOutputBytes ?? 8 * 1024 * 1024);
|
|
51
54
|
this.reconnectAttempts = Math.max(1, Math.min(10, options.reconnectAttempts ?? 4));
|
|
@@ -167,7 +170,7 @@ export class RemoteSshWorkerClient {
|
|
|
167
170
|
const delivery = pending?.dispatched ? 'unknown' : 'not_dispatched';
|
|
168
171
|
reject(new RemoteSshClientError(delivery === 'unknown' ? 'delivery_unknown' : 'disconnected_before_dispatch', delivery, delivery === 'not_dispatched' || request.type !== 'command'));
|
|
169
172
|
this.abortConnection('ssh_request_timeout');
|
|
170
|
-
}, this.requestTimeoutMs);
|
|
173
|
+
}, request.type === 'command' ? this.commandRequestTimeoutMs : this.requestTimeoutMs);
|
|
171
174
|
timer.unref?.();
|
|
172
175
|
const pending = { request, resolve, reject, timer, dispatched: false };
|
|
173
176
|
this.pending.set(request.id, pending);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
2
|
import fsp from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { createCodexAppServerV2Client } from '../codex-control/codex-app-server-v2-client.js';
|
|
4
|
+
import { CodexAppServerRequestError, createCodexAppServerV2Client } from '../codex-control/codex-app-server-v2-client.js';
|
|
5
|
+
import { CodexAppServerRuntimeEnvError, prepareCodexAppServerRuntimeEnv } from '../codex-control/codex-app-server-runtime-env.js';
|
|
5
6
|
import { RemoteAuditLog, RemoteCommandLedger, RemoteEventJournal, remoteRuntimePaths } from './audit-idempotency.js';
|
|
6
7
|
import { cancelOwnedSession, parseRemoteCancelPayload, RemoteOwnerProofError, RemoteOwnerProofStore } from './owner-proof.js';
|
|
7
8
|
import { RemoteProtocolError, workerErrorResponse, workerSuccessResponse } from './protocol.js';
|
|
@@ -9,6 +10,12 @@ import { RemoteCodexSessionBindingStore, readRemoteCodexBindingSnapshot, remoteC
|
|
|
9
10
|
import { listRemoteSessionRows, readRemoteSessionView, readRemoteSessionSnapshot, remoteSessionGeneration, remoteSessionRecord } from './session-snapshot.js';
|
|
10
11
|
import { REMOTE_COMMAND_RECEIPT_SCHEMA } from './types.js';
|
|
11
12
|
import { asRecordOrNull as asRecord } from '../json/records.js';
|
|
13
|
+
import { publicCodexJournalEvent } from './codex-public-activity.js';
|
|
14
|
+
const MAX_PUBLIC_CODEX_JOURNAL_EVENTS_PER_TURN = 256;
|
|
15
|
+
const PUBLIC_CODEX_JOURNAL_FLUSH_BATCH_SIZE = 8;
|
|
16
|
+
const PUBLIC_CODEX_JOURNAL_FLUSH_INTERVAL_MS = 400;
|
|
17
|
+
const PUBLIC_CODEX_JOURNAL_FLUSH_DEADLINE_MS = 750;
|
|
18
|
+
const TELEGRAM_CODEX_DEVELOPER_INSTRUCTIONS = 'This is a dedicated private Telegram coding thread. Work only inside the configured project workspace, never expose secrets, and return a concise user-facing final response for each turn.';
|
|
12
19
|
export class RemoteWorkerExecutionError extends Error {
|
|
13
20
|
code;
|
|
14
21
|
delivery;
|
|
@@ -41,7 +48,10 @@ export class RemoteWorker {
|
|
|
41
48
|
const paths = remoteRuntimePaths(this.root);
|
|
42
49
|
this.commands = options.commandLedger ?? new RemoteCommandLedger(paths.commands, { lockPath: paths.commandLock });
|
|
43
50
|
this.audit = options.audit ?? new RemoteAuditLog(paths.audit);
|
|
44
|
-
this.events = options.events ?? new RemoteEventJournal(paths.events, {
|
|
51
|
+
this.events = options.events ?? new RemoteEventJournal(paths.events, {
|
|
52
|
+
lockPath: paths.eventLock,
|
|
53
|
+
healthPath: paths.eventHealth
|
|
54
|
+
});
|
|
45
55
|
this.owners = options.owners ?? new RemoteOwnerProofStore(paths.owners);
|
|
46
56
|
this.bindings = options.bindings ?? new RemoteCodexSessionBindingStore(remoteCodexSessionBindingsPath(this.root));
|
|
47
57
|
this.codexClientFactory = options.codexClientFactory ?? defaultCodexClientFactory;
|
|
@@ -295,7 +305,9 @@ export class RemoteWorker {
|
|
|
295
305
|
if (!owner.codex_thread_id || !owner.active_turn_id)
|
|
296
306
|
throw new RemoteWorkerExecutionError('codex_turn_binding_missing');
|
|
297
307
|
const client = await this.codexClientFactory(this.root).catch((err) => {
|
|
298
|
-
|
|
308
|
+
if (err instanceof CodexAppServerRuntimeEnvError) {
|
|
309
|
+
throw new RemoteWorkerExecutionError(err.code, 'not_dispatched', true);
|
|
310
|
+
}
|
|
299
311
|
throw new RemoteWorkerExecutionError('codex_app_server_unavailable', 'not_dispatched', true);
|
|
300
312
|
});
|
|
301
313
|
try {
|
|
@@ -306,7 +318,7 @@ export class RemoteWorker {
|
|
|
306
318
|
threadId: owner.codex_thread_id,
|
|
307
319
|
clientUserMessageId: crypto.randomUUID(),
|
|
308
320
|
expectedTurnId: owner.active_turn_id,
|
|
309
|
-
input: [{ type: 'text', text
|
|
321
|
+
input: [{ type: 'text', text }]
|
|
310
322
|
});
|
|
311
323
|
}
|
|
312
324
|
catch (err) {
|
|
@@ -397,14 +409,96 @@ export class RemoteWorker {
|
|
|
397
409
|
}
|
|
398
410
|
}
|
|
399
411
|
async runDedicatedCodexTurn(binding, text) {
|
|
400
|
-
const client = await this.codexClientFactory(this.root).catch(() => {
|
|
412
|
+
const client = await this.codexClientFactory(this.root).catch((err) => {
|
|
413
|
+
if (err instanceof CodexAppServerRuntimeEnvError) {
|
|
414
|
+
throw new RemoteWorkerExecutionError(err.code, 'not_dispatched', true);
|
|
415
|
+
}
|
|
401
416
|
throw new RemoteWorkerExecutionError('codex_app_server_unavailable', 'not_dispatched', true);
|
|
402
417
|
});
|
|
403
418
|
const threadWasPersisted = Boolean(binding.codex_thread_id);
|
|
404
419
|
let threadId = binding.codex_thread_id;
|
|
405
420
|
let turnId = null;
|
|
421
|
+
let disposeEvents = null;
|
|
422
|
+
let journalEventCount = 0;
|
|
423
|
+
let journalTruncationRecorded = false;
|
|
424
|
+
const journalEvents = [];
|
|
425
|
+
let journalFlushTimer = null;
|
|
426
|
+
let journalFlushFailure = null;
|
|
427
|
+
let journalFlushChain = Promise.resolve();
|
|
428
|
+
const flushJournalEvents = () => {
|
|
429
|
+
if (journalFlushTimer) {
|
|
430
|
+
clearTimeout(journalFlushTimer);
|
|
431
|
+
journalFlushTimer = null;
|
|
432
|
+
}
|
|
433
|
+
if (journalEvents.length === 0 || journalFlushFailure)
|
|
434
|
+
return journalFlushChain;
|
|
435
|
+
const batch = journalEvents.splice(0, journalEvents.length);
|
|
436
|
+
journalFlushChain = journalFlushChain.then(async () => {
|
|
437
|
+
if (journalFlushFailure)
|
|
438
|
+
return;
|
|
439
|
+
const outcome = await settleWithin(this.events.appendMany(batch), PUBLIC_CODEX_JOURNAL_FLUSH_DEADLINE_MS);
|
|
440
|
+
if (outcome !== 'completed')
|
|
441
|
+
journalFlushFailure = outcome;
|
|
442
|
+
});
|
|
443
|
+
return journalFlushChain;
|
|
444
|
+
};
|
|
445
|
+
const scheduleJournalFlush = () => {
|
|
446
|
+
if (journalFlushFailure || journalFlushTimer)
|
|
447
|
+
return;
|
|
448
|
+
if (journalEvents.length >= PUBLIC_CODEX_JOURNAL_FLUSH_BATCH_SIZE) {
|
|
449
|
+
void flushJournalEvents();
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
journalFlushTimer = setTimeout(() => {
|
|
453
|
+
journalFlushTimer = null;
|
|
454
|
+
void flushJournalEvents();
|
|
455
|
+
}, PUBLIC_CODEX_JOURNAL_FLUSH_INTERVAL_MS);
|
|
456
|
+
journalFlushTimer.unref?.();
|
|
457
|
+
};
|
|
406
458
|
try {
|
|
407
|
-
await client.initialize()
|
|
459
|
+
await client.initialize().catch((error) => {
|
|
460
|
+
throw codexStageExecutionError('initialize', error);
|
|
461
|
+
});
|
|
462
|
+
if (client.onEvent) {
|
|
463
|
+
disposeEvents = client.onEvent((event) => {
|
|
464
|
+
const projected = publicCodexJournalEvent(event, threadId, this.root);
|
|
465
|
+
if (!projected)
|
|
466
|
+
return;
|
|
467
|
+
if (journalEventCount >= MAX_PUBLIC_CODEX_JOURNAL_EVENTS_PER_TURN) {
|
|
468
|
+
if (!journalTruncationRecorded) {
|
|
469
|
+
journalTruncationRecorded = true;
|
|
470
|
+
journalEvents.push({
|
|
471
|
+
type: 'codex.activity.truncated',
|
|
472
|
+
session_id: binding.session_id,
|
|
473
|
+
command_id: null,
|
|
474
|
+
summary: {
|
|
475
|
+
thread_id: threadId,
|
|
476
|
+
turn_id: projected.turn_id,
|
|
477
|
+
kind: 'activity',
|
|
478
|
+
status: 'truncated',
|
|
479
|
+
title: 'Live activity journal reached its per-turn limit',
|
|
480
|
+
detail: `Historical thread projection remains available after completion; live journal limit is ${MAX_PUBLIC_CODEX_JOURNAL_EVENTS_PER_TURN} events.`,
|
|
481
|
+
duration_ms: null,
|
|
482
|
+
exit_code: null
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
scheduleJournalFlush();
|
|
486
|
+
}
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
journalEventCount += 1;
|
|
490
|
+
journalEvents.push({
|
|
491
|
+
type: projected.type,
|
|
492
|
+
session_id: binding.session_id,
|
|
493
|
+
command_id: null,
|
|
494
|
+
summary: {
|
|
495
|
+
dedupe_key: projected.dedupe_key,
|
|
496
|
+
...projected.summary
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
scheduleJournalFlush();
|
|
500
|
+
});
|
|
501
|
+
}
|
|
408
502
|
if (!client.resumeThread || !client.startTurn || !client.readThread || !client.waitForTurnCompletion) {
|
|
409
503
|
throw new RemoteWorkerExecutionError('codex_app_server_session_api_unavailable', 'not_dispatched', false);
|
|
410
504
|
}
|
|
@@ -414,7 +508,8 @@ export class RemoteWorker {
|
|
|
414
508
|
threadId,
|
|
415
509
|
cwd: this.root,
|
|
416
510
|
approvalPolicy: 'never',
|
|
417
|
-
sandbox: 'workspace-write'
|
|
511
|
+
sandbox: 'workspace-write',
|
|
512
|
+
developerInstructions: TELEGRAM_CODEX_DEVELOPER_INSTRUCTIONS
|
|
418
513
|
}));
|
|
419
514
|
const resumedThread = asRecord(resumed?.thread);
|
|
420
515
|
if (String(resumedThread?.id ?? '') !== threadId)
|
|
@@ -436,6 +531,9 @@ export class RemoteWorker {
|
|
|
436
531
|
throw new RemoteWorkerExecutionError(missingRollout ? 'codex_thread_history_missing' : 'codex_thread_resume_failed', 'not_dispatched', !missingRollout);
|
|
437
532
|
}
|
|
438
533
|
if (!missingRollout) {
|
|
534
|
+
if (isCodexAppServerContractError(err)) {
|
|
535
|
+
throw new RemoteWorkerExecutionError('codex_thread_resume_contract_invalid', 'not_dispatched', false);
|
|
536
|
+
}
|
|
439
537
|
throw new RemoteWorkerExecutionError('codex_thread_resume_failed', 'not_dispatched', true);
|
|
440
538
|
}
|
|
441
539
|
threadId = null;
|
|
@@ -449,14 +547,15 @@ export class RemoteWorker {
|
|
|
449
547
|
cwd: this.root,
|
|
450
548
|
approvalPolicy: 'never',
|
|
451
549
|
sandbox: 'workspace-write',
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}).catch(() => {
|
|
455
|
-
throw
|
|
550
|
+
serviceName: 'sneakoscope_telegram',
|
|
551
|
+
developerInstructions: TELEGRAM_CODEX_DEVELOPER_INSTRUCTIONS
|
|
552
|
+
}).catch((error) => {
|
|
553
|
+
throw codexStageExecutionError('thread_start', error);
|
|
456
554
|
}));
|
|
457
555
|
threadId = stringValue(asRecord(started?.thread)?.id);
|
|
458
|
-
if (!threadId)
|
|
459
|
-
throw new
|
|
556
|
+
if (!threadId) {
|
|
557
|
+
throw new RemoteWorkerExecutionError('codex_thread_start_missing_id', 'unknown', false);
|
|
558
|
+
}
|
|
460
559
|
}
|
|
461
560
|
const started = asRecord(await client.startTurn({
|
|
462
561
|
threadId,
|
|
@@ -468,20 +567,29 @@ export class RemoteWorker {
|
|
|
468
567
|
networkAccess: false
|
|
469
568
|
},
|
|
470
569
|
clientUserMessageId: crypto.randomUUID(),
|
|
471
|
-
input: [{ type: 'text', text
|
|
570
|
+
input: [{ type: 'text', text }]
|
|
571
|
+
}).catch((error) => {
|
|
572
|
+
throw codexStageExecutionError('turn_start', error);
|
|
472
573
|
}));
|
|
473
574
|
turnId = stringValue(asRecord(started?.turn)?.id);
|
|
474
|
-
if (!turnId)
|
|
475
|
-
throw new
|
|
476
|
-
|
|
477
|
-
|
|
575
|
+
if (!turnId) {
|
|
576
|
+
throw new RemoteWorkerExecutionError('codex_turn_start_missing_id', 'unknown', false);
|
|
577
|
+
}
|
|
578
|
+
await client.waitForTurnCompletion(threadId, turnId, 30 * 60_000).catch(() => {
|
|
579
|
+
throw new RemoteWorkerExecutionError('codex_turn_completion_unknown', 'acknowledged', false);
|
|
580
|
+
});
|
|
581
|
+
const read = asRecord(await client.readThread(threadId, true).catch(() => {
|
|
582
|
+
throw new RemoteWorkerExecutionError('codex_turn_result_unavailable', 'acknowledged', false);
|
|
583
|
+
}));
|
|
478
584
|
const thread = asRecord(read?.thread);
|
|
479
|
-
if (String(thread?.id ?? '') !== threadId)
|
|
480
|
-
throw new
|
|
585
|
+
if (String(thread?.id ?? '') !== threadId) {
|
|
586
|
+
throw new RemoteWorkerExecutionError('codex_thread_read_mismatch', 'acknowledged', false);
|
|
587
|
+
}
|
|
481
588
|
const turns = Array.isArray(thread?.turns) ? thread.turns.map(asRecord).filter(Boolean) : [];
|
|
482
589
|
const turn = turns.find((candidate) => String(candidate.id ?? '') === turnId);
|
|
483
|
-
if (!turn)
|
|
484
|
-
throw new
|
|
590
|
+
if (!turn) {
|
|
591
|
+
throw new RemoteWorkerExecutionError('codex_completed_turn_missing', 'acknowledged', false);
|
|
592
|
+
}
|
|
485
593
|
const turnStatus = String(turn.status ?? '');
|
|
486
594
|
if (turnStatus !== 'completed') {
|
|
487
595
|
if (threadWasPersisted) {
|
|
@@ -501,9 +609,12 @@ export class RemoteWorker {
|
|
|
501
609
|
.map((item) => item.text)
|
|
502
610
|
.filter(Boolean)
|
|
503
611
|
.at(-1);
|
|
504
|
-
if (!finalMessage)
|
|
505
|
-
throw new
|
|
506
|
-
|
|
612
|
+
if (!finalMessage) {
|
|
613
|
+
throw new RemoteWorkerExecutionError('codex_final_response_missing', 'acknowledged', false);
|
|
614
|
+
}
|
|
615
|
+
await this.bindings.recordTurn(binding.session_id, threadId, turnId, 'completed').catch(() => {
|
|
616
|
+
throw new RemoteWorkerExecutionError('codex_session_binding_persist_failed', 'acknowledged', false);
|
|
617
|
+
});
|
|
507
618
|
return {
|
|
508
619
|
accepted: true,
|
|
509
620
|
control: 'codex_app_server_v2',
|
|
@@ -519,15 +630,52 @@ export class RemoteWorker {
|
|
|
519
630
|
if (threadWasPersisted && turnId && threadId) {
|
|
520
631
|
await this.bindings.recordTurn(binding.session_id, threadId, turnId, 'failed').catch(() => undefined);
|
|
521
632
|
}
|
|
522
|
-
throw new RemoteWorkerExecutionError(turnId ? 'codex_turn_failed' : '
|
|
633
|
+
throw new RemoteWorkerExecutionError(turnId ? 'codex_turn_failed' : 'codex_pre_dispatch_failed', turnId ? 'acknowledged' : 'not_dispatched', false);
|
|
523
634
|
}
|
|
524
635
|
finally {
|
|
636
|
+
disposeEvents?.();
|
|
637
|
+
if (journalFlushTimer) {
|
|
638
|
+
clearTimeout(journalFlushTimer);
|
|
639
|
+
journalFlushTimer = null;
|
|
640
|
+
}
|
|
641
|
+
const finalFlush = await settleWithin(flushJournalEvents(), PUBLIC_CODEX_JOURNAL_FLUSH_DEADLINE_MS * 2);
|
|
642
|
+
const flushFailure = journalFlushFailure
|
|
643
|
+
?? (finalFlush === 'completed' ? null : finalFlush);
|
|
644
|
+
if (flushFailure) {
|
|
645
|
+
await settleWithin(this.audit.append({
|
|
646
|
+
event: 'codex_public_activity_journal_failed',
|
|
647
|
+
session_id: binding.session_id,
|
|
648
|
+
turn_id: turnId,
|
|
649
|
+
error_code: flushFailure === 'timed_out'
|
|
650
|
+
? 'remote_event_journal_flush_timed_out'
|
|
651
|
+
: 'remote_event_journal_write_failed'
|
|
652
|
+
}), PUBLIC_CODEX_JOURNAL_FLUSH_DEADLINE_MS);
|
|
653
|
+
}
|
|
525
654
|
await client.close().catch(() => undefined);
|
|
526
655
|
}
|
|
527
656
|
}
|
|
528
657
|
}
|
|
658
|
+
async function settleWithin(promise, timeoutMs) {
|
|
659
|
+
return await new Promise((resolve) => {
|
|
660
|
+
let settled = false;
|
|
661
|
+
const finish = (outcome) => {
|
|
662
|
+
if (settled)
|
|
663
|
+
return;
|
|
664
|
+
settled = true;
|
|
665
|
+
clearTimeout(timer);
|
|
666
|
+
resolve(outcome);
|
|
667
|
+
};
|
|
668
|
+
const timer = setTimeout(() => finish('timed_out'), timeoutMs);
|
|
669
|
+
promise.then(() => finish('completed'), () => finish('failed'));
|
|
670
|
+
});
|
|
671
|
+
}
|
|
529
672
|
async function defaultCodexClientFactory(cwd) {
|
|
530
|
-
const
|
|
673
|
+
const env = await prepareCodexAppServerRuntimeEnv();
|
|
674
|
+
const created = await createCodexAppServerV2Client({
|
|
675
|
+
cwd,
|
|
676
|
+
env,
|
|
677
|
+
requestedBy: 'remote-worker'
|
|
678
|
+
});
|
|
531
679
|
return created.client;
|
|
532
680
|
}
|
|
533
681
|
function normalizeExecutionError(err) {
|
|
@@ -555,3 +703,34 @@ function isMissingCodexRolloutError(error) {
|
|
|
555
703
|
const message = error instanceof Error ? error.message : String(error);
|
|
556
704
|
return /no rollout found for thread id|thread(?:\/resume)?:? (?:thread )?(?:not found|not loaded)/i.test(message);
|
|
557
705
|
}
|
|
706
|
+
function codexStageExecutionError(stage, error) {
|
|
707
|
+
const contractInvalid = isCodexAppServerContractError(error);
|
|
708
|
+
if (stage === 'initialize') {
|
|
709
|
+
return new RemoteWorkerExecutionError(contractInvalid
|
|
710
|
+
? 'codex_app_server_initialize_contract_invalid'
|
|
711
|
+
: 'codex_app_server_initialize_failed', 'not_dispatched', !contractInvalid);
|
|
712
|
+
}
|
|
713
|
+
if (stage === 'thread_start') {
|
|
714
|
+
if (!isCodexAppServerMethodRejection(error, 'thread/start')) {
|
|
715
|
+
return new RemoteWorkerExecutionError('codex_thread_start_delivery_unknown', 'unknown', false);
|
|
716
|
+
}
|
|
717
|
+
return new RemoteWorkerExecutionError(contractInvalid ? 'codex_thread_start_contract_invalid' : 'codex_thread_start_failed', 'not_dispatched', false);
|
|
718
|
+
}
|
|
719
|
+
if (isCodexAppServerMethodRejection(error, 'turn/start')) {
|
|
720
|
+
return new RemoteWorkerExecutionError(contractInvalid ? 'codex_turn_start_contract_invalid' : 'codex_turn_start_rejected', 'not_dispatched', false);
|
|
721
|
+
}
|
|
722
|
+
return new RemoteWorkerExecutionError('codex_turn_start_delivery_unknown', 'unknown', false);
|
|
723
|
+
}
|
|
724
|
+
function isCodexAppServerContractError(error) {
|
|
725
|
+
if (error instanceof CodexAppServerRequestError && error.kind !== 'rpc_rejection')
|
|
726
|
+
return false;
|
|
727
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
728
|
+
return /invalid request|unknown variant|unknown field|invalid type|requires experimentalapi capability|method not found/i.test(message);
|
|
729
|
+
}
|
|
730
|
+
function isCodexAppServerMethodRejection(error, method) {
|
|
731
|
+
if (error instanceof CodexAppServerRequestError) {
|
|
732
|
+
return error.kind === 'rpc_rejection' && error.method === method;
|
|
733
|
+
}
|
|
734
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
735
|
+
return message.trimStart().startsWith(`${method}:`);
|
|
736
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fsp from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { nowIso, randomId, readJson, readText, sha256, writeJsonAtomic, writeTextAtomic } from '../fsx.js';
|
|
4
|
+
import { uniqueValues as unique } from '../text/strings.js';
|
|
4
5
|
import { buildOfficialSubagentPrompt } from '../subagents/official-subagent-prompt.js';
|
|
5
6
|
import { codexAppSessionKey, detectCodexAppSession, runOfficialSubagentWorkflow } from '../subagents/official-subagent-runner.js';
|
|
6
7
|
import { readOfficialSubagentConfig } from '../subagents/official-subagent-config.js';
|
|
@@ -1065,6 +1066,3 @@ function duplicates(values) {
|
|
|
1065
1066
|
}
|
|
1066
1067
|
return [...duplicates];
|
|
1067
1068
|
}
|
|
1068
|
-
function unique(values) {
|
|
1069
|
-
return [...new Set(values)];
|
|
1070
|
-
}
|