@teeras/afterhours 0.1.1 → 0.3.1

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 (84) hide show
  1. package/README.md +101 -15
  2. package/dist/activity.d.ts +35 -1
  3. package/dist/activity.d.ts.map +1 -1
  4. package/dist/activity.js +148 -1
  5. package/dist/activity.js.map +1 -1
  6. package/dist/autosync.d.ts +22 -0
  7. package/dist/autosync.d.ts.map +1 -0
  8. package/dist/autosync.js +85 -0
  9. package/dist/autosync.js.map +1 -0
  10. package/dist/cli.js +112 -9
  11. package/dist/cli.js.map +1 -1
  12. package/dist/cloud.d.ts +5 -0
  13. package/dist/cloud.d.ts.map +1 -1
  14. package/dist/cloud.js +10 -2
  15. package/dist/cloud.js.map +1 -1
  16. package/dist/collect.d.ts +3 -1
  17. package/dist/collect.d.ts.map +1 -1
  18. package/dist/collect.js +19 -7
  19. package/dist/collect.js.map +1 -1
  20. package/dist/detect.d.ts.map +1 -1
  21. package/dist/detect.js +35 -6
  22. package/dist/detect.js.map +1 -1
  23. package/dist/hooks.d.ts +29 -0
  24. package/dist/hooks.d.ts.map +1 -0
  25. package/dist/hooks.js +196 -0
  26. package/dist/hooks.js.map +1 -0
  27. package/dist/index.d.ts +9 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +8 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/install.d.ts +25 -0
  32. package/dist/install.d.ts.map +1 -0
  33. package/dist/install.js +155 -0
  34. package/dist/install.js.map +1 -0
  35. package/dist/moments.d.ts +21 -0
  36. package/dist/moments.d.ts.map +1 -0
  37. package/dist/moments.js +52 -0
  38. package/dist/moments.js.map +1 -0
  39. package/dist/off.d.ts +24 -0
  40. package/dist/off.d.ts.map +1 -0
  41. package/dist/off.js +36 -0
  42. package/dist/off.js.map +1 -0
  43. package/dist/privacy.d.ts +8 -0
  44. package/dist/privacy.d.ts.map +1 -1
  45. package/dist/privacy.js +27 -1
  46. package/dist/privacy.js.map +1 -1
  47. package/dist/qr.d.ts +29 -0
  48. package/dist/qr.d.ts.map +1 -0
  49. package/dist/qr.js +92 -0
  50. package/dist/qr.js.map +1 -0
  51. package/dist/render.d.ts.map +1 -1
  52. package/dist/render.js +61 -1
  53. package/dist/render.js.map +1 -1
  54. package/dist/report.d.ts.map +1 -1
  55. package/dist/report.js +115 -1
  56. package/dist/report.js.map +1 -1
  57. package/dist/runtime.d.ts +18 -0
  58. package/dist/runtime.d.ts.map +1 -0
  59. package/dist/runtime.js +70 -0
  60. package/dist/runtime.js.map +1 -0
  61. package/dist/secret.d.ts +9 -0
  62. package/dist/secret.d.ts.map +1 -0
  63. package/dist/secret.js +32 -0
  64. package/dist/secret.js.map +1 -0
  65. package/dist/setup.d.ts +18 -0
  66. package/dist/setup.d.ts.map +1 -0
  67. package/dist/setup.js +155 -0
  68. package/dist/setup.js.map +1 -0
  69. package/dist/sources/claude.d.ts.map +1 -1
  70. package/dist/sources/claude.js +162 -18
  71. package/dist/sources/claude.js.map +1 -1
  72. package/dist/sources/codex.d.ts.map +1 -1
  73. package/dist/sources/codex.js +240 -21
  74. package/dist/sources/codex.js.map +1 -1
  75. package/dist/sources/cursor.d.ts.map +1 -1
  76. package/dist/sources/cursor.js +1 -0
  77. package/dist/sources/cursor.js.map +1 -1
  78. package/dist/sources/gemini.d.ts.map +1 -1
  79. package/dist/sources/gemini.js +85 -8
  80. package/dist/sources/gemini.js.map +1 -1
  81. package/dist/types.d.ts +109 -6
  82. package/dist/types.d.ts.map +1 -1
  83. package/llms-install.md +29 -0
  84. package/package.json +3 -2
package/README.md CHANGED
@@ -3,13 +3,20 @@
3
3
  Private AI-life balance and usage analytics for Codex, Claude Code, Gemini CLI,
4
4
  Cursor, and other coding agents.
5
5
 
