@knpkv/agent-usage 0.1.0 → 0.2.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 (62) hide show
  1. package/README.md +129 -20
  2. package/dist/client/assets/index-BWajfpNv.js +55 -0
  3. package/dist/client/assets/{index-CUuLXODk.css → index-B_xl-_rU.css} +1 -1
  4. package/dist/client/index.html +2 -2
  5. package/dist/core/ClaudeLimitSamples.d.ts +30 -0
  6. package/dist/core/ClaudeLimitSamples.js +69 -0
  7. package/dist/core/ClaudeLimitSamples.js.map +1 -0
  8. package/dist/core/ClaudeLimits.d.ts +38 -4
  9. package/dist/core/ClaudeLimits.js +66 -19
  10. package/dist/core/ClaudeLimits.js.map +1 -1
  11. package/dist/core/ClaudeLimitsLive.d.ts +33 -7
  12. package/dist/core/ClaudeLimitsLive.js +54 -10
  13. package/dist/core/ClaudeLimitsLive.js.map +1 -1
  14. package/dist/core/Database.d.ts +9 -1
  15. package/dist/core/Database.js +6 -2
  16. package/dist/core/Database.js.map +1 -1
  17. package/dist/core/Ingest.d.ts +7 -1
  18. package/dist/core/Ingest.js +36 -6
  19. package/dist/core/Ingest.js.map +1 -1
  20. package/dist/core/Model.d.ts +19 -7
  21. package/dist/core/Model.js +15 -3
  22. package/dist/core/Model.js.map +1 -1
  23. package/dist/core/Report.js +21 -7
  24. package/dist/core/Report.js.map +1 -1
  25. package/dist/core/Store.js +14 -12
  26. package/dist/core/Store.js.map +1 -1
  27. package/dist/main.js +30 -20
  28. package/dist/main.js.map +1 -1
  29. package/dist/server/Api.d.ts +130 -94
  30. package/dist/server/Config.d.ts +22 -3
  31. package/dist/server/Config.js +66 -4
  32. package/dist/server/Config.js.map +1 -1
  33. package/dist/server/ControlSocket.d.ts +73 -0
  34. package/dist/server/ControlSocket.js +270 -0
  35. package/dist/server/ControlSocket.js.map +1 -0
  36. package/dist/server/HttpApplication.d.ts +1 -1
  37. package/dist/server/HttpApplication.js +2 -1
  38. package/dist/server/HttpApplication.js.map +1 -1
  39. package/dist/server/IngestSummary.d.ts +8 -0
  40. package/dist/server/IngestSummary.js +32 -0
  41. package/dist/server/IngestSummary.js.map +1 -0
  42. package/dist/server/Live.d.ts +4 -0
  43. package/dist/server/Live.js +49 -0
  44. package/dist/server/Live.js.map +1 -0
  45. package/dist/server/Login.d.ts +34 -0
  46. package/dist/server/Login.js +74 -0
  47. package/dist/server/Login.js.map +1 -0
  48. package/dist/server/OwnerSession.d.ts +15 -8
  49. package/dist/server/OwnerSession.js +33 -25
  50. package/dist/server/OwnerSession.js.map +1 -1
  51. package/dist/server/Runtime.d.ts +3 -1
  52. package/dist/server/Runtime.js +32 -8
  53. package/dist/server/Runtime.js.map +1 -1
  54. package/dist/server/Server.d.ts +2 -2
  55. package/dist/server/Server.js +19 -6
  56. package/dist/server/Server.js.map +1 -1
  57. package/dist/shared/contracts.d.ts +51 -6
  58. package/dist/shared/contracts.js +11 -1
  59. package/dist/shared/contracts.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +3 -3
  62. package/dist/client/assets/index-DB-VXWqy.js +0 -55
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `agent-usage login`: a fresh one-time link from the running server, printed and optionally opened.
3
+ *
4
+ * The link goes to stdout and nowhere else, like the startup link: it is the credential. Failures
5
+ * go to stderr as one sentence saying what to do, and end the process with a nonzero exit.
6
+ *
7
+ * @module
8
+ */
9
+ import { Console, Effect, Runtime, Schema } from "effect";
10
+ import { ChildProcess, ChildProcessSpawner } from "effect/process";
11
+ import { requestLoginUrl } from "./ControlSocket.js";
12
+ /** The failure, already explained on stderr: the runtime exits nonzero without logging it again. */
13
+ export class LoginFailed extends Schema.TaggedError()("LoginFailed", {
14
+ reason: Schema.String
15
+ }) {
16
+ [Runtime.errorReported] = false;
17
+ }
18
+ /** One sentence per failure, naming what to do about it. */
19
+ export const describeLoginFailure = (failure) => {
20
+ switch (failure._tag) {
21
+ case "ServerNotRunning":
22
+ return "agent-usage is not running on this store. Start it with `agent-usage serve` (or its service), then run login again. If it is running, it is an older version without login: restart it.";
23
+ case "SocketPathUnsafe":
24
+ return `agent-usage refused its control socket at ${failure.path}: ${failure.reason}. Remove it and restart the server.`;
25
+ case "SocketRefused":
26
+ return `agent-usage's control socket at ${failure.path} could not be used (${failure.reason}).`;
27
+ case "SocketPathTooLong":
28
+ return `${failure.message}, so this store has no login. Set AGENT_USAGE_HOME to a shorter path.`;
29
+ case "LoginReplyInvalid":
30
+ return "the running agent-usage did not answer with a link; is it an older version? Restart it.";
31
+ }
32
+ };
33
+ /** The command that opens a URL in the default browser, where there is one this tool knows. */
34
+ export const openerFor = (platform) => platform === "darwin" ? "open" : platform === "linux" ? "xdg-open" : undefined;
35
+ /**
36
+ * Opens `url` in the browser. Reports a failure on stderr and carries on: the link is printed
37
+ * either way. The link is on the opener's command line while it runs, visible to this machine's
38
+ * process list for that moment; it is spent on first use and expires within the minute.
39
+ */
40
+ const openInBrowser = Effect.fnUntraced(function* (url, platform) {
41
+ const opener = openerFor(platform);
42
+ if (opener === undefined) {
43
+ return yield* Console.error(`agent-usage: cannot open a browser on ${platform}; open the link above.`);
44
+ }
45
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
46
+ // In this process's group, not one of its own: the opener's group is killed when it is reaped,
47
+ // which would take the browser it just started with it. Its output is not ours to hold open
48
+ // either: the browser inherits it and would keep login waiting for as long as it runs.
49
+ const opening = ChildProcess.make(opener, [url], {
50
+ detached: false,
51
+ stdin: "ignore",
52
+ stdout: "ignore",
53
+ stderr: "ignore"
54
+ });
55
+ const code = yield* spawner.exitCode(opening).pipe(Effect.result);
56
+ if (code._tag === "Failure" || code.success !== 0) {
57
+ yield* Console.error(`agent-usage: ${opener} could not open the link; open it yourself.`);
58
+ }
59
+ });
60
+ /** Explains `failure` on stderr, then fails without the runtime reporting it again. */
61
+ const reported = (sentence, reason) => Console.error(`agent-usage: ${sentence}`).pipe(Effect.andThen(Effect.fail(new LoginFailed({ reason }))));
62
+ /**
63
+ * Reads the store directory from `config`, asks the server running there for a link, prints it, and
64
+ * opens it when asked. Every failure, an unreadable configuration included, goes to stderr only, so
65
+ * stdout carries the link or nothing.
66
+ */
67
+ export const login = Effect.fn("Login.login")(function* (config, open, platform, self) {
68
+ const settings = yield* config.pipe(Effect.catch((error) => reported(`its configuration could not be read: ${error.message}`, "ConfigError")));
69
+ const url = yield* requestLoginUrl(settings.storeDirectory, self).pipe(Effect.catch((failure) => reported(describeLoginFailure(failure), failure._tag)));
70
+ yield* Console.log(url);
71
+ if (open)
72
+ yield* openInBrowser(url, platform);
73
+ });
74
+ //# sourceMappingURL=Login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Login.js","sourceRoot":"","sources":["../../src/server/Login.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,12 @@ import type { PairingCode, SessionToken } from "@knpkv/browser-pairing/schema";
2
2
  import { Context, Effect, Layer, Redacted, Ref, Schema } from "effect";
