idlewatch 0.1.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 (110) hide show
  1. package/.env.example +73 -0
  2. package/.github/workflows/ci.yml +99 -0
  3. package/.github/workflows/release-macos-trusted.yml +103 -0
  4. package/README.md +336 -0
  5. package/bin/idlewatch-agent.js +1053 -0
  6. package/docs/onboarding-external.md +58 -0
  7. package/docs/packaging/macos-dmg.md +199 -0
  8. package/docs/packaging/macos-launch-agent.md +70 -0
  9. package/docs/qa/archive/mac-qa-log-2026-02-17.md +5838 -0
  10. package/docs/qa/mac-qa-log.md +2864 -0
  11. package/docs/telemetry/idle-stale-policy.md +57 -0
  12. package/docs/telemetry/openclaw-mapping.md +80 -0
  13. package/package.json +76 -0
  14. package/scripts/build-dmg.sh +65 -0
  15. package/scripts/install-macos-launch-agent.sh +78 -0
  16. package/scripts/lib/telemetry-row-parser.mjs +100 -0
  17. package/scripts/package-macos.sh +228 -0
  18. package/scripts/uninstall-macos-launch-agent.sh +30 -0
  19. package/scripts/validate-all.sh +142 -0
  20. package/scripts/validate-bin.mjs +25 -0
  21. package/scripts/validate-dmg-checksum.sh +37 -0
  22. package/scripts/validate-dmg-install.sh +155 -0
  23. package/scripts/validate-dry-run-schema.mjs +257 -0
  24. package/scripts/validate-onboarding.mjs +63 -0
  25. package/scripts/validate-openclaw-cache-recovery-e2e.mjs +113 -0
  26. package/scripts/validate-openclaw-release-gates.mjs +51 -0
  27. package/scripts/validate-openclaw-stats-ingestion.mjs +372 -0
  28. package/scripts/validate-openclaw-usage-health.mjs +95 -0
  29. package/scripts/validate-packaged-artifact.mjs +233 -0
  30. package/scripts/validate-packaged-bundled-runtime.sh +191 -0
  31. package/scripts/validate-packaged-metadata.sh +43 -0
  32. package/scripts/validate-packaged-openclaw-cache-recovery-e2e.mjs +153 -0
  33. package/scripts/validate-packaged-openclaw-release-gates.mjs +72 -0
  34. package/scripts/validate-packaged-openclaw-stats-ingestion.mjs +402 -0
  35. package/scripts/validate-packaged-sourcemaps.mjs +82 -0
  36. package/scripts/validate-packaged-usage-alert-rate-e2e.mjs +98 -0
  37. package/scripts/validate-packaged-usage-probe-noise-e2e.mjs +87 -0
  38. package/scripts/validate-packaged-usage-recovery-e2e.mjs +90 -0
  39. package/scripts/validate-trusted-prereqs.sh +44 -0
  40. package/scripts/validate-usage-alert-rate-e2e.mjs +91 -0
  41. package/scripts/validate-usage-freshness-e2e.mjs +81 -0
  42. package/skill/SKILL.md +43 -0
  43. package/src/config.js +100 -0
  44. package/src/enrollment.js +176 -0
  45. package/src/gpu.js +115 -0
  46. package/src/memory.js +67 -0
  47. package/src/openclaw-cache.js +51 -0
  48. package/src/openclaw-usage.js +1020 -0
  49. package/src/telemetry-mapping.js +54 -0
  50. package/src/usage-alert.js +41 -0
  51. package/src/usage-freshness.js +31 -0
  52. package/test/config.test.mjs +112 -0
  53. package/test/fixtures/gpu-agx.txt +2 -0
  54. package/test/fixtures/gpu-iogpu.txt +2 -0
  55. package/test/fixtures/gpu-top-grep.txt +2 -0
  56. package/test/fixtures/openclaw-fleet-sample-v1.json +68 -0
  57. package/test/fixtures/openclaw-mixed-equal-score-status-vs-generic-iso-ts.txt +2 -0
  58. package/test/fixtures/openclaw-mixed-equal-score-status-vs-generic-newest.txt +2 -0
  59. package/test/fixtures/openclaw-mixed-equal-score-status-vs-generic-string-ts.txt +2 -0
  60. package/test/fixtures/openclaw-mixed-status-then-generic-output.txt +2 -0
  61. package/test/fixtures/openclaw-stats-current-wrapper.json +12 -0
  62. package/test/fixtures/openclaw-stats-current-wrapper2.json +15 -0
  63. package/test/fixtures/openclaw-stats-data-wrapper.json +21 -0
  64. package/test/fixtures/openclaw-stats-nested-session-wrapper.json +23 -0
  65. package/test/fixtures/openclaw-stats-payload-wrapper.json +1 -0
  66. package/test/fixtures/openclaw-stats-status-current-wrapper.json +19 -0
  67. package/test/fixtures/openclaw-stats.json +17 -0
  68. package/test/fixtures/openclaw-status-ansi-complex-noise.txt +3 -0
  69. package/test/fixtures/openclaw-status-ansi-noise.txt +2 -0
  70. package/test/fixtures/openclaw-status-control-noise.txt +1 -0
  71. package/test/fixtures/openclaw-status-data-wrapper.json +20 -0
  72. package/test/fixtures/openclaw-status-dcs-noise.txt +1 -0
  73. package/test/fixtures/openclaw-status-epoch-seconds.json +15 -0
  74. package/test/fixtures/openclaw-status-mixed-noise.txt +1 -0
  75. package/test/fixtures/openclaw-status-multi-json.txt +3 -0
  76. package/test/fixtures/openclaw-status-nested-recent.json +19 -0
  77. package/test/fixtures/openclaw-status-noisy-default-then-usage.txt +2 -0
  78. package/test/fixtures/openclaw-status-noisy.txt +3 -0
  79. package/test/fixtures/openclaw-status-osc-noise.txt +1 -0
  80. package/test/fixtures/openclaw-status-result-session.json +15 -0
  81. package/test/fixtures/openclaw-status-session-map-with-defaults.json +23 -0
  82. package/test/fixtures/openclaw-status-session-map.json +28 -0
  83. package/test/fixtures/openclaw-status-session-model-name.json +18 -0
  84. package/test/fixtures/openclaw-status-snake-session-wrapper.json +13 -0
  85. package/test/fixtures/openclaw-status-stats-current-sessions-snake-tokens.json +25 -0
  86. package/test/fixtures/openclaw-status-stats-current-sessions.json +28 -0
  87. package/test/fixtures/openclaw-status-stats-current-usage-time-camelcase.json +19 -0
  88. package/test/fixtures/openclaw-status-stats-session-default-model.json +27 -0
  89. package/test/fixtures/openclaw-status-status-wrapper.json +13 -0
  90. package/test/fixtures/openclaw-status-strings.json +38 -0
  91. package/test/fixtures/openclaw-status-ts-ms-alias.json +14 -0
  92. package/test/fixtures/openclaw-status-updated-at-ms-alias.json +14 -0
  93. package/test/fixtures/openclaw-status-usage-timestamp-ms-alias.json +14 -0
  94. package/test/fixtures/openclaw-status-usage-ts-alias.json +14 -0
  95. package/test/fixtures/openclaw-status-wrap-session-object.json +24 -0
  96. package/test/fixtures/openclaw-status.json +41 -0
  97. package/test/fixtures/openclaw-usage-model-name-generic.json +9 -0
  98. package/test/gpu.test.mjs +58 -0
  99. package/test/memory.test.mjs +35 -0
  100. package/test/openclaw-cache.test.mjs +48 -0
  101. package/test/openclaw-env.test.mjs +365 -0
  102. package/test/openclaw-usage.test.mjs +555 -0
  103. package/test/telemetry-mapping.test.mjs +69 -0
  104. package/test/telemetry-row-parser.test.mjs +44 -0
  105. package/test/usage-alert.test.mjs +73 -0
  106. package/test/usage-freshness.test.mjs +63 -0
  107. package/test/validate-dry-run-schema.test.mjs +146 -0
  108. package/tui/Cargo.lock +801 -0
  109. package/tui/Cargo.toml +11 -0
  110. package/tui/src/main.rs +368 -0