6
+ ## For AI agents
7
+
8
+ Installing this for your user? Run `npx @teeras/afterhours setup`, relay the
9
+ printed code and link to your user, and let the command finish. Full
10
+ instructions: [`llms-install.md`](./llms-install.md). Counts only — prompts,
11
+ code, output, repo names, and paths never leave the machine.
12
+
6
13
  ```sh
7
14
  npx @teeras/afterhours
8
15
  ```
9
16
 
10
- The first run opens Google sign-in before reading activity, then returns to the
11
- terminal and prints the first report. A Teeras account is required. Install it
12
- once and the short command is simply:
17
+ The first run reads supported agent activity locally and prints a seven-day
18
+ view of agent activity, human attention, and after-hours check-ins without an
19
+ account. Install it once and the short command is simply:
13
20
 
14
21
  ```sh
15
22
  trs
@@ -19,19 +26,33 @@ trs login
19
26
  trs sync
20
27
  trs sources
21
28
  trs privacy
29
+ trs hook-config codex
30
+ trs hook-config claude
22
31
  ```
23
32
 
24
33
  Afterhours parses the local session histories already written by supported
25
34
  coding agents and immediately reduces them to counts and hourly buckets. It
26
35
  never retains or returns prompt text, source code, model output, repository
27
36
  names, working directories, or file paths. Only the documented aggregate
28
- snapshot syncs after account approval.
37
+ snapshot syncs after the user connects Teeras.
29
38
 
30
- Initial sources:
39
+ Support matrix:
31
40
 
32
- - Codex app and CLI (`~/.codex/sessions`)
33
- - Claude Code (`~/.claude/projects`)
34
- - Gemini CLI (`~/.gemini/tmp`, session-level fidelity)
41
+ - Codex desktop app and Codex CLI: activity, token, model, and episode
42
+ measurement from the shared `~/.codex/sessions` history. A distinct
43
+ `CODEX_HOME` is collected alongside the default App home.
44
+ - Claude Code CLI: activity, token, model, and episode measurement from
45
+ `~/.claude/projects`, plus a distinct `CLAUDE_CONFIG_DIR` when configured.
46
+ Subagent transcripts are excluded from primary episode counts rather than
47
+ double-counted as human delegations. Claude Code Desktop keeps separate
48
+ history, so its shared opt-in lifecycle hook is the trustworthy live path.
49
+ - Gemini CLI: activity, token, model, and episode measurement from current
50
+ `~/.gemini/tmp/*/chats` histories; older `logs.json` builds retain honest
51
+ session-level fidelity.
52
+ - Claude desktop: detected separately. General Claude chat and Cowork activity
53
+ are not claimed as measured because those surfaces do not expose a stable,
54
+ content-free local lifecycle feed. Claude Code remains a separate first-class
55
+ source.
35
56
  - Cursor detection, ready for a consented adapter once its local schema is stable
36
57
 
37
58
  `trs connect` also detects Windsurf, VS Code + Copilot, Zed, Amp, OpenCode,
@@ -40,18 +61,83 @@ the rest are reported honestly as requiring a source adapter. The exported
40
61
  `SourceAdapter` contract lets any coding agent add counts-only support without
41
62
  changing the Afterhours core.
42
63
 
43
- ## Keep your history in Teeras
64
+ ## Keep measuring across web and mobile
44
65
 
45
- The first `npx @teeras/afterhours` (or `trs login`) opens Teeras in the browser.
46
- Continue with Google, approve the counts-only boundary, and the CLI receives a
47
- revocable 90-day device token. Google OAuth tokens never enter the npm package.
66
+ The first report stays on the computer. Run `trs connect` when you want to keep
67
+ your history in Teeras. Continue with Google, approve the counts-only boundary,
68
+ and the CLI receives a revocable 30-day device token. Google OAuth tokens never
69
+ enter the npm package.
48
70
 
49
- Once connected, every deliberate `trs` run refreshes the account history. Use
50
- `trs sync` to sync without printing the report, or `trs logout` to remove this
51
- computer's token. There is no background daemon and no automatic LLM call.
71
+ Connecting syncs the first report immediately. After that, a counts-only
72
+ snapshot syncs as a side effect of your own agent activity: a lifecycle hook
73
+ event can trigger one detached, rate-limited sync (at most one every 45
74
+ minutes), so web and mobile stay current while you work. Every deliberate `trs`
75
+ run also refreshes the history. Use `trs sync` to sync without printing the
76
+ report, or `trs logout` to remove this computer's token. Nothing runs as a
77
+ background daemon, the hook itself makes no network call, and there is no
78
+ automatic LLM call.
52
79
 
