twinclaw 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/README.md +66 -0
  2. package/bin/npm-twinclaw.js +17 -0
  3. package/bin/run-twinbot-cli.js +36 -0
  4. package/bin/twinbot.js +4 -0
  5. package/bin/twinclaw.js +4 -0
  6. package/dist/api/handlers/browser.js +160 -0
  7. package/dist/api/handlers/callback.js +80 -0
  8. package/dist/api/handlers/config-validate.js +19 -0
  9. package/dist/api/handlers/health.js +117 -0
  10. package/dist/api/handlers/local-state-backup.js +118 -0
  11. package/dist/api/handlers/persona-state.js +59 -0
  12. package/dist/api/handlers/skill-packages.js +94 -0
  13. package/dist/api/router.js +278 -0
  14. package/dist/api/runtime-event-producer.js +99 -0
  15. package/dist/api/shared.js +82 -0
  16. package/dist/api/websocket-hub.js +305 -0
  17. package/dist/config/config-loader.js +2 -0
  18. package/dist/config/env-schema.js +202 -0
  19. package/dist/config/env-validator.js +223 -0
  20. package/dist/config/identity-bootstrap.js +115 -0
  21. package/dist/config/json-config.js +344 -0
  22. package/dist/config/workspace.js +186 -0
  23. package/dist/core/channels-cli.js +77 -0
  24. package/dist/core/cli.js +119 -0
  25. package/dist/core/context-assembly.js +33 -0
  26. package/dist/core/doctor.js +365 -0
  27. package/dist/core/gateway-cli.js +323 -0
  28. package/dist/core/gateway.js +416 -0
  29. package/dist/core/heartbeat.js +54 -0
  30. package/dist/core/install-cli.js +320 -0
  31. package/dist/core/lane-executor.js +134 -0
  32. package/dist/core/logs-cli.js +70 -0
  33. package/dist/core/onboarding.js +760 -0
  34. package/dist/core/pairing-cli.js +78 -0
  35. package/dist/core/secret-vault-cli.js +204 -0
  36. package/dist/core/types.js +1 -0
  37. package/dist/index.js +404 -0
  38. package/dist/interfaces/dispatcher.js +214 -0
  39. package/dist/interfaces/telegram_handler.js +82 -0
  40. package/dist/interfaces/tui-dashboard.js +53 -0
  41. package/dist/interfaces/whatsapp_handler.js +94 -0
  42. package/dist/release/cli.js +97 -0
  43. package/dist/release/mvp-gate-cli.js +118 -0
  44. package/dist/release/twinbot-config-schema.js +162 -0
  45. package/dist/release/twinclaw-config-schema.js +162 -0
  46. package/dist/services/block-chunker.js +174 -0
  47. package/dist/services/browser-service.js +334 -0
  48. package/dist/services/context-lifecycle.js +314 -0
  49. package/dist/services/db.js +1055 -0
  50. package/dist/services/delivery-tracker.js +110 -0
  51. package/dist/services/dm-pairing.js +245 -0
  52. package/dist/services/embedding-service.js +125 -0
  53. package/dist/services/file-watcher.js +125 -0
  54. package/dist/services/inbound-debounce.js +92 -0
  55. package/dist/services/incident-manager.js +516 -0
  56. package/dist/services/job-scheduler.js +176 -0
  57. package/dist/services/local-state-backup.js +682 -0
  58. package/dist/services/mcp-client-adapter.js +291 -0
  59. package/dist/services/mcp-server-manager.js +143 -0
  60. package/dist/services/model-router.js +927 -0
  61. package/dist/services/mvp-gate.js +845 -0
  62. package/dist/services/orchestration-service.js +422 -0
  63. package/dist/services/persona-state.js +256 -0
  64. package/dist/services/policy-engine.js +92 -0
  65. package/dist/services/proactive-notifier.js +94 -0
  66. package/dist/services/queue-service.js +146 -0
  67. package/dist/services/release-pipeline.js +652 -0
  68. package/dist/services/runtime-budget-governor.js +415 -0
  69. package/dist/services/secret-vault.js +704 -0
  70. package/dist/services/semantic-memory.js +249 -0
  71. package/dist/services/skill-package-manager.js +806 -0
  72. package/dist/services/skill-registry.js +122 -0
  73. package/dist/services/streaming-output.js +75 -0
  74. package/dist/services/stt-service.js +39 -0
  75. package/dist/services/tts-service.js +44 -0
  76. package/dist/skills/builtin.js +250 -0
  77. package/dist/skills/shell.js +87 -0
  78. package/dist/skills/types.js +1 -0
  79. package/dist/types/api.js +1 -0
  80. package/dist/types/context-budget.js +1 -0
  81. package/dist/types/doctor.js +1 -0
  82. package/dist/types/file-watcher.js +1 -0
  83. package/dist/types/incident.js +1 -0
  84. package/dist/types/local-state-backup.js +1 -0
  85. package/dist/types/mcp.js +1 -0
  86. package/dist/types/messaging.js +1 -0
  87. package/dist/types/model-routing.js +1 -0
  88. package/dist/types/mvp-gate.js +2 -0
  89. package/dist/types/orchestration.js +1 -0
  90. package/dist/types/persona-state.js +22 -0
  91. package/dist/types/policy.js +1 -0
  92. package/dist/types/reasoning-graph.js +1 -0
  93. package/dist/types/release.js +1 -0
  94. package/dist/types/reliability.js +1 -0
  95. package/dist/types/runtime-budget.js +1 -0
  96. package/dist/types/scheduler.js +1 -0
  97. package/dist/types/secret-vault.js +1 -0
  98. package/dist/types/skill-packages.js +1 -0
  99. package/dist/types/websocket.js +14 -0
  100. package/dist/utils/logger.js +57 -0
  101. package/dist/utils/retry.js +61 -0
  102. package/dist/utils/secret-scan.js +208 -0
  103. package/mcp-servers.json +179 -0
  104. package/package.json +81 -0
  105. package/skill-packages.json +92 -0
  106. package/skill-packages.lock.json +5 -0
  107. package/src/skills/builtin.ts +275 -0
  108. package/src/skills/shell.ts +118 -0
  109. package/src/skills/types.ts +30 -0
  110. package/src/types/api.ts +252 -0
  111. package/src/types/blessed-contrib.d.ts +4 -0
  112. package/src/types/context-budget.ts +76 -0
  113. package/src/types/doctor.ts +29 -0
  114. package/src/types/file-watcher.ts +26 -0
  115. package/src/types/incident.ts +57 -0
  116. package/src/types/local-state-backup.ts +121 -0
  117. package/src/types/mcp.ts +106 -0
  118. package/src/types/messaging.ts +35 -0
  119. package/src/types/model-routing.ts +61 -0
  120. package/src/types/mvp-gate.ts +99 -0
  121. package/src/types/orchestration.ts +65 -0
  122. package/src/types/persona-state.ts +61 -0
  123. package/src/types/policy.ts +27 -0
  124. package/src/types/reasoning-graph.ts +58 -0
  125. package/src/types/release.ts +115 -0
  126. package/src/types/reliability.ts +43 -0
  127. package/src/types/runtime-budget.ts +85 -0
  128. package/src/types/scheduler.ts +47 -0
  129. package/src/types/secret-vault.ts +62 -0
  130. package/src/types/skill-packages.ts +81 -0
  131. package/src/types/sqlite-vec.d.ts +5 -0
  132. package/src/types/websocket.ts +122 -0