3
3
  import { HttpRouter } from "effect/http";
4
4
  import { ForbiddenApiError, OwnerSessionAuth, UnauthorizedApiError } from "./Api.js";
5
+ /** One minted code: what to compare, until when, and whether it has been spent. */
6
+ export interface BootstrapCode {
7
+ readonly token: Redacted.Redacted<PairingCode>;
8
+ readonly expiresAt: number;
9
+ readonly available: boolean;
10
+ }
5
11
  export interface BootstrapAttemptState {
6
12
  readonly failedAttempts: number;
7
13
  readonly inFlight: number;
@@ -14,10 +20,9 @@ export interface OwnerSessionSecretsContract {
14
20
  * dev server when it proxies in front of it, because that is the origin the page runs on.
15
21
  */
16
22
  readonly browserOrigin: string;
17
- readonly bootstrapAvailable: Ref.Ref<boolean>;
23
+ /** The current one-time code, or none before the first mint. */
24
+ readonly bootstrap: Ref.Ref<BootstrapCode | undefined>;
18
25
  readonly bootstrapAttemptState: Ref.Ref<BootstrapAttemptState>;
19
- readonly bootstrapExpiresAtMillis: Ref.Ref<number | undefined>;
20
- readonly bootstrapToken: Redacted.Redacted<PairingCode>;
21
26
  readonly ownerToken: Redacted.Redacted<SessionToken>;
22
27
  }
23
28
  declare const OwnerSessionSecrets_base: Context.ServiceClass<OwnerSessionSecrets, "@knpkv/agent-usage/OwnerSessionSecrets", OwnerSessionSecretsContract>;
@@ -35,13 +40,15 @@ export declare const requireLoopbackOrigin: (origin: string) => Effect.Effect<st
35
40
  /** The advertised origin: the bound server, or the dev server that proxies to it. */
36
41
  export declare const resolvePublicOrigin: (configuredOrigin: string | undefined, authorityOrigin: string) => Effect.Effect<string, UnsafeServerOriginError, never>;
37
42
  export declare const makeOwnerSessionSecrets: (authorityOrigin: string, configuredPublicOrigin?: string | undefined) => Effect.Effect<OwnerSessionSecretsContract, import("@knpkv/browser-pairing").BrowserPairingError | UnsafeServerOriginError, import("effect/Crypto").Crypto>;
38
- /** Start the bootstrap clock. Called once the server is actually listening, never before. */
39
- export declare const activateOwnerSessionBootstrap: (secrets: OwnerSessionSecretsContract) => Effect.Effect<void, import("@knpkv/browser-pairing").BrowserPairingError, never>;
40
43
  /**
41
- * The URL to open. The code rides in the fragment, which browsers do not send to servers and
42
- * proxies do not log, and the page strips it from the address bar once it has been spent.
44
+ * Mints a fresh one-time code and returns the URL that carries it: usable once, for a minute. The
45
+ * startup link and every `agent-usage login` link come from here; a newer code replaces any unspent
46
+ * one and reopens an exchange that guesses had closed. Call it only once the server is listening.
47
+ *
48
+ * The code rides in the fragment, which browsers do not send to servers and proxies do not log,
49
+ * and the page strips it from the address bar once it has been spent.
43
50
  */
44
- export declare const ownerSessionUrl: (publicOrigin: string, secrets: Pick<OwnerSessionSecretsContract, "bootstrapToken">) => string;
51
+ export declare const mintBootstrapUrl: (secrets: OwnerSessionSecretsContract) => Effect.Effect<string, import("@knpkv/browser-pairing").BrowserPairingError, import("effect/Crypto").Crypto>;
45
52
  export declare const ownerSessionCookie: (secrets: Pick<OwnerSessionSecretsContract, "ownerToken">) => string;
46
53
  interface OwnerRequest {
47
54
  readonly credential: string;
@@ -7,8 +7,10 @@
7
7
  * itself at startup. There is no user table and no login: the person who can read the terminal is
8
8
  * the person who gets in, which is the authority a page showing their own agents' usage, ticket
9
9
  * keys and working directories should demand.
10
- * - **The URL is the handshake.** The bootstrap code is printed once, in a fragment the browser
11
- * never sends upstream, and is spent the first time it is exchanged for the session cookie.
10
+ * - **The URL is the handshake.** A bootstrap code rides in a fragment the browser never sends
11
+ * upstream and is spent the first time it is exchanged for the session cookie. One is minted when
12
+ * the server starts and another each time `agent-usage login` asks over the control socket; both
13
+ * go through {@link mintBootstrapUrl}, and a newer code replaces an unspent one.
12
14
  * - **Every route only reads, and a read needs the cookie and must not be a browser cross-origin
13
15
  * request.** Another page in the same browser can make the browser send a cookie, but Fetch
14
16
  * Metadata keeps that page from reading usage without an Origin. With no writes there is no CSRF
@@ -25,10 +27,10 @@ import { credentialValuesEqual, decideOneTimeCredential, expiresAt, issuePairing
25
27
  import { Clock, Context, Effect, Layer, Redacted, Ref, Schema } from "effect";
26
28
  import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/http";
27
29
  import { ForbiddenApiError, OwnerSessionAuth, UnauthorizedApiError } from "./Api.js";
28
- /** How long the printed bootstrap URL stays usable. Long enough to click, short enough to forget. */
30
+ /** How long a minted bootstrap URL stays usable. Long enough to click, short enough to forget. */
29
31
  const BOOTSTRAP_LIFETIME_MILLIS = 60_000;
30
32
  /**
31
- * Failed bootstrap exchanges before the exchange closes for the life of the process.
33
+ * Failed bootstrap exchanges before the exchange closes, until the owner mints a new code.
32
34
  *
33
35
  * The code is high-entropy, so this is not what makes guessing hard — it is what stops a process
34
36
  * that is being guessed at from staying open all afternoon.
@@ -77,27 +79,31 @@ export const resolvePublicOrigin = Effect.fn("OwnerSession.resolvePublicOrigin")
77
79
  export const makeOwnerSessionSecrets = Effect.fn("OwnerSession.makeSecrets")(function* (authorityOrigin, configuredPublicOrigin) {
78
80
  const validated = yield* requireLoopbackOrigin(authorityOrigin);
79
81
  const browserOrigin = yield* resolvePublicOrigin(configuredPublicOrigin, validated);
80
- const [ownerToken, bootstrapToken] = yield* Effect.all([issueSessionToken(), issuePairingCode()]);
82
+ const ownerToken = yield* issueSessionToken();
81
83
  return OwnerSessionSecrets.of({
82
84
  authorityOrigin: validated,
85
+ bootstrap: yield* Ref.make(undefined),
83
86
  bootstrapAttemptState: yield* Ref.make({ failedAttempts: 0, inFlight: 0 }),
84
- bootstrapAvailable: yield* Ref.make(true),
85
- bootstrapExpiresAtMillis: yield* Ref.make(undefined),
86
- bootstrapToken,
87
87
  browserOrigin,
88
88
  ownerToken
89
89
  });
90
90
  });
91
- /** Start the bootstrap clock. Called once the server is actually listening, never before. */
92
- export const activateOwnerSessionBootstrap = Effect.fn("OwnerSession.activateBootstrap")(function* (secrets) {
93
- const now = yield* Clock.currentTimeMillis;
94
- yield* Ref.set(secrets.bootstrapExpiresAtMillis, yield* expiresAt(now, BOOTSTRAP_LIFETIME_MILLIS));
95
- });
96
91
  /**
97
- * The URL to open. The code rides in the fragment, which browsers do not send to servers and
98
- * proxies do not log, and the page strips it from the address bar once it has been spent.
92
+ * Mints a fresh one-time code and returns the URL that carries it: usable once, for a minute. The
93
+ * startup link and every `agent-usage login` link come from here; a newer code replaces any unspent
94
+ * one and reopens an exchange that guesses had closed. Call it only once the server is listening.
95
+ *
96
+ * The code rides in the fragment, which browsers do not send to servers and proxies do not log,
97
+ * and the page strips it from the address bar once it has been spent.
99
98
  */
100
- export const ownerSessionUrl = (publicOrigin, secrets) => `${publicOrigin.replace(/\/+$/u, "")}/#bootstrap_token=${encodeURIComponent(Redacted.value(secrets.bootstrapToken))}`;
99
+ export const mintBootstrapUrl = Effect.fn("OwnerSession.mintBootstrapUrl")(function* (secrets) {
100
+ const token = yield* issuePairingCode();
101
+ const now = yield* Clock.currentTimeMillis;
102
+ const until = yield* expiresAt(now, BOOTSTRAP_LIFETIME_MILLIS);
103
+ yield* Ref.set(secrets.bootstrap, { token, expiresAt: until, available: true });
104
+ yield* Ref.set(secrets.bootstrapAttemptState, { failedAttempts: 0, inFlight: 0 });
105
+ return `${secrets.browserOrigin.replace(/\/+$/u, "")}/#bootstrap_token=${encodeURIComponent(Redacted.value(token))}`;
106
+ });
101
107
  export const ownerSessionCookie = (secrets) => serializeCredentialCookie(secrets.ownerToken, {
102
108
  httpOnly: true,
103
109
  name: "agent_usage_owner",
@@ -135,13 +141,14 @@ export const authorizeBootstrapRequest = Effect.fn("OwnerSession.authorizeBootst
135
141
  return yield* new ForbiddenApiError({ message: "Bootstrap origin does not match this agent-usage server" });
136
142
  }
137
143
  const supplied = bearerToken(request.authorization);
144
+ const current = yield* Ref.get(secrets.bootstrap);
138
145
  // Counted before the code is even compared, so a burst of parallel guesses cannot all pass the
139
146
  // check together and then be counted afterwards.
140
147
  const admit = Ref.modify(secrets.bootstrapAttemptState, (state) => {
141
148
  if (state.failedAttempts + state.inFlight >= MAX_BOOTSTRAP_FAILURES)
142
149
  return ["unavailable", state];
143
- const matches = supplied !== undefined &&
144
- credentialValuesEqual(supplied, Redacted.value(secrets.bootstrapToken)) === true;
150
+ const matches = supplied !== undefined && current !== undefined &&
151
+ credentialValuesEqual(supplied, Redacted.value(current.token)) === true;
145
152
  if (!matches) {
146
153
  return ["invalid", {
147
154
  failedAttempts: Math.min(MAX_BOOTSTRAP_FAILURES, state.failedAttempts + 1),
@@ -155,18 +162,19 @@ export const authorizeBootstrapRequest = Effect.fn("OwnerSession.authorizeBootst
155
162
  ? Effect.fail(new UnauthorizedApiError({ message: "Missing or invalid bootstrap token" }))
156
163
  : Effect.void));
157
164
  return yield* Effect.acquireUseRelease(admit, () => Effect.gen(function* () {
158
- const expiry = yield* Ref.get(secrets.bootstrapExpiresAtMillis);
159
- if (expiry === undefined)
160
- return yield* new UnauthorizedApiError({ message: "Bootstrap is not active yet" });
161
165
  const now = yield* Clock.currentTimeMillis;
162
- const decision = yield* Ref.modify(secrets.bootstrapAvailable, (available) => {
163
- const next = decideOneTimeCredential({ consumedAt: available ? null : 0, expiresAt: expiry, revokedAt: null }, now);
164
- return [next, next === "accepted" ? false : available];
166
+ // Spent only if it is still the code that was compared: a newer mint replaced it otherwise.
167
+ const decision = yield* Ref.modify(secrets.bootstrap, (code) => {
168
+ if (code === undefined || current === undefined || code.token !== current.token) {
169
+ return ["consumed", code];
170
+ }
171
+ const next = decideOneTimeCredential({ consumedAt: code.available ? null : 0, expiresAt: code.expiresAt, revokedAt: null }, now);
172
+ return [next, next === "accepted" ? { ...code, available: false } : code];
165
173
  });
166
174
  if (decision === "accepted")
167
175
  return;
168
176
  const message = decision === "expired"
169
- ? "Bootstrap token has expired — restart agent-usage for a fresh URL"
177
+ ? "Bootstrap token has expired"
170
178
  : decision === "consumed"
171
179
  ? "Bootstrap token has already been used"
172
180
  : "Bootstrap token state is invalid";
@@ -1 +1 @@
1
- {"version":3,"file":"OwnerSession.js","sourceRoot":"","sources":["../../src/server/OwnerSession.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OwnerSession.js","sourceRoot":"","sources":["../../src/server/OwnerSession.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@ import { type ClaudeUsageDeps } from "../core/ClaudeLimits.js";
20
20
  import { type SourceRoots } from "../core/Ingest.js";
21
21
  import { UsageStore } from "../core/Store.js";
22
22
  import { type TicketSearch } from "../core/Tickets.js";
23
- import type { ServerStatus } from "../shared/contracts.js";
23
+ import type { LiveVersions, ServerStatus } from "../shared/contracts.js";
24
24
  export declare const INGEST_INTERVAL: Duration.Duration;
25
25
  export declare const CLAUDE_POLL_INTERVAL: Duration.Duration;
26
26
  declare const RuntimeState_base: Context.ServiceClass<RuntimeState, "@knpkv/agent-usage/server/Runtime/RuntimeState", {
@@ -29,6 +29,8 @@ declare const RuntimeState_base: Context.ServiceClass<RuntimeState, "@knpkv/agen
29
29
  readonly projects: ReadonlyArray<string>;
30
30
  /** The status the page shows; a SubscriptionRef so its changes can be followed. */
31
31
  readonly status: SubscriptionRef.SubscriptionRef<ServerStatus>;
32
+ /** What the live-updates socket pushes; moved only after the store has committed the change. */
33
+ readonly versions: SubscriptionRef.SubscriptionRef<LiveVersions>;
32
34
  }>;
33
35
  export declare class RuntimeState extends RuntimeState_base {
34
36
  static readonly layer: (machine: string, projects?: ReadonlyArray<string>) => Layer.Layer<RuntimeState, never, never>;
@@ -9,14 +9,27 @@ export const CLAUDE_POLL_INTERVAL = Duration.minutes(5);
9
9
  /** How far back ticket titles are kept fresh. */
10
10
  const TITLE_HORIZON_MILLIS = 90 * 24 * 60 * 60 * 1000;
11
11
  export class RuntimeState extends Context.Service()("@knpkv/agent-usage/server/Runtime/RuntimeState") {
12
- static layer = (machine, projects = []) => Layer.effect(RuntimeState, Effect.map(SubscriptionRef.make({
13
- machine,
14
- ingest: null,
15
- ingestFailure: null,
16
- limitsFailure: null,
17
- ticketLookupFailures: []
18
- }), (status) => RuntimeState.of({ machine, projects, status })));
12
+ static layer = (machine, projects = []) => Layer.effect(RuntimeState, Effect.gen(function* () {
13
+ const status = yield* SubscriptionRef.make({
14
+ machine,
15
+ ingest: null,
16
+ ingestFailure: null,
17
+ limitsFailure: null,
18
+ ticketLookupFailures: []
19
+ });
20
+ const versions = yield* SubscriptionRef.make({ usage: 0, limits: 0, status: 0 });
21
+ return RuntimeState.of({ machine, projects, status, versions });
22
+ }));
19
23
  }
24
+ /** Moves the named counters by one; called once the change they announce is in the store. */
25
+ const announce = (reads) => Effect.gen(function* () {
26
+ const state = yield* RuntimeState;
27
+ yield* SubscriptionRef.update(state.versions, (versions) => ({
28
+ usage: versions.usage + (reads.includes("usage") ? 1 : 0),
29
+ limits: versions.limits + (reads.includes("limits") ? 1 : 0),
30
+ status: versions.status + (reads.includes("status") ? 1 : 0)
31
+ }));
32
+ });
20
33
  /** The Known Projects now: those the store's branches and paths name, plus the configured ones. */
21
34
  export const currentKnownProjects = Effect.gen(function* () {
22
35
  const store = yield* UsageStore;
@@ -43,13 +56,21 @@ export const ingestCycle = (options) => Effect.gen(function* () {
43
56
  const state = yield* RuntimeState;
44
57
  const outcome = yield* Effect.result(ingestOnce(options.roots));
45
58
  if (outcome._tag === "Failure") {
59
+ // The page shows which operation failed; the log keeps why, for whoever runs the server.
60
+ yield* Effect.logWarning("ingest pass failed", outcome.failure.operation, outcome.failure.cause);
46
61
  yield* SubscriptionRef.update(state.status, (status) => ({
47
62
  ...status,
48
63
  ingestFailure: `${outcome.failure.operation}: the store could not be written`
49
64
  }));
65
+ // Chunks committed before the failure are in the store, so both reads may have moved.
66
+ yield* announce(["usage", "limits", "status"]);
50
67
  return;
51
68
  }
52
69
  yield* SubscriptionRef.update(state.status, (status) => ({ ...status, ingest: outcome.success, ingestFailure: null }));
70
+ // Every chunk of the pass is committed by now. Rollouts and samples carry limit readings too.
71
+ const { claude, claudeLimitSamples, codex } = outcome.success;
72
+ const read = claude.filesRead + codex.filesRead + claudeLimitSamples.filesRead > 0;
73
+ yield* announce(read ? ["usage", "limits", "status"] : ["status"]);
53
74
  });
54
75
  /**
55
76
  * One title refresh for the tickets booked recently. It runs on its own schedule: a slow or hung
@@ -57,8 +78,10 @@ export const ingestCycle = (options) => Effect.gen(function* () {
57
78
  */
58
79
  export const titleCycle = (options) => Effect.gen(function* () {
59
80
  const state = yield* RuntimeState;
60
- const failures = yield* recentTicketKeys.pipe(Effect.flatMap((keys) => refreshTicketTitles(keys, options.ticketSearch)), Effect.map((lookups) => lookups.map((failure) => failure.reason)), Effect.catchTag("StoreError", (error) => Effect.succeed([`ticket titles: ${error.operation} failed`])));
81
+ const failures = yield* recentTicketKeys.pipe(Effect.flatMap((keys) => refreshTicketTitles(keys, options.ticketSearch)), Effect.map((lookups) => lookups.map((failure) => failure.reason)), Effect.catchTag("StoreError", (error) => Effect.logWarning("ticket title refresh failed", error.operation, error.cause).pipe(Effect.as([`ticket titles: ${error.operation} failed`]))));
61
82
  yield* SubscriptionRef.update(state.status, (status) => ({ ...status, ticketLookupFailures: [...new Set(failures)] }));
83
+ // Titles saved in this cycle change the Booking table.
84
+ yield* announce(["usage", "status"]);
62
85
  });
63
86
  /**
64
87
  * One Claude limit poll, recorded. Failing to store it is reported apart from ingest, so a good
@@ -75,6 +98,7 @@ export const claudePollCycle = (options) => Effect.gen(function* () {
75
98
  ? `${stored.failure.operation}: Claude limits could not be stored`
76
99
  : null
77
100
  }));
101
+ yield* announce(stored._tag === "Failure" ? ["status"] : ["limits", "status"]);
78
102
  });
79
103
  /** Runs both cycles on their intervals for the life of the layer's scope. */
80
104
  export const backgroundLayer = (options) => Layer.effectDiscard(Effect.gen(function* () {
@@ -1 +1 @@
1
- {"version":3,"file":"Runtime.js","sourceRoot":"","sources":["../../src/server/Runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Runtime.js","sourceRoot":"","sources":["../../src/server/Runtime.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,10 @@ export interface AgentUsageServerOptions {
5
5
  readonly config: AgentUsageConfig;
6
6
  readonly hostname?: string;
7
7
  readonly port: number;
8
- readonly ready?: Deferred.Deferred<void>;
8
+ readonly ready?: Deferred.Deferred<string>;
9
9
  readonly security: OwnerSessionSecretsContract;
10
10
  }
11
- export declare const makeServer: (options: AgentUsageServerOptions) => Layer.Layer<never, import("@knpkv/browser-pairing").BrowserPairingError | Schema.SchemaError | import("effect/http/HttpServerError").ServeError | import("../core/Store.js").StoreError, never>;
11
+ export declare const makeServer: (options: AgentUsageServerOptions) => Layer.Layer<never, import("@knpkv/browser-pairing").BrowserPairingError | Schema.SchemaError | import("effect/http/HttpServerError").ServeError | import("./ControlSocket.js").ServerAlreadyRunning | import("./ControlSocket.js").SocketPathUnsafe | import("./ControlSocket.js").SocketRefused | import("../core/Store.js").StoreError, import("effect/Crypto").Crypto>;
12
12
  /** The port to bind: next to jcf-web's 3111. */
13
13
  export declare const Port: Config.Config<number>;
14
14
  /** Set by `pnpm dev` so the printed URL points at the Vite dev server that proxies here. */
@@ -13,25 +13,38 @@
13
13
  import { NodeHttpServer, NodeServices } from "@effect/platform-node";
14
14
  import { Config, Deferred, Effect, Layer, Schema } from "effect";
15
15
  import { Etag, FetchHttpClient, HttpPlatform, HttpRouter } from "effect/http";
16
+ import * as Reactivity from "effect/reactivity/Reactivity";
16
17
  import { createServer } from "node:http";
17
18
  import { liveClaudeUsageDeps } from "../core/ClaudeLimitsLive.js";
18
19
  import { databaseLayer } from "../core/Database.js";
19
20
  import { acliTicketSearch } from "../core/Tickets.js";
21
+ import { controlSocket } from "./ControlSocket.js";
20
22
  import { application } from "./HttpApplication.js";
21
- import { activateOwnerSessionBootstrap, OwnerSessionSecrets } from "./OwnerSession.js";
23
+ import { mintBootstrapUrl, OwnerSessionSecrets } from "./OwnerSession.js";
22
24
  import { backgroundLayer, RuntimeState } from "./Runtime.js";
23
25
  const HttpPlatformLive = HttpPlatform.layer.pipe(Layer.provide(NodeServices.layer));
24
26
  const LoopbackHostname = Schema.Literals(["127.0.0.1", "localhost", "::1"]);
25
27
  /** The background ingest and polling, with their live dependencies. */
26
28
  const background = (config) => Layer.unwrap(Effect.gen(function* () {
27
- const claude = yield* liveClaudeUsageDeps(config.claudeConfigDir);
29
+ const claude = yield* liveClaudeUsageDeps(config.claudeCredentials);
28
30
  const ticketSearch = yield* acliTicketSearch;
29
31
  return backgroundLayer({ roots: config.roots, claude, ticketSearch });
30
32
  }));
31
- export const makeServer = (options) => Layer.unwrap(Schema.decodeUnknownEffect(LoopbackHostname)(options.hostname ?? "127.0.0.1").pipe(Effect.map((hostname) => {
32
- const services = Layer.mergeAll(databaseLayer(options.config.storeDirectory), RuntimeState.layer(options.config.roots.machine, options.config.projects));
33
- return Layer.mergeAll(HttpRouter.serve(application), background(options.config)).pipe(Layer.provide(services), Layer.provide(NodeHttpServer.layerServer(createServer, { host: hostname, port: options.port })), Layer.provide(Etag.layer), Layer.provide(HttpPlatformLive), Layer.provide(FetchHttpClient.layer), Layer.provide(NodeServices.layer), Layer.provide(Layer.succeed(OwnerSessionSecrets, options.security)), Layer.tap(() => activateOwnerSessionBootstrap(options.security).pipe(Effect.andThen(options.ready === undefined ? Effect.void : Deferred.succeed(options.ready, undefined)))));
34
- })));
33
+ export const makeServer = (options) => Layer.unwrap(Effect.gen(function* () {
34
+ const hostname = yield* Schema.decodeUnknownEffect(LoopbackHostname)(options.hostname ?? "127.0.0.1");
35
+ // Opened once the HTTP listener is up: the control socket mints nothing before then.
36
+ const listening = yield* Deferred.make();
37
+ // The store's lock and login socket. Everything that touches the store or binds a port waits
38
+ // for it, so a second server on this store stops before reading anything or binding.
39
+ const control = Layer.effectDiscard(controlSocket(options.config.storeDirectory, options.security, Deferred.await(listening))).pipe(Layer.provide(Reactivity.layer), Layer.provide(NodeServices.layer));
40
+ const store = databaseLayer(options.config.storeDirectory).pipe(Layer.provide(control));
41
+ const services = Layer.mergeAll(store, RuntimeState.layer(options.config.roots.machine, options.config.projects));
42
+ // Bound only once the control layer holds the store's lock.
43
+ const listener = NodeHttpServer.layerServer(createServer, { host: hostname, port: options.port }).pipe(Layer.provide(control));
44
+ return Layer.mergeAll(HttpRouter.serve(application), background(options.config)).pipe(Layer.provide(services), Layer.provide(listener), Layer.provide(Etag.layer), Layer.provide(HttpPlatformLive), Layer.provide(FetchHttpClient.layer), Layer.provide(NodeServices.layer), Layer.provide(Layer.succeed(OwnerSessionSecrets, options.security)), Layer.tap(() =>
45
+ // The startup link: minted only once the server is listening, handed to whoever prints it.
46
+ mintBootstrapUrl(options.security).pipe(Effect.tap(() => Deferred.succeed(listening, undefined)), Effect.flatMap((url) => options.ready === undefined ? Effect.void : Deferred.succeed(options.ready, url)))));
47
+ }));
35
48
  /** The port to bind: next to jcf-web's 3111. */
36
49
  export const Port = Config.Int("PORT").pipe(Config.withDefault(3112));
37
50
  /** Set by `pnpm dev` so the printed URL points at the Vite dev server that proxies here. */
@@ -1 +1 @@
1
- {"version":3,"file":"Server.js","sourceRoot":"","sources":["../../src/server/Server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Server.js","sourceRoot":"","sources":["../../src/server/Server.ts"],"names":[],"mappings":"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"}