53
80
  The default command (and `trs week`) prints a calm seven-day report. Use
54
81
  `--json` to inspect the privacy-safe snapshot consumed by the dashboard and
55
82
  optional MCP adapter. The cloud keeps one replaceable snapshot per device per
56
83
  day in a 790-day active-history window; the dashboard lets users export or
57
84
  delete that history.
85
+
86
+
87
+ ## Optional Codex and Claude Code lifecycle hooks
88
+
89
+ Afterhours can measure episode boundaries and permission requests more
90
+ accurately from opt-in lifecycle hooks.
91
+
92
+ ```sh
93
+ # install the fragments for the agents found on this computer
94
+ npx @teeras/afterhours setup
95
+ ```
96
+
97
+ Running `setup` is the consent: it merges the Teeras fragment into the agents
98
+ it finds on this computer, leaves every other hook untouched, and is safe to
99
+ run again — a second run reports what is already connected instead of
100
+ duplicating it. The hook command it writes is an absolute path inside
101
+ `~/.teeras/afterhours`, so it keeps working after the `npx` directory is gone.
102
+ Remove the Teeras entries from the settings file to stop hook measurement, or
103
+ run `trs off` to do that for you — it clears the Teeras entries from both
104
+ agents' settings and deletes the local runtime, leaving every other hook and
105
+ your local journal and credentials untouched. If a settings file cannot be
106
+ read, `trs off` leaves both that file and the runtime alone and says so: the
107
+ entry it could not remove still points at the runtime, and deleting it would
108
+ leave your agent calling a command that is gone.
109
+
110
+ To review the configuration and merge it by hand instead:
111
+
112
+ ```sh
113
+ # Codex CLI and Codex desktop app
114
+ trs hook-config codex
115
+
116
+ # Claude Code
117
+ trs hook-config claude
118
+ ```
119
+
120
+ For Codex, review the fragment and merge it into
121
+ `$CODEX_HOME/hooks.json` (normally `~/.codex/hooks.json`), then review and trust
122
+ the hook in Codex. The user-level Codex configuration is shared by the desktop
123
+ app and CLI. For Claude Code, merge the fragment into
124
+ `$CLAUDE_CONFIG_DIR/settings.json` (normally `~/.claude/settings.json`).
125
+ Claude Code Desktop and CLI share hooks even though they maintain separate
126
+ session histories.
127
+
128
+ The hook command reduces each event immediately to a timestamp, an opaque
129
+ device-keyed session id, and one allowlisted lifecycle kind. The id is keyed
130
+ with a stable per-device secret (never a rotating login token), so episodes
131
+ stay consistent across logins. Prompt text, working directories, transcript
132
+ paths, tool inputs, notification messages, and outputs are discarded before
133
+ the local journal is written.
134
+
135
+ `trs sources` reports Codex and Claude Code hook status separately — event
136
+ count and last event time — so a misconfigured or logged-out hook is visible
137
+ instead of silently recording nothing. Passive local-history measurement
138
+ continues even if hooks are unavailable in an older client version.
139
+
140
+ Hooks improve measurement only. They do not currently trigger Walk Mode or
141
+ claim that an autonomous runway prediction is valid. Teeras first asks
142
+ participants to confirm episode boundaries and attention estimates in order to
143
+ validate the measurement contract.
@@ -1,13 +1,47 @@
1
- import type { ActivityBucket, SourceId, SourceSnapshot, TokenCounts } from "./types.js";
1
+ import type { ActivityBucket, DelegationEpisode, EpisodeConfidence, EpisodeLatency, LatencyStats, ModelActivity, SourceId, SourceSnapshot, TokenCounts } from "./types.js";
2
2
  export interface LocalEvent {
3
3
  at: number;
4
4
  kind: "agent" | "human";
5
+ /** Model that produced an agent event; absent when the source names none. */
6
+ model?: string;
5
7
  }
6
8
  export declare const EMPTY_TOKENS: TokenCounts;
7
9
  export declare function finiteNumber(value: unknown): number;
10
+ export declare function optionalFiniteNumber(value: unknown): number | null;
11
+ export declare function addToken(total: number | null, value: number | null): number | null;
8
12
  export declare function timestamp(value: unknown): number | null;
9
13
  export declare function inWindow(at: number, sinceMs: number, untilMs: number): boolean;
