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
|
@@ -2,23 +2,36 @@ import { REMOTE_COMMAND_SCHEMA, REMOTE_R2_APPROVAL_SCHEMA, REMOTE_WORKER_REQUEST
|
|
|
2
2
|
import { nowIso, readJson, sha256, writeJsonAtomic } from '../fsx.js';
|
|
3
3
|
import { TelegramActionBroker, TelegramAuditLedger, TelegramTopicRegistry } from './ledgers.js';
|
|
4
4
|
import { TelegramBotApiError } from './bot-api.js';
|
|
5
|
+
import { telegramConfigPairing } from './config.js';
|
|
5
6
|
import { TelegramHubRouter } from './hub.js';
|
|
7
|
+
import { TelegramIngressSpool } from './ingress-spool.js';
|
|
6
8
|
import { TelegramMessageProjector, publicSafeText } from './messages.js';
|
|
7
|
-
import { asRecord, boundedIdentifier, cardFromSnapshot, commandView, emptyProjection, pickerAction, requestId, routeKey, snapshotSummary, successSummary, topicName } from './runtime-projection.js';
|
|
9
|
+
import { asRecord, boundedIdentifier, cardFromSnapshot, commandView, emptyProjection, pickerAction, requestId, routeKey, snapshotSummary, failureSummary, successSummary, topicName } from './runtime-projection.js';
|
|
8
10
|
export class TelegramHubRuntime {
|
|
9
11
|
options;
|
|
10
12
|
clients = new Map();
|
|
11
13
|
now;
|
|
14
|
+
pairedChatId;
|
|
12
15
|
constructor(options) {
|
|
13
16
|
this.options = options;
|
|
14
17
|
this.now = options.now ?? Date.now;
|
|
18
|
+
this.pairedChatId = telegramConfigPairing(options.config).chatId;
|
|
15
19
|
}
|
|
16
20
|
async initialize() {
|
|
17
21
|
return this.syncSessions();
|
|
18
22
|
}
|
|
19
23
|
async processUpdate(update) {
|
|
20
|
-
const routed = await this.
|
|
21
|
-
await this.
|
|
24
|
+
const routed = await this.prepareUpdate(update);
|
|
25
|
+
await this.executePreparedUpdate(update, routed);
|
|
26
|
+
return routed;
|
|
27
|
+
}
|
|
28
|
+
async prepareUpdate(update, options = {}) {
|
|
29
|
+
await this.acknowledgeCallback(update);
|
|
30
|
+
return this.options.router.handleUpdate(update, {
|
|
31
|
+
skipIdempotency: options.durablyAdmitted === true
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async executePreparedUpdate(update, routed) {
|
|
22
35
|
try {
|
|
23
36
|
if (routed.session_picker)
|
|
24
37
|
await this.sendSessionPicker(update);
|
|
@@ -26,9 +39,12 @@ export class TelegramHubRuntime {
|
|
|
26
39
|
await this.executeRoutedAction(update, routed);
|
|
27
40
|
}
|
|
28
41
|
catch (error) {
|
|
29
|
-
|
|
42
|
+
if (this.options.ingress)
|
|
43
|
+
throw error;
|
|
44
|
+
const handled = await this.reportEffectFailure(update, routed.action, error);
|
|
45
|
+
if (!handled)
|
|
46
|
+
throw error;
|
|
30
47
|
}
|
|
31
|
-
return routed;
|
|
32
48
|
}
|
|
33
49
|
async tick() {
|
|
34
50
|
const routes = await this.options.topics.list();
|
|
@@ -38,6 +54,7 @@ export class TelegramHubRuntime {
|
|
|
38
54
|
let changed = false;
|
|
39
55
|
for (const route of routes) {
|
|
40
56
|
try {
|
|
57
|
+
this.assertCurrentRoute(route);
|
|
41
58
|
const key = routeKey(route);
|
|
42
59
|
const row = state.sessions[key] ?? emptyProjection();
|
|
43
60
|
state.sessions[key] = row;
|
|
@@ -103,10 +120,12 @@ export class TelegramHubRuntime {
|
|
|
103
120
|
});
|
|
104
121
|
const snapshot = snapshotResponse.ok ? asRecord(snapshotResponse.data) : null;
|
|
105
122
|
let route = await this.options.topics.findBySession(target.machine_id, target.project_id, sessionId);
|
|
123
|
+
if (route && route.chat_id !== this.pairedChatId)
|
|
124
|
+
route = null;
|
|
106
125
|
if (!route) {
|
|
107
126
|
let messageThreadId = 0;
|
|
108
127
|
try {
|
|
109
|
-
const topic = await this.options.projector.createSessionTopic(this.
|
|
128
|
+
const topic = await this.options.projector.createSessionTopic(this.pairedChatId, topicName(target, sessionId, snapshot));
|
|
110
129
|
messageThreadId = topic.message_thread_id;
|
|
111
130
|
}
|
|
112
131
|
catch (error) {
|
|
@@ -118,11 +137,12 @@ export class TelegramHubRuntime {
|
|
|
118
137
|
machine_id: target.machine_id,
|
|
119
138
|
project_id: target.project_id,
|
|
120
139
|
session_id: sessionId,
|
|
121
|
-
chat_id: this.
|
|
140
|
+
chat_id: this.pairedChatId,
|
|
122
141
|
message_thread_id: messageThreadId,
|
|
123
142
|
pinned_message_id: null
|
|
124
143
|
});
|
|
125
144
|
}
|
|
145
|
+
this.assertCurrentRoute(route);
|
|
126
146
|
if (snapshot) {
|
|
127
147
|
const needsInitialProjection = route.pinned_message_id === null || !state.sessions[routeKey(route)];
|
|
128
148
|
await this.projectSnapshot(route, snapshot, state, needsInitialProjection);
|
|
@@ -146,53 +166,146 @@ export class TelegramHubRuntime {
|
|
|
146
166
|
const route = await this.options.topics.findBySession(action.machine_id, action.project_id, action.session_id);
|
|
147
167
|
if (!route)
|
|
148
168
|
throw new Error('telegram_action_route_missing');
|
|
169
|
+
this.assertCurrentRoute(route);
|
|
170
|
+
if (route.generation !== action.route_generation) {
|
|
171
|
+
throw new Error('telegram_action_route_generation_stale');
|
|
172
|
+
}
|
|
149
173
|
if (action.prompt === 'pick') {
|
|
150
|
-
|
|
174
|
+
const text = 'Session selected. Use this topic for typed SKS controls.';
|
|
175
|
+
await this.checkpointEffectless(update.update_id, text, action.status === 'claimed' ? 'resolved' : 'none');
|
|
176
|
+
await this.sendTelegramOnce(update.update_id, () => (this.options.projector.sendFinal({ route, text })));
|
|
151
177
|
if (action.status === 'claimed')
|
|
152
178
|
await this.options.actions.complete(action.action_id, 'resolved');
|
|
179
|
+
await this.options.ingress?.markAuditCompleted(update.update_id);
|
|
153
180
|
return;
|
|
154
181
|
}
|
|
155
182
|
if (routed.status === 'approval_required' && routed.callback_data) {
|
|
156
|
-
|
|
157
|
-
await this.
|
|
183
|
+
await this.checkpointEffectless(update.update_id, 'Cancel approval requested.', 'none');
|
|
184
|
+
const sent = await this.sendTelegramOnce(update.update_id, async () => {
|
|
185
|
+
const messageId = await this.options.projector.sendApproval(route, routed.callback_data);
|
|
186
|
+
return { method: 'sendMessage', message_id: messageId };
|
|
187
|
+
});
|
|
188
|
+
if (sent.newlyDelivered) {
|
|
189
|
+
await this.options.projector.setReaction(route, sent.receipt.message_id, 'needs_input');
|
|
190
|
+
}
|
|
191
|
+
await this.options.ingress?.markAuditCompleted(update.update_id);
|
|
158
192
|
return;
|
|
159
193
|
}
|
|
160
194
|
if (action.kind === 'input' && action.prompt === '/input') {
|
|
161
|
-
|
|
195
|
+
const text = 'Reply to this message with the exact Codex follow-up input.';
|
|
196
|
+
await this.checkpointEffectless(update.update_id, text, 'none');
|
|
197
|
+
await this.sendTelegramOnce(update.update_id, async () => ({
|
|
198
|
+
method: 'sendMessage',
|
|
199
|
+
message_id: await this.options.projector.requestInput({
|
|
200
|
+
route,
|
|
201
|
+
prompt: text,
|
|
202
|
+
placeholder: 'Send input to this session'
|
|
203
|
+
})
|
|
204
|
+
}));
|
|
205
|
+
await this.options.ingress?.markAuditCompleted(update.update_id);
|
|
162
206
|
return;
|
|
163
207
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
208
|
+
let execution = await this.options.ingress?.execution(update.update_id) ?? null;
|
|
209
|
+
let outcome = checkpointedOutcome(execution);
|
|
210
|
+
let responseData = null;
|
|
211
|
+
if (!outcome) {
|
|
212
|
+
await this.reactToUpdate(update, route, 'running');
|
|
213
|
+
await this.options.ingress?.markEffectDispatching(update.update_id);
|
|
214
|
+
try {
|
|
215
|
+
const response = await this.dispatch(route, action);
|
|
216
|
+
responseData = asRecord(response.receipt?.result ?? response.data);
|
|
217
|
+
const errorDelivery = response.error?.delivery;
|
|
218
|
+
outcome = {
|
|
219
|
+
effectState: response.ok
|
|
220
|
+
? 'applied'
|
|
221
|
+
: errorDelivery === 'not_dispatched'
|
|
222
|
+
? 'rejected'
|
|
223
|
+
: 'unknown',
|
|
224
|
+
effectReceipt: response.receipt
|
|
225
|
+
? `${response.receipt.command_id}:${response.receipt.status}`
|
|
226
|
+
: null,
|
|
227
|
+
finalText: response.ok
|
|
228
|
+
? successSummary(action, responseData)
|
|
229
|
+
: failureSummary(publicSafeText(response.error?.code ?? 'remote_command_failed'), errorDelivery),
|
|
230
|
+
decision: response.ok ? 'accepted' : 'rejected',
|
|
231
|
+
policyReason: response.ok
|
|
232
|
+
? 'effect_completed'
|
|
233
|
+
: publicSafeText(response.error?.code ?? 'effect_failed').slice(0, 160),
|
|
234
|
+
actionCompletion: action.status === 'claimed'
|
|
235
|
+
? response.ok || errorDelivery !== 'not_dispatched'
|
|
236
|
+
? 'resolved'
|
|
237
|
+
: 'cancelled'
|
|
238
|
+
: 'none'
|
|
239
|
+
};
|
|
174
240
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
241
|
+
catch (error) {
|
|
242
|
+
const delivery = error instanceof RemoteSshClientError ? error.delivery : 'unknown';
|
|
243
|
+
const code = error instanceof RemoteSshClientError
|
|
244
|
+
? `${error.code}:${delivery}`
|
|
245
|
+
: error instanceof Error
|
|
246
|
+
? publicSafeText(error.message || 'telegram_effect_failed').slice(0, 160)
|
|
247
|
+
: 'telegram_effect_failed';
|
|
248
|
+
outcome = {
|
|
249
|
+
effectState: delivery === 'not_dispatched' ? 'rejected' : 'unknown',
|
|
250
|
+
effectReceipt: null,
|
|
251
|
+
finalText: failureSummary(code, delivery),
|
|
252
|
+
decision: 'rejected',
|
|
253
|
+
policyReason: code,
|
|
254
|
+
actionCompletion: action.status === 'claimed'
|
|
255
|
+
? delivery === 'not_dispatched' ? 'cancelled' : 'resolved'
|
|
256
|
+
: 'none'
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
await this.options.ingress?.markEffectOutcome(update.update_id, outcome);
|
|
178
260
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
261
|
+
const sent = await this.sendTelegramOnce(update.update_id, () => (this.options.projector.sendFinal({ route, text: outcome.finalText })));
|
|
262
|
+
if (sent.newlyDelivered) {
|
|
263
|
+
if (outcome.decision === 'accepted' && responseData) {
|
|
264
|
+
if (commandView(action.prompt) === 'artifacts') {
|
|
265
|
+
await this.options.projector.sendArtifactManifest({
|
|
266
|
+
route,
|
|
267
|
+
artifacts: Array.isArray(responseData.artifacts) ? responseData.artifacts : []
|
|
268
|
+
}).catch(() => undefined);
|
|
269
|
+
}
|
|
270
|
+
if (responseData.schema === 'sks.remote-session-snapshot.v1') {
|
|
271
|
+
try {
|
|
272
|
+
const state = await this.readProjectionState();
|
|
273
|
+
await this.projectSnapshot(route, responseData, state, true);
|
|
274
|
+
await writeJsonAtomic(this.options.projectionStatePath, state);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
await this.reactToUpdate(update, route, outcome.decision === 'rejected'
|
|
281
|
+
? 'blocked'
|
|
282
|
+
: action.kind === 'cancel'
|
|
283
|
+
? 'blocked'
|
|
284
|
+
: action.kind === 'verify' || action.kind === 'input'
|
|
285
|
+
? 'verified'
|
|
286
|
+
: 'observed');
|
|
287
|
+
}
|
|
288
|
+
if (action.status === 'claimed' && outcome.actionCompletion !== 'none') {
|
|
289
|
+
await this.options.actions.complete(action.action_id, outcome.actionCompletion);
|
|
290
|
+
}
|
|
291
|
+
execution = await this.options.ingress?.execution(update.update_id) ?? execution;
|
|
292
|
+
if (execution?.audit_state !== 'completed') {
|
|
293
|
+
await this.options.audit.record({
|
|
294
|
+
update_id: update.update_id,
|
|
295
|
+
chat_id: route.chat_id,
|
|
296
|
+
topic_id: route.message_thread_id,
|
|
297
|
+
action_alias: update.callback_query?.data?.startsWith('cb:')
|
|
298
|
+
? update.callback_query.data.slice(3)
|
|
299
|
+
: null,
|
|
300
|
+
command_kind: action.kind,
|
|
301
|
+
decision: outcome.decision,
|
|
302
|
+
policy_reason: outcome.policyReason,
|
|
303
|
+
effect_receipt: outcome.effectReceipt,
|
|
304
|
+
telegram_delivery: 'delivered',
|
|
305
|
+
telegram_delivery_receipt: `${sent.receipt.method}:${sent.receipt.message_id}`
|
|
306
|
+
});
|
|
307
|
+
await this.options.ingress?.markAuditCompleted(update.update_id);
|
|
185
308
|
}
|
|
186
|
-
await this.options.audit.record({
|
|
187
|
-
update_id: update.update_id,
|
|
188
|
-
chat_id: route.chat_id,
|
|
189
|
-
topic_id: route.message_thread_id,
|
|
190
|
-
action_alias: update.callback_query?.data?.startsWith('cb:') ? update.callback_query.data.slice(3) : null,
|
|
191
|
-
command_kind: action.kind,
|
|
192
|
-
decision: response.ok ? 'accepted' : 'rejected',
|
|
193
|
-
policy_reason: response.ok ? 'effect_completed' : response.error?.code ?? 'effect_failed',
|
|
194
|
-
effect_receipt: response.receipt ? `${response.receipt.command_id}:${response.receipt.status}` : null
|
|
195
|
-
});
|
|
196
309
|
}
|
|
197
310
|
async dispatch(route, action) {
|
|
198
311
|
if (action.risk === 'R3')
|
|
@@ -260,40 +373,126 @@ export class TelegramHubRuntime {
|
|
|
260
373
|
const chatId = update.message?.chat.id ?? update.callback_query?.message?.chat.id;
|
|
261
374
|
if (chatId === undefined)
|
|
262
375
|
return;
|
|
376
|
+
if (String(chatId) !== this.pairedChatId)
|
|
377
|
+
throw new Error('telegram_route_identity_mismatch');
|
|
263
378
|
const routes = (await this.options.topics.list()).filter((route) => route.chat_id === String(chatId)).slice(0, 24);
|
|
379
|
+
for (const route of routes)
|
|
380
|
+
this.assertCurrentRoute(route);
|
|
264
381
|
if (!routes.length) {
|
|
265
|
-
|
|
382
|
+
const text = 'No registered SKS session topics are available. Run hub sync after the remote session index is configured.';
|
|
383
|
+
await this.checkpointEffectless(update.update_id, text, 'none');
|
|
384
|
+
await this.sendTelegramOnce(update.update_id, async () => ({
|
|
385
|
+
method: 'sendMessage',
|
|
386
|
+
message_id: await this.options.projector.sendFlat({ chatId: String(chatId), text })
|
|
387
|
+
}));
|
|
388
|
+
await this.options.ingress?.markAuditCompleted(update.update_id);
|
|
266
389
|
return;
|
|
267
390
|
}
|
|
391
|
+
const createdActions = await this.options.actions.createMany(routes.map((route) => ({
|
|
392
|
+
action: pickerAction(route, this.now(), update.update_id),
|
|
393
|
+
route: { chat_id: route.chat_id, message_thread_id: 0 }
|
|
394
|
+
})));
|
|
268
395
|
const buttons = [];
|
|
269
|
-
for (
|
|
270
|
-
const
|
|
271
|
-
const created =
|
|
396
|
+
for (let index = 0; index < routes.length; index += 1) {
|
|
397
|
+
const route = routes[index];
|
|
398
|
+
const created = createdActions[index];
|
|
272
399
|
buttons.push([{ text: `${route.machine_id} · ${route.project_id} · ${route.session_id}`.slice(0, 56), callback_data: created.callback_data }]);
|
|
273
400
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
401
|
+
const text = 'Choose a session. The bot will post into the exact private topic; subsequent controls must stay in that topic.';
|
|
402
|
+
await this.checkpointEffectless(update.update_id, text, 'none');
|
|
403
|
+
await this.sendTelegramOnce(update.update_id, async () => ({
|
|
404
|
+
method: 'sendMessage',
|
|
405
|
+
message_id: await this.options.projector.sendFlat({
|
|
406
|
+
chatId: String(chatId),
|
|
407
|
+
text,
|
|
408
|
+
replyMarkup: { inline_keyboard: buttons }
|
|
409
|
+
})
|
|
410
|
+
}));
|
|
411
|
+
await this.options.ingress?.markAuditCompleted(update.update_id);
|
|
412
|
+
}
|
|
413
|
+
async checkpointEffectless(updateId, finalText, actionCompletion) {
|
|
414
|
+
const execution = await this.options.ingress?.execution(updateId) ?? null;
|
|
415
|
+
if (checkpointedOutcome(execution))
|
|
416
|
+
return;
|
|
417
|
+
await this.options.ingress?.markEffectOutcome(updateId, {
|
|
418
|
+
effectState: 'applied',
|
|
419
|
+
effectReceipt: null,
|
|
420
|
+
finalText,
|
|
421
|
+
decision: 'accepted',
|
|
422
|
+
policyReason: 'telegram_projection_prepared',
|
|
423
|
+
actionCompletion
|
|
278
424
|
});
|
|
279
425
|
}
|
|
280
|
-
async
|
|
426
|
+
async sendTelegramOnce(updateId, send) {
|
|
427
|
+
const ingress = this.options.ingress;
|
|
428
|
+
if (!ingress)
|
|
429
|
+
return { receipt: await send(), newlyDelivered: true };
|
|
430
|
+
const execution = await ingress.execution(updateId);
|
|
431
|
+
if (!execution)
|
|
432
|
+
throw new Error('telegram_ingress_entry_missing');
|
|
433
|
+
if (execution.telegram_delivery === 'delivered') {
|
|
434
|
+
if (!execution.telegram_message_receipt) {
|
|
435
|
+
throw new Error('telegram_ingress_message_receipt_missing');
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
receipt: execution.telegram_message_receipt,
|
|
439
|
+
newlyDelivered: false
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
if (execution.telegram_delivery === 'dispatching'
|
|
443
|
+
|| execution.telegram_delivery === 'unknown') {
|
|
444
|
+
throw new Error('telegram_ingress_telegram_delivery_ambiguous');
|
|
445
|
+
}
|
|
446
|
+
await ingress.markTelegramDispatching(updateId);
|
|
447
|
+
try {
|
|
448
|
+
const receipt = await send();
|
|
449
|
+
await ingress.markTelegramDelivered(updateId, receipt);
|
|
450
|
+
return { receipt, newlyDelivered: true };
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
await ingress.markTelegramDeliveryFailure(updateId, telegramDeliveryFromError(error));
|
|
454
|
+
throw error;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
assertCurrentRoute(route) {
|
|
458
|
+
if (route.chat_id !== this.pairedChatId) {
|
|
459
|
+
throw new Error('telegram_route_identity_mismatch');
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
async acknowledgeCallback(update) {
|
|
281
463
|
const id = update.callback_query?.id;
|
|
282
464
|
if (!id)
|
|
283
465
|
return;
|
|
284
|
-
|
|
285
|
-
? routed.status === 'claimed' ? 'Approved; applying exact scope.' : 'Request accepted.'
|
|
286
|
-
: routed.status === 'already_resolved' ? 'Already resolved.' : `Request rejected: ${routed.status}`;
|
|
287
|
-
await this.options.projector.answerCallbackQuery(id, text, false).catch(() => undefined);
|
|
466
|
+
await this.options.projector.answerCallbackQuery(id, 'Request received. SKS will validate and apply the exact linked scope.', false).catch(() => undefined);
|
|
288
467
|
}
|
|
289
468
|
async reportEffectFailure(update, action, error) {
|
|
290
469
|
if (!action)
|
|
291
|
-
return;
|
|
470
|
+
return false;
|
|
292
471
|
const route = await this.options.topics.findBySession(action.machine_id, action.project_id, action.session_id);
|
|
293
472
|
if (!route)
|
|
294
|
-
return;
|
|
295
|
-
const code = error instanceof RemoteSshClientError
|
|
296
|
-
|
|
473
|
+
return false;
|
|
474
|
+
const code = error instanceof RemoteSshClientError
|
|
475
|
+
? `${error.code}:${error.delivery}`
|
|
476
|
+
: error instanceof Error
|
|
477
|
+
? publicSafeText(error.message || 'telegram_effect_failed').slice(0, 160)
|
|
478
|
+
: 'telegram_effect_failed';
|
|
479
|
+
if (action.status === 'claimed') {
|
|
480
|
+
const appliedOrUnknown = error instanceof RemoteSshClientError && error.delivery !== 'not_dispatched';
|
|
481
|
+
await this.options.actions.complete(action.action_id, appliedOrUnknown ? 'resolved' : 'cancelled');
|
|
482
|
+
}
|
|
483
|
+
let telegramDelivery = 'not_dispatched';
|
|
484
|
+
let telegramDeliveryReceipt = null;
|
|
485
|
+
try {
|
|
486
|
+
const final = await this.options.projector.sendFinal({
|
|
487
|
+
route,
|
|
488
|
+
text: `Remote action blocked: ${publicSafeText(code)}`
|
|
489
|
+
});
|
|
490
|
+
telegramDelivery = 'delivered';
|
|
491
|
+
telegramDeliveryReceipt = `${final.method}:${final.message_id}`;
|
|
492
|
+
}
|
|
493
|
+
catch (deliveryError) {
|
|
494
|
+
telegramDelivery = telegramDeliveryFromError(deliveryError);
|
|
495
|
+
}
|
|
297
496
|
await this.options.audit.record({
|
|
298
497
|
update_id: update.update_id,
|
|
299
498
|
chat_id: route.chat_id,
|
|
@@ -302,13 +501,15 @@ export class TelegramHubRuntime {
|
|
|
302
501
|
command_kind: action.kind,
|
|
303
502
|
decision: 'rejected',
|
|
304
503
|
policy_reason: code,
|
|
305
|
-
effect_receipt: null
|
|
504
|
+
effect_receipt: null,
|
|
505
|
+
telegram_delivery: telegramDelivery,
|
|
506
|
+
telegram_delivery_receipt: telegramDeliveryReceipt
|
|
306
507
|
});
|
|
307
|
-
|
|
308
|
-
await this.options.actions.complete(action.action_id, 'cancelled').catch(() => undefined);
|
|
508
|
+
return true;
|
|
309
509
|
}
|
|
310
510
|
async projectSnapshot(routeInput, snapshot, state, force = false) {
|
|
311
511
|
let route = routeInput;
|
|
512
|
+
this.assertCurrentRoute(route);
|
|
312
513
|
const key = routeKey(route);
|
|
313
514
|
const projection = state.sessions[key] ?? emptyProjection();
|
|
314
515
|
const digest = sha256(JSON.stringify(snapshot));
|
|
@@ -334,14 +535,28 @@ export class TelegramHubRuntime {
|
|
|
334
535
|
projection.snapshot_digest = digest;
|
|
335
536
|
if (draft.message_id)
|
|
336
537
|
projection.draft_message_id = draft.message_id;
|
|
337
|
-
if (snapshot.completion_verified === true
|
|
338
|
-
|
|
339
|
-
projection.
|
|
538
|
+
if (snapshot.completion_verified === true
|
|
539
|
+
&& projection.final_generation !== route.generation
|
|
540
|
+
&& projection.final_generation_unknown !== route.generation) {
|
|
541
|
+
try {
|
|
542
|
+
await this.options.projector.sendFinal({
|
|
543
|
+
route,
|
|
544
|
+
text: `Verified terminal session: ${route.session_id}. Machine gates and trust evidence are complete.`
|
|
545
|
+
});
|
|
546
|
+
projection.final_generation = route.generation;
|
|
547
|
+
projection.final_generation_unknown = null;
|
|
548
|
+
}
|
|
549
|
+
catch (error) {
|
|
550
|
+
if (telegramDeliveryFromError(error) !== 'unknown')
|
|
551
|
+
throw error;
|
|
552
|
+
projection.final_generation_unknown = route.generation;
|
|
553
|
+
}
|
|
340
554
|
}
|
|
341
555
|
state.sessions[key] = projection;
|
|
342
556
|
return true;
|
|
343
557
|
}
|
|
344
558
|
clientForRoute(route) {
|
|
559
|
+
this.assertCurrentRoute(route);
|
|
345
560
|
return this.clientForTarget(findRemoteSessionTarget(this.options.sessionIndex, route.machine_id, route.project_id));
|
|
346
561
|
}
|
|
347
562
|
clientForTarget(target) {
|
|
@@ -376,3 +591,23 @@ export class TelegramHubRuntime {
|
|
|
376
591
|
: { schema: 'sks.telegram-projection-state.v1', sessions: {} };
|
|
377
592
|
}
|
|
378
593
|
}
|
|
594
|
+
function telegramDeliveryFromError(error) {
|
|
595
|
+
return error instanceof TelegramBotApiError ? error.delivery : 'unknown';
|
|
596
|
+
}
|
|
597
|
+
function checkpointedOutcome(execution) {
|
|
598
|
+
if (!execution
|
|
599
|
+
|| !['applied', 'rejected', 'unknown'].includes(execution.effect_state)
|
|
600
|
+
|| !execution.final_text
|
|
601
|
+
|| !execution.decision
|
|
602
|
+
|| !execution.policy_reason) {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
return {
|
|
606
|
+
effectState: execution.effect_state,
|
|
607
|
+
effectReceipt: execution.effect_receipt,
|
|
608
|
+
finalText: execution.final_text,
|
|
609
|
+
decision: execution.decision,
|
|
610
|
+
policyReason: execution.policy_reason,
|
|
611
|
+
actionCompletion: execution.action_completion
|
|
612
|
+
};
|
|
613
|
+
}
|