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.
- package/.env.example +73 -0
- package/.github/workflows/ci.yml +99 -0
- package/.github/workflows/release-macos-trusted.yml +103 -0
- package/README.md +336 -0
- package/bin/idlewatch-agent.js +1053 -0
- package/docs/onboarding-external.md +58 -0
- package/docs/packaging/macos-dmg.md +199 -0
- package/docs/packaging/macos-launch-agent.md +70 -0
- package/docs/qa/archive/mac-qa-log-2026-02-17.md +5838 -0
- package/docs/qa/mac-qa-log.md +2864 -0
- package/docs/telemetry/idle-stale-policy.md +57 -0
- package/docs/telemetry/openclaw-mapping.md +80 -0
- package/package.json +76 -0
- package/scripts/build-dmg.sh +65 -0
- package/scripts/install-macos-launch-agent.sh +78 -0
- package/scripts/lib/telemetry-row-parser.mjs +100 -0
- package/scripts/package-macos.sh +228 -0
- package/scripts/uninstall-macos-launch-agent.sh +30 -0
- package/scripts/validate-all.sh +142 -0
- package/scripts/validate-bin.mjs +25 -0
- package/scripts/validate-dmg-checksum.sh +37 -0
- package/scripts/validate-dmg-install.sh +155 -0
- package/scripts/validate-dry-run-schema.mjs +257 -0
- package/scripts/validate-onboarding.mjs +63 -0
- package/scripts/validate-openclaw-cache-recovery-e2e.mjs +113 -0
- package/scripts/validate-openclaw-release-gates.mjs +51 -0
- package/scripts/validate-openclaw-stats-ingestion.mjs +372 -0
- package/scripts/validate-openclaw-usage-health.mjs +95 -0
- package/scripts/validate-packaged-artifact.mjs +233 -0
- package/scripts/validate-packaged-bundled-runtime.sh +191 -0
- package/scripts/validate-packaged-metadata.sh +43 -0
- package/scripts/validate-packaged-openclaw-cache-recovery-e2e.mjs +153 -0
- package/scripts/validate-packaged-openclaw-release-gates.mjs +72 -0
- package/scripts/validate-packaged-openclaw-stats-ingestion.mjs +402 -0
- package/scripts/validate-packaged-sourcemaps.mjs +82 -0
- package/scripts/validate-packaged-usage-alert-rate-e2e.mjs +98 -0
- package/scripts/validate-packaged-usage-probe-noise-e2e.mjs +87 -0
- package/scripts/validate-packaged-usage-recovery-e2e.mjs +90 -0
- package/scripts/validate-trusted-prereqs.sh +44 -0
- package/scripts/validate-usage-alert-rate-e2e.mjs +91 -0
- package/scripts/validate-usage-freshness-e2e.mjs +81 -0
- package/skill/SKILL.md +43 -0
- package/src/config.js +100 -0
- package/src/enrollment.js +176 -0
- package/src/gpu.js +115 -0
- package/src/memory.js +67 -0
- package/src/openclaw-cache.js +51 -0
- package/src/openclaw-usage.js +1020 -0
- package/src/telemetry-mapping.js +54 -0
- package/src/usage-alert.js +41 -0
- package/src/usage-freshness.js +31 -0
- package/test/config.test.mjs +112 -0
- package/test/fixtures/gpu-agx.txt +2 -0
- package/test/fixtures/gpu-iogpu.txt +2 -0
- package/test/fixtures/gpu-top-grep.txt +2 -0
- package/test/fixtures/openclaw-fleet-sample-v1.json +68 -0
- package/test/fixtures/openclaw-mixed-equal-score-status-vs-generic-iso-ts.txt +2 -0
- package/test/fixtures/openclaw-mixed-equal-score-status-vs-generic-newest.txt +2 -0
- package/test/fixtures/openclaw-mixed-equal-score-status-vs-generic-string-ts.txt +2 -0
- package/test/fixtures/openclaw-mixed-status-then-generic-output.txt +2 -0
- package/test/fixtures/openclaw-stats-current-wrapper.json +12 -0
- package/test/fixtures/openclaw-stats-current-wrapper2.json +15 -0
- package/test/fixtures/openclaw-stats-data-wrapper.json +21 -0
- package/test/fixtures/openclaw-stats-nested-session-wrapper.json +23 -0
- package/test/fixtures/openclaw-stats-payload-wrapper.json +1 -0
- package/test/fixtures/openclaw-stats-status-current-wrapper.json +19 -0
- package/test/fixtures/openclaw-stats.json +17 -0
- package/test/fixtures/openclaw-status-ansi-complex-noise.txt +3 -0
- package/test/fixtures/openclaw-status-ansi-noise.txt +2 -0
- package/test/fixtures/openclaw-status-control-noise.txt +1 -0
- package/test/fixtures/openclaw-status-data-wrapper.json +20 -0
- package/test/fixtures/openclaw-status-dcs-noise.txt +1 -0
- package/test/fixtures/openclaw-status-epoch-seconds.json +15 -0
- package/test/fixtures/openclaw-status-mixed-noise.txt +1 -0
- package/test/fixtures/openclaw-status-multi-json.txt +3 -0
- package/test/fixtures/openclaw-status-nested-recent.json +19 -0
- package/test/fixtures/openclaw-status-noisy-default-then-usage.txt +2 -0
- package/test/fixtures/openclaw-status-noisy.txt +3 -0
- package/test/fixtures/openclaw-status-osc-noise.txt +1 -0
- package/test/fixtures/openclaw-status-result-session.json +15 -0
- package/test/fixtures/openclaw-status-session-map-with-defaults.json +23 -0
- package/test/fixtures/openclaw-status-session-map.json +28 -0
- package/test/fixtures/openclaw-status-session-model-name.json +18 -0
- package/test/fixtures/openclaw-status-snake-session-wrapper.json +13 -0
- package/test/fixtures/openclaw-status-stats-current-sessions-snake-tokens.json +25 -0
- package/test/fixtures/openclaw-status-stats-current-sessions.json +28 -0
- package/test/fixtures/openclaw-status-stats-current-usage-time-camelcase.json +19 -0
- package/test/fixtures/openclaw-status-stats-session-default-model.json +27 -0
- package/test/fixtures/openclaw-status-status-wrapper.json +13 -0
- package/test/fixtures/openclaw-status-strings.json +38 -0
- package/test/fixtures/openclaw-status-ts-ms-alias.json +14 -0
- package/test/fixtures/openclaw-status-updated-at-ms-alias.json +14 -0
- package/test/fixtures/openclaw-status-usage-timestamp-ms-alias.json +14 -0
- package/test/fixtures/openclaw-status-usage-ts-alias.json +14 -0
- package/test/fixtures/openclaw-status-wrap-session-object.json +24 -0
- package/test/fixtures/openclaw-status.json +41 -0
- package/test/fixtures/openclaw-usage-model-name-generic.json +9 -0
- package/test/gpu.test.mjs +58 -0
- package/test/memory.test.mjs +35 -0
- package/test/openclaw-cache.test.mjs +48 -0
- package/test/openclaw-env.test.mjs +365 -0
- package/test/openclaw-usage.test.mjs +555 -0
- package/test/telemetry-mapping.test.mjs +69 -0
- package/test/telemetry-row-parser.test.mjs +44 -0
- package/test/usage-alert.test.mjs +73 -0
- package/test/usage-freshness.test.mjs +63 -0
- package/test/validate-dry-run-schema.test.mjs +146 -0
- package/tui/Cargo.lock +801 -0
- package/tui/Cargo.toml +11 -0
- 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,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,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 @@
|
|
|
1
|
+
[2K{"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 @@
|
|
|
1
|
+
[2J[?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,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
|
+
}
|