@@ -0,0 +1,54 @@
1
+ export const OPENCLAW_FLEET_SCHEMA = Object.freeze({
2
+ family: 'idlewatch.openclaw.fleet',
3
+ version: '1.0.0',
4
+ backwardCompatibleWith: ['0.x-flat-row']
5
+ })
6
+
7
+ export function enrichWithOpenClawFleetTelemetry(sample, context = {}) {
8
+ const host = context.host ?? sample.host ?? null
9
+ const collector = context.collector ?? 'idlewatch-agent'
10
+ const collectorVersion = context.collectorVersion ?? null
11
+ const collectedAtMs = context.collectedAtMs ?? sample.ts ?? null
12
+
13
+ return {
14
+ ...sample,
15
+ schemaFamily: OPENCLAW_FLEET_SCHEMA.family,
16
+ schemaVersion: OPENCLAW_FLEET_SCHEMA.version,
17
+ schemaCompat: OPENCLAW_FLEET_SCHEMA.backwardCompatibleWith,
18
+ fleet: {
19
+ host,
20
+ collectedAtMs,
21
+ resources: {
22
+ cpuPct: sample.cpuPct ?? null,
23
+ memUsedPct: sample.memUsedPct ?? sample.memPct ?? null,
24
+ memPressurePct: sample.memPressurePct ?? null,
25
+ memPressureClass: sample.memPressureClass ?? 'unavailable'
26
+ },
27
+ usage: {
28
+ model: sample.openclawModel ?? null,
29
+ totalTokens: sample.openclawTotalTokens ?? null,
30
+ tokensPerMin: sample.tokensPerMin ?? null,
31
+ sessionId: sample.openclawSessionId ?? null,
32
+ agentId: sample.openclawAgentId ?? null,
33
+ usageTimestampMs: sample.openclawUsageTs ?? null,
34
+ usageAgeMs: sample.openclawUsageAgeMs ?? null,
35
+ freshnessState: sample.source?.usageFreshnessState ?? null,
36
+ integrationStatus: sample.source?.usageIntegrationStatus ?? 'unavailable',
37
+ ingestionStatus: sample.source?.usageIngestionStatus ?? 'unavailable',
38
+ activityStatus: sample.source?.usageActivityStatus ?? 'unavailable',
39
+ alertLevel: sample.source?.usageAlertLevel ?? 'critical',
40
+ alertReason: sample.source?.usageAlertReason ?? 'ingestion-unavailable'
41
+ },
42
+ provenance: {
43
+ collector,
44
+ collectorVersion,
45
+ usageSource: sample.source?.usage ?? 'unavailable',
46
+ usageCommand: sample.source?.usageCommand ?? null,
47
+ usageProbeResult: sample.source?.usageProbeResult ?? 'unavailable',
48
+ usageProbeAttempts: sample.source?.usageProbeAttempts ?? 0,
49
+ usageUsedFallbackCache: sample.source?.usageUsedFallbackCache ?? false,
50
+ usageFallbackCacheSource: sample.source?.usageFallbackCacheSource ?? null
51
+ }
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,41 @@
1
+ export function deriveUsageAlert(source, options = {}) {
2
+ const ingestion = source?.usageIngestionStatus
3
+ const activity = source?.usageActivityStatus
4
+ const nearStale = source?.usageNearStale === true
5
+ const pastStaleThreshold = source?.usagePastStaleThreshold === true
6
+ const refreshAttempted = source?.usageRefreshAttempted === true
7
+ const refreshRecovered = source?.usageRefreshRecovered === true
8
+ const usageAgeMs = Number.isFinite(options?.usageAgeMs) ? options.usageAgeMs : null
9
+ const idleAfterMs = Number.isFinite(options?.idleAfterMs) && options.idleAfterMs > 0 ? options.idleAfterMs : null
10
+ const isIdle = idleAfterMs !== null && usageAgeMs !== null && usageAgeMs >= idleAfterMs
11
+
12
+ if (ingestion === 'disabled') {
13
+ return { level: 'off', reason: 'usage-disabled' }
14
+ }
15
+
16
+ if (ingestion === 'unavailable') {
17
+ return { level: 'critical', reason: 'ingestion-unavailable' }
18
+ }
19
+
20
+ if (isIdle) {
21
+ return { level: 'notice', reason: 'activity-idle' }
22
+ }
23
+
24
+ if (pastStaleThreshold) {
25
+ return { level: 'warning', reason: 'activity-past-threshold' }
26
+ }
27
+
28
+ if (activity === 'stale' && refreshAttempted && !refreshRecovered) {
29
+ return { level: 'notice', reason: 'activity-no-new-usage' }
30
+ }
31
+
32
+ if (activity === 'stale') {
33
+ return { level: 'warning', reason: 'activity-stale' }
34
+ }
35
+
36
+ if (nearStale) {
37
+ return { level: 'notice', reason: 'activity-near-stale' }
38
+ }
39
+
40
+ return { level: 'ok', reason: 'healthy' }
41
+ }
@@ -0,0 +1,31 @@
1
+ export function deriveUsageFreshness(usage, nowMs, staleMs, nearStaleMs = null, staleGraceMs = 0) {
2
+ const usageTs = usage?.usageTimestampMs
3
+ if (typeof usageTs !== 'number' || !Number.isFinite(usageTs)) {
4
+ return { usageAgeMs: null, isStale: false, isNearStale: false, isPastStaleThreshold: false, freshnessState: 'unknown' }
5
+ }
6
+
7
+ if (typeof nowMs !== 'number' || !Number.isFinite(nowMs)) {
8
+ return { usageAgeMs: null, isStale: false, isNearStale: false, isPastStaleThreshold: false, freshnessState: 'unknown' }
9
+ }
10
+
11
+ const ageMs = nowMs - usageTs
12
+ if (!Number.isFinite(ageMs) || ageMs < 0) {
13
+ return { usageAgeMs: null, isStale: false, isNearStale: false, isPastStaleThreshold: false, freshnessState: 'unknown' }
14
+ }
15
+
16
+ const staleThresholdMs = typeof staleMs === 'number' && Number.isFinite(staleMs) && staleMs > 0 ? staleMs : null
17
+ const nearThresholdMs = typeof nearStaleMs === 'number' && Number.isFinite(nearStaleMs) && nearStaleMs > 0 ? nearStaleMs : null
18
+ const graceWindowMs = typeof staleGraceMs === 'number' && Number.isFinite(staleGraceMs) && staleGraceMs > 0 ? staleGraceMs : 0
19
+ const staleAtMs = staleThresholdMs === null ? null : staleThresholdMs + graceWindowMs
20
+ const isPastStaleThreshold = staleThresholdMs === null ? false : ageMs > staleThresholdMs
21
+ const isStale = staleAtMs === null ? false : ageMs > staleAtMs
22
+ const isNearStale = nearThresholdMs === null ? false : ageMs >= nearThresholdMs
23
+
24
+ return {
25
+ usageAgeMs: ageMs,
26
+ isStale,
27
+ isNearStale,
28
+ isPastStaleThreshold,
29
+ freshnessState: isStale ? 'stale' : (isNearStale ? 'aging' : 'fresh')
30
+ }
31
+ }
@@ -0,0 +1,112 @@
1
+ import { describe, it, beforeEach, afterEach } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ // Snapshot and restore env around each test
5
+ let savedEnv
6
+
7
+ function clearIdlewatchEnv() {
8
+ for (const key of Object.keys(process.env)) {
9
+ if (key.startsWith('IDLEWATCH_') || key.startsWith('FIREBASE_') || key === 'FIRESTORE_EMULATOR_HOST') {
10
+ delete process.env[key]
11
+ }
12
+ }
13
+ }
14
+
15
+ async function freshBuildConfig() {
16
+ // Dynamic import with cache-bust to pick up env changes
17
+ const mod = await import(`../src/config.js?t=${Date.now()}-${Math.random()}`)
18
+ return mod.buildConfig
19
+ }
20
+
21
+ describe('buildConfig', () => {
22
+ beforeEach(() => {
23
+ savedEnv = { ...process.env }
24
+ clearIdlewatchEnv()
25
+ })
26
+
27
+ afterEach(() => {
28
+ // Restore original env
29
+ clearIdlewatchEnv()
30
+ for (const [k, v] of Object.entries(savedEnv)) {
31
+ process.env[k] = v
32
+ }
33
+ })
34
+
35
+ it('returns default config with no env vars', async () => {
36
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}`)).buildConfig
37
+ const cfg = buildConfig()
38
+ assert.equal(cfg.INTERVAL_MS, 10000)
39
+ assert.equal(cfg.OPENCLAW_USAGE_MODE, 'auto')
40
+ assert.equal(cfg.OPENCLAW_PROBE_TIMEOUT_MS, 2500)
41
+ assert.equal(cfg.OPENCLAW_PROBE_RETRIES, 1)
42
+ assert.equal(cfg.USAGE_REFRESH_ON_NEAR_STALE, 1)
43
+ assert.equal(cfg.REQUIRE_FIREBASE_WRITES, false)
44
+ assert.ok(cfg.HOST)
45
+ assert.ok(cfg.LOCAL_LOG_PATH)
46
+ assert.ok(Object.isFrozen(cfg))
47
+ })
48
+
49
+ it('respects IDLEWATCH_INTERVAL_MS', async () => {
50
+ process.env.IDLEWATCH_INTERVAL_MS = '5000'
51
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-2`)).buildConfig
52
+ const cfg = buildConfig()
53
+ assert.equal(cfg.INTERVAL_MS, 5000)
54
+ })
55
+
56
+ it('throws on invalid IDLEWATCH_INTERVAL_MS', async () => {
57
+ process.env.IDLEWATCH_INTERVAL_MS = '-1'
58
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-3`)).buildConfig
59
+ assert.throws(() => buildConfig(), /Invalid IDLEWATCH_INTERVAL_MS/)
60
+ })
61
+
62
+ it('throws on non-numeric IDLEWATCH_INTERVAL_MS', async () => {
63
+ process.env.IDLEWATCH_INTERVAL_MS = 'abc'
64
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-4`)).buildConfig
65
+ assert.throws(() => buildConfig(), /Invalid IDLEWATCH_INTERVAL_MS/)
66
+ })
67
+
68
+ it('throws on invalid IDLEWATCH_USAGE_REFRESH_ON_NEAR_STALE', async () => {
69
+ process.env.IDLEWATCH_USAGE_REFRESH_ON_NEAR_STALE = '3'
70
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-5`)).buildConfig
71
+ assert.throws(() => buildConfig(), /Invalid IDLEWATCH_USAGE_REFRESH_ON_NEAR_STALE/)
72
+ })
73
+
74
+ it('derives stale thresholds from interval', async () => {
75
+ process.env.IDLEWATCH_INTERVAL_MS = '20000'
76
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-6`)).buildConfig
77
+ const cfg = buildConfig()
78
+ assert.equal(cfg.USAGE_STALE_MS, 60000) // max(20000*3, 60000)
79
+ assert.equal(cfg.USAGE_STALE_GRACE_MS, 10000) // min(20000, 10000)
80
+ })
81
+
82
+ it('picks up custom host', async () => {
83
+ process.env.IDLEWATCH_HOST = 'my-host'
84
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-7`)).buildConfig
85
+ const cfg = buildConfig()
86
+ assert.equal(cfg.HOST, 'my-host')
87
+ assert.equal(cfg.SAFE_HOST, 'my-host')
88
+ })
89
+
90
+ it('sanitizes host with special chars', async () => {
91
+ process.env.IDLEWATCH_HOST = 'my host/foo'
92
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-8`)).buildConfig
93
+ const cfg = buildConfig()
94
+ assert.equal(cfg.SAFE_HOST, 'my_host_foo')
95
+ })
96
+
97
+ it('sets openclaw usage mode from env', async () => {
98
+ process.env.IDLEWATCH_OPENCLAW_USAGE = 'OFF'
99
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-9`)).buildConfig
100
+ const cfg = buildConfig()
101
+ assert.equal(cfg.OPENCLAW_USAGE_MODE, 'off')
102
+ })
103
+
104
+ it('sets firebase config', async () => {
105
+ process.env.FIREBASE_PROJECT_ID = 'test-project'
106
+ process.env.FIREBASE_SERVICE_ACCOUNT_FILE = '/tmp/sa.json'
107
+ const buildConfig = (await import(`../src/config.js?t=${Date.now()}-10`)).buildConfig
108
+ const cfg = buildConfig()
109
+ assert.equal(cfg.FIREBASE.PROJECT_ID, 'test-project')
110
+ assert.equal(cfg.FIREBASE.CREDS_FILE, '/tmp/sa.json')
111
+ })
112
+ })
@@ -0,0 +1,2 @@
1
+ AGXPerformanceStatistics
2
+ "PerformanceStatistics" = {"Renderer Utilization %"=12,"Device Utilization %"=34,"Tiler Utilization %"=5}
@@ -0,0 +1,2 @@
1
+ IOGPUStatistics
2
+ "PerformanceStatistics" = {"Renderer Utilization %"=23.4,"Device Utilization %"=1.2}
@@ -0,0 +1,2 @@
1
+ Processes: 312 total
2
+ GPU usage: 7.8% some text
@@ -0,0 +1,68 @@
1
+ {
2
+ "schemaFamily": "idlewatch.openclaw.fleet",
3
+ "schemaVersion": "1.0.0",
4
+ "schemaCompat": ["0.x-flat-row"],
5
+ "host": "mac-mini-1",
6
+ "ts": 1771278899999,
7
+ "cpuPct": 12.5,
8
+ "memPct": 63.2,
9
+ "memUsedPct": 63.2,
10
+ "memPressurePct": 42,
11
+ "memPressureClass": "normal",
12
+ "tokensPerMin": 128.4,
13
+ "openclawModel": "gpt-5.3-codex",
14
+ "openclawTotalTokens": 70500,
15
+ "openclawSessionId": "90d2a820-6d77-42f0-8db4-12b90f9f7203",
16
+ "openclawAgentId": "main",
17
+ "openclawUsageTs": 1771278893678,
18
+ "openclawUsageAgeMs": 6321,
19
+ "source": {
20
+ "usage": "openclaw",
21
+ "usageIntegrationStatus": "ok",
22
+ "usageIngestionStatus": "ok",
23
+ "usageActivityStatus": "fresh",
24
+ "usageFreshnessState": "fresh",
25
+ "usageAlertLevel": "ok",
26
+ "usageAlertReason": "healthy",
27
+ "usageCommand": "openclaw status --json",
28
+ "usageProbeResult": "ok",
29
+ "usageProbeAttempts": 1,
30
+ "usageUsedFallbackCache": false,
31
+ "usageFallbackCacheSource": null
32
+ },
33
+ "fleet": {
34
+ "host": "mac-mini-1",
35
+ "collectedAtMs": 1771278899999,
36
+ "resources": {
37
+ "cpuPct": 12.5,
38
+ "memUsedPct": 63.2,
39
+ "memPressurePct": 42,
40
+ "memPressureClass": "normal"
41
+ },
42
+ "usage": {
43
+ "model": "gpt-5.3-codex",
44
+ "totalTokens": 70500,
45
+ "tokensPerMin": 128.4,
46
+ "sessionId": "90d2a820-6d77-42f0-8db4-12b90f9f7203",
47
+ "agentId": "main",
48
+ "usageTimestampMs": 1771278893678,
49
+ "usageAgeMs": 6321,
50
+ "freshnessState": "fresh",
51
+ "integrationStatus": "ok",
52
+ "ingestionStatus": "ok",
53
+ "activityStatus": "fresh",
54
+ "alertLevel": "ok",
55
+ "alertReason": "healthy"
56
+ },
57
+ "provenance": {
58
+ "collector": "idlewatch-agent",
59
+ "collectorVersion": "0.1.0",
60
+ "usageSource": "openclaw",
61
+ "usageCommand": "openclaw status --json",
62
+ "usageProbeResult": "ok",
63
+ "usageProbeAttempts": 1,
64
+ "usageUsedFallbackCache": false,
65
+ "usageFallbackCacheSource": null
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,2 @@
1
+ {"status":{"current":{"session":{"session_id":"status-old","agent_id":"agent-status","model":"qwen-3","totalTokens":100,"tokens_per_minute":2.2,"updatedAt":"2026-02-16T00:00:00.000Z"}}}
2
+ {"model":"qwen-3","total_tokens":"100","tokens_per_minute":"2.2","session_id":"generic-newer","agent_id":"agent-generic","updatedAt":"2026-02-17T00:00:00.000Z"}
@@ -0,0 +1,2 @@
1
+ {"status":{"current":{"session":{"sessionId":"status-older","agentId":"agent-status","model":"claude-3","totalTokens":100,"tokens_per_minute":4.4,"updatedAt":1771280000000}}}
2
+ {"model":"claude-3","total_tokens":"999","tokens_per_minute":"4.4","session_id":"generic-newer","agent_id":"agent-generic","updatedAt":1771290000000}
@@ -0,0 +1,2 @@
1
+ {"status":{"current":{"session":{"session_id":"status-older","agent_id":"agent-status","model":"qwen-2.5","totalTokens":"100","tokens_per_minute":"3.3","updatedAt":"1771280000000"}}}
2
+ {"model":"qwen-2.5","total_tokens":"100","tokens_per_minute":"3.3","session_id":"generic-newer","agent_id":"agent-generic","updatedAt":"1771290000000"}
@@ -0,0 +1,2 @@
1
+ {"status":{"sessions":{"active":{"updatedAt":1771270000000}},"updatedAt":1771270000000}
2
+ {"model":"gpt-5.3-codex","total_tokens":"777","tokens_per_minute":"11.1","session_id":"standalone","agent_id":"agent-stand","updatedAt":1771281000000}
@@ -0,0 +1,12 @@
1
+ {
2
+ "data": {
3
+ "current": {
4
+ "model": "claude-opus-4-6",
5
+ "sessionId": "current-wrapper-session",
6
+ "agentId": "agent-current",
7
+ "totalTokens": 987,
8
+ "tokensPerMinute": 12.34,
9
+ "updatedAt": 1771290000000
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "status": {
3
+ "stats": {
4
+ "model": "claude-opus-4-6",
5
+ "current": {
6
+ "model": "gpt-5.3-codex-spark",
7
+ "sessionId": "status-current-stats-01",
8
+ "agentId": "agent-current-wrap",
9
+ "totalTokens": 555,
10
+ "tokensPerMinute": 21.5,
11
+ "updatedAt": 1771295000000
12
+ }
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "data": {
3
+ "stats": {
4
+ "model": "gpt-5.3-codex-spark",
5
+ "session_id": "data-wrap-session",
6
+ "agent_id": "agent-data-wrap",
7
+ "totals": {
8
+ "total_tokens": 999,
9
+ "tokens": {
10
+ "total": 999
11
+ }
12
+ },
13
+ "tokens_per_minute": 88.75,
14
+ "usage_timestamp": 1771281010000
15
+ },
16
+ "defaults": {
17
+ "model": "gpt-5.3-codex-spark"
18
+ },
19
+ "ts": 1771281020000
20
+ }
21
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "status": {
3
+ "result": {
4
+ "stats": {
5
+ "current": {
6
+ "session": {
7
+ "sessionId": "stats-nested-session-1",
8
+ "agentId": "agent-stats-nested",
9
+ "model": "claude-opus-4-6",
10
+ "totalTokens": 3141,
11
+ "tokensPerMinute": 77.7,
12
+ "updatedAt": "1771303100000"
13
+ },
14
+ "agentId": "agent-stats-wrapper"
15
+ },
16
+ "totals": {
17
+ "model": "ignored"
18
+ }
19
+ }
20
+ }
21
+ },
22
+ "ts": 1771303170000
23
+ }
@@ -0,0 +1 @@
1
+ {"payload":{"stats":{"model":"gpt-5.3-codex-spark","totalTokens":9876,"sessionId":"payload-wrap-session","agentId":"agent-payload","updatedAt":1771302500},"meta":{"note":"payload-style stats wrapper"},"session":{"sessionId":"ignored"}},"timestamp":1771302500123}
@@ -0,0 +1,19 @@
1
+ {
2
+ "ts": 1771304500000,
3
+ "status": {
4
+ "current": {
5
+ "stats": {
6
+ "current": {
7
+ "session": {
8
+ "sessionId": "status-current-stats-02",
9
+ "agentId": "agent-status-current",
10
+ "model": "gpt-5.3-codex-pro",
11
+ "totalTokens": 2048,
12
+ "tokensPerMinute": 42,
13
+ "updatedAt": 1771304500000
14
+ }
15
+ }
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "ts": 1771279123456,
3
+ "stats": {
4
+ "model": "claude-opus-4-6",
5
+ "totals": {
6
+ "tokens": {
7
+ "total": 4560,
8
+ "input": 3000,
9
+ "output": 1560
10
+ },
11
+ "updatedAt": 1771279012345
12
+ },
13
+ "agentId": "agent-stats",
14
+ "sessionId": "sess-stats-01",
15
+ "tokensPerMinute": 123.45
16
+ }
17
+ }
@@ -0,0 +1,3 @@
1
+ start-up
2
+ {"status":"ok","sessions":{"active":[{"sessionId":"complex-ansi","agentId":"agent-ansi","model":"claude-opus-4-6","totalTokens":9999,"updatedAt":1771313300000,"totalTokensFresh":true}]}}
3
+  done
@@ -0,0 +1,2 @@
1
+ [warn] starting OpenClaw probe
2
+ {"status":"ok","sessions":{"active":[{"sessionId":"ansi1","agentId":"agent-ansi","model":"gpt-5.3-codex","totalTokens":4444,"updatedAt":1771309900000,"totalTokensFresh":true}]}}[done]
@@ -0,0 +1 @@
1
+ {"status":"ok","sessions":{"active":[{"sessionId":"control-ansi","agentId":"agent-control","model":"gpt-4.1","totalTokens":3333,"updatedAt":1771314400000,"totalTokensFresh":true}]}}
@@ -0,0 +1,20 @@
1
+ {
2
+ "data": {
3
+ "result": {
4
+ "sessions": {
5
+ "current": {
6
+ "sessionId": "data-wrapper-current",
7
+ "agentId": "agent-wrapper",
8
+ "model": "claude-opus-4-6",
9
+ "modelName": "Claude Opus 4.6",
10
+ "totalTokens": 3333,
11
+ "ageMs": 1200,
12
+ "updatedAt": 1771279300000
13
+ }
14
+ },
15
+ "defaults": {
16
+ "model": "gpt-5.3-codex"
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1 @@
1
+ P0;2;1 10st\{"status":"ok","sessions":{"active":[{"sessionId":"dcs1","agentId":"agent-dcs","model":"deepseek-coder","totalTokens":6000,"updatedAt":1771316600000,"totalTokensFresh":true}]}}
@@ -0,0 +1,15 @@
1
+ {
2
+ "ts": 1771277700,
3
+ "sessions": {
4
+ "recent": [
5
+ {
6
+ "sessionId": "sec-session",
7
+ "agentId": "agent-sec",
8
+ "model": "gpt-5.3-codex-spark",
9
+ "updatedAt": 1771278800,
10
+ "totalTokens": 1200,
11
+ "tokensPerMinute": 30
12
+ }
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1 @@
1
+ [?25h]0;OpenClaw ProbeP0;2;1 12:34:56\\{"status":"ok","sessions":{"active":[{"sessionId":"mixed-ansi","agentId":"agent-mixed","model":"gemini-pro","totalTokens":1010,"updatedAt":1771317600000,"totalTokensFresh":true}]}}
@@ -0,0 +1,3 @@
1
+ {"debug":"skip","step":1}
2
+ {"status":"ok","sessions":{"recent":[{"id":"old","agentId":"main","updatedAt":1771278000000,"totalTokens":111,"model":"gpt-5.3-codex","totalTokensFresh":true},{"id":"new","agentId":"main","updatedAt":1771279012345,"totalTokens":333,"model":"gpt-5.3-codex","totalTokensFresh":true}]}}
3
+ {"ignored":"keepalive"}
@@ -0,0 +1,19 @@
1
+ {
2
+ "sessions": {
3
+ "defaults": {
4
+ "model": "gpt-4o-mini"
5
+ },
6
+ "recent": [
7
+ {
8
+ "agentId": "agent-007",
9
+ "sessionId": "sess-1",
10
+ "updatedAt": 1739703000,
11
+ "model": "gpt-5.3-codex-spark",
12
+ "totalTokens": 21737,
13
+ "ageMs": 45000,
14
+ "totalTokensFresh": true,
15
+ "tokensPerMinute": 32502.31
16
+ }
17
+ ]
18
+ }
19
+ }
@@ -0,0 +1,2 @@
1
+ {"defaultModel":"gpt-5.3-codex"}
2
+ {"status":"ok","sessions":{"recent":[{"id":"main","agentId":"agent-priority","model":"gpt-5.3-codex-pro","totalTokens":7777,"updatedAt":1771312500000,"totalTokensFresh":true}]}}
@@ -0,0 +1,3 @@
1
+ [info] collecting sessions...
2
+ {"status":"ok","sessions":{"defaults":{"model":"gpt-5.3-codex"},"activeSessions":[{"id":"old","agentId":"main","updatedAt":1771278000000,"totalTokens":111,"model":"gpt-5.3-codex","totalTokensFresh":true},{"id":"new","agentId":"main","updatedAt":1771278999999,"totalTokens":222,"model":"gpt-5.3-codex","totalTokensFresh":true}]}}
3
+ warning: cache refresh complete
@@ -0,0 +1 @@
1
+ ]0;OpenClaw Probe{"status":"ok","sessions":{"active":[{"sessionId":"osc1","agentId":"agent-osc","model":"qwen2.5-coder","totalTokens":5555,"updatedAt":1771315500000,"totalTokensFresh":true}]}}\
@@ -0,0 +1,15 @@
1
+ {
2
+ "result": {
3
+ "session": {
4
+ "sessionId": "result-session-1",
5
+ "agentId": "agent-result",
6
+ "model": "gpt-5.3-codex",
7
+ "totalTokens": 1111,
8
+ "tokensPerMinute": 1234.56,
9
+ "updatedAt": 1771279000000,
10
+ "age": 7000
11
+ },
12
+ "defaultModel": "fallback-model"
13
+ },
14
+ "ts": 1771279000000
15
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "sessions": {
3
+ "defaults": {
4
+ "model": "gpt-5.3-codex"
5
+ },
6
+ "map-main-2": {
7
+ "sessionId": "map-main-2",
8
+ "agentId": "agent-map-main-2",
9
+ "model": "claude-opus-4-6",
10
+ "updatedAt": 1771278960000,
11
+ "totalTokens": 2222,
12
+ "totalTokensFresh": true
13
+ },
14
+ "map-stale": {
15
+ "sessionId": "map-stale-2",
16
+ "agentId": "agent-map-stale-2",
17
+ "model": "gpt-5.3-codex",
18
+ "updatedAt": 1771278950000,
19
+ "totalTokens": 111,
20
+ "totalTokensFresh": false
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "sessions": {
3
+ "main": {
4
+ "agentId": "agent-map-main",
5
+ "sessionId": "map-main-1",
6
+ "model": "gpt-5.3-codex",
7
+ "updatedAt": 1771278900000,
8
+ "totalTokens": 1100,
9
+ "totalTokensFresh": true
10
+ },
11
+ "backup": {
12
+ "agentId": "agent-map-backup",
13
+ "sessionId": "map-backup-1",
14
+ "model": "claude-opus-4-6",
15
+ "updatedAt": 1771278950000,
16
+ "totalTokens": 1200,
17
+ "totalTokensFresh": true
18
+ },
19
+ "stale": {
20
+ "agentId": "agent-map-stale",
21
+ "sessionId": "map-stale-1",
22
+ "model": "gpt-5.3-codex",
23
+ "updatedAt": 1771278800000,
24
+ "totalTokens": null,
25
+ "totalTokensFresh": false
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "status": {
3
+ "stats": {
4
+ "current": {
5
+ "sessions": [
6
+ {
7
+ "sessionId": "name-case",
8
+ "agentId": "agent-name",
9
+ "model_name": "claude-3-opus",
10
+ "total_tokens": "888",
11
+ "updatedAt": 1771289000000,
12
+ "tokens_per_minute": "25.5"
13
+ }
14
+ ]
15
+ }
16
+ }
17
+ }
18
+ }