14
+ /** Local calendar date in the same format buckets and episodes use. */
15
+ export declare function localDateOf(at: number): string;
16
+ export declare const NO_LATENCY: EpisodeLatency;
17
+ export declare function latencyStats(samples: number[]): LatencyStats | null;
18
+ /**
19
+ * Gap from each human message to the first agent activity that follows it.
20
+ * A second human message before any agent activity restarts the clock — the
21
+ * person re-prompted, so the first wait was abandoned, not answered.
22
+ */
23
+ export declare function humanWaitSamples(events: LocalEvent[]): number[];
24
+ export declare function opaqueEpisodeId(secret: string, sourceId: string, sourceSession: string): string;
10
25
  export declare function bucketsFrom(events: LocalEvent[]): ActivityBucket[];
26
+ /**
27
+ * Per-model rollup of a source's work. Minutes use the same gap-to-next rule
28
+ * as the activity buckets, computed over ALL agent events so a model's share
29
+ * is its slice of the real timeline — a per-model subset would misread the
30
+ * gaps between models as one model's idle time. Events that never named a
31
+ * model shape the gaps but credit no entry, so the rollup can honestly sum
32
+ * to less than the source total.
33
+ */
34
+ export declare function modelActivityFrom(activityEvents: LocalEvent[], turnEvents: LocalEvent[]): ModelActivity[];
11
35
  export declare function emptySource(id: SourceId, name: string, configured: boolean): SourceSnapshot;
36
+ export declare function delegationEpisode(input: {
37
+ id: string;
38
+ adapterVersion: string;
39
+ events: LocalEvent[];
40
+ tokens: TokenCounts;
41
+ untilMs: number;
42
+ confidence?: EpisodeConfidence;
43
+ modelFamily?: string | null;
44
+ latency?: EpisodeLatency;
45
+ }): DelegationEpisode | null;
12
46
  export declare function finishSource(source: SourceSnapshot, events: LocalEvent[], fidelity?: SourceSnapshot["fidelity"]): SourceSnapshot;
13
47
  //# sourceMappingURL=activity.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,YAAY,EAAE,WAA8D,CAAC;AAE1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9E;AAwBD,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,EAAE,CAyBlE;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,cAAc,CAY3F;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,UAAU,EAAE,EACpB,QAAQ,GAAE,cAAc,CAAC,UAAU,CAAc,GAChD,cAAc,CAMhB"}
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,YAAY,EAAE,WAA0E,CAAC;AAEtG,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAElE;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAElF;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIvD;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAE9E;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C;AAUD,eAAO,MAAM,UAAU,EAAE,cAAgF,CAAC;AAK1G,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,YAAY,GAAG,IAAI,CAKnE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CAe/D;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAQ/F;AAgBD,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,cAAc,EAAE,CAyBlE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,UAAU,EAAE,EAC5B,UAAU,EAAE,UAAU,EAAE,GACvB,aAAa,EAAE,CA2BjB;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAG,cAAc,CAc3F;AA2BD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B,GAAG,iBAAiB,GAAG,IAAI,CA+B3B;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,UAAU,EAAE,EACpB,QAAQ,GAAE,cAAc,CAAC,UAAU,CAAc,GAChD,cAAc,CAMhB"}
package/dist/activity.js CHANGED
@@ -1,7 +1,14 @@
1
- export const EMPTY_TOKENS = { input: 0, cached: 0, output: 0, reasoning: 0 };
1
+ import { createHmac } from "node:crypto";
2
+ export const EMPTY_TOKENS = { input: null, cached: null, output: null, reasoning: null };
2
3
  export function finiteNumber(value) {
3
4
  return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
4
5
  }