@@ -0,0 +1,35 @@
1
+ /** Supported messaging platforms. */
2
+ export type Platform = 'telegram' | 'whatsapp';
3
+
4
+ /** A normalized inbound message from any supported platform. */
5
+ export interface InboundMessage {
6
+ platform: Platform;
7
+ /** The sender's user ID as a string (platform-specific). */
8
+ senderId: string;
9
+ /** The destination chat/channel ID used for reply routing. */
10
+ chatId: string | number;
11
+ /** Transcribed or raw text content of the message. */
12
+ text?: string;
13
+ /** Absolute path to a downloaded audio file, if the message is a voice note. */
14
+ audioFilePath?: string;
15
+ /** Original platform payload, kept for platform-specific extensions. */
16
+ rawPayload: unknown;
17
+ }
18
+
19
+ /** A normalized outbound response to be sent back to the user. */
20
+ export interface OutboundMessage {
21
+ platform: Platform;
22
+ chatId: string | number;
23
+ /** Plain-text response. */
24
+ text?: string;
25
+ /** Encoded audio buffer for a voice reply (mp3). */
26
+ audioBuffer?: Buffer;
27
+ }
28
+
29
+ /**
30
+ * Contract for the core gateway that processes normalized messages.
31
+ * Implemented by the core_persona track; imported here as a dependency boundary.
32
+ */
33
+ export interface GatewayHandler {
34
+ processMessage(message: InboundMessage): Promise<string>;
35
+ }
@@ -0,0 +1,61 @@
1
+ export type ModelRoutingFallbackMode = 'intelligent_pacing' | 'aggressive_fallback';
2
+
3
+ export type ModelRoutingEventType =
4
+ | 'attempt'
5
+ | 'success'
6
+ | 'failure'
7
+ | 'rate_limit'
8
+ | 'cooldown_set'
9
+ | 'cooldown_wait'
10
+ | 'cooldown_skip'
11
+ | 'failover'
12
+ | 'mode_change';
13
+
14
+ export interface ModelRoutingCooldownSnapshot {
15
+ modelId: string;
16
+ modelName: string;
17
+ provider: string;
18
+ reason: string;
19
+ remainingMs: number;
20
+ until: string;
21
+ }
22
+
23
+ export interface ModelRoutingUsageSnapshot {
24
+ modelId: string;
25
+ modelName: string;
26
+ provider: string;
27
+ attempts: number;
28
+ successes: number;
29
+ failures: number;
30
+ rateLimits: number;
31
+ lastUsedAt: string | null;
32
+ lastError: string | null;
33
+ }
34
+
35
+ export interface ModelRoutingEventSnapshot {
36
+ id: string;
37
+ type: ModelRoutingEventType;
38
+ modelId: string | null;
39
+ modelName: string | null;
40
+ provider: string | null;
41
+ fallbackMode: ModelRoutingFallbackMode;
42
+ detail: string;
43
+ createdAt: string;
44
+ }
45
+
46
+ export interface ModelRoutingTelemetrySnapshot {
47
+ fallbackMode: ModelRoutingFallbackMode;
48
+ preferredModelId: string | null;
49
+ currentModelId: string | null;
50
+ currentModelName: string | null;
51
+ totalRequests: number;
52
+ totalFailures: number;
53
+ consecutiveFailures: number;
54
+ failoverCount: number;
55
+ lastError: string | null;
56
+ lastFailureAt: string | null;
57
+ activeCooldowns: ModelRoutingCooldownSnapshot[];
58
+ usage: ModelRoutingUsageSnapshot[];
59
+ recentEvents: ModelRoutingEventSnapshot[];
60
+ operatorGuidance: string[];
61
+ }
@@ -0,0 +1,99 @@
1
+ // ─── MVP Gate Criterion IDs ──────────────────────────────────────────────────
2
+
3
+ /**
4
+ * Hard-gate IDs block the "go" verdict if they fail.
5
+ * Advisory IDs produce warnings only.
6
+ */
7
+ export type MvpHardGateId =
8
+ | 'build'
9
+ | 'tests'
10
+ | 'api-health'
11
+ | 'config-schema'
12
+ | 'vault-health'
13
+ | 'interface-readiness'
14
+ | 'npm-commands'
15
+ | 'installer-smoke'
16
+ | 'onboarding-smoke';
17
+
18
+ export type MvpAdvisoryId = 'dist-artifact' | 'test-coverage' | 'doctor-readiness';
19
+
20
+ export type MvpCriterionId = MvpHardGateId | MvpAdvisoryId;
21
+
22
+ export type MvpCriterionClass = 'hard-gate' | 'advisory';
23
+
24
+ export type MvpCheckStatus = 'passed' | 'failed' | 'skipped';
25
+
26
+ export type TriageSeverity = 'blocker' | 'advisory';
27
+
28
+ export type MvpGateVerdict = 'go' | 'no-go' | 'advisory-only';
29
+
30
+ // ─── Per-Check Result ────────────────────────────────────────────────────────
31
+
32
+ export interface MvpCheckResult {
33
+ id: MvpCriterionId;
34
+ class: MvpCriterionClass;
35
+ status: MvpCheckStatus;
36
+ detail: string;
37
+ startedAt: string;
38
+ completedAt: string;
39
+ durationMs: number;
40
+ command?: string;
41
+ artifacts?: string[];
42
+ }
43
+
44
+ // ─── Smoke Scenarios ─────────────────────────────────────────────────────────
45
+
46
+ /**
47
+ * A smoke scenario is a deterministic, side-effect-free static check of a
48
+ * critical runtime asset or configuration file.
49
+ */
50
+ export interface MvpSmokeScenario {
51
+ id: string;
52
+ label: string;
53
+ pass: boolean;
54
+ detail: string;
55
+ }
56
+
57
+ // ─── Failure Triage ──────────────────────────────────────────────────────────
58
+
59
+ /**
60
+ * Maps a failing check to its owning track/agent and a concrete next-action.
61
+ */
62
+ export interface TriageEntry {
63
+ checkId: MvpCriterionId;
64
+ severity: TriageSeverity;
65
+ ownerTrack: string;
66
+ detail: string;
67
+ nextAction: string;
68
+ }
69
+
70
+ // ─── Gate Report ─────────────────────────────────────────────────────────────
71
+
72
+ export interface MvpGateReport {
73
+ reportVersion: 1;
74
+ reportId: string;
75
+ generatedAt: string;
76
+ verdict: MvpGateVerdict;
77
+ hardGatePassed: boolean;
78
+ checks: MvpCheckResult[];
79
+ failedHardGates: MvpCheckResult[];
80
+ advisoryFailures: MvpCheckResult[];
81
+ smokeScenarios: MvpSmokeScenario[];
82
+ triage: TriageEntry[];
83
+ summary: string;
84
+ reportPath: string;
85
+ markdownPath: string;
86
+ }
87
+
88
+ // ─── Service Options ─────────────────────────────────────────────────────────
89
+
90
+ export interface MvpGateOptions {
91
+ /**
92
+ * URL of the health endpoint. If not provided, defaults to localhost:18789/health.
93
+ */
94
+ healthUrl?: string;
95
+ /**
96
+ * If true, skip the api-health hard gate entirely.
97
+ */
98
+ skipHealth?: boolean;
99
+ }
@@ -0,0 +1,65 @@
1
+ export type OrchestrationJobState =
2
+ | 'queued'
3
+ | 'running'
4
+ | 'completed'
5
+ | 'failed'
6
+ | 'cancelled';
7
+
8
+ /** Constraints applied to delegated sub-agent work. */
9
+ export interface DelegationConstraints {
10
+ toolBudget: number;
11
+ timeoutMs: number;
12
+ maxTurns: number;
13
+ }
14
+
15
+ /** Work brief for one delegated sub-agent. */
16
+ export interface DelegationBrief {
17
+ /** Stable node identifier within the delegation graph. */
18
+ id: string;
19
+ /** Upstream node IDs that must complete successfully first. */
20
+ dependsOn?: string[];
21
+ title: string;
22
+ objective: string;
23
+ scopedContext: string;
24
+ expectedOutput: string;
25
+ constraints: DelegationConstraints;
26
+ }
27
+
28
+ /** Context package prepared by the gateway for delegated jobs. */
29
+ export interface DelegationScope {
30
+ sessionId: string;
31
+ memoryContext: string;
32
+ recentMessages: Array<{
33
+ role: 'user' | 'assistant' | 'tool';
34
+ content: string;
35
+ }>;
36
+ }
37
+
38
+ /** One delegation request can spawn multiple jobs under the same parent turn. */
39
+ export interface DelegationRequest {
40
+ sessionId: string;
41
+ parentMessage: string;
42
+ scope: DelegationScope;
43
+ briefs: DelegationBrief[];
44
+ }
45
+
46
+ export interface OrchestrationJobSnapshot {
47
+ id: string;
48
+ sessionId: string;
49
+ parentMessage: string;
50
+ brief: DelegationBrief;
51
+ state: OrchestrationJobState;
52
+ attempt: number;
53
+ createdAt: string;
54
+ updatedAt: string;
55
+ startedAt?: string;
56
+ completedAt?: string;
57
+ output?: string;
58
+ error?: string;
59
+ }
60
+
61
+ export interface DelegationExecutionResult {
62
+ jobs: OrchestrationJobSnapshot[];
63
+ summary: string;
64
+ hasFailures: boolean;
65
+ }
@@ -0,0 +1,61 @@
1
+ export const PERSONA_DOCUMENT_KEYS = ['soul', 'identity', 'user'] as const;
2
+
3
+ export type PersonaDocumentKey = (typeof PERSONA_DOCUMENT_KEYS)[number];
4
+
5
+ export interface PersonaStateSnapshot {
6
+ revision: string;
7
+ updatedAt: string;
8
+ soul: string;
9
+ identity: string;
10
+ user: string;
11
+ }
12
+
13
+ export interface PersonaStateUpdateInput {
14
+ expectedRevision: unknown;
15
+ soul: unknown;
16
+ identity: unknown;
17
+ user: unknown;
18
+ }
19
+
20
+ export interface PersonaStateValidatedUpdateInput {
21
+ expectedRevision: string;
22
+ soul: string;
23
+ identity: string;
24
+ user: string;
25
+ }
26
+
27
+ export interface PersonaStateUpdateDiagnostics {
28
+ outcome: 'updated' | 'noop';
29
+ changedDocuments: PersonaDocumentKey[];
30
+ warnings: string[];
31
+ }
32
+
33
+ export interface PersonaStateUpdateResult {
34
+ state: PersonaStateSnapshot;
35
+ diagnostics: PersonaStateUpdateDiagnostics;
36
+ }
37
+
38
+ export class PersonaValidationError extends Error {
39
+ readonly hints: string[];
40
+
41
+ constructor(hints: string[]) {
42
+ super('Persona state validation failed.');
43
+ this.name = 'PersonaValidationError';
44
+ this.hints = hints;
45
+ }
46
+ }
47
+
48
+ export class PersonaConflictError extends Error {
49
+ readonly latestRevision: string;
50
+ readonly hints: string[];
51
+
52
+ constructor(latestRevision: string) {
53
+ super('Persona state is stale. Reload and retry.');
54
+ this.name = 'PersonaConflictError';
55
+ this.latestRevision = latestRevision;
56
+ this.hints = [
57
+ 'Reload persona state before saving again.',
58
+ 'Re-apply your edits on top of the latest revision.',
59
+ ];
60
+ }
61
+ }
@@ -0,0 +1,27 @@
1
+ export type PolicyAction = 'allow' | 'deny' | 'require_approval';
2
+
3
+ export interface PolicyRule {
4
+ /** The name of the skill to match. Can be '*' to match any skill. */
5
+ skillName: string;
6
+ /** The action to take if this rule matches. */
7
+ action: PolicyAction;
8
+ /** Optional reason explaining the policy rule. */
9
+ reason?: string;
10
+ }
11
+
12
+ export interface PolicyProfile {
13
+ id: string;
14
+ /**
15
+ * What to do if no rule matches.
16
+ * If 'fallback', it defers to the next profile in the chain (e.g., global default).
17
+ */
18
+ defaultAction: PolicyAction | 'fallback';
19
+ rules: PolicyRule[];
20
+ }
21
+
22
+ export interface PolicyDecision {
23
+ action: PolicyAction;
24
+ reason: string;
25
+ skillName: string;
26
+ profileId: string;
27
+ }
@@ -0,0 +1,58 @@
1
+ export type ReasoningNodeType = 'entity' | 'fact' | 'task' | 'artifact';
2
+
3
+ export type ReasoningEdgeRelation =
4
+ | 'supports'
5
+ | 'contradicts'
6
+ | 'depends_on'
7
+ | 'derived_from';
8
+
9
+ export interface ReasoningNodeUpsertInput {
10
+ nodeId: string;
11
+ claimKey: string;
12
+ nodeType: ReasoningNodeType;
13
+ sourceRole: string;
14
+ canonicalText: string;
15
+ polarity: 1 | -1;
16
+ confidence: number;
17
+ sessionId: string;
18
+ }
19
+
20
+ export interface ReasoningEdgeUpsertInput {
21
+ edgeId: string;
22
+ fromNodeId: string;
23
+ toNodeId: string;
24
+ relation: ReasoningEdgeRelation;
25
+ weight: number;
26
+ provenance: string;
27
+ }
28
+
29
+ export interface MemoryProvenanceRow {
30
+ memoryRowId: number;
31
+ nodeId: string;
32
+ claimKey: string;
33
+ nodeType: ReasoningNodeType;
34
+ polarity: 1 | -1;
35
+ canonicalText: string;
36
+ updatedAt: string;
37
+ supportsCount: number;
38
+ contradictsCount: number;
39
+ dependsCount: number;
40
+ derivedCount: number;
41
+ }
42
+
43
+ export interface ReasoningEdgeRow {
44
+ edgeId: string;
45
+ fromNodeId: string;
46
+ toNodeId: string;
47
+ relation: ReasoningEdgeRelation;
48
+ weight: number;
49
+ provenance: string;
50
+ updatedAt: string;
51
+ }
52
+
53
+ export interface EvidenceAwareMemoryContext {
54
+ context: string;
55
+ diagnostics: string[];
56
+ conflictCount: number;
57
+ hitCount: number;
58
+ }
@@ -0,0 +1,115 @@
1
+ export type ReleaseCheckId =
2
+ | 'build'
3
+ | 'tests'
4
+ | 'api-health'
5
+ | 'interface-readiness';
6
+
7
+ export type ReleaseCheckStatus = 'passed' | 'failed';
8
+
9
+ export interface ReleaseCheckResult {
10
+ id: ReleaseCheckId;
11
+ status: ReleaseCheckStatus;
12
+ detail: string;
13
+ command?: string;
14
+ startedAt: string;
15
+ completedAt: string;
16
+ durationMs: number;
17
+ }
18
+
19
+ export interface PreflightResult {
20
+ passed: boolean;
21
+ checks: ReleaseCheckResult[];
22
+ failedChecks: ReleaseCheckResult[];
23
+ }
24
+
25
+ export interface SnapshotAssetRecord {
26
+ key: string;
27
+ relativePath: string;
28
+ kind: 'file' | 'directory';
29
+ exists: boolean;
30
+ sourcePath: string;
31
+ snapshotPath: string;
32
+ }
33
+
34
+ export interface RuntimeSnapshotMetadata {
35
+ snapshotId: string;
36
+ releaseId: string;
37
+ createdAt: string;
38
+ retentionLimit: number;
39
+ assets: SnapshotAssetRecord[];
40
+ metadataPath: string;
41
+ }
42
+
43
+ export interface ArtifactPointer {
44
+ id: string;
45
+ path: string;
46
+ exists: boolean;
47
+ }
48
+
49
+ export type ReleaseManifestStatus = 'ready' | 'blocked' | 'rolled_back';
50
+
51
+ export interface ReleaseManifest {
52
+ manifestVersion: 1;
53
+ releaseId: string;
54
+ generatedAt: string;
55
+ appVersion: string;
56
+ gitCommit: string | null;
57
+ status: ReleaseManifestStatus;
58
+ preflight: PreflightResult;
59
+ snapshot?: {
60
+ snapshotId: string;
61
+ metadataPath: string;
62
+ };
63
+ artifacts: ArtifactPointer[];
64
+ diagnostics: string[];
65
+ manifestPath: string;
66
+ }
67
+
68
+ export interface CommandExecutionResult {
69
+ ok: boolean;
70
+ exitCode: number;
71
+ output: string;
72
+ durationMs: number;
73
+ }
74
+
75
+ export type CommandRunner = (command: string, cwd: string) => Promise<CommandExecutionResult>;
76
+
77
+ export interface HealthProbeResult {
78
+ ok: boolean;
79
+ detail: string;
80
+ statusCode?: number;
81
+ payloadStatus?: string;
82
+ }
83
+
84
+ export type HealthProbe = (url: string) => Promise<HealthProbeResult>;
85
+
86
+ export type RollbackStatus = 'restored' | 'noop' | 'failed';
87
+
88
+ export interface RollbackResult {
89
+ status: RollbackStatus;
90
+ snapshotId: string;
91
+ startedAt: string;
92
+ completedAt: string;
93
+ restoredAssets: string[];
94
+ skippedAssets: string[];
95
+ healthCheck: ReleaseCheckResult;
96
+ diagnostics: string[];
97
+ }
98
+
99
+ export type DrillStatus = 'passed' | 'failed';
100
+
101
+ export interface DrillResult {
102
+ status: DrillStatus;
103
+ drillId: string;
104
+ startedAt: string;
105
+ completedAt: string;
106
+ simulatedFailure: boolean;
107
+ snapshotRestored: boolean;
108
+ preflightResult: PreflightResult | null;
109
+ rollbackResult: RollbackResult | null;
110
+ integrityCheck: {
111
+ passed: boolean;
112
+ issues: string[];
113
+ };
114
+ diagnostics: string[];
115
+ }
@@ -0,0 +1,43 @@
1
+ /** Delivery lifecycle states for outbound messages in the persistent queue. */
2
+ export type DeliveryState = 'queued' | 'dispatching' | 'sent' | 'failed' | 'dead_letter';
3
+
4
+ /** A single tracked outbound delivery attempt. */
5
+ export interface DeliveryAttempt {
6
+ attemptNumber: number;
7
+ startedAt: string;
8
+ completedAt?: string;
9
+ error?: string;
10
+ durationMs?: number;
11
+ }
12
+
13
+ /** Full delivery record for a single outbound message. */
14
+ export interface DeliveryRecord {
15
+ id: string;
16
+ platform: string;
17
+ chatId: string | number;
18
+ textPayload: string;
19
+ state: DeliveryState;
20
+ attempts: DeliveryAttempt[];
21
+ createdAt: string;
22
+ nextAttemptAt?: string;
23
+ resolvedAt?: string;
24
+ }
25
+
26
+ /** Summary telemetry counters for reliability reporting. */
27
+ export interface ReliabilityMetrics {
28
+ totalSent: number;
29
+ totalFailed: number;
30
+ totalRetries: number;
31
+ averageAttempts: number;
32
+ /** Delivery records for the most recent N sends. */
33
+ recentRecords: DeliveryRecord[];
34
+ }
35
+
36
+ /** Callback reconciliation payload from an async interface operation. */
37
+ export interface CallbackReconciliation {
38
+ taskId: string;
39
+ platform: string;
40
+ status: 'delivered' | 'failed' | 'expired';
41
+ detail?: string;
42
+ reconciledAt: string;
43
+ }
@@ -0,0 +1,85 @@
1
+ export type RuntimeBudgetProfile = 'economy' | 'balanced' | 'performance';
2
+
3
+ export type RuntimeBudgetSeverity = 'ok' | 'warning' | 'hard_limit';
4
+
5
+ export type RuntimeBudgetAction =
6
+ | 'none'
7
+ | 'intelligent_pacing'
8
+ | 'provider_cooldown'
9
+ | 'fallback_tightening'
10
+ | 'prefer_local_model';
11
+
12
+ export type RuntimeUsageStage = 'success' | 'failure' | 'skipped';
13
+
14
+ export interface RuntimeBudgetLimits {
15
+ dailyRequestLimit: number;
16
+ dailyTokenLimit: number;
17
+ sessionRequestLimit: number;
18
+ sessionTokenLimit: number;
19
+ providerRequestLimit: number;
20
+ providerTokenLimit: number;
21
+ warningRatio: number;
22
+ warningPacingMs: number;
23
+ hardLimitPacingMs: number;
24
+ providerCooldownMs: number;
25
+ }
26
+
27
+ export interface RuntimeUsageAggregate {
28
+ requestCount: number;
29
+ requestTokens: number;
30
+ responseTokens: number;
31
+ failureCount: number;
32
+ skippedCount: number;
33
+ }
34
+
35
+ export interface RuntimeProviderUsageAggregate extends RuntimeUsageAggregate {
36
+ providerId: string;
37
+ }
38
+
39
+ export interface RuntimeBudgetDirective {
40
+ profile: RuntimeBudgetProfile;
41
+ severity: RuntimeBudgetSeverity;
42
+ actions: RuntimeBudgetAction[];
43
+ pacingDelayMs: number;
44
+ blockedModelIds: string[];
45
+ blockedProviders: string[];
46
+ reason: string;
47
+ evaluatedAt: string;
48
+ }
49
+
50
+ export interface RuntimeBudgetEvent {
51
+ id: string;
52
+ sessionId: string | null;
53
+ severity: RuntimeBudgetSeverity;
54
+ profile: RuntimeBudgetProfile;
55
+ action: RuntimeBudgetAction;
56
+ reason: string;
57
+ detail: Record<string, unknown>;
58
+ createdAt: string;
59
+ }
60
+
61
+ export interface RuntimeBudgetSnapshot {
62
+ sessionId: string;
63
+ manualProfile: RuntimeBudgetProfile | null;
64
+ limits: RuntimeBudgetLimits;
65
+ daily: RuntimeUsageAggregate;
66
+ session: RuntimeUsageAggregate;
67
+ providers: RuntimeProviderUsageAggregate[];
68
+ directive: RuntimeBudgetDirective;
69
+ recentEvents: RuntimeBudgetEvent[];
70
+ }
71
+
72
+ export interface RuntimeUsageEvent {
73
+ id: string;
74
+ sessionId: string | null;
75
+ modelId: string;
76
+ providerId: string;
77
+ profile: RuntimeBudgetProfile;
78
+ stage: RuntimeUsageStage;
79
+ requestTokens: number;
80
+ responseTokens: number;
81
+ latencyMs: number;
82
+ statusCode: number | null;
83
+ error: string | null;
84
+ createdAt: string;
85
+ }
@@ -0,0 +1,47 @@
1
+ /** Status of a registered scheduled job. */
2
+ export type JobStatus = 'idle' | 'running' | 'stopped' | 'error';
3
+
4
+ /** Configuration required to register a new repeating job. */
5
+ export interface JobConfig {
6
+ /** Unique human-readable identifier for this job (e.g. 'daily-heartbeat'). */
7
+ id: string;
8
+ /** A cron expression defining the schedule (node-cron format). */
9
+ cronExpression: string;
10
+ /** Human-readable description of what this job does. */
11
+ description: string;
12
+ /** The async callback to execute on each tick. */
13
+ handler: () => Promise<void> | void;
14
+ /**
15
+ * If true, the job will start immediately upon registration.
16
+ * @default true
17
+ */
18
+ autoStart?: boolean;
19
+ }
20
+
21
+ /** Read-only snapshot of a registered job's state. */
22
+ export interface JobSnapshot {
23
+ id: string;
24
+ cronExpression: string;
25
+ description: string;
26
+ status: JobStatus;
27
+ lastRunAt: Date | null;
28
+ lastError: string | null;
29
+ }
30
+
31
+ /**
32
+ * Event types emitted by the job scheduler.
33
+ * - 'job:start' — fired just before a job handler executes.
34
+ * - 'job:done' — fired after a job handler completes successfully.
35
+ * - 'job:error' — fired when a job handler throws.
36
+ */
37
+ export type SchedulerEventType = 'job:start' | 'job:done' | 'job:error';
38
+
39
+ export interface SchedulerEvent {
40
+ type: SchedulerEventType;
41
+ jobId: string;
42
+ timestamp: Date;
43
+ error?: string;
44
+ }
45
+
46
+ /** Callback signature for scheduler event listeners. */
47
+ export type SchedulerEventListener = (event: SchedulerEvent) => void;