6
+ export function optionalFiniteNumber(value) {
7
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : null;
8
+ }
9
+ export function addToken(total, value) {
10
+ return value == null ? total : (total ?? 0) + value;
11
+ }
5
12
  export function timestamp(value) {
6
13
  if (typeof value !== "string" && typeof value !== "number")
7
14
  return null;
@@ -11,6 +18,10 @@ export function timestamp(value) {
11
18
  export function inWindow(at, sinceMs, untilMs) {
12
19
  return at >= sinceMs && at <= untilMs;
13
20
  }
21
+ /** Local calendar date in the same format buckets and episodes use. */
22
+ export function localDateOf(at) {
23
+ return localClock(at).localDate;
24
+ }
14
25
  function localClock(at) {
15
26
  const d = new Date(at);
16
27
  const localDate = [d.getFullYear(), String(d.getMonth() + 1).padStart(2, "0"), String(d.getDate()).padStart(2, "0")].join("-");
@@ -18,6 +29,48 @@ function localClock(at) {
18
29
  d.setMinutes(0, 0, 0);
19
30
  return { hour: d.toISOString(), localDate, localHour: hourOfDay };
20
31
  }
32
+ export const NO_LATENCY = { timeToFirstToken: null, turnDuration: null, humanWait: null };
33
+ /** Waits longer than this read as the person walking away, not the model. */
34
+ const MAX_HUMAN_WAIT_MS = 30 * 60_000;
35
+ export function latencyStats(samples) {
36
+ const clean = samples.filter((value) => Number.isFinite(value) && value >= 0).sort((a, b) => a - b);
37
+ if (clean.length === 0)
38
+ return null;
39
+ const rank = (q) => clean[Math.min(clean.length - 1, Math.ceil(q * clean.length) - 1)];
40
+ return { samples: clean.length, p50Ms: Math.round(rank(0.5)), p90Ms: Math.round(rank(0.9)) };
41
+ }
42
+ /**
43
+ * Gap from each human message to the first agent activity that follows it.
44
+ * A second human message before any agent activity restarts the clock — the
45
+ * person re-prompted, so the first wait was abandoned, not answered.
46
+ */
47
+ export function humanWaitSamples(events) {
48
+ const sorted = [...events].sort((a, b) => a.at - b.at);
49
+ const waits = [];
50
+ let pendingHumanAt = null;
51
+ for (const event of sorted) {
52
+ if (event.kind === "human") {
53
+ pendingHumanAt = event.at;
54
+ continue;
55
+ }
56
+ if (pendingHumanAt == null)
57
+ continue;
58
+ const wait = event.at - pendingHumanAt;
59
+ if (wait >= 0 && wait <= MAX_HUMAN_WAIT_MS)
60
+ waits.push(wait);
61
+ pendingHumanAt = null;
62
+ }
63
+ return waits;
64
+ }
65
+ export function opaqueEpisodeId(secret, sourceId, sourceSession) {
66
+ return createHmac("sha256", secret)
67
+ .update("afterhours/delegation-episode/v1\0")
68
+ .update(sourceId)
69
+ .update("\0")
70
+ .update(sourceSession)
71
+ .digest("hex")
72
+ .slice(0, 40);
73
+ }
21
74
  function observedMinutes(events, capMinutes) {
22
75
  const byHour = new Map();
23
76
  const sorted = [...new Set(events)].sort((a, b) => a - b);
@@ -58,6 +111,43 @@ export function bucketsFrom(events) {
58
111
  }
59
112
  return [...rows.values()].sort((a, b) => a.hour.localeCompare(b.hour));
60
113
  }
114
+ /**
115
+ * Per-model rollup of a source's work. Minutes use the same gap-to-next rule
116
+ * as the activity buckets, computed over ALL agent events so a model's share
117
+ * is its slice of the real timeline — a per-model subset would misread the
118
+ * gaps between models as one model's idle time. Events that never named a
119
+ * model shape the gaps but credit no entry, so the rollup can honestly sum
120
+ * to less than the source total.
121
+ */
122
+ export function modelActivityFrom(activityEvents, turnEvents) {
123
+ const modelAt = new Map();
124
+ for (const event of activityEvents) {
125
+ if (event.kind === "agent" && event.model)
126
+ modelAt.set(event.at, event.model);
127
+ }
128
+ const times = [...new Set(activityEvents.filter((event) => event.kind === "agent").map((event) => event.at))].sort((a, b) => a - b);
129
+ const rollup = new Map();
130
+ const entry = (model) => {
131
+ const existing = rollup.get(model) ?? { model, agentTurns: 0, agentActiveMinutes: 0 };
132
+ rollup.set(model, existing);
133
+ return existing;
134
+ };
135
+ for (let index = 0; index < times.length; index += 1) {
136
+ const at = times[index];
137
+ const model = modelAt.get(at);
138
+ if (!model)
139
+ continue;
140
+ const next = times[index + 1];
141
+ entry(model).agentActiveMinutes += next == null ? 1 : Math.max(1, Math.min(5, (next - at) / 60_000));
142
+ }
143
+ for (const event of turnEvents) {
144
+ if (event.model)
145
+ entry(event.model).agentTurns += 1;
146
+ }
147
+ return [...rollup.values()]
148
+ .map((item) => ({ ...item, agentActiveMinutes: Math.round(item.agentActiveMinutes * 100) / 100 }))
149
+ .sort((a, b) => b.agentActiveMinutes - a.agentActiveMinutes || a.model.localeCompare(b.model));
150
+ }
61
151
  export function emptySource(id, name, configured) {
62
152
  return {
63
153
  id,
@@ -68,7 +158,64 @@ export function emptySource(id, name, configured) {
68
158
  agentTurns: 0,
69
159
  humanCheckIns: 0,
70
160
  tokens: { ...EMPTY_TOKENS },
161
+ models: [],
71
162
  buckets: [],
163
+ episodes: [],
164
+ };
165
+ }
166
+ function minutesFrom(events, kind, capMinutes) {
167
+ return [...observedMinutes(events.filter((event) => event.kind === kind).map((event) => event.at), capMinutes).values()].reduce((sum, value) => sum + value, 0);
168
+ }
169
+ function longestAutonomousRun(events) {
170
+ const sorted = [...events].sort((a, b) => a.at - b.at);
171
+ let current = 0;
172
+ let longest = 0;
173
+ for (let index = 0; index < sorted.length; index += 1) {
174
+ const event = sorted[index];
175
+ if (!event)
176
+ continue;
177
+ if (event.kind === "human") {
178
+ current = 0;
179
+ continue;
180
+ }
181
+ const next = sorted[index + 1];
182
+ current += next == null ? 1 : Math.max(1, Math.min(5, (next.at - event.at) / 60_000));
183
+ longest = Math.max(longest, current);
184
+ }
185
+ return Math.round(longest * 100) / 100;
186
+ }
187
+ export function delegationEpisode(input) {
188
+ if (input.events.length === 0)
189
+ return null;
190
+ const events = [...input.events].sort((a, b) => a.at - b.at);
191
+ const first = events[0];
192
+ const last = events.at(-1);
193
+ if (!first || !last)
194
+ return null;
195
+ const humanCheckIns = events.filter((event) => event.kind === "human").length;
196
+ const clock = localClock(first.at);
197
+ return {
198
+ id: input.id,
199
+ startedAt: new Date(first.at).toISOString(),
200
+ endedAt: new Date(last.at).toISOString(),
201
+ localDate: clock.localDate,
202
+ localStartHour: clock.localHour,
203
+ status: input.untilMs - last.at <= 5 * 60_000 ? "open" : "observed_end",
204
+ confidence: input.confidence ?? "high",
205
+ metricVersion: "delegation-episode-v1",
206
+ adapterVersion: input.adapterVersion,
207
+ modelFamily: input.modelFamily ?? null,
208
+ agentTurns: events.filter((event) => event.kind === "agent").length,
209
+ humanCheckIns,
210
+ humanReEntries: Math.max(0, humanCheckIns - 1),
211
+ agentActiveMinutes: Math.round(minutesFrom(events, "agent", 5) * 100) / 100,
212
+ humanAttentionMinutes: Math.round(minutesFrom(events, "human", 10) * 100) / 100,
213
+ longestAutonomousRunMinutes: longestAutonomousRun(events),
214
+ approvalRequests: null,
215
+ failureEvents: null,
216
+ reworkEvents: null,
217
+ latency: input.latency ?? { ...NO_LATENCY },
218
+ tokens: { ...input.tokens },
72
219
  };
73
220
  }
74
221
  export function finishSource(source, events, fidelity = "activity") {
@@ -1 +1 @@
1
- {"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAoBzC,MAAM,CAAC,MAAM,YAAY,GAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAEtG,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,KAAoB,EAAE,KAAoB;IACjE,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACxE,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrE,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAU,EAAE,OAAe,EAAE,OAAe;IACnE,OAAO,EAAE,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,CAAC;AACxC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,UAAU,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CAAC,EAAU;IAC5B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/H,MAAM,SAAS,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/B,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACtB,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAmB,EAAE,gBAAgB,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAE1G,6EAA6E;AAC7E,MAAM,iBAAiB,GAAG,EAAE,GAAG,MAAM,CAAC;AAEtC,MAAM,UAAU,YAAY,CAAC,OAAiB;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACpG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC;IACxG,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AAC/F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,cAAc,GAAkB,IAAI,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,cAAc,GAAG,KAAK,CAAC,EAAE,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,IAAI,cAAc,IAAI,IAAI;YAAE,SAAS;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,GAAG,cAAc,CAAC;QACvC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,iBAAiB;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,QAAgB,EAAE,aAAqB;IACrF,OAAO,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAChC,MAAM,CAAC,oCAAoC,CAAC;SAC5C,MAAM,CAAC,QAAQ,CAAC;SAChB,MAAM,CAAC,IAAI,CAAC;SACZ,MAAM,CAAC,aAAa,CAAC;SACrB,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,MAAgB,EAAE,UAAkB;IAC3D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACrB,IAAI,EAAE,IAAI,IAAI;YAAE,SAAS;QACzB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QAC3F,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAoB;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxF,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxF,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC/C,MAAM,YAAY,GAAG,eAAe,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;YAC5B,IAAI;YACJ,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,CAAC;YACb,aAAa,EAAE,CAAC;YAChB,kBAAkB,EAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/C,qBAAqB,EAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;SACnD,CAAC;QACF,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC;;YAC3C,GAAG,CAAC,aAAa,IAAI,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,cAA4B,EAC5B,UAAwB;IAExB,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CACvB,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAClF,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,KAAa,EAAiB,EAAE;QAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;QACtF,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC5B,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC;IACF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAE,CAAC;QACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC9B,KAAK,CAAC,KAAK,CAAC,CAAC,kBAAkB,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACvG,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;SACxB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;SACjG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB,GAAG,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACnG,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAAY,EAAE,IAAY,EAAE,UAAmB;IACzE,OAAO;QACL,EAAE;QACF,IAAI;QACJ,UAAU;QACV,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;QAC1C,QAAQ,EAAE,CAAC;QACX,UAAU,EAAE,CAAC;QACb,aAAa,EAAE,CAAC;QAChB,MAAM,EAAE,EAAE,GAAG,YAAY,EAAE;QAC3B,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,MAAoB,EAAE,IAAwB,EAAE,UAAkB;IACrF,OAAO,CAAC,GAAG,eAAe,CACxB,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,EACtE,UAAU,CACX,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,oBAAoB,CAAC,MAAoB;IAChD,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC,CAAC;YACZ,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/B,OAAO,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QACtF,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KASjC;IACC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAC9E,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnC,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,SAAS,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE;QAC3C,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE;QACxC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,SAAS;QAC/B,MAAM,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc;QACvE,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,MAAM;QACtC,aAAa,EAAE,uBAAuB;QACtC,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,IAAI;QACtC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM;QACnE,aAAa;QACb,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC;QAC9C,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG;QAC3E,qBAAqB,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG;QAC/E,2BAA2B,EAAE,oBAAoB,CAAC,MAAM,CAAC;QACzD,gBAAgB,EAAE,IAAI;QACtB,aAAa,EAAE,IAAI;QACnB,YAAY,EAAE,IAAI;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE,GAAG,UAAU,EAAE;QAC3C,MAAM,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE;KAC5B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAAsB,EACtB,MAAoB,EACpB,WAAuC,UAAU;IAEjD,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAC5E,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAC/E,MAAM,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACzE,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { spawn } from "node:child_process";
2
+ export declare const AUTO_SYNC_WINDOW_MS: number;
3
+ export interface SyncStamp {
4
+ attemptedAt: string | null;
5
+ succeededAt: string | null;
6
+ }
7
+ export declare function syncStampPath(home?: string): string;
8
+ export declare function readSyncStamp(home?: string): SyncStamp;
9
+ export declare function markSyncAttempt(home?: string, now?: number): void;
10
+ export declare function markSyncSuccess(home?: string, now?: number): void;
11
+ export declare function shouldAutoSync(home?: string, now?: number, windowMs?: number): boolean;
12
+ /**
13
+ * Authoritative, child-side sync. Attempts are stamped before the network call
14
+ * so a failing server is retried at the window cadence, never per hook event.
15
+ */
16
+ export declare function runAutoSync(home?: string, fetcher?: typeof fetch, now?: number): Promise<boolean>;
17
+ /**
18
+ * Cheap parent-side decision inside `trs hook`: never network I/O here — the
19
+ * hook must return within the agent's timeout. The child re-checks the window.
20
+ */
21
+ export declare function maybeSpawnAutoSync(cliPath: string, home?: string, spawner?: typeof spawn, now?: number): boolean;
22
+ //# sourceMappingURL=autosync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autosync.d.ts","sourceRoot":"","sources":["../src/autosync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAO3C,eAAO,MAAM,mBAAmB,QAAc,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAgB,aAAa,CAAC,IAAI,SAAY,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,IAAI,SAAY,GAAG,SAAS,CASzD;AAUD,wBAAgB,eAAe,CAAC,IAAI,SAAY,EAAE,GAAG,SAAa,GAAG,IAAI,CAExE;AAED,wBAAgB,eAAe,CAAC,IAAI,SAAY,EAAE,GAAG,SAAa,GAAG,IAAI,CAExE;AAED,wBAAgB,cAAc,CAAC,IAAI,SAAY,EAAE,GAAG,SAAa,EAAE,QAAQ,SAAsB,GAAG,OAAO,CAW1G;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,IAAI,SAAY,EAAE,OAAO,GAAE,OAAO,KAAa,EAAE,GAAG,SAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAarH;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,SAAY,EAChB,OAAO,GAAE,OAAO,KAAa,EAC7B,GAAG,SAAa,GACf,OAAO,CAST"}
@@ -0,0 +1,85 @@
1
+ import { spawn } from "node:child_process";
2
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { dirname, join } from "node:path";
5
+ import { readCredentials, syncSnapshot } from "./cloud.js";
6
+ import { collectAfterhours } from "./collect.js";
7
+ export const AUTO_SYNC_WINDOW_MS = 45 * 60_000;
8
+ export function syncStampPath(home = homedir()) {
9
+ return join(home, ".teeras", "afterhours", "last-sync.json");
10
+ }
11
+ export function readSyncStamp(home = homedir()) {
12
+ try {
13
+ const value = JSON.parse(readFileSync(syncStampPath(home), "utf8"));
14
+ const iso = (candidate) => typeof candidate === "string" && Number.isFinite(Date.parse(candidate)) ? candidate : null;
15
+ return { attemptedAt: iso(value.attemptedAt), succeededAt: iso(value.succeededAt) };
16
+ }
17
+ catch {
18
+ return { attemptedAt: null, succeededAt: null };
19
+ }
20
+ }
21
+ function writeSyncStamp(stamp, home) {
22
+ const path = syncStampPath(home);
23
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
24
+ chmodSync(dirname(path), 0o700);
25
+ writeFileSync(path, `${JSON.stringify(stamp, null, 2)}\n`, { mode: 0o600 });
26
+ chmodSync(path, 0o600);
27
+ }
28
+ export function markSyncAttempt(home = homedir(), now = Date.now()) {
29
+ writeSyncStamp({ ...readSyncStamp(home), attemptedAt: new Date(now).toISOString() }, home);
30
+ }
31
+ export function markSyncSuccess(home = homedir(), now = Date.now()) {
32
+ writeSyncStamp({ ...readSyncStamp(home), succeededAt: new Date(now).toISOString() }, home);
33
+ }
34
+ export function shouldAutoSync(home = homedir(), now = Date.now(), windowMs = AUTO_SYNC_WINDOW_MS) {
35
+ if (!readCredentials(home))
36
+ return false;
37
+ const stamp = readSyncStamp(home);
38
+ // Manual commands (`setup`, `connect`, `login`, `sync`, `week`) stamp success
39
+ // only, so the window has to answer to whichever happened last — otherwise a
40
+ // hook event seconds after `trs setup` spawns a redundant sync.
41
+ const times = [stamp.attemptedAt, stamp.succeededAt]
42
+ .map((value) => (value ? Date.parse(value) : null))
43
+ .filter((value) => value != null);
44
+ if (times.length === 0)
45
+ return true;
46
+ return now - Math.max(...times) >= windowMs;
47
+ }
48
+ /**
49
+ * Authoritative, child-side sync. Attempts are stamped before the network call
50
+ * so a failing server is retried at the window cadence, never per hook event.
51
+ */
52
+ export async function runAutoSync(home = homedir(), fetcher = fetch, now = Date.now()) {
53
+ if (!shouldAutoSync(home, now))
54
+ return false;
55
+ const credentials = readCredentials(home);
56
+ if (!credentials)
57
+ return false;
58
+ markSyncAttempt(home, now);
59
+ try {
60
+ await syncSnapshot(collectAfterhours({ home }), credentials, fetcher);
61
+ markSyncSuccess(home, now);
62
+ return true;
63
+ }
64
+ catch {
65
+ // Failure is visible via `trs sources` (last attempt vs last success).
66
+ return false;
67
+ }
68
+ }
69
+ /**
70
+ * Cheap parent-side decision inside `trs hook`: never network I/O here — the
71
+ * hook must return within the agent's timeout. The child re-checks the window.
72
+ */
73
+ export function maybeSpawnAutoSync(cliPath, home = homedir(), spawner = spawn, now = Date.now()) {
74
+ if (!shouldAutoSync(home, now))
75
+ return false;
76
+ try {
77
+ const child = spawner(process.execPath, [cliPath, "autosync"], { detached: true, stdio: "ignore" });
78
+ child.unref();
79
+ return true;
80
+ }
81
+ catch {
82
+ return false;
83
+ }
84
+ }
85
+ //# sourceMappingURL=autosync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autosync.js","sourceRoot":"","sources":["../src/autosync.ts"],"names":[],"mappings":"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"}