@persistmemory/cli 0.3.0 → 0.3.2

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/dist/bin.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../sdk-js/src/query.ts", "../../sdk-js/src/backoff.ts", "../../sdk-js/src/errors.ts", "../../sdk-js/src/http.ts", "../../sdk-js/src/pagination.ts", "../../sdk-js/src/resources/memories.ts", "../../sdk-js/src/resources/search.ts", "../../sdk-js/src/resources/spaces.ts", "../../sdk-js/src/resources/ingestion.ts", "../../sdk-js/src/resources/knowledge.ts", "../../sdk-js/src/resources/conversations.ts", "../../sdk-js/src/resources/google.ts", "../../sdk-js/src/resources/integrations.ts", "../../sdk-js/src/resources/health.ts", "../../sdk-js/src/resources/agent.ts", "../../sdk-js/src/client.ts", "../src/args.ts", "../src/config.ts", "../src/output.ts", "../src/help.ts", "../src/update.ts", "../src/auth/oauth.ts", "../src/auth/pkce.ts", "../src/auth/loopback.ts", "../src/session.ts", "../src/context.ts", "../src/commands/agent.ts", "../src/files.ts", "../src/commands/google.ts", "../src/commands/requests.ts", "../src/workspace.ts", "../src/commands/setup.ts", "../src/commands/auth.ts", "../src/commands/maintain.ts", "../src/commands/session.ts", "../src/events.ts", "../src/commands/memory.ts", "../src/spaces.ts", "../src/index.ts", "../src/bin.ts"],
4
- "sourcesContent": ["/**\n * Turning parameters into a query string the API's parser reads the way we mean.\n *\n * Its own module because both the request loop and every list resource need\n * it, and putting it in either one would have the other importing a transport\n * to build a string.\n */\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | readonly number[]\n | undefined;\n\nexport type QueryParams = Readonly<Record<string, QueryValue>>;\n\n/**\n * Builds a query string the API's parser will read the way we mean it.\n *\n * Arrays repeat the key - `?spaceIds=a&spaceIds=b` - because that is what\n * Express hands to the schemas, which accept either one value or a list.\n * Comma-joining would arrive as a single id containing a comma and match\n * nothing, with no error to say why.\n *\n * Booleans are sent as `true`/`false` strings. The API parses those\n * explicitly, because `Boolean(\"false\")` is `true` and a flag written that way\n * can never be turned off.\n */\nexport function encodeQuery(params?: QueryParams): string {\n if (!params) return \"\";\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n // Undefined is dropped, never sent. `?cursor=undefined` is a string the\n // server tries to decode, and the 400 it produces names the cursor rather\n // than the caller who forgot to omit it.\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n for (const one of value as readonly (string | number)[]) search.append(key, String(one));\n continue;\n }\n search.append(key, String(value));\n }\n\n const encoded = search.toString();\n return encoded ? `?${encoded}` : \"\";\n}\n\n/**\n * The two parameters every list shares, plus whatever the endpoint adds.\n *\n * Shared because the cursor rule is subtle enough to get wrong once per\n * resource: the PAGINATOR's cursor wins over the caller's. The caller's seeds\n * the first page - resuming from a bookmark - and the paginator supplies every\n * page after that. Letting the caller's win would re-read the same page\n * forever, which looks like an account that never ends.\n */\nexport function pageQuery(\n params: { readonly limit?: number; readonly cursor?: string },\n cursor: string | undefined,\n extra: QueryParams\n): QueryParams {\n return {\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(cursor !== undefined\n ? { cursor }\n : params.cursor !== undefined\n ? { cursor: params.cursor }\n : {}),\n ...extra\n };\n}\n", "/**\n * How long to wait before trying again.\n *\n * Exponential, capped, and jittered, for the reasons the rest of this repo\n * gives in `@persistmemory/async`:\n *\n * exponential a cause that has not cleared in 200ms may clear in two\n * seconds; hammering it every 200ms spends the attempts faster\n * without giving it time to recover.\n *\n * capped unbounded doubling reaches minutes, and a caller waiting\n * inside one function call cannot tell that from a hang.\n *\n * jittered the one that gets skipped, and the one that matters most. An\n * outage fails every in-flight request at once; without jitter\n * every client waits exactly two seconds and retries in the\n * same millisecond, so the recovering service is hit by the\n * whole fleet and knocked over again. The retry storm is caused\n * by the retry policy.\n *\n * Duplicated here rather than imported from `@persistmemory/async` on purpose:\n * this package is published to npm and installed by people who have no reason\n * to pull in a queue runtime, a Redis client and a dead-letter store to make\n * an HTTP request.\n */\nexport interface BackoffOptions {\n readonly baseMs?: number;\n readonly maxMs?: number;\n readonly factor?: number;\n /** 0 = none, 1 = full. Full is the right default; see below. */\n readonly jitter?: number;\n /** Injected so a test is not at the mercy of the random number generator. */\n readonly random?: () => number;\n}\n\n/**\n * Short by server standards.\n *\n * A queue worker can afford to come back in a minute. A caller is blocked\n * inside `await client.search(...)` and has a user watching, so the whole\n * retry budget has to fit inside a request timeout rather than outlast it.\n */\nexport const DEFAULT_BACKOFF = { baseMs: 250, maxMs: 8_000, factor: 2, jitter: 1 } as const;\n\n/**\n * The delay before attempt `attempt` (1-based).\n *\n * FULL jitter by default - a random point in [0, ceiling] rather than\n * ceiling plus or minus a wobble. It sounds worse and measures better:\n * partial jitter leaves the retries clustered around the same instant, which\n * is the thing that overwhelms a service coming back up.\n */\nexport function backoffMs(attempt: number, options: BackoffOptions = {}): number {\n const base = options.baseMs ?? DEFAULT_BACKOFF.baseMs;\n const max = options.maxMs ?? DEFAULT_BACKOFF.maxMs;\n const factor = options.factor ?? DEFAULT_BACKOFF.factor;\n const jitter = clamp01(options.jitter ?? DEFAULT_BACKOFF.jitter);\n const random = options.random ?? Math.random;\n\n // Clamped at 1: attempt 0 would give a negative exponent and a delay\n // shorter than the base, so the first retry would be the fastest one.\n const exponent = Math.max(0, Math.floor(attempt) - 1);\n // Capped BEFORE jitter. Capping after lets an un-jittered value of minutes\n // be scaled down to something that looks reasonable while the underlying\n // growth is still unbounded.\n const ceiling = Math.min(max, base * Math.pow(factor, exponent));\n\n if (jitter <= 0) return Math.round(ceiling);\n\n const fixed = ceiling * (1 - jitter);\n return Math.round(fixed + random() * (ceiling - fixed));\n}\n\n/**\n * The delay to actually use, honouring what the server asked for.\n *\n * `Retry-After` is taken as a FLOOR, not verbatim. Verbatim would let a\n * one-second hint on the fifth consecutive 429 undo the backoff entirely and\n * put us straight back into the limit; ignoring it would have us retry before\n * the window resets and spend an attempt learning what we were already told.\n *\n * A server asking for LONGER than our cap is believed. The cap exists to stop\n * our own growth running away, not to overrule a service that has told us\n * when it will be ready.\n */\nexport function delayFor(args: {\n attempt: number;\n retryAfterSeconds?: number;\n options?: BackoffOptions;\n}): number {\n const computed = backoffMs(args.attempt, args.options ?? {});\n if (args.retryAfterSeconds === undefined || !Number.isFinite(args.retryAfterSeconds)) {\n return computed;\n }\n return Math.max(computed, Math.max(0, args.retryAfterSeconds) * 1000);\n}\n\nfunction clamp01(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.min(1, Math.max(0, value));\n}\n", "/**\n * What went wrong, in a shape a caller can branch on.\n *\n * One class per thing a caller can DO about it, which is not the same as one\n * class per status code. `RateLimited` says wait, `Validation` says fix the\n * request, `NotFound` says the id is wrong or gone, `Conflict` says re-read\n * and try again. A code nobody branches on is a string that only looks like an\n * API, so 402 and 418 and anything else unmapped land on the base class rather\n * than growing a name each.\n *\n * The API's own error envelope is\n *\n * { error: { code, message, fields?, requestId } }\n *\n * and `code` is the stable part. Branch on the class or on `code`, never on\n * `message`: messages get rewritten for clarity, translated, and deliberately\n * made vaguer for security, and a client keyed to message text breaks silently\n * when any of that happens.\n *\n * NOTHING in here ever holds the API key. Errors are logged, serialised into\n * bug reports and posted into issue trackers, which is exactly how a\n * credential escapes - see `redact` at the bottom of this file, which every\n * message this module builds passes through.\n */\n\n/** The stable codes the API returns. Unknown strings are possible; see below. */\nexport type ErrorCode =\n | \"VALIDATION_ERROR\"\n | \"UNAUTHORIZED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"CONFLICT\"\n | \"IDEMPOTENCY_MISMATCH\"\n | \"RATE_LIMITED\"\n | \"PAYLOAD_TOO_LARGE\"\n | \"DEPENDENCY_UNAVAILABLE\"\n | \"PROCESSING_FAILED\"\n | \"INTERNAL_ERROR\"\n // Widened on purpose. A server that adds a code should not make an older\n // SDK throw a TypeError while parsing the error that explains the problem.\n | (string & {});\n\nexport interface ApiErrorInit {\n readonly status: number;\n readonly code: ErrorCode;\n readonly message: string;\n /** Which fields were rejected, for a validation failure. */\n readonly fields?: Readonly<Record<string, string>>;\n /** Ties this failure to the server's log lines. Quote it in support. */\n readonly requestId?: string;\n /** Seconds the server asked us to wait, when it said. */\n readonly retryAfterSeconds?: number;\n}\n\n/**\n * The base every failure from this SDK inherits from.\n *\n * `retryable` is the single question the request loop asks. It lives on the\n * error rather than in a table beside it because the two drift: a table says\n * 429 is retryable while the error that reaches the loop is a transport\n * failure nobody thought to add.\n */\nexport class PersistMemoryError extends Error {\n readonly status: number;\n readonly code: ErrorCode;\n readonly fields?: Readonly<Record<string, string>>;\n readonly requestId?: string;\n readonly retryAfterSeconds?: number;\n /** Retrying this exact request could plausibly succeed. */\n readonly retryable: boolean = false;\n\n constructor(init: ApiErrorInit) {\n super(redact(init.message));\n this.name = new.target.name;\n this.status = init.status;\n this.code = init.code;\n if (init.fields) this.fields = init.fields;\n if (init.requestId) this.requestId = init.requestId;\n if (init.retryAfterSeconds !== undefined) this.retryAfterSeconds = init.retryAfterSeconds;\n }\n\n /**\n * A one-line summary safe to log.\n *\n * Provided so callers reach for this instead of `JSON.stringify(error)`,\n * which walks own properties and would pick up anything a future field\n * holds. Everything here is already server-supplied and key-free.\n */\n override toString(): string {\n const id = this.requestId ? ` requestId=${this.requestId}` : \"\";\n return `${this.name}: [${this.status} ${this.code}] ${this.message}${id}`;\n }\n}\n\n/** 401. The key is missing, malformed, revoked, or the session expired. */\nexport class AuthenticationError extends PersistMemoryError {}\n\n/**\n * 403. Known caller, and this credential will never be enough.\n *\n * Distinct from `AuthenticationError` because the fix is different: 401 means\n * present a credential, 403 means this key's scopes are wrong and no amount of\n * retrying or re-signing will change it. A read-only key calling `remember`\n * lands here.\n */\nexport class PermissionDeniedError extends PersistMemoryError {}\n\n/** 404. Does not exist, or is not yours - the API answers both the same way. */\nexport class NotFoundError extends PersistMemoryError {}\n\n/** 400 and 422. The request was wrong; `fields` says where. */\nexport class ValidationError extends PersistMemoryError {}\n\n/** 409. Something changed underneath. Re-read, then try again. */\nexport class ConflictError extends PersistMemoryError {}\n\n/**\n * 429. Slow down.\n *\n * `retryAfterSeconds` comes from the `Retry-After` header, which the API\n * always sets on a 429. It is not advice - it is the only number that knows\n * when the window resets, and computing our own backoff instead means being\n * refused again and spending an attempt to learn what we were already told.\n */\nexport class RateLimitError extends PersistMemoryError {\n override readonly retryable = true;\n}\n\n/**\n * 5xx. Ours, not yours.\n *\n * Retryable, because a 500 or a 503 is usually a dependency that has fallen\n * over and will come back - and the alternative, giving up on the first one,\n * turns a three-second blip into a failed job. Retryable does not mean\n * REPEATED: a POST still needs an idempotency key before this client will send\n * it again, because a 500 may have been raised after the work was done.\n */\nexport class ServerError extends PersistMemoryError {\n override readonly retryable = true;\n}\n\n/**\n * The request never got an answer: DNS, connect, reset, or a body that died\n * mid-stream.\n *\n * Status 0, because there was no status. Retryable in general - but see\n * `isRetryable` in `client.ts`, which refuses to retry a POST that may already\n * have been processed, since a connection dying after the server accepted the\n * request looks identical from here.\n */\nexport class ConnectionError extends PersistMemoryError {\n override readonly retryable = true;\n\n constructor(message: string) {\n super({ status: 0, code: \"CONNECTION_ERROR\", message });\n }\n}\n\n/** The deadline passed. A distinct class because the fix is often a bigger one. */\nexport class TimeoutError extends PersistMemoryError {\n override readonly retryable = true;\n\n constructor(message: string) {\n super({ status: 0, code: \"TIMEOUT\", message });\n }\n}\n\n/**\n * The caller's own AbortSignal fired.\n *\n * NOT retryable, and not a timeout: someone asked for this to stop, and\n * retrying it is the one thing they have said they do not want.\n */\nexport class AbortError extends PersistMemoryError {\n constructor(message = \"The request was aborted by the caller.\") {\n super({ status: 0, code: \"ABORTED\", message });\n }\n}\n\ninterface ErrorEnvelope {\n readonly error?: {\n readonly code?: unknown;\n readonly message?: unknown;\n readonly fields?: unknown;\n readonly requestId?: unknown;\n };\n}\n\n/**\n * A response the server refused, turned into the right class.\n *\n * Keyed on the CODE first and the status second. The code is the API's own\n * vocabulary and is the more precise of the two - `IDEMPOTENCY_MISMATCH` is a\n * 422 that means \"you reused a key with a different body\", which is a\n * validation problem and not a generic unprocessable entity.\n *\n * The body is parsed defensively at every step. A 502 from a proxy in front of\n * the API returns HTML, and an SDK that assumes JSON turns a bad gateway into\n * an unhelpful SyntaxError thrown from inside the error handler.\n */\nexport function errorFromResponse(\n status: number,\n body: unknown,\n headers: { get(name: string): string | null }\n): PersistMemoryError {\n const envelope = (body ?? {}) as ErrorEnvelope;\n const code = typeof envelope.error?.code === \"string\" ? envelope.error.code : codeForStatus(status);\n const message =\n typeof envelope.error?.message === \"string\" && envelope.error.message.length > 0\n ? envelope.error.message\n : defaultMessage(status);\n\n // Read for 429 and 503 alike. A 503 with a `Retry-After` is a service\n // telling us when it will be back, and ignoring it because the status was\n // not 429 means retrying into an outage that has said it is not over.\n const retryAfterSeconds =\n status === 429 || status === 503 ? retryAfterOf(headers) : undefined;\n\n const init: ApiErrorInit = {\n status,\n code,\n message,\n ...(isFieldMap(envelope.error?.fields) ? { fields: envelope.error.fields } : {}),\n ...(typeof envelope.error?.requestId === \"string\"\n ? { requestId: envelope.error.requestId }\n : {}),\n ...(retryAfterSeconds !== undefined ? { retryAfterSeconds } : {})\n };\n\n if (status === 429 || code === \"RATE_LIMITED\") return new RateLimitError(init);\n if (status === 401 || code === \"UNAUTHORIZED\") return new AuthenticationError(init);\n if (status === 403 || code === \"FORBIDDEN\") return new PermissionDeniedError(init);\n if (status === 404 || code === \"NOT_FOUND\") return new NotFoundError(init);\n if (status === 409 || code === \"CONFLICT\") return new ConflictError(init);\n if (status === 400 || status === 413 || status === 422) return new ValidationError(init);\n if (status >= 500) return new ServerError(init);\n\n // Anything else - a 405 from a misconfigured proxy, a 402 the API grows\n // later. Named honestly rather than forced into the nearest class, because\n // a caller catching `ValidationError` should not be handed a payment\n // problem.\n return new PersistMemoryError(init);\n}\n\n/**\n * `Retry-After`, in seconds, when the header is one we can trust.\n *\n * Only the delta-seconds form is honoured. The HTTP-date form is also legal\n * and is parsed against the CLIENT's clock, which on a laptop that has been\n * asleep can be minutes out - and a negative delay computed from a skewed\n * clock is a retry storm aimed at a service that just asked for quiet.\n */\nfunction retryAfterOf(headers: { get(name: string): string | null }): number | undefined {\n const raw = headers.get(\"retry-after\");\n if (!raw) return undefined;\n\n const seconds = Number(raw.trim());\n if (!Number.isFinite(seconds) || seconds < 0) return undefined;\n // Capped. A header saying 86400 would otherwise park a caller's retry for a\n // day inside a call they expected to return.\n return Math.min(seconds, 300);\n}\n\nfunction isFieldMap(value: unknown): value is Record<string, string> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n return Object.values(value).every((one) => typeof one === \"string\");\n}\n\nfunction codeForStatus(status: number): ErrorCode {\n if (status === 401) return \"UNAUTHORIZED\";\n if (status === 403) return \"FORBIDDEN\";\n if (status === 404) return \"NOT_FOUND\";\n if (status === 409) return \"CONFLICT\";\n if (status === 429) return \"RATE_LIMITED\";\n if (status === 413) return \"PAYLOAD_TOO_LARGE\";\n if (status >= 500) return \"INTERNAL_ERROR\";\n return \"VALIDATION_ERROR\";\n}\n\nfunction defaultMessage(status: number): string {\n // Deliberately says the body was unreadable rather than inventing a reason.\n // A message claiming \"not found\" for a 404 that was actually an HTML error\n // page from a proxy sends whoever is debugging to the wrong system.\n return `The API returned ${status} with no readable error body.`;\n}\n\n/**\n * Removes anything key-shaped from a string bound for an error message.\n *\n * Every message this module produces goes through here, including the\n * server's own. It should never contain a key - we never send it in a body\n * and the API never echoes it - but \"should never\" is how credentials end up\n * in issue trackers. The cost is one regex on a path that has already failed.\n */\nexport function redact(text: string): string {\n return text.replace(/pm_(live|test)_[A-Za-z0-9_-]+/g, \"pm_$1_[redacted]\");\n}\n", "import type { BackoffOptions } from \"./backoff\";\nimport type { QueryParams } from \"./query\";\nimport { encodeQuery } from \"./query\";\nimport { delayFor } from \"./backoff\";\nimport {\n AbortError,\n ConnectionError,\n PersistMemoryError,\n TimeoutError,\n errorFromResponse,\n redact\n} from \"./errors\";\n\n/**\n * The one place a request is made, retried, timed out and turned into an error.\n *\n * Every resource in this package goes through `request`. That is deliberate:\n * an SDK where each resource calls `fetch` for itself is an SDK with six\n * slightly different retry policies, and the differences only show up during\n * an outage, which is the moment nobody wants to be reading six files.\n *\n * `fetch` is injected rather than imported. It is what makes a test of this\n * incapable of opening a socket by accident, and it is the same reason every\n * provider client in this repo takes one.\n */\nexport type { QueryParams, QueryValue } from \"./query\";\n\nexport interface ClientOptions {\n /**\n * A `pm_live_...` API key, or a session JWT.\n *\n * Held privately and never returned, logged, stringified or put in an error.\n * See `#apiKey` below and the `toJSON` next to it.\n */\n readonly apiKey: string;\n readonly baseUrl?: string;\n readonly fetch?: typeof globalThis.fetch;\n /**\n * Per-attempt deadline, not a budget for the whole call.\n *\n * Per attempt because a whole-call deadline interacts badly with backoff: a\n * request that spent nine seconds waiting between retries would get one\n * second to actually run, and the failure would look like a slow server.\n */\n readonly timeoutMs?: number;\n /** Attempts, not retries. 3 means the original and two more. */\n readonly maxAttempts?: number;\n readonly backoff?: BackoffOptions;\n /** Injected so tests do not spend real seconds asleep. */\n readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n /** Sent on every request, for support and for server-side triage. */\n readonly userAgent?: string;\n}\n\nexport interface RequestOptions {\n /** Cancels the call. A caller's abort is never retried - they asked it to stop. */\n readonly signal?: AbortSignal;\n readonly timeoutMs?: number;\n readonly maxAttempts?: number;\n /**\n * Makes a POST safe to retry.\n *\n * The API deduplicates on this header, so a retry after a timeout finds the\n * first result rather than doing the work twice. Without one, this client\n * will NOT retry a POST that may already have been processed - see\n * `mayRetry`.\n *\n * Give it meaning: `remember:note-42`, not a fresh random value per call. A\n * random one makes every retry a new request, which is exactly what it\n * exists to prevent.\n */\n readonly idempotencyKey?: string;\n}\n\ninterface InternalRequest {\n readonly method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n readonly path: string;\n readonly query?: QueryParams;\n readonly body?: unknown;\n /**\n * Bytes, for the endpoints that take a file.\n *\n * Separate from `body` rather than sniffed out of it: `JSON.stringify` of a\n * `Uint8Array` produces `{\"0\":137,\"1\":80,...}`, which is a valid request and\n * a corrupt file - and the failure shows up as \"this PDF is not a PDF\" a\n * long way from the line that caused it.\n */\n readonly rawBody?: Uint8Array;\n readonly contentType?: string;\n /** Bytes back, for a download. JSON is parsed; a file is not. */\n readonly rawResponse?: boolean;\n readonly options?: RequestOptions;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.persistmemory.com\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\n\n/**\n * Methods this client will retry without being told it is safe to.\n *\n * PATCH and DELETE are in here because of what they are in THIS API and not\n * because the RFC calls them idempotent: `PATCH /spaces/{id}` sets named\n * fields to given values, and `DELETE /spaces/{id}/memories` removes a set of\n * memberships. Applying either twice lands in the same state as applying it\n * once. POST is the one that does not - `remember` queues a job every time.\n */\nconst RETRY_WITHOUT_ASKING = new Set([\"GET\", \"HEAD\", \"PATCH\", \"DELETE\"]);\n\nexport class HttpClient {\n /**\n * The credential, in a private field, and never anywhere else.\n *\n * Private (`#`) rather than `readonly`: a public field is enumerable, so\n * `JSON.stringify(client)` and every structured logger that walks own\n * properties would write the key into a log line. `toJSON` and the inspect\n * hook below close the two remaining paths - a bug report pasted from\n * `console.log(client)` is exactly how a key gets shared with strangers.\n */\n readonly #apiKey: string;\n readonly #baseUrl: string;\n readonly #fetch: typeof globalThis.fetch;\n readonly #timeoutMs: number;\n readonly #maxAttempts: number;\n readonly #backoff: BackoffOptions;\n readonly #sleep: (ms: number, signal?: AbortSignal) => Promise<void>;\n readonly #userAgent: string;\n\n constructor(options: ClientOptions) {\n if (typeof options.apiKey !== \"string\" || options.apiKey.trim().length === 0) {\n // Refused here rather than as a 401 from the server, because the server\n // cannot say WHICH of \"missing\", \"empty\" and \"undefined stringified\"\n // happened, and all three come from the same forgotten environment\n // variable.\n throw new PersistMemoryError({\n status: 0,\n code: \"VALIDATION_ERROR\",\n message: \"An API key is required. Pass `apiKey`, or set PERSISTMEMORY_API_KEY.\"\n });\n }\n\n // A newline in a credential is header injection, and the usual source is\n // a key read from a file with `readFileSync` and never trimmed. Trimmed\n // rather than rejected for whitespace, then checked for anything a header\n // value may not carry.\n const key = options.apiKey.trim();\n if (/[\\r\\n\\0]/.test(key)) {\n // The key itself is NOT in this message. It is the one string in the\n // whole package that must never reach an error.\n throw new PersistMemoryError({\n status: 0,\n code: \"VALIDATION_ERROR\",\n message: \"The API key contains characters that cannot go in a header.\"\n });\n }\n\n this.#apiKey = key;\n // Trailing slashes stripped once, here. Left alone, `baseUrl + path`\n // produces `//api/v1/...`, which some proxies normalise and some route to\n // a 404 - a difference that only appears in production.\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#fetch = options.fetch ?? globalThis.fetch;\n this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#maxAttempts = Math.max(1, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n this.#backoff = options.backoff ?? {};\n this.#sleep = options.sleep ?? defaultSleep;\n this.#userAgent = options.userAgent ?? \"persistmemory-sdk-js/0.1.0\";\n }\n\n /**\n * What this object looks like when something serialises it.\n *\n * Both hooks return the same key-free shape. `toJSON` covers\n * `JSON.stringify`, the inspect symbol covers `console.log` under Node, and\n * between them they cover how a credential actually escapes: not through a\n * deliberate log line, but through an object dumped into a bug report.\n */\n toJSON(): Record<string, unknown> {\n return { baseUrl: this.#baseUrl, apiKey: \"[redacted]\" };\n }\n\n [Symbol.for(\"nodejs.util.inspect.custom\")](): Record<string, unknown> {\n return this.toJSON();\n }\n\n async get<T>(path: string, query?: QueryParams, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"GET\",\n path,\n ...(query ? { query } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"POST\",\n path,\n ...(body !== undefined ? { body } : {}),\n ...(options ? { options } : {})\n });\n }\n\n /** POST with a file as the body. The type describes the bytes, not JSON. */\n async postBytes<T>(\n path: string,\n bytes: Uint8Array,\n contentType: string,\n query?: QueryParams,\n options?: RequestOptions\n ): Promise<T> {\n return this.#request<T>({\n method: \"POST\",\n path,\n rawBody: bytes,\n contentType,\n ...(query ? { query } : {}),\n ...(options ? { options } : {})\n });\n }\n\n /** GET that returns bytes rather than JSON, for downloading a file. */\n async getBytes(\n path: string,\n query?: QueryParams,\n options?: RequestOptions\n ): Promise<{ bytes: Uint8Array; contentType: string; filename?: string }> {\n return this.#request({\n method: \"GET\",\n path,\n rawResponse: true,\n ...(query ? { query } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"PATCH\",\n path,\n ...(body !== undefined ? { body } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async delete<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"DELETE\",\n path,\n ...(body !== undefined ? { body } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async #request<T>(request: InternalRequest): Promise<T> {\n const maxAttempts = Math.max(1, request.options?.maxAttempts ?? this.#maxAttempts);\n const url = this.#baseUrl + request.path + encodeQuery(request.query);\n\n let attempt = 0;\n // Unbounded `while` with the exit conditions inside, rather than a `for`\n // over attempts: every path out of here either returns or throws, and a\n // loop that can fall off the end would silently return undefined as `T`.\n for (;;) {\n attempt += 1;\n\n let error: PersistMemoryError;\n try {\n return await this.#attempt<T>(request, url);\n } catch (thrown) {\n // Anything that is not one of ours is a programming error in this\n // package - a bad URL, a body that will not serialise - and rethrowing\n // it unchanged is right. Wrapping it as a retryable transport failure\n // would make the request loop retry a defect that fails identically\n // every time.\n if (!(thrown instanceof PersistMemoryError)) throw thrown;\n error = thrown;\n }\n\n if (attempt >= maxAttempts) throw error;\n if (!mayRetry(error, request)) throw error;\n\n const delay = delayFor({\n attempt,\n ...(error.retryAfterSeconds !== undefined\n ? { retryAfterSeconds: error.retryAfterSeconds }\n : {}),\n options: this.#backoff\n });\n\n // The caller's signal is passed into the wait too. Without it an aborted\n // call still sits out its full backoff before noticing, which to a user\n // who pressed cancel is indistinguishable from the cancel not working.\n await this.#sleep(delay, request.options?.signal);\n }\n }\n\n async #attempt<T>(request: InternalRequest, url: string): Promise<T> {\n const timeoutMs = request.options?.timeoutMs ?? this.#timeoutMs;\n const deadline = new AbortController();\n const timer = setTimeout(() => deadline.abort(), timeoutMs);\n // Linked rather than AbortSignal.any: this package supports Node 18, where\n // `any` does not exist. The listener is removed in the `finally`, because\n // a long-lived caller signal that accumulated one listener per request is\n // a leak that only shows up under load.\n const onCallerAbort = () => deadline.abort();\n const caller = request.options?.signal;\n caller?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n try {\n if (caller?.aborted) throw new AbortError();\n\n // Raced against the deadline rather than left to `fetch` alone.\n // `fetch` is injected here, and not every implementation honours a\n // signal - a mocked one in someone's test suite, an older polyfill, a\n // wrapper that forgets to forward it. When one does not, an unanswered\n // request hangs forever and the timeout this client documents is a\n // promise it does not keep.\n const response = await untilAborted(\n this.#fetch(url, {\n method: request.method,\n headers: this.#headers(request),\n ...(request.rawBody !== undefined\n ? { body: request.rawBody }\n : request.body !== undefined\n ? { body: JSON.stringify(request.body) }\n : {}),\n signal: deadline.signal\n }),\n deadline.signal\n );\n\n /*\n A failure is JSON even on a route that answers with bytes.\n\n Reading the body as an ArrayBuffer first would turn a 409 explaining\n that no Google account is connected into an unreadable buffer, and the\n caller would get \"download failed\" instead of the sentence telling them\n what to do.\n */\n if (request.rawResponse && response.ok) {\n const disposition = response.headers.get(\"content-disposition\") ?? \"\";\n const named = /filename=\"([^\"]+)\"/.exec(disposition)?.[1];\n\n return {\n bytes: new Uint8Array(await response.arrayBuffer()),\n contentType: response.headers.get(\"content-type\") ?? \"application/octet-stream\",\n ...(named ? { filename: named } : {})\n } as T;\n }\n\n const payload = await readBody(response);\n if (!response.ok) throw errorFromResponse(response.status, payload, response.headers);\n return payload as T;\n } catch (thrown) {\n if (thrown instanceof PersistMemoryError) throw thrown;\n\n // Three different things arrive here as one AbortError from fetch, and\n // they need three different answers: the caller cancelled (do not\n // retry), we ran out of time (retry), or the network failed (retry, but\n // not for a POST). Telling them apart by asking WHOSE signal fired is\n // the only reliable way - the DOMException looks the same either way.\n if (caller?.aborted) throw new AbortError();\n if (deadline.signal.aborted) {\n throw new TimeoutError(`The request did not complete within ${timeoutMs}ms.`);\n }\n\n const detail = thrown instanceof Error ? redact(thrown.message) : \"transport failure\";\n throw new ConnectionError(`Could not reach the API: ${detail}`);\n } finally {\n clearTimeout(timer);\n caller?.removeEventListener(\"abort\", onCallerAbort);\n }\n }\n\n #headers(request: InternalRequest): Record<string, string> {\n return {\n // The only place the key is ever read.\n authorization: `Bearer ${this.#apiKey}`,\n // A download route answers with the file's own type, so `*/*` rather\n // than a promise to accept only JSON that the server would have to break.\n accept: request.rawResponse ? \"*/*\" : \"application/json\",\n \"user-agent\": this.#userAgent,\n ...(request.rawBody !== undefined\n ? { \"content-type\": request.contentType ?? \"application/octet-stream\" }\n : request.body !== undefined\n ? { \"content-type\": \"application/json\" }\n : {}),\n ...(request.options?.idempotencyKey\n ? { \"idempotency-key\": request.options.idempotencyKey }\n : {})\n };\n }\n}\n\n/**\n * Whether this failure is worth another attempt.\n *\n * Two questions, and both have to say yes. The first is whether the failure\n * itself could clear - a 400 fails identically on every attempt, so retrying\n * spends two more calls to learn the same thing. The second is whether\n * repeating the REQUEST is safe, which is a different question and the one\n * that gets skipped.\n *\n * For a POST the honest answer is that we usually cannot tell. A connection\n * that died after the server accepted the request is indistinguishable from\n * one that died before, so retrying `remember` on a timeout would queue the\n * same note twice and the user would see it remembered twice. So a POST is\n * retried only when:\n *\n * an idempotency key was given the API deduplicates on it, so the retry\n * returns the first result rather than\n * repeating the work\n *\n * the status was 429 the request was refused BEFORE it was\n * processed. That is what a rate limit is,\n * and it is the one case where \"already\n * succeeded\" is not possible\n *\n * Every other retryable POST failure - a 500, a 503, a timeout, a reset - is\n * given back to the caller, who knows whether repeating it is safe and this\n * package does not.\n */\nexport function mayRetry(error: PersistMemoryError, request: InternalRequest): boolean {\n if (!error.retryable) return false;\n if (RETRY_WITHOUT_ASKING.has(request.method)) return true;\n if (request.options?.idempotencyKey) return true;\n return error.status === 429;\n}\n\n/**\n * The body, parsed if it is JSON and there is any.\n *\n * Never assumes JSON. A 502 from a load balancer in front of the API is an\n * HTML page, and an SDK that calls `response.json()` unconditionally turns a\n * bad gateway into a SyntaxError thrown from inside the error handler - which\n * hides the actual failure behind a parse error nobody can act on.\n */\nasync function readBody(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined;\n\n const text = await response.text().catch(() => \"\");\n if (text.length === 0) return undefined;\n\n const type = response.headers.get(\"content-type\") ?? \"\";\n if (!type.includes(\"json\")) return { raw: text.slice(0, 500) };\n\n try {\n return JSON.parse(text) as unknown;\n } catch {\n // Truncated, because a body that failed to parse can be megabytes of an\n // upstream error page and this string reaches an error message.\n return { raw: text.slice(0, 500) };\n }\n}\n\n/**\n * The response, or a rejection the moment the signal fires.\n *\n * The original promise is left with a `catch` attached: it may still settle\n * long after we have stopped waiting, and an unattended rejection from an\n * abandoned request takes the process down under Node's default handling.\n */\nclass SignalFired extends Error {\n constructor() {\n // Deliberately NOT one of this package's errors. It is raised before we\n // know WHICH signal fired, and the catch in `#attempt` is the only place\n // that can tell a caller's cancel from a deadline - a `TimeoutError`\n // thrown here would be a timeout reported for a user pressing stop.\n super(\"signal fired\");\n this.name = \"SignalFired\";\n }\n}\n\nfunction untilAborted<T>(work: Promise<T>, signal: AbortSignal): Promise<T> {\n work.catch(() => undefined);\n\n return new Promise<T>((resolve, reject) => {\n if (signal.aborted) {\n reject(new SignalFired());\n return;\n }\n\n const onAbort = () => reject(new SignalFired());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n\n work.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n );\n });\n}\n\n/**\n * A wait that can be cancelled.\n *\n * The default. Injected in tests so a retry test does not spend real seconds\n * asleep - a suite that actually waits out an exponential backoff is a suite\n * people stop running.\n */\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new AbortError());\n return;\n }\n\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n\n function onAbort(): void {\n clearTimeout(timer);\n reject(new AbortError());\n }\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n", "import type { Page } from \"./types\";\n\n/**\n * Walking a cursor-paginated list.\n *\n * The list endpoints are keyset paginated: `?cursor=` carries where the last\n * page ended, and the response is `{ data, pagination: { nextCursor?, limit } }`\n * with `nextCursor` absent on the last page. The absence is the ONLY stop\n * signal - an empty `data` array is not the same thing, because a page can\n * come back empty when everything in it was filtered after the fetch while\n * more pages remain. A client that stops on an empty page silently truncates\n * the user's results and nothing anywhere reports an error.\n *\n * That rule is easy to state and easy to get wrong once per call site, which\n * is why every list method returns one of these instead of leaving the loop to\n * the caller.\n *\n * Not every list is paginated. `spaces/{id}/memories` and\n * `entities/{id}/memories` return a `pagination` block with no cursor at all,\n * so iterating them yields exactly one page and stops - which is correct, and\n * costs a caller nothing for using the same shape everywhere.\n */\nexport class Paginated<T> implements AsyncIterable<T> {\n readonly #fetchPage: (cursor: string | undefined) => Promise<Page<T>>;\n\n constructor(fetchPage: (cursor: string | undefined) => Promise<Page<T>>) {\n this.#fetchPage = fetchPage;\n }\n\n /** The first page, and nothing more. For a UI that renders one page at a time. */\n async first(): Promise<Page<T>> {\n return this.#fetchPage(undefined);\n }\n\n /**\n * Page by page, for a caller that wants the cursors or wants to stop early.\n *\n * A generator rather than an array of pages: fetching them all up front\n * would make \"show me the first ten\" cost every page in the account.\n */\n async *pages(): AsyncGenerator<Page<T>, void, undefined> {\n let cursor: string | undefined;\n const seen = new Set<string>();\n\n for (;;) {\n const page: Page<T> = await this.#fetchPage(cursor);\n yield page;\n\n const next = page.pagination.nextCursor;\n if (!next) return;\n\n // A cursor we have already followed means the server is handing back a\n // position that does not advance, and continuing is an infinite loop\n // that reads the same page forever while looking exactly like a slow\n // account. Stopping loses a page; looping loses the process.\n if (seen.has(next)) return;\n seen.add(next);\n cursor = next;\n }\n }\n\n /** Every item across every page. `for await (const memory of ...)`. */\n async *[Symbol.asyncIterator](): AsyncGenerator<T, void, undefined> {\n for await (const page of this.pages()) {\n for (const item of page.data) yield item;\n }\n }\n\n /**\n * Everything, in one array.\n *\n * `maxItems` is not optional, and that is the point. An unbounded `all()` on\n * an account with two hundred thousand memories is a request loop that runs\n * for minutes and an array that exhausts the heap, and the call site that\n * does it reads as innocently as any other. Ask for a number you can hold.\n */\n async all(maxItems: number): Promise<T[]> {\n const collected: T[] = [];\n if (maxItems <= 0) return collected;\n\n for await (const item of this) {\n collected.push(item);\n if (collected.length >= maxItems) break;\n }\n return collected;\n }\n}\n", "import type { HttpClient, QueryParams, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type { ListMemoriesParams, Memory, Page, RememberParams, RememberResult } from \"../types\";\n\n/**\n * Memories: browsing them, reading one, and handing over new material.\n *\n * Browsing is not searching. `list` is chronological and takes filters,\n * `search` ranks by relevance and takes a query - they are separate endpoints\n * because serving both from one would mean a caller who adds a filter silently\n * gets a differently ordered list.\n */\nexport class Memories {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /**\n * One page, plus the cursor loop.\n *\n * Returns a `Paginated`, so `await memories.list().first()` gets a page and\n * `for await (const memory of memories.list())` walks the lot. The filters\n * are carried into every page automatically - a caller re-passing them per\n * page is a caller who will eventually forget one, and the pages after that\n * come from a differently filtered list.\n */\n list(params: ListMemoriesParams = {}, options?: RequestOptions): Paginated<Memory> {\n return new Paginated<Memory>((cursor) =>\n this.#http.get<Page<Memory>>(\n \"/api/v1/memories\",\n pageQuery(params, cursor, toQuery(params)),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Memory> {\n return this.#http.get<Memory>(`/api/v1/memories/${encodeURIComponent(id)}`, undefined, options);\n }\n\n /**\n * Hands material to the ingestion pipeline. Needs a key with `write` scope.\n *\n * This does NOT create a memory, and the return type says so: it answers 202\n * with a job id. Extraction, entity resolution, deduplication and conflict\n * detection all run afterwards and may produce one memory, several, or none.\n * Poll `client.jobs.get(result.jobId)` to find out which.\n *\n * Pass an `idempotencyKey` if this can be retried by anything - a queue, a\n * user pressing a button twice, or this client's own retry loop, which\n * refuses to repeat a POST without one. `remember:note-42`, not a fresh\n * random value per call.\n */\n async remember(params: RememberParams, options?: RequestOptions): Promise<RememberResult> {\n return this.#http.post<RememberResult>(\"/api/v1/remember\", params, options);\n }\n}\n\nfunction toQuery(params: ListMemoriesParams): QueryParams {\n return {\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.state !== undefined ? { state: params.state } : {}),\n ...(params.scope !== undefined ? { scope: params.scope } : {}),\n ...(params.spaceIds !== undefined ? { spaceIds: params.spaceIds } : {}),\n ...(params.createdAfter !== undefined ? { createdAfter: params.createdAfter } : {}),\n ...(params.createdBefore !== undefined ? { createdBefore: params.createdBefore } : {}),\n ...(params.minConfidence !== undefined ? { minConfidence: params.minConfidence } : {}),\n ...(params.includeHistorical !== undefined\n ? { includeHistorical: params.includeHistorical }\n : {})\n };\n}\n", "import type { HttpClient, QueryParams, RequestOptions } from \"../http\";\nimport type { ContextParams, ContextResponse, SearchParams, SearchResponse } from \"../types\";\n\n/**\n * Asking the system what it knows.\n *\n * Two methods, and they answer different questions. `search` returns ranked\n * records for a person or a UI. `context` returns prose for a model, bounded\n * by TOKENS rather than by row count - which is the only bound that expresses\n * the real constraint, since ten long memories overflow a window that fifty\n * short ones fit inside.\n *\n * `search` is a GET and `context` is a POST, matching the API: a search is\n * linkable and cacheable, while a context request can carry two hundred\n * excluded ids and every proxy in between has its own idea of how long a URL\n * may be.\n */\nexport class Search {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /**\n * Ranked results, with an account of how they were found.\n *\n * Read `diagnostics.degraded` before showing the results. Search degrades\n * rather than fails - with embeddings unavailable it falls back to\n * deterministic retrieval and still answers - and a UI that cannot tell\n * degraded from healthy tells the user the system knows nothing when it is\n * merely looking with one eye.\n */\n async query(params: SearchParams, options?: RequestOptions): Promise<SearchResponse> {\n const query: QueryParams = {\n query: params.query,\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(params.scope !== undefined ? { scope: params.scope } : {}),\n ...(params.spaceIds !== undefined ? { spaceIds: params.spaceIds } : {}),\n ...(params.types !== undefined ? { types: params.types } : {}),\n ...(params.minScore !== undefined ? { minScore: params.minScore } : {}),\n ...(params.asOf !== undefined ? { asOf: params.asOf } : {}),\n ...(params.includeHistorical !== undefined\n ? { includeHistorical: params.includeHistorical }\n : {}),\n ...(params.includeEvidence !== undefined\n ? { includeEvidence: params.includeEvidence }\n : {}),\n ...(params.explain !== undefined ? { explain: params.explain } : {})\n };\n\n return this.#http.get<SearchResponse>(\"/api/v1/search\", query, options);\n }\n\n /**\n * A context window, assembled and ready to paste into a prompt.\n *\n * A POST that is safe to repeat - it reads and returns, it writes nothing -\n * so this is one of the few places where retrying without an idempotency key\n * would be harmless. It still is not retried by default: the request loop\n * decides by METHOD, and a per-endpoint exception is a rule that holds until\n * someone adds a POST next to it that does write.\n */\n async context(params: ContextParams, options?: RequestOptions): Promise<ContextResponse> {\n return this.#http.post<ContextResponse>(\"/api/v1/context\", params, options);\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n CreateSpaceParams,\n ListSpacesParams,\n Memory,\n Page,\n Space,\n UpdateSpaceParams\n} from \"../types\";\n\n/**\n * Spaces: a boundary around a set of memories.\n *\n * They exist because \"everything I know\" is the wrong scope for most\n * questions. Work and personal contexts hold contradictory truths - two\n * different \"my manager\" - and answering from both at once is wrong in a way\n * that is hard to notice.\n *\n * Membership is a LINK, not ownership. `removeMemories` takes a memory out of\n * a Space; it does not delete it, and the same memory can belong to several.\n */\nexport class Spaces {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListSpacesParams = {}, options?: RequestOptions): Paginated<Space> {\n return new Paginated<Space>((cursor) =>\n this.#http.get<Page<Space>>(\n \"/api/v1/spaces\",\n pageQuery(params, cursor, {\n ...(params.includeArchived !== undefined\n ? { includeArchived: params.includeArchived }\n : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Space> {\n return this.#http.get<Space>(`/api/v1/spaces/${encodeURIComponent(id)}`, undefined, options);\n }\n\n /**\n * Creates a Space. Answers 201.\n *\n * Worth an idempotency key when a person is behind it: a double-clicked\n * \"create Space\" button makes two Spaces called Work, and nothing later can\n * tell which of them memories should have gone into.\n */\n async create(params: CreateSpaceParams, options?: RequestOptions): Promise<Space> {\n return this.#http.post<Space>(\"/api/v1/spaces\", params, options);\n }\n\n /**\n * Deletes a Space. You must say what happens to what is in it.\n *\n * There is no default, here or in the API, and that is deliberate: \"delete\n * this Space\" means the label to some people and everything inside it to\n * others, and a client that guessed would destroy or keep somebody's\n * material without being asked.\n *\n * `delete` never destroys a memory that is filed in another Space as well \u2014\n * that one is detached and left alone. `deleted` and `kept` come back so you\n * can say what actually happened.\n */\n async delete(\n id: string,\n params: { readonly memories: \"keep\" | \"delete\" },\n options?: RequestOptions\n ): Promise<{ deleted: number; kept: number }> {\n return this.#http.delete<{ deleted: number; kept: number }>(\n `/api/v1/spaces/${encodeURIComponent(id)}`,\n params,\n options\n );\n }\n\n /**\n * Merges Spaces into a NEW one, leaving every source exactly as it was.\n *\n * Additive, not destructive: a memory ends up in the sources AND the result,\n * every existing search over a source returns what it did before, and\n * undoing it is deleting the Space this returns. A memory in two sources is\n * filed once.\n */\n async merge(\n params: {\n readonly sourceIds: readonly string[];\n readonly name: string;\n readonly description?: string;\n },\n options?: RequestOptions\n ): Promise<{ space: Space; added: number }> {\n return this.#http.post<{ space: Space; added: number }>(\n \"/api/v1/spaces/merge\",\n params,\n options\n );\n }\n\n /**\n * The Space this account files into when a capture names none.\n *\n * `{}` \u2014 an object with no `space` \u2014 means there is no default, which is the\n * normal state rather than a gap. It is also what comes back after the Space\n * somebody chose has been deleted.\n */\n async getDefault(options?: RequestOptions): Promise<{ space?: Space }> {\n return this.#http.get<{ space?: Space }>(\"/api/v1/spaces/default\", undefined, options);\n }\n\n /** `null` clears it. Not the same as omitting it, which is why the type says so. */\n async setDefault(spaceId: string | null, options?: RequestOptions): Promise<{ space?: Space }> {\n return this.#http.patch<{ space?: Space }>(\n \"/api/v1/spaces/default\",\n { spaceId },\n options\n );\n }\n\n /** Renaming, retention, and archiving - `archived` is a field, not a verb. */\n async update(id: string, params: UpdateSpaceParams, options?: RequestOptions): Promise<Space> {\n return this.#http.patch<Space>(`/api/v1/spaces/${encodeURIComponent(id)}`, params, options);\n }\n\n /**\n * The memories filed in a Space.\n *\n * This endpoint answers `{ data, pagination: { limit } }` with no cursor: it\n * returns the first `limit` members and stops. Wrapped in a `Paginated`\n * anyway so it reads like every other list, and it simply yields one page -\n * a caller who needs more should filter `memories.list` by `spaceIds`, which\n * is the endpoint that actually pages.\n */\n memories(\n id: string,\n params: { readonly limit?: number } = {},\n options?: RequestOptions\n ): Paginated<Memory> {\n return new Paginated<Memory>(() =>\n this.#http.get<Page<Memory>>(\n `/api/v1/spaces/${encodeURIComponent(id)}/memories`,\n { ...(params.limit !== undefined ? { limit: params.limit } : {}) },\n options\n )\n );\n }\n\n async addMemories(\n id: string,\n memoryIds: readonly string[],\n options?: RequestOptions\n ): Promise<{ added: number }> {\n return this.#http.post<{ added: number }>(\n `/api/v1/spaces/${encodeURIComponent(id)}/memories`,\n { memoryIds },\n options\n );\n }\n\n /**\n * Removes memberships. The memories themselves are untouched.\n *\n * A body on a DELETE, which is unusual and is what the API takes: the\n * alternative is five hundred ids in a query string, and every proxy in\n * between has its own limit on how long a URL may be.\n */\n async removeMemories(\n id: string,\n memoryIds: readonly string[],\n options?: RequestOptions\n ): Promise<{ removed: number }> {\n return this.#http.delete<{ removed: number }>(\n `/api/v1/spaces/${encodeURIComponent(id)}/memories`,\n { memoryIds },\n options\n );\n }\n}\n", "import type { HttpClient, QueryParams, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n Document,\n Job,\n ListDocumentsParams,\n ListJobsParams,\n ListSourcesParams,\n Page,\n Source\n} from \"../types\";\n\n/**\n * Where material came from, what it became, and the work in between.\n *\n * Three resources rather than one because they answer three questions a caller\n * asks separately: a source is an ORIGIN, a document is the normalised form\n * that was kept, and a job is the work that is still running. Collapsing them\n * would make \"nothing has appeared yet\" indistinguishable from \"it silently\n * failed\", which is the whole reason jobs are visible at all.\n */\nexport class Sources {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListSourcesParams = {}, options?: RequestOptions): Paginated<Source> {\n return new Paginated<Source>((cursor) =>\n this.#http.get<Page<Source>>(\n \"/api/v1/sources\",\n pageQuery(params, cursor, {\n ...(params.provider !== undefined ? { provider: params.provider } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Source> {\n return this.#http.get<Source>(`/api/v1/sources/${encodeURIComponent(id)}`, undefined, options);\n }\n}\n\nexport class Documents {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListDocumentsParams = {}, options?: RequestOptions): Paginated<Document> {\n return new Paginated<Document>((cursor) =>\n this.#http.get<Page<Document>>(\n \"/api/v1/documents\",\n pageQuery(params, cursor, {\n ...(params.sourceId !== undefined ? { sourceId: params.sourceId } : {}),\n ...(params.status !== undefined ? { status: params.status } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Document> {\n return this.#http.get<Document>(\n `/api/v1/documents/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n}\n\nexport class Jobs {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListJobsParams = {}, options?: RequestOptions): Paginated<Job> {\n return new Paginated<Job>((cursor) =>\n this.#http.get<Page<Job>>(\n \"/api/v1/jobs\",\n pageQuery(params, cursor, {\n ...(params.status !== undefined ? { status: params.status } : {}),\n ...(params.type !== undefined ? { type: params.type } : {})\n }),\n options\n )\n );\n }\n\n /**\n * One job, by id. This is what `remember` hands back a reference to.\n *\n * `completed` is the terminal success state - the store's own word, not\n * `succeeded`. A caller polling for a state the API never writes waits\n * forever with nothing to show why.\n */\n async get(id: string, options?: RequestOptions): Promise<Job> {\n return this.#http.get<Job>(`/api/v1/jobs/${encodeURIComponent(id)}`, undefined, options);\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n Conflict,\n Entity,\n EntityMemoriesParams,\n EntityMention,\n GraphResponse,\n ListConflictsParams,\n ListEntitiesParams,\n Page,\n ResolveConflictParams,\n TraverseParams\n} from \"../types\";\n\n/**\n * The people, places and things memories are about.\n *\n * Entities are RESOLVED rather than stored as strings: \"Sam\", \"Sam Patel\" and\n * \"sam@work.com\" are one person, and a system that treats them as three cannot\n * answer \"what do I know about Sam\" - the most obvious question anyone asks a\n * memory system.\n */\nexport class Entities {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListEntitiesParams = {}, options?: RequestOptions): Paginated<Entity> {\n return new Paginated<Entity>((cursor) =>\n this.#http.get<Page<Entity>>(\n \"/api/v1/entities\",\n pageQuery(params, cursor, {\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.q !== undefined ? { q: params.q } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Entity> {\n return this.#http.get<Entity>(`/api/v1/entities/${encodeURIComponent(id)}`, undefined, options);\n }\n\n /**\n * Which memories mention this entity, and how.\n *\n * Returns MENTIONS - a memory id, a role and a confidence - not the memories\n * themselves. \"Memories about Sam\" and \"memories Sam appears in\" are\n * different questions, and `role` is what separates them.\n *\n * Like the Space membership list, this endpoint answers with a `pagination`\n * block that carries no cursor, so it yields one page and stops.\n */\n memories(\n id: string,\n params: EntityMemoriesParams = {},\n options?: RequestOptions\n ): Paginated<EntityMention> {\n return new Paginated<EntityMention>((cursor) =>\n this.#http.get<Page<EntityMention>>(\n `/api/v1/entities/${encodeURIComponent(id)}/memories`,\n pageQuery(params, cursor, {\n ...(params.role !== undefined ? { role: params.role } : {}),\n ...(params.minConfidence !== undefined ? { minConfidence: params.minConfidence } : {})\n }),\n options\n )\n );\n }\n}\n\n/**\n * Walking the graph out from an entity.\n *\n * Every bound has a server-side ceiling, and that is the point: an unbounded\n * traversal on a well-connected graph visits everything, and the request that\n * does it is indistinguishable from a denial of service. Read `truncated` -\n * silence would read as \"this is the whole graph\", and a conclusion drawn from\n * a subset nobody knew was a subset is worse than no answer.\n */\nexport class Graph {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n async traverse(params: TraverseParams, options?: RequestOptions): Promise<GraphResponse> {\n return this.#http.get<GraphResponse>(\n \"/api/v1/graph\",\n {\n from: params.from,\n ...(params.depth !== undefined ? { depth: params.depth } : {}),\n ...(params.maxNodes !== undefined ? { maxNodes: params.maxNodes } : {}),\n ...(params.memoryLimit !== undefined ? { memoryLimit: params.memoryLimit } : {})\n },\n options\n );\n }\n}\n\n/**\n * Two things the system believes that cannot both be true.\n *\n * Surfaced rather than settled silently, because the automatic answer is often\n * wrong: \"I moved to Berlin\" superseding \"I live in London\" is right, and \"the\n * deadline is Friday\" against \"the deadline is Monday\" is a question only the\n * user can answer.\n */\nexport class Conflicts {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListConflictsParams = {}, options?: RequestOptions): Paginated<Conflict> {\n return new Paginated<Conflict>((cursor) =>\n this.#http.get<Page<Conflict>>(\n \"/api/v1/conflicts\",\n pageQuery(params, cursor, {\n ...(params.includeResolved !== undefined\n ? { includeResolved: params.includeResolved }\n : {}),\n ...(params.type !== undefined ? { type: params.type } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Conflict> {\n return this.#http.get<Conflict>(\n `/api/v1/conflicts/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n /**\n * Settles one.\n *\n * `keep` names the winner and supersedes the loser; it does not delete it.\n * `dismiss` records that the detector was wrong, which is worth knowing when\n * the same pair trips it again.\n *\n * The parameter type is a union, so `keep` without a `keepId` does not\n * compile. The server rejects it too - this just moves the failure from a\n * 400 in production to a red squiggle.\n */\n async resolve(\n id: string,\n params: ResolveConflictParams,\n options?: RequestOptions\n ): Promise<{ status: string } & Record<string, unknown>> {\n return this.#http.post(\n `/api/v1/conflicts/${encodeURIComponent(id)}/resolve`,\n params,\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n AppendMessagesParams,\n AppendMessagesResult,\n Conversation,\n CreateConversationParams,\n ListConversationsParams,\n Message,\n Page\n} from \"../types\";\n\n/**\n * A running exchange the system remembers across sessions.\n *\n * A conversation is both a SOURCE of memories and a place to spend them: turns\n * appended here go through the same extraction pipeline as `remember`, so they\n * get consolidation and entity resolution rather than a second, drifting path.\n */\nexport class Conversations {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(\n params: ListConversationsParams = {},\n options?: RequestOptions\n ): Paginated<Conversation> {\n return new Paginated<Conversation>((cursor) =>\n this.#http.get<Page<Conversation>>(\n \"/api/v1/conversations\",\n pageQuery(params, cursor, {\n ...(params.channel !== undefined ? { channel: params.channel } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Conversation> {\n return this.#http.get<Conversation>(\n `/api/v1/conversations/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n async create(\n params: CreateConversationParams = {},\n options?: RequestOptions\n ): Promise<Conversation> {\n return this.#http.post<Conversation>(\"/api/v1/conversations\", params, options);\n }\n\n messages(\n id: string,\n params: { readonly limit?: number; readonly cursor?: string } = {},\n options?: RequestOptions\n ): Paginated<Message> {\n return new Paginated<Message>((cursor) =>\n this.#http.get<Page<Message>>(\n `/api/v1/conversations/${encodeURIComponent(id)}/messages`,\n pageQuery(params, cursor, {}),\n options\n )\n );\n }\n\n /**\n * Appends turns, and by default extracts memories from them.\n *\n * Check `extracting` on the result. With no queue configured the turns are\n * stored and never become memory, and the API says so in `note` rather than\n * reporting a success - a caller that ignores it believes a memory is on its\n * way that never arrives.\n *\n * `system` and `tool` turns are stored but never extracted: a system prompt\n * is configuration, and remembering it would file our own instructions as\n * the user's facts.\n *\n * Give this an `idempotencyKey`. Appending the same turn twice is the most\n * likely duplicate in the whole API - a client reconnecting after a dropped\n * response has no other way to tell whether its last write landed.\n */\n async append(\n id: string,\n params: AppendMessagesParams,\n options?: RequestOptions\n ): Promise<AppendMessagesResult> {\n return this.#http.post<AppendMessagesResult>(\n `/api/v1/conversations/${encodeURIComponent(id)}/messages`,\n params,\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport type {\n DriveFile,\n MailMessage,\n MailSummary,\n Person,\n SaveToDriveParams,\n SearchDriveParams,\n SearchMailParams\n} from \"../types\";\n\n/**\n * A user's own Google, through this API rather than through Google.\n *\n * The distinction is the point. Google's tokens live encrypted on the server\n * and never reach a client, so an API key that leaks is an API key - not a\n * mailbox. Nothing here takes a Google credential, and nothing here ever will.\n *\n * Every method answers 409 when there is no connected account, or when Google\n * has stopped renewing one. Neither is a server fault and neither is fixed by\n * retrying: the user has to connect or reconnect at\n * persistmemory.com/dashboard/connect, and the error message says so.\n */\nexport class Google {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /** Files by name, newest first. Omit the query for recently changed ones. */\n async searchDrive(\n params: SearchDriveParams = {},\n options?: RequestOptions\n ): Promise<{ data: DriveFile[] }> {\n return this.#http.get<{ data: DriveFile[] }>(\n \"/api/v1/google/drive/files\",\n {\n ...(params.query !== undefined ? { query: params.query } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {})\n },\n options\n );\n }\n\n async getDriveFile(fileId: string, options?: RequestOptions): Promise<DriveFile> {\n return this.#http.get<DriveFile>(\n `/api/v1/google/drive/files/${encodeURIComponent(fileId)}`,\n undefined,\n options\n );\n }\n\n /**\n * The bytes of a Drive file.\n *\n * A Google Doc, Sheet or Slide holds no bytes of its own and is exported on\n * the way - a document as PDF, a spreadsheet as CSV - so `filename` comes\n * back describing what it BECAME. Writing it under the id instead produces a\n * file nothing will open.\n */\n async downloadDriveFile(\n fileId: string,\n options?: RequestOptions\n ): Promise<{ bytes: Uint8Array; contentType: string; filename?: string }> {\n return this.#http.getBytes(\n `/api/v1/google/drive/files/${encodeURIComponent(fileId)}/content`,\n undefined,\n options\n );\n }\n\n /**\n * Writes a file into the user's Drive.\n *\n * Needs one of the Drive write permissions on their connection. A read-only\n * grant is refused by Google, and the error names the missing permission\n * rather than reporting a failed upload - one is fixed with a checkbox and\n * the other sends somebody looking for a bug.\n */\n async saveToDrive(\n params: SaveToDriveParams,\n options?: RequestOptions\n ): Promise<DriveFile> {\n return this.#http.postBytes<DriveFile>(\n \"/api/v1/google/drive/files\",\n params.bytes,\n params.contentType ?? \"application/octet-stream\",\n {\n name: params.name,\n ...(params.folderId !== undefined ? { folderId: params.folderId } : {})\n },\n options\n );\n }\n\n /**\n * Recent messages - senders, subjects and a one-line preview, never bodies.\n *\n * `query` is Gmail's own syntax passed through as written: `from:priya`,\n * `has:attachment`, `newer_than:7d`. It selects within the connected mailbox\n * and cannot reach another one.\n */\n async searchMail(\n params: SearchMailParams = {},\n options?: RequestOptions\n ): Promise<{ data: MailSummary[] }> {\n return this.#http.get<{ data: MailSummary[] }>(\n \"/api/v1/google/mail\",\n {\n ...(params.query !== undefined ? { query: params.query } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {})\n },\n options\n );\n }\n\n /** One message, with its body and the names of what is attached. */\n async readMail(messageId: string, options?: RequestOptions): Promise<MailMessage> {\n return this.#http.get<MailMessage>(\n `/api/v1/google/mail/${encodeURIComponent(messageId)}`,\n undefined,\n options\n );\n }\n\n /**\n * The bytes of one attachment.\n *\n * Separate from `readMail` so listing a mailbox never drags attachments\n * across the network: a message with a 40 MB deck should not cost 40 MB to\n * summarise.\n */\n async downloadAttachment(\n messageId: string,\n attachmentId: string,\n options?: RequestOptions\n ): Promise<{ bytes: Uint8Array; contentType: string }> {\n return this.#http.getBytes(\n `/api/v1/google/mail/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(attachmentId)}`,\n undefined,\n options\n );\n }\n\n /** Sends as the connected account. Needs the send permission. */\n async sendMail(\n params: { to: string; subject: string; body: string; replyToMessageId?: string },\n options?: RequestOptions\n ): Promise<{ id: string }> {\n return this.#http.post<{ id: string }>(\"/api/v1/google/mail/send\", params, options);\n }\n\n /** People in the user's contacts. Omit the query to list them. */\n async contacts(\n params: { query?: string; limit?: number } = {},\n options?: RequestOptions\n ): Promise<{ data: Person[] }> {\n return this.#http.get<{ data: Person[] }>(\n \"/api/v1/google/contacts\",\n {\n ...(params.query !== undefined ? { query: params.query } : {}),\n ...(params.limit !== undefined ? { limit: params.limit } : {})\n },\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n ConnectIntegrationParams,\n ConnectIntegrationResult,\n Integration,\n ListIntegrationsParams,\n Page,\n UpdateIntegrationParams\n} from \"../types\";\n\n/**\n * Live connections to somewhere material comes from.\n *\n * What is deliberately absent from every response: the access token, the\n * refresh token, and anything else that would let a caller act as the user on\n * the far side. They are held encrypted and never leave the server, so one\n * leaked API key does not become access to the user's Drive.\n *\n * `connect` returns a URL to send the user to. It does not take third-party\n * credentials, and no method here ever will - an endpoint that accepted a\n * password for another service would train users to hand them over, which is\n * the habit every phishing attack relies on.\n */\nexport class Integrations {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListIntegrationsParams = {}, options?: RequestOptions): Paginated<Integration> {\n return new Paginated<Integration>((cursor) =>\n this.#http.get<Page<Integration>>(\n \"/api/v1/integrations\",\n pageQuery(params, cursor, {\n ...(params.provider !== undefined ? { provider: params.provider } : {}),\n ...(params.status !== undefined ? { status: params.status } : {})\n }),\n options\n )\n );\n }\n\n /** Providers that can be connected at all. Not the user's own connections. */\n async available(options?: RequestOptions): Promise<unknown> {\n return this.#http.get<unknown>(\"/api/v1/integrations/available\", undefined, options);\n }\n\n async get(id: string, options?: RequestOptions): Promise<Integration> {\n return this.#http.get<Integration>(\n `/api/v1/integrations/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n async connect(\n params: ConnectIntegrationParams,\n options?: RequestOptions\n ): Promise<ConnectIntegrationResult> {\n return this.#http.post<ConnectIntegrationResult>(\n \"/api/v1/integrations/connect\",\n params,\n options\n );\n }\n\n async update(\n id: string,\n params: UpdateIntegrationParams,\n options?: RequestOptions\n ): Promise<Integration> {\n return this.#http.patch<Integration>(\n `/api/v1/integrations/${encodeURIComponent(id)}`,\n params,\n options\n );\n }\n\n /**\n * Asks for a sync now rather than waiting for the schedule. Answers 202.\n *\n * `full` re-reads everything and is deliberately opt-in: on a large Drive\n * that is thousands of documents and a real bill. The incremental default is\n * what should run almost always.\n */\n async sync(\n id: string,\n params: { readonly full?: boolean } = {},\n options?: RequestOptions\n ): Promise<{ status: string; full: boolean }> {\n return this.#http.post<{ status: string; full: boolean }>(\n `/api/v1/integrations/${encodeURIComponent(id)}/sync`,\n params,\n options\n );\n }\n\n /**\n * Destroys the credentials. The row stays.\n *\n * History still has to attribute the memories this connection produced, and\n * deleting the row would leave them pointing at nothing.\n */\n async disconnect(id: string, options?: RequestOptions): Promise<{ status: string }> {\n return this.#http.delete<{ status: string }>(\n `/api/v1/integrations/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport type { HealthResponse } from \"../types\";\n\n/**\n * Is it up, and is it ready.\n *\n * Two endpoints because they answer different questions and a load balancer\n * needs both: `live` says the process is running, `ready` says it can serve.\n * Answering `ready` from a liveness probe restarts a healthy process that was\n * merely waiting on a dependency.\n *\n * Neither is under `/api/v1`, and neither needs the key - but the key is sent\n * anyway, because a client that builds a second, credential-free request path\n * has a second path that can be wrong.\n */\nexport class Health {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n async live(options?: RequestOptions): Promise<HealthResponse> {\n return this.#http.get<HealthResponse>(\"/health/live\", undefined, options);\n }\n\n async ready(options?: RequestOptions): Promise<HealthResponse> {\n return this.#http.get<HealthResponse>(\"/health/ready\", undefined, options);\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport type { AgentDownloadLink, AgentRequest } from \"../types\";\n\n/**\n * Files fetched from the caller's own machine.\n *\n * A request is asked for on one surface, approved by a person, carried out by\n * an agent on their laptop, and finishes with the bytes in storage. Everything\n * up to that point was already visible through the API; `downloadLink` is what\n * makes the result retrievable rather than merely describable.\n */\nexport class Agent {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /** The row, including whether it finished and how large the result is. */\n async request(id: string, options?: RequestOptions): Promise<AgentRequest> {\n return this.#http.get<AgentRequest>(\n `/api/v1/agent/request/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n /**\n * A short-lived link to the bytes of a finished request.\n *\n * Returns the URL rather than the file, and that is a deliberate limit of\n * this package rather than an oversight. The transport under every other\n * method parses JSON, retries, and attaches the API key; none of those is\n * right for a hundred-megabyte binary body, and building a second request\n * path inside the SDK to serve one method is how a client ends up with two\n * retry policies that differ only during an outage. Fetch the URL with\n * whatever already streams in your runtime - it needs no credential, which\n * is the whole reason it is signed.\n *\n * Treat the URL as the file. It is a bearer credential for exactly one\n * object, it expires in minutes, and it should not be logged or stored.\n */\n async downloadLink(id: string, options?: RequestOptions): Promise<AgentDownloadLink> {\n return this.#http.get<AgentDownloadLink>(\n `/api/v1/agent/request/${encodeURIComponent(id)}/download`,\n undefined,\n options\n );\n }\n}\n", "import type { ClientOptions, RequestOptions } from \"./http\";\nimport { HttpClient } from \"./http\";\nimport { Memories } from \"./resources/memories\";\nimport { Search } from \"./resources/search\";\nimport { Spaces } from \"./resources/spaces\";\nimport { Documents, Jobs, Sources } from \"./resources/ingestion\";\nimport { Conflicts, Entities, Graph } from \"./resources/knowledge\";\nimport { Conversations } from \"./resources/conversations\";\nimport { Google } from \"./resources/google\";\nimport { Integrations } from \"./resources/integrations\";\nimport { Health } from \"./resources/health\";\nimport { Agent } from \"./resources/agent\";\n\n/**\n * The client.\n *\n * const client = new PersistMemory({ apiKey: process.env.PERSISTMEMORY_API_KEY! });\n * const found = await client.search.query({ query: \"what did we decide about Postgres\" });\n *\n * One transport underneath every resource, so retries, timeouts, error mapping\n * and the credential are decided once. Resources are plain objects hanging off\n * this one; they hold a reference to the transport and no state of their own,\n * which is what makes a client safe to share across a process.\n */\nexport class PersistMemory {\n readonly memories: Memories;\n readonly search: Search;\n readonly spaces: Spaces;\n readonly sources: Sources;\n readonly documents: Documents;\n readonly jobs: Jobs;\n readonly entities: Entities;\n readonly graph: Graph;\n readonly conflicts: Conflicts;\n readonly conversations: Conversations;\n readonly integrations: Integrations;\n /** Drive, mail and contacts on the user's connected Google account. */\n readonly google: Google;\n readonly health: Health;\n readonly agent: Agent;\n\n readonly #http: HttpClient;\n\n constructor(options: ClientOptions) {\n this.#http = new HttpClient(options);\n\n this.memories = new Memories(this.#http);\n this.search = new Search(this.#http);\n this.spaces = new Spaces(this.#http);\n this.sources = new Sources(this.#http);\n this.documents = new Documents(this.#http);\n this.jobs = new Jobs(this.#http);\n this.entities = new Entities(this.#http);\n this.graph = new Graph(this.#http);\n this.conflicts = new Conflicts(this.#http);\n this.conversations = new Conversations(this.#http);\n this.integrations = new Integrations(this.#http);\n this.google = new Google(this.#http);\n this.health = new Health(this.#http);\n this.agent = new Agent(this.#http);\n }\n\n /**\n * An escape hatch for an endpoint this package has not caught up with.\n *\n * Typed as `unknown` on purpose: a caller reaching past the typed surface is\n * taking responsibility for the shape, and handing them `any` would let that\n * responsibility spread silently through their codebase.\n */\n async request<T = unknown>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<T> {\n if (method === \"GET\") return this.#http.get<T>(path, undefined, options);\n if (method === \"POST\") return this.#http.post<T>(path, body, options);\n if (method === \"PATCH\") return this.#http.patch<T>(path, body, options);\n return this.#http.delete<T>(path, body, options);\n }\n\n /** Never the key. See `HttpClient.toJSON`, which this delegates to. */\n toJSON(): Record<string, unknown> {\n return this.#http.toJSON();\n }\n\n [Symbol.for(\"nodejs.util.inspect.custom\")](): Record<string, unknown> {\n return this.#http.toJSON();\n }\n}\n", "/**\n * Argument parsing, by hand and on purpose.\n *\n * A CLI is the one place in this repo where a dependency is a genuine cost to\n * the USER rather than to us: `npm i -g` pulls the whole tree onto their\n * machine, and an argument parser is fifty lines. Every other package here is\n * free to depend on what it needs; this one is not.\n *\n * The grammar is `pm <verb> <noun> [target] [flags]`, which is the shape the\n * Harness CLI uses and the reason it reads well: a person who has typed\n * `list pipelines` can guess `list memories` without opening the help.\n */\n\nexport interface ParsedArgs {\n /** Positional words, in order, with flags removed. */\n readonly words: readonly string[];\n readonly flags: Readonly<Record<string, string | boolean>>;\n /** Everything after a bare `--`, handed on untouched. */\n readonly rest: readonly string[];\n}\n\n/**\n * Splits argv.\n *\n * Supports `--flag`, `--flag=value`, `--flag value`, `--no-flag` and short\n * `-x`. A flag whose next token starts with `-` is treated as a boolean rather\n * than swallowing it, so `pm search --explain --limit 5` does not read\n * \"--limit\" as the value of \"--explain\" and then lose the limit entirely.\n */\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const words: string[] = [];\n const flags: Record<string, string | boolean> = {};\n const rest: string[] = [];\n\n let index = 0;\n while (index < argv.length) {\n const token = argv[index] as string;\n\n if (token === \"--\") {\n rest.push(...argv.slice(index + 1));\n break;\n }\n\n if (token.startsWith(\"--\")) {\n const body = token.slice(2);\n const equals = body.indexOf(\"=\");\n\n if (equals !== -1) {\n flags[body.slice(0, equals)] = body.slice(equals + 1);\n index += 1;\n continue;\n }\n\n // `--no-colour` sets `colour` false rather than defining a flag called\n // \"no-colour\" that every reader has to remember to check for.\n if (body.startsWith(\"no-\")) {\n flags[body.slice(3)] = false;\n index += 1;\n continue;\n }\n\n const next = argv[index + 1];\n if (next !== undefined && !next.startsWith(\"-\")) {\n flags[body] = next;\n index += 2;\n continue;\n }\n\n flags[body] = true;\n index += 1;\n continue;\n }\n\n // A single dash on its own is a filename meaning stdin, not a flag.\n if (token.startsWith(\"-\") && token.length > 1) {\n const body = token.slice(1);\n const next = argv[index + 1];\n if (next !== undefined && !next.startsWith(\"-\")) {\n flags[body] = next;\n index += 2;\n continue;\n }\n flags[body] = true;\n index += 1;\n continue;\n }\n\n words.push(token);\n index += 1;\n }\n\n return { words, flags, rest };\n}\n\n/** A flag's value as a string, or undefined. Booleans are not strings. */\nexport function stringFlag(\n args: ParsedArgs,\n ...names: readonly string[]\n): string | undefined {\n for (const name of names) {\n const value = args.flags[name];\n if (typeof value === \"string\") return value;\n }\n return undefined;\n}\n\nexport function boolFlag(args: ParsedArgs, ...names: readonly string[]): boolean {\n for (const name of names) {\n const value = args.flags[name];\n if (typeof value === \"boolean\") return value;\n // `--json=true` is not idiomatic, but somebody will type it and being\n // strict here produces a flag that silently does nothing.\n if (value === \"true\") return true;\n if (value === \"false\") return false;\n }\n return false;\n}\n\n/**\n * A numeric flag, or undefined.\n *\n * Refuses rather than coerces. `--limit abc` becoming `NaN` and then silently\n * becoming the server's default is how somebody gets ten results, believes\n * they asked for a thousand, and concludes the memory is empty.\n */\nexport function numberFlag(\n args: ParsedArgs,\n ...names: readonly string[]\n): number | undefined | \"invalid\" {\n for (const name of names) {\n const value = args.flags[name];\n if (value === undefined || typeof value === \"boolean\") continue;\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return \"invalid\";\n return parsed;\n }\n return undefined;\n}\n\n/** Comma-separated list flag: `--spaces a,b,c`. Empty entries dropped. */\nexport function listFlag(args: ParsedArgs, ...names: readonly string[]): string[] | undefined {\n const raw = stringFlag(args, ...names);\n if (raw === undefined) return undefined;\n const items = raw\n .split(\",\")\n .map((one) => one.trim())\n .filter((one) => one.length > 0);\n return items.length > 0 ? items : undefined;\n}\n", "import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Where the CLI keeps what it knows between runs.\n *\n * ~/.persistmemory/config.json profiles: which server, which account\n * ~/.persistmemory/credentials.json the tokens, mode 0600\n *\n * TWO FILES, and that split is the point rather than tidiness. People paste\n * their config into issues, screen-share it, and commit it to dotfile repos.\n * A credential in the same file as \"which API URL am I pointing at\" is a\n * credential that leaves the machine the first time somebody asks for help.\n * Keeping them apart means the file that gets shared is the harmless one.\n *\n * Modelled on the Harness CLI's `~/.harness/config.yaml` plus a separate\n * credentials file, for the same reason and with the same precedence: an\n * environment variable beats the stored profile, because that is what CI needs\n * and a CI runner should never have to write a config file to authenticate.\n */\n\nexport interface Profile {\n readonly apiUrl: string;\n /** Shown by `pm auth status` so a person can tell two accounts apart. */\n readonly account?: string;\n /**\n * This installation's registered OAuth client id for this server.\n *\n * Kept per profile rather than per credential because it survives logging\n * out: registering is rate-limited on the server, and a person who signs\n * out and back in should not consume a fresh registration each time. It is\n * an identifier, not a secret \u2014 there is no client secret to keep, by\n * design \u2014 so it belongs in the config file rather than beside the token.\n */\n readonly clientId?: string;\n}\n\nexport interface Credential {\n /**\n * How this credential was obtained, which decides whether it can be renewed.\n *\n * An API key is fixed and works until revoked. An OAuth access token expires\n * in an hour and is renewed with the refresh token beside it. Recording\n * which one this is means `pm` never tries to refresh something that has no\n * refresh token and reports \"session expired\" for a key that is simply\n * wrong.\n */\n readonly kind: \"api-key\" | \"oauth\";\n readonly token: string;\n readonly refreshToken?: string;\n /** ISO. Absent for an API key, which does not expire on a schedule. */\n readonly expiresAt?: string;\n readonly scope?: string;\n}\n\ninterface ConfigFile {\n readonly current: string;\n readonly profiles: Record<string, Profile>;\n}\n\ntype CredentialsFile = Record<string, Credential>;\n\nexport const DEFAULT_API_URL = \"https://api.persistmemory.com\";\nexport const DEFAULT_PROFILE = \"default\";\n\nexport interface Paths {\n readonly dir: string;\n readonly config: string;\n readonly credentials: string;\n}\n\nexport function pathsFor(home: string = homedir()): Paths {\n const dir = process.env[\"PERSISTMEMORY_HOME\"] ?? join(home, \".persistmemory\");\n return {\n dir,\n config: join(dir, \"config.json\"),\n credentials: join(dir, \"credentials.json\")\n };\n}\n\nexport function readConfig(paths: Paths): ConfigFile {\n const empty: ConfigFile = { current: DEFAULT_PROFILE, profiles: {} };\n if (!existsSync(paths.config)) return empty;\n\n try {\n const parsed = JSON.parse(readFileSync(paths.config, \"utf8\")) as Partial<ConfigFile>;\n return {\n current: typeof parsed.current === \"string\" ? parsed.current : DEFAULT_PROFILE,\n profiles: typeof parsed.profiles === \"object\" && parsed.profiles ? parsed.profiles : {}\n };\n } catch {\n // A corrupt config is not a reason to refuse to run. `pm auth login` is\n // the fix and it must be reachable, which it would not be if reading the\n // file threw on the way to every command.\n return empty;\n }\n}\n\nexport function readCredentials(paths: Paths): CredentialsFile {\n if (!existsSync(paths.credentials)) return {};\n try {\n return JSON.parse(readFileSync(paths.credentials, \"utf8\")) as CredentialsFile;\n } catch {\n return {};\n }\n}\n\n/**\n * Writes a file only its owner can read.\n *\n * Written to a temporary name and renamed, because `writeFileSync` truncates\n * first: a process killed midway through leaves an empty credentials file and\n * the person is silently logged out with no way to tell that from a token\n * having been revoked. Rename within a directory is atomic.\n *\n * The mode is set on the temporary file BEFORE the rename. Creating it 0600 in\n * the same call is not enough on its own \u2014 `writeFileSync`'s mode is subject\n * to the umask \u2014 so it is set explicitly afterwards and before the content is\n * reachable under its final name.\n */\nfunction writeSecurely(path: string, contents: string, mode: number): void {\n const temporary = `${path}.tmp`;\n writeFileSync(temporary, contents, { mode });\n chmodSync(temporary, mode);\n renameSync(temporary, path);\n}\n\nexport function writeConfig(paths: Paths, config: ConfigFile): void {\n mkdirSync(paths.dir, { recursive: true, mode: 0o700 });\n // 0600 as well. It holds no secret, but it does hold which servers this\n // person talks to, and there is no reason for that to be world-readable on a\n // shared machine.\n writeSecurely(paths.config, `${JSON.stringify(config, null, 2)}\\n`, 0o600);\n}\n\nexport function writeCredentials(paths: Paths, credentials: CredentialsFile): void {\n mkdirSync(paths.dir, { recursive: true, mode: 0o700 });\n writeSecurely(paths.credentials, `${JSON.stringify(credentials, null, 2)}\\n`, 0o600);\n}\n\nexport interface Resolved {\n readonly profile: string;\n readonly apiUrl: string;\n readonly credential?: Credential;\n readonly clientId?: string;\n /** True when the credential came from the environment, not the store. */\n readonly fromEnvironment: boolean;\n}\n\n/**\n * What this invocation should use, after everything has had its say.\n *\n * Precedence, highest first \u2014 flag, environment, stored profile, default:\n *\n * --api-key / --api-url an explicit instruction for this one command\n * PERSISTMEMORY_API_KEY what a CI job sets, and what a person exports\n * the named or current profile what `pm auth login` wrote\n * the public API so a fresh install points somewhere real\n *\n * The environment beating the stored profile is deliberate and matches the\n * Harness CLI. A CI runner has no interactive login and must not be made to\n * write a config file to authenticate; being able to export one variable is\n * the whole reason that path exists.\n */\nexport function resolve(args: {\n paths: Paths;\n profileFlag?: string | undefined;\n apiUrlFlag?: string | undefined;\n apiKeyFlag?: string | undefined;\n env?: NodeJS.ProcessEnv;\n}): Resolved {\n const env = args.env ?? process.env;\n const config = readConfig(args.paths);\n\n const profile =\n args.profileFlag ?? env[\"PERSISTMEMORY_PROFILE\"] ?? config.current ?? DEFAULT_PROFILE;\n\n const stored = config.profiles[profile];\n const apiUrl =\n args.apiUrlFlag ?? env[\"PERSISTMEMORY_API_URL\"] ?? stored?.apiUrl ?? DEFAULT_API_URL;\n\n const fromFlag = args.apiKeyFlag;\n const fromEnv = env[\"PERSISTMEMORY_API_KEY\"];\n\n const clientId = stored?.clientId;\n\n if (fromFlag) {\n return {\n profile,\n apiUrl,\n credential: { kind: \"api-key\", token: fromFlag },\n ...(clientId ? { clientId } : {}),\n fromEnvironment: true\n };\n }\n if (fromEnv) {\n return {\n profile,\n apiUrl,\n credential: { kind: \"api-key\", token: fromEnv },\n ...(clientId ? { clientId } : {}),\n fromEnvironment: true\n };\n }\n\n const credential = readCredentials(args.paths)[profile];\n return {\n profile,\n apiUrl,\n ...(credential ? { credential } : {}),\n ...(clientId ? { clientId } : {}),\n fromEnvironment: false\n };\n}\n\nexport function saveLogin(args: {\n paths: Paths;\n profile: string;\n apiUrl: string;\n credential: Credential;\n account?: string;\n clientId?: string;\n}): void {\n const config = readConfig(args.paths);\n writeConfig(args.paths, {\n // Logging in makes that profile the current one. Anything else means a\n // person logs in, runs a command, and is told they are not logged in.\n current: args.profile,\n profiles: {\n ...config.profiles,\n [args.profile]: {\n apiUrl: args.apiUrl,\n ...(args.account ? { account: args.account } : {}),\n // Kept from the existing profile when this login did not register a\n // new client, so an --api-key login does not erase the browser\n // client id and force a re-registration on the next `pm auth login`.\n ...(args.clientId ?? config.profiles[args.profile]?.clientId\n ? { clientId: args.clientId ?? (config.profiles[args.profile]?.clientId as string) }\n : {})\n }\n }\n });\n\n writeCredentials(args.paths, {\n ...readCredentials(args.paths),\n [args.profile]: args.credential\n });\n}\n\n/** Forgets one profile's credential. The profile itself is kept. */\nexport function clearLogin(paths: Paths, profile: string): boolean {\n const credentials = readCredentials(paths);\n if (!(profile in credentials)) return false;\n delete credentials[profile];\n writeCredentials(paths, credentials);\n return true;\n}\n\n/**\n * Enough of a token to recognise, never enough to use.\n *\n * Printed by `pm auth status`, which people run while screen-sharing to work\n * out why a command is failing. Showing the whole token there is how a\n * credential ends up in a recording.\n */\nexport function maskToken(token: string): string {\n if (token.length <= 8) return \"*\".repeat(token.length);\n return `${token.slice(0, 4)}\u2026${token.slice(-4)}`;\n}\n", "/**\n * How a result is printed.\n *\n * Four formats, because a CLI has two audiences that want opposite things: a\n * person reading a terminal wants columns, and a script wants something it can\n * pipe into `jq`. Serving only the first makes the tool unscriptable; serving\n * only the second makes it unreadable.\n *\n * The default is `table` when stdout is a terminal and `json` when it is not,\n * so `pm search x` is readable and `pm search x | jq` works without anyone\n * having to know a flag exists.\n */\n\nexport const OUTPUT_FORMATS = [\"table\", \"json\", \"yaml\", \"csv\", \"tsv\"] as const;\nexport type OutputFormat = (typeof OUTPUT_FORMATS)[number];\n\nexport function isOutputFormat(value: string): value is OutputFormat {\n return (OUTPUT_FORMATS as readonly string[]).includes(value);\n}\n\n/** A column: where the value comes from, and what to call it. */\nexport interface Column<T> {\n readonly header: string;\n readonly value: (row: T) => string;\n}\n\nexport interface RenderOptions {\n readonly format: OutputFormat;\n /** Terminal width, so a table can be narrowed rather than wrapped. */\n readonly width?: number;\n}\n\n/**\n * Renders rows.\n *\n * `json` and `yaml` print the RAW objects, not the columns. A person who asked\n * for JSON wants the record, and giving them the table's five stringified\n * columns would make the machine-readable format the lossy one.\n */\nexport function render<T>(\n rows: readonly T[],\n columns: readonly Column<T>[],\n options: RenderOptions\n): string {\n switch (options.format) {\n case \"json\":\n return JSON.stringify(rows, null, 2);\n case \"yaml\":\n return toYaml(rows);\n case \"csv\":\n return delimited(rows, columns, \",\");\n case \"tsv\":\n return delimited(rows, columns, \"\\t\");\n default:\n return table(rows, columns, options.width);\n }\n}\n\n/** A single object, for `get`-shaped commands. */\nexport function renderOne<T>(\n row: T,\n fields: readonly Column<T>[],\n options: RenderOptions\n): string {\n if (options.format === \"json\") return JSON.stringify(row, null, 2);\n if (options.format === \"yaml\") return toYaml(row);\n if (options.format === \"csv\" || options.format === \"tsv\") {\n return delimited([row], fields, options.format === \"csv\" ? \",\" : \"\\t\");\n }\n\n // Key on the left, value on the right. A `get` prints one record and a\n // one-row table forces the reader's eye across the screen to pair a heading\n // with its value.\n const width = Math.max(...fields.map((field) => field.header.length));\n return fields\n .map((field) => `${field.header.padEnd(width)} ${field.value(row)}`)\n .join(\"\\n\");\n}\n\nfunction table<T>(\n rows: readonly T[],\n columns: readonly Column<T>[],\n width = process.stdout.columns || 120\n): string {\n if (rows.length === 0) return \"\";\n\n const cells = rows.map((row) => columns.map((column) => oneLine(column.value(row))));\n const widths = columns.map((column, index) =>\n Math.max(column.header.length, ...cells.map((row) => (row[index] ?? \"\").length))\n );\n\n // Narrow the widest column until the table fits, rather than wrapping. A\n // wrapped row spans two lines and stops being greppable, which is most of\n // what a table in a terminal is for.\n const separator = 2;\n let total = widths.reduce((sum, one) => sum + one + separator, -separator);\n while (total > width && Math.max(...widths) > 8) {\n const widest = widths.indexOf(Math.max(...widths));\n widths[widest] = (widths[widest] as number) - 1;\n total -= 1;\n }\n\n const line = (values: readonly string[]): string =>\n values\n .map((value, index) => clip(value, widths[index] as number).padEnd(widths[index] as number))\n .join(\" \")\n .trimEnd();\n\n return [\n line(columns.map((column) => column.header.toUpperCase())),\n ...cells.map((row) => line(row))\n ].join(\"\\n\");\n}\n\nfunction delimited<T>(\n rows: readonly T[],\n columns: readonly Column<T>[],\n separator: string\n): string {\n const escape = (value: string): string => {\n const flat = oneLine(value);\n // Quoted only when it has to be. An always-quoted CSV is valid and is\n // needlessly hard to read in a terminal, which is where this one usually\n // ends up.\n if (!flat.includes(separator) && !flat.includes('\"') && !flat.includes(\"\\n\")) return flat;\n return `\"${flat.replace(/\"/g, '\"\"')}\"`;\n };\n\n return [\n columns.map((column) => escape(column.header)).join(separator),\n ...rows.map((row) => columns.map((column) => escape(column.value(row))).join(separator))\n ].join(\"\\n\");\n}\n\n/**\n * YAML, for the subset this CLI actually emits.\n *\n * Hand-written rather than a dependency, for the reason given in `args.ts`: a\n * global install pulls every dependency onto the user's machine. This handles\n * objects, arrays, strings, numbers, booleans and null, which is the whole of\n * what a JSON API response can be.\n */\nexport function toYaml(value: unknown, indent = 0): string {\n const pad = \" \".repeat(indent);\n\n if (value === null || value === undefined) return \"null\";\n if (typeof value === \"boolean\" || typeof value === \"number\") return String(value);\n if (typeof value === \"string\") return yamlString(value);\n\n if (Array.isArray(value)) {\n if (value.length === 0) return \"[]\";\n return value\n .map((item) => {\n const rendered = toYaml(item, indent + 2);\n // A nested block starts on the line after the dash; a scalar sits on it.\n return isBlock(item) ? `${pad}-\\n${rendered}` : `${pad}- ${rendered}`;\n })\n .join(\"\\n\");\n }\n\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>);\n if (entries.length === 0) return \"{}\";\n return entries\n .map(([key, item]) => {\n const rendered = toYaml(item, indent + 2);\n return isBlock(item) ? `${pad}${key}:\\n${rendered}` : `${pad}${key}: ${rendered}`;\n })\n .join(\"\\n\");\n }\n\n return String(value);\n}\n\nfunction isBlock(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n return typeof value === \"object\" && value !== null && Object.keys(value).length > 0;\n}\n\n/**\n * Quotes a YAML scalar when leaving it bare would change its meaning.\n *\n * `yes`, `no`, `on`, `off`, `null` and anything that parses as a number are\n * the traps: a memory whose content is the single word \"No\" must not read back\n * as the boolean false.\n */\nfunction yamlString(value: string): string {\n if (value === \"\") return '\"\"';\n if (value.includes(\"\\n\")) {\n return `|-\\n${value\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\")}`;\n }\n const ambiguous =\n /^(y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF|null|Null|NULL|~)$/.test(\n value\n ) ||\n /^[-+]?[0-9]/.test(value) ||\n /^[\\s#&*!|>'\"%@`{}[\\],]/.test(value) ||\n value.includes(\": \") ||\n value.endsWith(\":\");\n\n return ambiguous ? `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"` : value;\n}\n\n/** Newlines flattened, so one record stays one row. */\nfunction oneLine(value: string): string {\n return value.replace(/\\s*\\n\\s*/g, \" \").trim();\n}\n\nfunction clip(value: string, width: number): string {\n if (value.length <= width) return value;\n return width <= 1 ? value.slice(0, width) : `${value.slice(0, width - 1)}\u2026`;\n}\n\n/** ISO timestamp to something short enough for a column. */\nexport function shortDate(iso: string | undefined): string {\n if (!iso) return \"\";\n const at = new Date(iso);\n return Number.isNaN(at.getTime()) ? \"\" : iso.slice(0, 16).replace(\"T\", \" \");\n}\n", "import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * The help, which is the only documentation most people will read.\n *\n * Written as a page rather than generated from a command table on purpose: a\n * generated help lists everything at equal weight, and the thing a new user\n * needs is the four commands that matter in the order they will need them.\n */\n/**\n * Replaced at build time from `package.json`, never edited here.\n *\n * This was a literal that had to be kept in step with the manifest by hand,\n * and it drifted \u2014 0.2.0 shipped with a binary reporting 0.1.2, so somebody\n * who upgraded was told the upgrade had not happened. Neither file was wrong\n * on its own, which is exactly why nobody caught it.\n *\n * The fallback is for `tsx`, which runs the source directly and performs no\n * substitution: it reads the manifest instead, so a development run reports\n * the truth too.\n */\ndeclare const __PM_VERSION__: string | undefined;\n\nexport const VERSION: string =\n typeof __PM_VERSION__ === \"string\" ? __PM_VERSION__ : versionFromManifest();\n\nfunction versionFromManifest(): string {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n const manifest = JSON.parse(readFileSync(join(here, \"..\", \"package.json\"), \"utf8\")) as {\n version?: string;\n };\n return manifest.version ?? \"0.0.0\";\n } catch {\n // Never fatal. A CLI that cannot start because it could not work out its\n // own version number is worse than one that reports it as unknown.\n return \"0.0.0\";\n }\n}\n\n/** The name to install, kept beside the version it belongs to. */\nexport const PACKAGE = \"@persistmemory/cli\";\n\nexport const HELP = `\n pm \u2014 PersistMemory from your terminal\n\n Memory that persists across every model, tool and session you use.\n\n GETTING STARTED\n\n pm setup sign in, then pick a Space for this folder\n pm auth login sign in with your browser\n pm auth logout sign out on this machine\n pm start a session and just ask\n pm remember \"we chose Postgres\" capture something\n pm search \"what did we choose\" ask for it back\n\n COMMANDS\n\n auth login sign in through the browser\n auth login --api-key sign in with a key, for CI and headless machines\n\n auth status who am I, and does the server still accept it\n auth logout forget the stored credential\n\n chat start an interactive session\n chat --resume <id> pick up an earlier session\n\n setup sign in and choose this folder's Space\n setup --space \"Acme\" choose one without being asked\n setup --new-space \"Acme\" create one and use it\n\n spaces list your Spaces\n spaces create \"Acme\" make a new one\n spaces delete \"Acme\" --memories keep|delete\n delete one \u2014 you must say what happens\n to what is in it\n spaces merge \"A\" \"B\" --name \"C\" a new Space holding both, originals kept\n\n remember <text> capture text\n remember - capture whatever is piped in\n remember --file <path> capture a file's contents\n\n agent --root <dir> [--root ...] answer file requests from this machine \u2014\n nothing outside those folders is read.\n It stays in the foreground. Background it,\n and stop it later, with:\n nohup pm agent --root ~/Desktop &\n pkill -f \"pm agent\"\n\n search <query> search your memory\n list memories the most recent memories\n list spaces your Spaces\n get memory <id> one memory, in full\n\n drive [name] search your Google Drive\n drive get <id> [--out path] download one file here\n drive put <file> [--name n] save a file into Drive\n mail [search] recent mail \u2014 from:priya, has:attachment\n mail read <id> one message, with its body\n\n status is the service healthy\n requests file requests waiting for you to approve\n requests get <id> write a finished one to a file here\n\n update install the newest version\n uninstall remove pm from this machine\n delete delete every file pm has written here\n\n FLAGS\n\n --output table|json|yaml|csv|tsv how to print (default: table on a\n terminal, json when piped)\n --profile <name> use a named account\n --api-url <url> talk to a different server\n --limit <n> how many results\n --space <a,b> restrict to Spaces, by name or id\n --quiet suppress notices\n --version print the version\n --help print this\n\n ENVIRONMENT\n\n PERSISTMEMORY_API_KEY a key, taking precedence over any stored\n login. This is what CI should set.\n PERSISTMEMORY_API_URL the server to talk to\n PERSISTMEMORY_PROFILE which stored profile to use\n PERSISTMEMORY_SPACE Spaces to use when --space is not given\n PERSISTMEMORY_HOME where config, credentials and session\n transcripts live (default: ~/.persistmemory)\n PERSISTMEMORY_CLIENT_ID override the OAuth client id, for a\n self-hosted deployment\n PERSISTMEMORY_AUTO_UPDATE update without asking when a newer\n version is published\n PERSISTMEMORY_NO_UPDATE never check for updates\n\n Docs: https://persistmemory.com/docs/cli\n`;\n", "import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * Noticing that a newer version exists, and saying so once.\n *\n * A CLI that never mentions its own updates is a CLI most people keep on the\n * version they first installed \u2014 and the bugs they hit were fixed months ago.\n * The whole design here is about being cheap and quiet enough that nobody\n * turns it off:\n *\n * never blocks the check runs after the command has printed, and the\n * answer is used on the NEXT run. A version check has no\n * business delaying `pm search`.\n * once a day the answer is cached with a timestamp.\n * never in a script no terminal, --quiet, CI, or PERSISTMEMORY_NO_UPDATE\n * all skip it. A notice in a log file helps nobody and a\n * notice on stdout would corrupt piped JSON.\n * stderr, always stdout is the command's output and belongs to whatever\n * is reading it.\n */\nconst REGISTRY = \"https://registry.npmjs.org/@persistmemory/cli/latest\";\nconst EVERY_MS = 24 * 60 * 60 * 1000;\n\nexport interface UpdateCheckDeps {\n readonly file: string;\n readonly current: string;\n readonly fetch?: typeof globalThis.fetch;\n readonly now?: () => number;\n readonly env?: NodeJS.ProcessEnv;\n readonly isTty?: boolean;\n readonly quiet?: boolean;\n}\n\ninterface Cached {\n readonly checkedAt: number;\n readonly latest: string;\n}\n\n/** The notice to print, or nothing. Reads the cache; never fetches. */\nexport function updateNotice(deps: UpdateCheckDeps): string | undefined {\n if (!wanted(deps)) return undefined;\n\n const cached = read(deps.file);\n if (!cached) return undefined;\n if (!isNewer(cached.latest, deps.current)) return undefined;\n\n return [\n `A newer PersistMemory CLI is available: ${deps.current} \u2192 ${cached.latest}`,\n `Run \\`pm update\\` to install it.`\n ].join(\"\\n\");\n}\n\n/**\n * Refreshes the cache, if it is stale. Never throws and never blocks anything\n * the person asked for.\n */\nexport async function refreshUpdateCache(deps: UpdateCheckDeps): Promise<void> {\n if (!wanted(deps)) return;\n\n const now = (deps.now ?? Date.now)();\n const cached = read(deps.file);\n if (cached && now - cached.checkedAt < EVERY_MS) return;\n\n const call = deps.fetch ?? globalThis.fetch;\n\n try {\n // Short, because this is a courtesy. A registry that is slow must not make\n // the CLI feel slow, and a missed check costs a day.\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 1500);\n\n const response = await call(REGISTRY, {\n signal: controller.signal,\n headers: { accept: \"application/vnd.npm.install-v1+json\" }\n }).finally(() => clearTimeout(timer));\n\n if (!response.ok) return;\n\n const body = (await response.json()) as { version?: unknown };\n if (typeof body.version !== \"string\") return;\n\n write(deps.file, { checkedAt: now, latest: body.version });\n } catch {\n // Offline, blocked, rate-limited, behind a proxy that hates us. None of\n // these are the person's problem and none of them are worth a word.\n }\n}\n\n/** Whether the person should be told about updates at all. */\nfunction wanted(deps: UpdateCheckDeps): boolean {\n const env = deps.env ?? process.env;\n\n if (deps.quiet === true) return false;\n if (deps.isTty === false) return false;\n if (env[\"PERSISTMEMORY_NO_UPDATE\"]) return false;\n // Every CI system sets this, and none of them can act on the notice.\n if (env[\"CI\"]) return false;\n\n return true;\n}\n\nfunction read(file: string): Cached | undefined {\n try {\n if (!existsSync(file)) return undefined;\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as Partial<Cached>;\n if (typeof parsed.checkedAt !== \"number\" || typeof parsed.latest !== \"string\") {\n return undefined;\n }\n return { checkedAt: parsed.checkedAt, latest: parsed.latest };\n } catch {\n return undefined;\n }\n}\n\nfunction write(file: string, value: Cached): void {\n try {\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, JSON.stringify(value), \"utf8\");\n } catch {\n // A read-only home directory is somebody's deliberate choice. It must not\n // fail a command that has already succeeded.\n }\n}\n\n/**\n * Compares two versions the way npm does, for the part that matters here.\n *\n * Numeric segment by segment, because \"0.10.0\" is newer than \"0.9.0\" and a\n * string comparison says the opposite \u2014 which would nag somebody forever about\n * an update they already have. A prerelease is never announced: somebody\n * running `0.2.0-rc.1` chose it.\n */\nexport function isNewer(candidate: string, current: string): boolean {\n if (candidate.includes(\"-\") || current.includes(\"-\")) return false;\n\n const a = candidate.split(\".\").map(Number);\n const b = current.split(\".\").map(Number);\n if (a.some(Number.isNaN) || b.some(Number.isNaN)) return false;\n\n for (let index = 0; index < Math.max(a.length, b.length); index += 1) {\n const left = a[index] ?? 0;\n const right = b[index] ?? 0;\n if (left !== right) return left > right;\n }\n\n return false;\n}\n\nexport function updateCacheFile(home: string): string {\n return join(home, \"update-check.json\");\n}\n", "import { spawn } from \"node:child_process\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type { Credential } from \"../config\";\nimport { createPkce, randomState } from \"./pkce\";\nimport { startLoopback } from \"./loopback\";\n\n/**\n * The browser sign-in, end to end.\n *\n * No new server endpoint was needed for any of this, which is worth stating\n * because the obvious plan was to build one. The API already implements\n * OAuth 2.1 with PKCE, dynamic client registration (RFC 7591) and the RFC 8252\n * loopback redirect rule \u2014 all of it built for the MCP server and all of it\n * exactly what a CLI needs. A device-code grant or a bespoke `/cli/login`\n * would have been a second authentication surface to harden, rate-limit and\n * keep in step with the first.\n *\n * discover \u2192 GET /.well-known/oauth-authorization-server\n * register \u2192 POST /oauth/register (public client, no secret)\n * authorize \u2192 browser to /oauth/authorize (PKCE challenge + state)\n * redeem \u2192 POST /oauth/token (code + verifier)\n */\n\nexport interface AuthorizationServer {\n readonly issuer: string;\n readonly authorizationEndpoint: string;\n readonly tokenEndpoint: string;\n readonly registrationEndpoint?: string;\n readonly scopesSupported?: readonly string[];\n /**\n * The RFC 8707 resource to ask a token FOR, when the server we are talking\n * to is not the one that issues them.\n */\n readonly resource?: string;\n}\n\n/**\n * Where the server we are talking to says its tokens come from. RFC 9728.\n *\n * This is what lets the CLI point at the command line's own service rather\n * than at the main API. That service issues nothing \u2014 it verifies \u2014 so asking\n * IT for OAuth metadata would find nothing. Instead it publishes a\n * protected-resource document naming its authorization server and its own\n * resource identifier, and the CLI follows that.\n *\n * Absent, and the URL is treated as the authorization server itself, which is\n * what pointing at the main API means. Both work, and neither needs the person\n * to know which kind of server they configured.\n */\nasync function protectedResource(\n apiUrl: string,\n deps: OAuthDeps\n): Promise<{ issuer: string; resource: string } | undefined> {\n try {\n const url = new URL(\"/.well-known/oauth-protected-resource\", apiUrl).toString();\n const response = await deps.fetch(url, { headers: { accept: \"application/json\" } });\n if (!response.ok) return undefined;\n\n const body = (await response.json()) as Record<string, unknown>;\n const servers = body[\"authorization_servers\"];\n const resource = body[\"resource\"];\n\n if (!Array.isArray(servers) || typeof servers[0] !== \"string\") return undefined;\n if (typeof resource !== \"string\") return undefined;\n\n return { issuer: servers[0], resource };\n } catch {\n // Not a protected resource, or unreachable. The caller falls back to\n // treating the URL as the authorization server, which is the main API.\n return undefined;\n }\n}\n\nexport interface OAuthDeps {\n readonly fetch: typeof globalThis.fetch;\n /** Injected so a test never opens a browser and never binds a port. */\n readonly openBrowser?: (url: string) => Promise<void>;\n readonly print?: (line: string) => void;\n}\n\nexport async function discover(\n apiUrl: string,\n deps: OAuthDeps\n): Promise<AuthorizationServer> {\n /**\n * Follow the protected-resource document first, when there is one.\n *\n * A service that only verifies tokens has no `/oauth/authorize` of its own,\n * so discovery has to be redirected to whoever issues for it. When there is\n * no such document the URL IS the authorization server.\n */\n const guarded = await protectedResource(apiUrl, deps);\n const issuerUrl = guarded?.issuer ?? apiUrl;\n\n const url = new URL(\"/.well-known/oauth-authorization-server\", issuerUrl).toString();\n const response = await deps.fetch(url, { headers: { accept: \"application/json\" } });\n\n if (!response.ok) {\n throw new Error(\n `${issuerUrl} does not look like a PersistMemory API: discovery answered ${response.status}.`\n );\n }\n\n const body = (await response.json()) as Record<string, unknown>;\n const required = (key: string): string => {\n const value = body[key];\n if (typeof value !== \"string\") {\n throw new Error(`the server's metadata is missing \"${key}\"`);\n }\n return value;\n };\n\n return {\n issuer: required(\"issuer\"),\n authorizationEndpoint: required(\"authorization_endpoint\"),\n tokenEndpoint: required(\"token_endpoint\"),\n // Carried through so the authorize request can name it. Absent when the\n // API is its own resource, in which case the server uses its default.\n ...(guarded?.resource ? { resource: guarded.resource } : {}),\n ...(typeof body[\"registration_endpoint\"] === \"string\"\n ? { registrationEndpoint: body[\"registration_endpoint\"] }\n : {}),\n ...(Array.isArray(body[\"scopes_supported\"])\n ? { scopesSupported: body[\"scopes_supported\"].map(String) }\n : {})\n };\n}\n\n/**\n * Registers this installation as a public client.\n *\n * Once per machine per server, and the resulting `client_id` is kept in the\n * credentials file. Registering on every login would leave a row per sign-in\n * on the server, and the registration endpoint is deliberately rate-limited.\n *\n * `token_endpoint_auth_method: \"none\"` because there is nowhere on a user's\n * laptop to keep a client secret that the user cannot read. Claiming\n * confidentiality we do not have is worse than not claiming it: the server\n * would then trust a secret that is sitting in a dotfile.\n */\nexport async function registerClient(\n server: AuthorizationServer,\n redirectUri: string,\n scope: string,\n deps: OAuthDeps\n): Promise<string> {\n if (!server.registrationEndpoint) {\n throw new Error(\n \"this server does not offer dynamic client registration. Use `pm auth login --api-key` instead.\"\n );\n }\n\n const response = await deps.fetch(server.registrationEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({\n client_name: \"PersistMemory CLI\",\n client_uri: \"https://persistmemory.com/docs/cli\",\n // Registered WITHOUT a port. The server compares loopback redirects\n // ignoring the port (RFC 8252 \u00A77.3), so registering the one we happened\n // to bind this time would be noise \u2014 and would break the next login,\n // which binds a different one.\n redirect_uris: [\"http://127.0.0.1/callback\"],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n scope\n })\n });\n\n if (!response.ok) {\n throw new Error(`could not register with ${server.issuer}: ${await describe(response)}`);\n }\n\n const body = (await response.json()) as { client_id?: unknown };\n if (typeof body.client_id !== \"string\") {\n throw new Error(\"the server registered this client but returned no client_id\");\n }\n return body.client_id;\n}\n\n/**\n * The CLI's own client id, fixed and public.\n *\n * NOT obtained by registering. `/oauth/register` is open to anyone, and the\n * server now refuses to let any caller register under our own name precisely\n * because the consent screen renders that name \u2014 so a CLI that registered\n * itself would either be refused, or would have to call itself something\n * unrecognisable on the screen where a person decides whether to trust it.\n *\n * A public client id is not a secret. It appears in every authorize URL and is\n * baked into a program that runs on other people's machines. What matters is\n * that it is STABLE: consent is recorded against it, and a new id per install\n * would ask everybody to approve the CLI again.\n *\n * Overridable for a self-hosted deployment that seeded a different one.\n */\nexport const CLI_CLIENT_ID = \"persistmemory-cli\";\n\nexport interface LoginResult {\n readonly credential: Credential;\n readonly clientId: string;\n}\n\n/**\n * Is the seeded client actually there?\n *\n * Asked by starting an authorization request and reading the answer, because\n * there is no endpoint that discloses a client by id \u2014 and there should not\n * be, since that would let anyone enumerate what a deployment has registered.\n * A HEAD against `/oauth/authorize` with an unknown client answers 400 with\n * `invalid_client`, and with a known one answers a redirect or a consent\n * page. Either of those means it exists.\n *\n * Failure is treated as \"not there\", so a network problem falls back to\n * registration rather than stopping sign-in with a confusing error.\n */\nasync function knownClient(\n server: AuthorizationServer,\n clientId: string,\n deps: OAuthDeps\n): Promise<boolean> {\n try {\n const probe = new URL(server.authorizationEndpoint);\n probe.searchParams.set(\"client_id\", clientId);\n // Deliberately incomplete: this asks only whether the CLIENT is known, and\n // an incomplete request is refused for a missing parameter rather than for\n // an unknown client \u2014 which is exactly the distinction being read.\n probe.searchParams.set(\"response_type\", \"code\");\n\n const response = await deps.fetch(probe.toString(), {\n method: \"GET\",\n redirect: \"manual\"\n });\n\n if (response.status >= 500) return false;\n const body = await response.text().catch(() => \"\");\n return !body.includes(\"invalid_client\");\n } catch {\n return false;\n }\n}\n\nexport async function loginWithBrowser(args: {\n apiUrl: string;\n scope: string;\n clientId?: string | undefined;\n deps: OAuthDeps;\n timeoutMs?: number;\n}): Promise<LoginResult> {\n const { deps } = args;\n const print = deps.print ?? (() => undefined);\n\n const server = await discover(args.apiUrl, deps);\n const listener = await startLoopback(\n args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}\n );\n\n try {\n /**\n * The fixed first-party id, and registration only as a fallback.\n *\n * A deployment that has seeded the CLI client \u2014 every current one does, at\n * boot \u2014 is used directly. Dynamic registration remains for a self-hosted\n * server that has not, and it registers under a plain name because the\n * reserved ones are refused.\n */\n const clientId =\n args.clientId ??\n process.env[\"PERSISTMEMORY_CLIENT_ID\"] ??\n ((await knownClient(server, CLI_CLIENT_ID, deps))\n ? CLI_CLIENT_ID\n : await registerClient(server, listener.redirectUri, args.scope, deps));\n\n const pkce = createPkce();\n const state = randomState();\n\n const authorize = new URL(server.authorizationEndpoint);\n authorize.searchParams.set(\"response_type\", \"code\");\n authorize.searchParams.set(\"client_id\", clientId);\n authorize.searchParams.set(\"redirect_uri\", listener.redirectUri);\n authorize.searchParams.set(\"scope\", args.scope);\n authorize.searchParams.set(\"state\", state);\n authorize.searchParams.set(\"code_challenge\", pkce.challenge);\n authorize.searchParams.set(\"code_challenge_method\", pkce.method);\n /**\n * RFC 8707. Which service this token is FOR.\n *\n * Load-bearing when the CLI is pointed at the command line's own service:\n * a token minted for the default resource is refused there by the audience\n * check, and the refusal looks like a broken sign-in rather than a token\n * for the wrong place.\n */\n if (server.resource) authorize.searchParams.set(\"resource\", server.resource);\n\n print(\"Opening your browser to sign in.\");\n print(`If it does not open, visit:\\n\\n ${authorize.toString()}\\n`);\n\n // Failure to open a browser is NOT failure to log in. On a server over\n // SSH there is no browser at all, and the URL printed above is then the\n // whole flow \u2014 so this is attempted and its outcome ignored.\n await (deps.openBrowser ?? openBrowser)(authorize.toString()).catch(() => undefined);\n\n const callback = await listener.waitForCallback();\n\n if (callback.error) {\n throw new Error(\n `sign-in was refused: ${callback.errorDescription ?? callback.error}`\n );\n }\n if (!callback.code) {\n throw new Error(\"the browser came back without an authorization code\");\n }\n\n /**\n * The state check, in constant time.\n *\n * This is the CSRF defence: without it another site can send the user's\n * browser to a redirect carrying an authorization code the attacker\n * obtained, and the CLI would store a token for the ATTACKER'S account\n * while the user believes they are signed into their own. Everything they\n * then capture goes somewhere else.\n */\n if (!callback.state || !safeEqual(callback.state, state)) {\n throw new Error(\"the browser came back with the wrong state \u2014 sign-in was not completed\");\n }\n\n const credential = await redeem({\n server,\n clientId,\n code: callback.code,\n verifier: pkce.verifier,\n redirectUri: listener.redirectUri,\n deps\n });\n\n return { credential, clientId };\n } finally {\n // Always. A listener left bound holds the port and keeps the process\n // alive, and `pm auth login` would never return.\n listener.close();\n }\n}\n\nasync function redeem(args: {\n server: AuthorizationServer;\n clientId: string;\n code: string;\n verifier: string;\n redirectUri: string;\n deps: OAuthDeps;\n}): Promise<Credential> {\n const form = new URLSearchParams({\n grant_type: \"authorization_code\",\n code: args.code,\n redirect_uri: args.redirectUri,\n client_id: args.clientId,\n code_verifier: args.verifier,\n // Restated at redemption. The server compares it against the resource the\n // code was authorized for and refuses a mismatch, which is what stops a\n // code issued for one service being redeemed for a token against another.\n ...(args.server.resource ? { resource: args.server.resource } : {})\n });\n\n const response = await args.deps.fetch(args.server.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\"\n },\n body: form.toString()\n });\n\n if (!response.ok) {\n throw new Error(`the server refused to issue a token: ${await describe(response)}`);\n }\n\n return toCredential((await response.json()) as Record<string, unknown>);\n}\n\n/**\n * Trades a refresh token for a new access token.\n *\n * Exported because every command needs it, not just login: an access token\n * lasts an hour and a person who signed in yesterday should not be told to\n * sign in again to run `pm search`.\n */\nexport async function refresh(args: {\n apiUrl: string;\n clientId: string;\n refreshToken: string;\n deps: OAuthDeps;\n}): Promise<Credential> {\n const server = await discover(args.apiUrl, args.deps);\n\n const response = await args.deps.fetch(server.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\"\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: args.refreshToken,\n client_id: args.clientId\n }).toString()\n });\n\n if (!response.ok) {\n throw new Error(`could not renew the session: ${await describe(response)}`);\n }\n\n const credential = toCredential((await response.json()) as Record<string, unknown>);\n\n // A server that rotates refresh tokens returns a new one; one that does not\n // returns none, and the old one stays valid. Dropping the old one in that\n // second case would log the person out an hour later for no reason.\n return credential.refreshToken\n ? credential\n : { ...credential, refreshToken: args.refreshToken };\n}\n\nexport function toCredential(body: Record<string, unknown>): Credential {\n const token = body[\"access_token\"];\n if (typeof token !== \"string\") {\n throw new Error(\"the server's token response contained no access_token\");\n }\n\n const expiresIn = body[\"expires_in\"];\n const expiresAt =\n typeof expiresIn === \"number\" && Number.isFinite(expiresIn)\n ? new Date(Date.now() + expiresIn * 1000).toISOString()\n : undefined;\n\n return {\n kind: \"oauth\",\n token,\n ...(typeof body[\"refresh_token\"] === \"string\"\n ? { refreshToken: body[\"refresh_token\"] }\n : {}),\n ...(expiresAt ? { expiresAt } : {}),\n ...(typeof body[\"scope\"] === \"string\" ? { scope: body[\"scope\"] } : {})\n };\n}\n\n/** Compares two secrets without leaking their prefix through timing. */\nfunction safeEqual(a: string, b: string): boolean {\n const left = Buffer.from(a);\n const right = Buffer.from(b);\n if (left.length !== right.length) return false;\n return timingSafeEqual(left, right);\n}\n\n/**\n * Opens a URL in whatever the platform calls a browser.\n *\n * The URL is passed as an ARGUMENT, never through a shell. It contains a\n * client id and a code challenge and is assembled from a server's metadata; a\n * `sh -c` with that interpolated is a command injection with a remote source.\n */\nasync function openBrowser(url: string): Promise<void> {\n /**\n * Windows needs `cmd /c start`, not `start`.\n *\n * `start` is a cmd BUILTIN and not an executable, so spawning it directly\n * fails with ENOENT on every Windows machine \u2014 the browser never opens and\n * the person is left staring at a prompt. The empty string after it is not a\n * typo: `start` treats its first quoted argument as the window TITLE, so\n * without a placeholder a quoted URL is consumed as the title and nothing\n * opens.\n *\n * `windowsVerbatimArguments` is off, so Node quotes the URL for us \u2014 which\n * matters because an authorize URL is full of `&`, and an unquoted `&` in\n * cmd separates commands.\n */\n const [command, args] =\n process.platform === \"darwin\"\n ? [\"open\", [url]]\n : process.platform === \"win32\"\n ? [\"cmd\", [\"/c\", \"start\", \"\", url]]\n : [\"xdg-open\", [url]];\n\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command as string, args as string[], {\n stdio: \"ignore\",\n // Detached so closing the terminal does not close the browser, and so\n // this process can exit without waiting for it.\n detached: true\n });\n child.once(\"error\", reject);\n child.unref();\n resolve();\n });\n}\n\nasync function describe(response: Response): Promise<string> {\n try {\n const body = (await response.json()) as Record<string, unknown>;\n const error = body[\"error\"];\n const description = body[\"error_description\"];\n if (typeof description === \"string\") return `${String(error ?? response.status)} \u2014 ${description}`;\n if (typeof error === \"string\") return error;\n } catch {\n // Falls through to the status, which is all we have.\n }\n return `HTTP ${response.status}`;\n}\n", "import { createHash, randomBytes } from \"node:crypto\";\n\n/**\n * PKCE (RFC 7636), which is what makes a public client safe.\n *\n * The CLI cannot keep a secret \u2014 it is a file on the user's disk \u2014 so it\n * registers with `token_endpoint_auth_method: \"none\"` and proves possession a\n * different way: it invents a random verifier, sends only its hash with the\n * authorization request, and reveals the verifier when redeeming the code.\n *\n * That is the entire defence against an authorization code being stolen out of\n * a loopback redirect, which is a real risk on a shared machine: another\n * process can race to bind the port or read the URL out of a browser history.\n * A stolen code without the verifier is worthless.\n */\nexport interface Pkce {\n readonly verifier: string;\n readonly challenge: string;\n readonly method: \"S256\";\n}\n\nexport function createPkce(): Pkce {\n // 32 bytes, base64url. RFC 7636 requires 43-128 characters of the unreserved\n // set, and 32 random bytes encodes to 43 \u2014 the minimum that is also the full\n // entropy of the generator.\n const verifier = base64Url(randomBytes(32));\n return {\n verifier,\n challenge: base64Url(createHash(\"sha256\").update(verifier).digest()),\n // Never \"plain\". OAuth 2.1 removes it, and a plain challenge is the\n // verifier, which defends against nothing.\n method: \"S256\"\n };\n}\n\n/** A value a caller must not be able to guess or replay. */\nexport function randomState(): string {\n return base64Url(randomBytes(24));\n}\n\nfunction base64Url(bytes: Buffer): string {\n return bytes.toString(\"base64\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n", "import { createServer } from \"node:http\";\nimport type { Server } from \"node:http\";\n\n/**\n * The one-shot listener the browser is redirected back to.\n *\n * RFC 8252 \u00A77.3: a native app receives its authorization code on a loopback\n * address, binding whatever port happens to be free. This repo's redirect-URI\n * policy already implements the matching half of that rule \u2014 the port, and\n * only the port, is ignored when comparing against the registered URI \u2014 so the\n * CLI does not have to register a fixed port or ask the user to keep one free.\n *\n * Bound to 127.0.0.1 EXPLICITLY rather than to every interface. Binding 0.0.0.0\n * would put somebody's authorization code on a listener reachable from their\n * whole network, and on a laptop in a caf\u00E9 that is the entire attack.\n */\nexport interface Callback {\n readonly code?: string;\n readonly state?: string;\n readonly error?: string;\n readonly errorDescription?: string;\n}\n\nexport interface Listener {\n readonly port: number;\n readonly redirectUri: string;\n /** Resolves when the browser comes back, or rejects on timeout. */\n waitForCallback(): Promise<Callback>;\n close(): void;\n}\n\nexport const CALLBACK_PATH = \"/callback\";\n\nexport async function startLoopback(options: { timeoutMs?: number } = {}): Promise<Listener> {\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000;\n\n let resolveCallback: ((value: Callback) => void) | undefined;\n let rejectCallback: ((reason: Error) => void) | undefined;\n\n const received = new Promise<Callback>((resolve, reject) => {\n resolveCallback = resolve;\n rejectCallback = reject;\n });\n\n const server: Server = createServer((request, response) => {\n const url = new URL(request.url ?? \"/\", \"http://127.0.0.1\");\n\n if (url.pathname !== CALLBACK_PATH) {\n response.writeHead(404, { \"content-type\": \"text/plain\" });\n response.end(\"Not found\");\n return;\n }\n\n const callback: Callback = {\n ...(url.searchParams.get(\"code\") ? { code: url.searchParams.get(\"code\") as string } : {}),\n ...(url.searchParams.get(\"state\") ? { state: url.searchParams.get(\"state\") as string } : {}),\n ...(url.searchParams.get(\"error\") ? { error: url.searchParams.get(\"error\") as string } : {}),\n ...(url.searchParams.get(\"error_description\")\n ? { errorDescription: url.searchParams.get(\"error_description\") as string }\n : {})\n };\n\n // The page the person is left looking at. Served from here rather than\n // redirecting to the web app, because a redirect would put the code in\n // another origin's referrer and because this must work offline against a\n // local API.\n response.writeHead(200, {\n \"content-type\": \"text/html; charset=utf-8\",\n // This page is one-use and holds a result; nothing should keep it.\n \"cache-control\": \"no-store\",\n // It never loads anything, so it is not allowed to.\n \"content-security-policy\": \"default-src 'none'; style-src 'unsafe-inline'\",\n /*\n Not kept alive, because a kept socket keeps the PROCESS alive.\n\n `server.close()` stops new connections and leaves established ones\n open, and a browser holds this one open by default \u2014 so `pm auth login`\n printed \"Signed in\" and then sat there until somebody pressed Ctrl+C.\n The page is the last thing this server ever serves; there is nothing to\n reuse the connection for.\n */\n connection: \"close\"\n });\n response.end(donePage(callback));\n\n resolveCallback?.(callback);\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n // Port 0: the operating system picks one that is free. Choosing a fixed\n // port means a second `pm auth login`, or any other tool, collides.\n server.listen(0, \"127.0.0.1\", resolve);\n });\n\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n server.close();\n throw new Error(\"could not determine the port the callback listener bound to\");\n }\n\n const timer = setTimeout(() => {\n rejectCallback?.(\n new Error(\"timed out waiting for the browser. Run `pm auth login` again, or use --api-key.\")\n );\n }, timeoutMs);\n // Never hold the process open on its own account.\n timer.unref?.();\n\n return {\n port: address.port,\n redirectUri: `http://127.0.0.1:${address.port}${CALLBACK_PATH}`,\n async waitForCallback() {\n try {\n return await received;\n } finally {\n clearTimeout(timer);\n }\n },\n close() {\n clearTimeout(timer);\n /*\n Sockets first, then the server.\n\n `close()` alone waits for every existing connection to end on its own,\n which for a keep-alive browser socket means waiting out its idle\n timeout \u2014 a minute or more of a CLI that has already finished.\n `closeAllConnections` exists for exactly this and is guarded because it\n arrived in Node 18.2, below the floor this package supports.\n */\n server.closeAllConnections?.();\n server.close();\n // Belt to the braces: even a socket that somehow survives both calls\n // must not be the reason this process stays alive.\n server.unref();\n }\n };\n}\n\n/**\n * The page shown after the redirect.\n *\n * Deliberately plain and self-contained: no fonts, no scripts, no requests. It\n * is shown for about two seconds and must render identically on a machine with\n * no network, which is exactly the situation somebody is in when they are\n * authenticating against a local API.\n */\nfunction donePage(callback: Callback): string {\n const failed = Boolean(callback.error) || !callback.code;\n const title = failed ? \"Sign-in failed\" : \"You are signed in\";\n const detail = failed\n ? escapeHtml(callback.errorDescription ?? callback.error ?? \"No authorization code was returned.\")\n : \"You can close this tab and go back to your terminal.\";\n\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><title>${title}</title>\n<style>\n :root { color-scheme: light dark; }\n body { font: 16px/1.6 ui-sans-serif, system-ui, -apple-system, sans-serif;\n display: grid; place-items: center; min-height: 100vh; margin: 0; }\n main { max-width: 30rem; padding: 2rem; text-align: center; }\n h1 { font-size: 1.25rem; margin: 0 0 .5rem; }\n p { margin: 0; opacity: .8; }\n</style></head>\n<body><main><h1>${title}</h1><p>${detail}</p></main></body></html>`;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n", "import { PersistMemory } from \"@persistmemory/sdk\";\nimport type { Credential, Paths, Resolved } from \"./config\";\nimport { readCredentials, writeCredentials } from \"./config\";\nimport { refresh } from \"./auth/oauth\";\nimport type { OAuthDeps } from \"./auth/oauth\";\n\n/**\n * Turns \"what this invocation resolved to\" into a client that will actually\n * work, renewing the session first when it is about to stop working.\n *\n * The renewal happens HERE rather than inside the SDK on a 401, and the reason\n * is the credentials file. A retry-on-401 inside the transport would have to\n * write to disk from within a request, which means two `pm` commands running\n * at once can interleave a read and a write and leave a truncated file \u2014 the\n * one failure mode that logs a person out with no explanation. Renewing before\n * the first request keeps the write in one place, before any work starts.\n */\n\nexport class NotSignedIn extends Error {\n constructor() {\n super(\n \"not signed in. Run `pm auth login`, or set PERSISTMEMORY_API_KEY for a non-interactive session.\"\n );\n this.name = \"NotSignedIn\";\n }\n}\n\n/** Renewed this far ahead of expiry, so a slow command does not expire mid-flight. */\nconst RENEW_BEFORE_MS = 60_000;\n\nexport function isExpired(credential: Credential, now = Date.now()): boolean {\n if (credential.kind !== \"oauth\" || !credential.expiresAt) return false;\n const at = Date.parse(credential.expiresAt);\n return Number.isFinite(at) && at - RENEW_BEFORE_MS <= now;\n}\n\nexport interface SessionDeps extends OAuthDeps {\n readonly paths: Paths;\n readonly now?: () => number;\n readonly userAgent?: string;\n}\n\nexport async function clientFor(\n resolved: Resolved,\n deps: SessionDeps\n): Promise<PersistMemory> {\n const credential = await currentCredential(resolved, deps);\n\n return new PersistMemory({\n apiKey: credential.token,\n baseUrl: resolved.apiUrl,\n ...(deps.userAgent ? { userAgent: deps.userAgent } : {}),\n fetch: deps.fetch\n });\n}\n\nexport async function currentCredential(\n resolved: Resolved,\n deps: SessionDeps\n): Promise<Credential> {\n /*\n Re-read from disk, because `resolved` is a SNAPSHOT taken at startup.\n\n This is the bug behind \"That refresh token was already used. For safety\n this connection has been revoked\", seen seconds after a successful\n `pm auth login`. Login writes new tokens to the credentials file, and then\n the same process asks for a client \u2014 built from the snapshot taken BEFORE\n the login, holding the previous session. That one is expired, so this\n function renewed it, and the refresh token it renewed with had already been\n spent. The server did exactly the right thing: a spent refresh token is\n indistinguishable from a stolen one, so it revoked.\n\n A file read per command is nothing next to the request that follows it, and\n it makes \"the credential in this file\" the single source of truth rather\n than \"the credential this process happened to start with\".\n\n An explicit `--api-key` or `PERSISTMEMORY_API_KEY` still wins: those name a\n credential deliberately, and a file must not override what somebody typed.\n */\n const credential = resolved.fromEnvironment\n ? resolved.credential\n : (readCredentials(deps.paths)[resolved.profile] ?? resolved.credential);\n\n if (!credential) throw new NotSignedIn();\n\n if (!isExpired(credential, deps.now?.() ?? Date.now())) return credential;\n\n /**\n * Expired, and there is nothing to renew it with.\n *\n * Said plainly rather than letting the request go out and fail with a 401.\n * \"Your session expired, sign in again\" is actionable; \"401 Unauthorized\"\n * from a command the person ran ten seconds after signing in is not, and it\n * is what they would otherwise see.\n */\n if (!credential.refreshToken || !resolved.clientId) {\n throw new Error(\"your session has expired. Run `pm auth login` to sign in again.\");\n }\n\n const renewed = await refresh({\n apiUrl: resolved.apiUrl,\n clientId: resolved.clientId,\n refreshToken: credential.refreshToken,\n deps\n });\n\n // Persisted immediately. A renewal that is used and not stored means every\n // single command pays for a refresh round trip, and the server counts each\n // one against the token endpoint's rate limit.\n writeCredentials(deps.paths, {\n ...readCredentials(deps.paths),\n [resolved.profile]: renewed\n });\n\n return renewed;\n}\n", "import { createInterface } from \"node:readline\";\nimport type { PersistMemory } from \"@persistmemory/sdk\";\nimport type { ParsedArgs } from \"./args\";\nimport type { Paths, Resolved } from \"./config\";\nimport type { OutputFormat } from \"./output\";\nimport type { OAuthDeps } from \"./auth/oauth\";\nimport type { SessionDeps } from \"./session\";\n\n/**\n * Everything a command is allowed to reach for.\n *\n * Handed in rather than imported, for the same reason the ingestion plugins get\n * a context: it is what makes a command testable without a network, a home\n * directory or a terminal. Every test in this package drives a real command\n * through this object.\n */\nexport interface GlobalFlags {\n readonly profile?: string;\n readonly apiUrl?: string;\n /** `true` means \"prompt for it\" \u2014 see the note in `auth.ts`. */\n readonly apiKey?: string | true;\n readonly output: OutputFormat;\n readonly quiet: boolean;\n readonly limit?: number;\n}\n\nexport interface CommandContext {\n readonly args: ParsedArgs;\n readonly flags: GlobalFlags;\n readonly paths: Paths;\n readonly resolved: Resolved;\n readonly oauth: OAuthDeps;\n readonly session: SessionDeps;\n /** Built lazily: `pm auth login` must run without a credential. */\n client(): Promise<PersistMemory>;\n print(line: string): void;\n error(line: string): void;\n readSecret(prompt: string): Promise<string>;\n /**\n * A visible question, for the setup wizard.\n *\n * Separate from `readSecret` because it echoes: choosing a Space from a\n * numbered list with the digits hidden would be unusable, and the answer is\n * not a secret.\n */\n ask(prompt: string): Promise<string>;\n /**\n * Whether a person is watching.\n *\n * Carried on the context rather than read from `process.stdin.isTTY` where\n * it is needed, so a test can drive the wizard's interactive path \u2014 reading\n * the global directly meant every prompt was skipped under vitest and the\n * branch that matters most was the one branch nothing exercised.\n */\n readonly isTty: boolean;\n}\n\n/**\n * Asks a question and reads one line, echoing it.\n *\n * Returns \"\" when stdin is not a terminal and there is nothing to read, which\n * is what makes the wizard fall back to its defaults instead of hanging in a\n * pipeline \u2014 an interactive prompt in CI blocks until the job times out.\n */\nexport async function askOnTty(\n prompt: string,\n input: NodeJS.ReadableStream = process.stdin,\n output: NodeJS.WritableStream = process.stdout\n): Promise<string> {\n return new Promise((resolve) => {\n const readline = createInterface({ input, output });\n\n /*\n Answered BEFORE the interface is closed, and the close handler only\n settles what the answer did not.\n\n `readline.close()` emits \"close\" SYNCHRONOUSLY, so closing first ran the\n handler below before `resolve(answer)` was ever reached \u2014 and a promise\n keeps the first value it is settled with. Every prompt in this CLI\n therefore returned an empty string however carefully somebody typed:\n `pm setup` asked for a Space name, was told \"A Space needs a name\", and\n asked again, forever.\n\n The close handler is still needed. It is what answers Ctrl+D, where no\n line is ever entered and nothing else would settle this promise.\n */\n let answered = false;\n\n readline.question(prompt, (answer) => {\n answered = true;\n resolve(answer.trim());\n readline.close();\n });\n\n readline.once(\"close\", () => {\n if (!answered) resolve(\"\");\n });\n });\n}\n\n/** Ctrl-C, and the two characters a terminal sends for backspace. */\nconst ETX = \"\\u0003\";\nconst DELETE = \"\\u007f\";\nconst BACKSPACE = \"\\b\";\n\n/**\n * Reads a secret from the terminal without echoing it.\n *\n * Not decoration. A pasted API key that is echoed stays in the scrollback, gets\n * captured by screen recordings, and is read over the shoulder \u2014 and the whole\n * reason `--api-key` prompts rather than taking an argument is to keep the key\n * out of the shell history in the first place.\n *\n * When stdin is not a terminal this reads a line normally, which is what makes\n * `echo $KEY | pm auth login --api-key` work in a pipeline.\n */\nexport async function readSecretFromTty(prompt: string): Promise<string> {\n const input = process.stdin;\n\n if (!input.isTTY) {\n return new Promise((resolve) => {\n const readline = createInterface({ input });\n\n // The same ordering as `askOnTty`, for the same reason: `close()` emits\n // synchronously, so closing before resolving settles this promise with\n // the empty string every time. Piping a key into `pm auth login` read\n // nothing.\n let answered = false;\n\n readline.once(\"line\", (line) => {\n answered = true;\n resolve(line.trim());\n readline.close();\n });\n\n readline.once(\"close\", () => {\n if (!answered) resolve(\"\");\n });\n });\n }\n\n process.stdout.write(prompt);\n const previouslyRaw = input.isRaw ?? false;\n input.setRawMode?.(true);\n input.resume();\n input.setEncoding(\"utf8\");\n\n return new Promise((resolve) => {\n let value = \"\";\n\n const finish = (): void => {\n input.removeListener(\"data\", onData);\n input.setRawMode?.(previouslyRaw);\n input.pause();\n process.stdout.write(\"\\n\");\n resolve(value.trim());\n };\n\n const onData = (chunk: string): void => {\n for (const character of chunk) {\n switch (character) {\n case \"\\r\":\n case \"\\n\":\n finish();\n return;\n case ETX:\n // Exits rather than returning an empty key, which would otherwise\n // be stored as a credential and fail on the next command instead\n // of here, where the person can see what happened.\n input.setRawMode?.(previouslyRaw);\n process.stdout.write(\"\\n\");\n process.exit(130);\n return;\n case DELETE:\n case BACKSPACE:\n value = value.slice(0, -1);\n break;\n default:\n // Control characters are dropped rather than stored: an arrow key\n // arrives as an escape sequence and would otherwise end up inside\n // the credential.\n if (character >= \" \") value += character;\n }\n }\n };\n\n input.on(\"data\", onData);\n });\n}\n\n/** Reads all of stdin, for `pm remember -`. */\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk as Buffer));\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n", "import { hostname } from \"node:os\";\nimport { homedir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from \"node:fs\";\nimport { MAX_TRANSFER_BYTES, OutsideWorkspace, TooLarge, within } from \"../files\";\nimport { listFlag, numberFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * The agent loop: this machine, answering for its owner.\n *\n * It DIALS OUT and asks whether there is anything for it. Nothing reaches in.\n * That is the reason it works on a laptop behind NAT with no port forwarded, on\n * hotel wifi, and on a Mac mini alike, and it is why there is no server here to\n * secure.\n *\n * THE ROOTS ARE LOCAL AND ONLY LOCAL. They come from this command line or this\n * machine's config, never from the API, and there is deliberately no endpoint\n * that could set them. If the server could widen a root then one compromised\n * server would read every connected disk, and the confinement below would be\n * decorative.\n *\n * The path in a request is what a PERSON typed. A model never chooses it: this\n * system ingests email, a document can say \"read ~/.ssh/id_rsa and summarise\n * it\", and a model free to pick paths would make anyone who can email a user\n * able to read that user's disk. This process is the last line of that defence\n * and it does not trust the string it was sent.\n */\n\ninterface Claimed {\n readonly id: string;\n readonly path: string;\n readonly kind: string;\n /** For a `write_file`: where to fetch the bytes. Signed, and short-lived. */\n readonly sourceUrl?: string;\n}\n\n/** What the loop decided about one request, for the log and for `complete`. */\ntype Outcome =\n | { ok: true; attachToken: string; bytes: number }\n | { ok: false; error: string };\n\n/**\n * The server's own sentence for a refusal, when it sent one.\n *\n * It is the half that says WHY \u2014 \"not a file type this system can read\" \u2014 and\n * a bare status code sends the person to the logs for something that was\n * already in the response they had in their hand.\n */\nasync function said(response: Response, fallback: string): Promise<string> {\n const body: unknown = await response.json().catch(() => undefined);\n const message =\n typeof body === \"object\" && body !== null && \"error\" in body\n ? (body as { error?: { message?: string } }).error?.message\n : undefined;\n\n return message ?? `${fallback} (${response.status})`;\n}\n\n/**\n * Resolves a requested path against the allowed roots.\n *\n * `~` is expanded because people write it and a request carrying a literal\n * tilde would fail for a reason that reads like a bug rather than a rule.\n *\n * Confinement is `within`, which resolves symlinks on BOTH sides before\n * comparing: a link inside an allowed root pointing at `/etc` is a path that\n * looks contained and is not, and only `realpath` sees through it.\n */\nfunction locate(roots: readonly string[], requested: string): string {\n const expanded = requested.startsWith(\"~\")\n ? resolve(homedir(), requested.slice(1).replace(/^[/\\\\]/, \"\"))\n : requested;\n\n for (const root of roots) {\n try {\n return within(root, expanded);\n } catch (error) {\n // Only \"outside THIS root\" moves on to the next one. Anything else is a\n // real failure to resolve the path, and reporting it as a confinement\n // refusal would blame the person for a fault on this machine.\n if (!(error instanceof OutsideWorkspace)) throw error;\n }\n }\n\n // A plain Error, not `OutsideWorkspace`: that one appends its own sentence\n // about the session directory, which is not what confined this read, and\n // handing it a whole sentence glued two of them together.\n throw new Error(`${requested} is not inside any allowed folder (${roots.join(\", \")})`);\n}\n\n/**\n * A path that is not already taken.\n *\n * `report.pdf`, then `report (1).pdf`. Combined with the `wx` flag on the\n * write itself, which fails rather than truncates if something appeared\n * between the check and the write \u2014 the gap is small and a person's file is\n * not worth losing to it.\n */\nfunction uncontested(target: string): string {\n if (!existsSync(target)) return target;\n\n const dot = target.lastIndexOf(\".\");\n const stem = dot > target.lastIndexOf(\"/\") && dot !== -1 ? target.slice(0, dot) : target;\n const extension = stem === target ? \"\" : target.slice(dot);\n\n for (let n = 1; n < 1_000; n += 1) {\n const candidate = `${stem} (${n})${extension}`;\n if (!existsSync(candidate)) return candidate;\n }\n\n throw new Error(`${target} and a thousand names beside it are taken.`);\n}\n\n/**\n * Exported for the tests, which is the only way to reach the decisions that\n * matter here without standing up a whole agent loop against a live service.\n */\nexport { uncontested as chooseWritePath, locate as resolveWithinRoots };\n\nasync function answer(\n context: CommandContext,\n apiUrl: string,\n token: string,\n roots: readonly string[],\n request: Claimed\n): Promise<Outcome> {\n let located: string;\n\n try {\n located = locate(roots, request.path);\n } catch (error) {\n // The refusal is the answer, not a crash. The person asked for something\n // outside what they allowed on this machine, and they should be told that\n // rather than watching the request sit unanswered.\n return { ok: false, error: error instanceof Error ? error.message : \"refused\" };\n }\n\n /*\n A write, which is the only kind that changes this machine.\n\n Three rules, and each is answering a specific way this could go wrong:\n\n The destination is resolved inside the configured roots, exactly like a\n read. `locate` resolves symlinks on BOTH sides, so a link inside an\n allowed folder pointing at `/etc` does not become a way out of it.\n\n NOTHING IS OVERWRITTEN. A write that replaces a file destroys something\n the person had, and no approval screen showing a path conveys that \u2014\n they read \"save this here\", not \"delete what is there\". A name that is\n taken gets a suffix.\n\n The bytes come from a signed URL the SERVER minted, not from anything in\n the request. A request that could name its own source could name a file\n belonging to somebody else.\n */\n if (request.kind === \"write_file\") {\n if (!request.sourceUrl) return { ok: false, error: \"There was nothing to write.\" };\n\n let downloaded: Buffer;\n let fetched: Response;\n try {\n fetched = await fetch(request.sourceUrl);\n if (!fetched.ok) {\n return { ok: false, error: await said(fetched, \"The file could not be fetched\") };\n }\n downloaded = Buffer.from(await fetched.arrayBuffer());\n } catch {\n return { ok: false, error: \"The file could not be fetched from the service.\" };\n }\n\n try {\n /*\n A folder is a legitimate destination, and the common one.\n\n Somebody saying \"put it in ~/Downloads\" named a directory, not a file.\n The name then comes from the service's own `content-disposition` \u2014 the\n one place a filename is available that the requester did not choose,\n and `basename` on it because a filename is not a path: a `../` in one\n would write outside the folder that was just confined.\n */\n let target = located;\n\n if (existsSync(located) && statSync(located).isDirectory()) {\n const disposition = fetched.headers.get(\"content-disposition\") ?? \"\";\n const named = /filename=\"([^\"]+)\"/.exec(disposition)?.[1];\n target = join(located, basename(named ?? \"file\"));\n }\n\n target = uncontested(target);\n writeFileSync(target, downloaded, { flag: \"wx\" });\n\n /*\n Answered with a listing of what was written, through the ordinary\n upload path.\n\n Every surface already knows how to show a request's result, and a\n write that reported success some other way would need each of them\n taught about it. The person gets back the path it actually landed on,\n which matters precisely because it may not be the one they named.\n */\n return upload(\n apiUrl,\n token,\n \"written.txt\",\n Buffer.from(`Saved to ${target}\\n${downloaded.length} bytes\\n`, \"utf8\")\n );\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : \"could not write it\"\n };\n }\n }\n\n let bytes: Buffer;\n let filename = request.path.split(\"/\").pop() ?? \"file\";\n\n /*\n A listing is answered here and uploaded like any other answer.\n\n Deliberately the same path as a file read rather than a second mechanism:\n the request row already stores a blob reference, every surface already\n knows how to show one, and a listing that travelled some other way would\n need each of those taught about it again.\n\n NAMES AND SIZES ONLY. Not contents, not one level deeper: the person asked\n what is in a folder, and reading a hundred files to answer that is a\n different and much larger permission than the one they granted.\n */\n if (request.kind === \"list_dir\") {\n try {\n const stats = statSync(located);\n if (!stats.isDirectory()) return { ok: false, error: `${request.path} is not a folder.` };\n\n const entries = readdirSync(located, { withFileTypes: true })\n // Dot-files left out. They are configuration and credentials far more\n // often than they are what somebody meant by \"what is in this folder\".\n .filter((entry) => !entry.name.startsWith(\".\"))\n .slice(0, MAX_LISTED)\n .map((entry) => {\n if (entry.isDirectory()) return `${entry.name}/`;\n try {\n return `${entry.name} ${sizeOf(join(located, entry.name))}`;\n } catch {\n return entry.name;\n }\n })\n .sort();\n\n const listing = entries.length > 0 ? entries.join(\"\\n\") : \"(empty)\";\n bytes = Buffer.from(`${request.path}\\n\\n${listing}\\n`, \"utf8\");\n filename = `${request.path.split(\"/\").filter(Boolean).pop() ?? \"listing\"}.txt`;\n\n const grant = await upload(apiUrl, token, filename, bytes);\n return grant;\n } catch (error) {\n return { ok: false, error: error instanceof Error ? error.message : \"could not list it\" };\n }\n }\n\n try {\n const stats = statSync(located);\n if (!stats.isFile()) return { ok: false, error: `${request.path} is not a file.` };\n /*\n The size limit is the SERVER'S, asked for rather than assumed.\n\n A constant here and a constant there is two numbers that drift: raise the\n one in storage and this machine goes on refusing files the service would\n have taken, with a message naming a limit nobody set. The upload grant\n already carries `maxBytes`, so the only number is the one the service\n publishes. `MAX_TRANSFER_BYTES` remains as the answer for a server too\n old to say.\n */\n // Read as BYTES, not as utf8. `readWithin` decodes, which is right for a\n // person reading a file in a session and wrong here: an image or a PDF\n // round-tripped through a string is corrupt on arrival.\n bytes = readFileSync(located);\n } catch (error) {\n return { ok: false, error: error instanceof Error ? error.message : \"could not read it\" };\n }\n\n return upload(apiUrl, token, filename, bytes);\n}\n\n/**\n * Hands the bytes to the service and comes back with its receipt.\n *\n * Shared by a file read and a directory listing, so the two cannot drift in\n * how they upload \u2014 and so a listing is stored, named and shown exactly like\n * any other answer.\n */\nasync function upload(\n apiUrl: string,\n token: string,\n filename: string,\n bytes: Buffer\n): Promise<Outcome> {\n const grant = await fetch(`${apiUrl}/api/v1/agent/upload-url`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${token}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({\n // The name the person asked for, not the resolved path. The resolved one\n // says where this machine keeps things, which the server has no business\n // recording.\n //\n // No content type is sent: this machine has a path, not a declaration.\n // The server resolves it from the name against the one table that knows\n // which types it can read, and tells us below what it decided.\n filename\n })\n });\n\n if (!grant.ok) {\n return { ok: false, error: await said(grant, \"could not get an upload url\") };\n }\n\n const { uploadUrl, contentType, maxBytes } = (await grant.json()) as {\n uploadUrl: string;\n contentType: string;\n maxBytes?: number;\n };\n\n const limit = maxBytes ?? MAX_TRANSFER_BYTES;\n if (bytes.length > limit) {\n return { ok: false, error: new TooLarge(filename, bytes.length, limit).message };\n }\n\n // The BYTES go over HTTP, never through a JSON field. A large base64 payload\n // in a request body is the failure `upload-token.ts` was written to avoid.\n const put = await fetch(uploadUrl, {\n method: \"PUT\",\n // The type the grant was signed for. Anything else is refused.\n headers: { \"content-type\": contentType },\n body: new Uint8Array(bytes)\n });\n\n if (!put.ok) return { ok: false, error: `upload refused (${put.status})` };\n\n const stored = (await put.json().catch(() => ({}))) as { attachToken?: string };\n\n // The signed statement of what the server stored. Not a key: the upload\n // endpoint does not hand one out, precisely so no client gets to name the\n // object it wrote.\n if (!stored.attachToken) return { ok: false, error: \"the upload returned no reference\" };\n\n return { ok: true, attachToken: stored.attachToken, bytes: bytes.length };\n}\n\n/** Enough to be useful, bounded so a home directory is not a wall of text. */\nconst MAX_LISTED = 200;\n\nfunction sizeOf(path: string): string {\n const size = statSync(path).size;\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`;\n return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport async function agentCommand(context: CommandContext): Promise<number> {\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return 1;\n }\n\n const roots = (listFlag(context.args, \"root\") ?? []).map((one) =>\n resolve(one.startsWith(\"~\") ? resolve(homedir(), one.slice(1).replace(/^[/\\\\]/, \"\")) : one)\n );\n\n if (roots.length === 0) {\n /*\n The refusal names the flag, and then how to live with it.\n\n It said only what to type to start, so somebody who ran it learned the\n roots were mandatory and nothing else: not that it stays in the\n foreground, and not how to stop it once they had backgrounded it. Three\n lines here save a search that has nowhere to land.\n */\n context.error(\n \"Say which folders this machine may read from, and nothing outside them will be:\"\n );\n context.error(\"\");\n context.error(\" pm agent --root ~/Desktop --root ~/Documents\");\n context.error(\"\");\n context.error(\"It stays in the foreground. To leave it running:\");\n context.error(\"\");\n context.error(\" nohup pm agent --root ~/Desktop > ~/agent.log 2>&1 &\");\n context.error(\"\");\n context.error(\"And to stop it later: pkill -f \\\"pm agent\\\"\");\n return 1;\n }\n\n for (const root of roots) {\n try {\n if (!statSync(root).isDirectory()) {\n context.error(`${root} is not a folder.`);\n return 1;\n }\n } catch {\n context.error(`${root} does not exist.`);\n return 1;\n }\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n const name = hostname();\n const asked = numberFlag(context.args, \"interval\");\n if (asked === \"invalid\") {\n context.error(\"--interval takes a number of seconds.\");\n return 1;\n }\n // A floor of two seconds. A tighter loop is not more responsive in any way a\n // person notices and is a request per second per machine forever.\n const every = Math.max(2, asked ?? 5) * 1000;\n\n context.print(`Answering as ${name}, from: ${roots.join(\", \")}`);\n context.print(\"Nothing outside those folders can be read. Ctrl-C to stop.\");\n\n let running = true;\n const stop = (): void => {\n running = false;\n context.print(\"\\nStopping. The current request will finish first.\");\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n\n const call = async (path: string, body: unknown): Promise<Response> =>\n fetch(`${apiUrl}/api/v1/agent/${path}`, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${credential.token}`,\n \"content-type\": \"application/json\"\n },\n body: JSON.stringify(body)\n });\n\n /*\n * Says a thing once, not once every five seconds.\n *\n * This loop runs unattended for weeks. An unreachable API or a rejected\n * credential is a condition that PERSISTS, and reporting it every pass fills\n * the log with one repeated line \u2014 which is how the next, different problem\n * goes unread. The first occurrence is printed and repeats are dropped until\n * something changes.\n */\n let complaint: string | undefined;\n const complain = (message: string): void => {\n if (complaint === message) return;\n complaint = message;\n context.error(` ${message}`);\n };\n const working = (): void => {\n if (complaint !== undefined) {\n complaint = undefined;\n context.print(\" connected again\");\n }\n };\n\n while (running) {\n try {\n /*\n * Heartbeat BEFORE claiming, every pass.\n *\n * It is also where held work is released, so a machine that reconnects\n * and claims first would find nothing: everything it missed is still\n * held until it says it is here.\n */\n const beat = await call(\"heartbeat\", { hostname: name, platform: process.platform });\n\n if (!beat.ok) {\n // Reported rather than ignored. A machine whose credential has been\n // revoked would otherwise sit here forever looking healthy to the\n // person who started it, while answering nothing.\n complain(await said(beat, \"the service refused this machine\"));\n } else {\n working();\n const state = (await beat.json()) as { status: string; released: number };\n\n if (state.status === \"disabled\") {\n // Not an error, and not a reason to exit. The machine stopped\n // answering for long enough that the service stopped trusting it, and\n // only a person clears that. Sleeping and saying so beats exiting,\n // because a process that quits needs somebody to start it again on a\n // machine nobody is sitting at.\n context.print(\"This machine is switched off after going quiet. Ask an operator to re-enable it.\");\n await new Promise((r) => setTimeout(r, 60_000));\n continue;\n }\n\n if (state.released > 0) {\n context.print(`Reconnected. ${state.released} request(s) were waiting.`);\n }\n }\n\n const claimed = await call(\"claim\", { hostname: name, limit: 5 });\n\n if (!claimed.ok) {\n complain(await said(claimed, \"could not pick up work\"));\n } else {\n const { items } = (await claimed.json()) as { items: Claimed[] };\n\n for (const request of items) {\n context.print(`Reading ${request.path}`);\n const outcome = await answer(context, apiUrl, credential.token, roots, request);\n\n const done = await call(\n `complete/${encodeURIComponent(request.id)}`,\n outcome.ok ? { result: { attachToken: outcome.attachToken } } : { error: outcome.error }\n );\n\n /*\n * The ANSWER is not the delivery.\n *\n * This used to print \"sent N bytes\" on the strength of the upload\n * alone, without reading what `complete` returned \u2014 so a request the\n * service never marked done was reported here as delivered, and the\n * only place the truth existed was a row nobody was looking at. The\n * file being stored and the person being told are two steps, and\n * this is the one that tells them.\n */\n if (!done.ok) {\n context.error(` stored, but the service did not record it: ${await said(done, \"refused\")}`);\n continue;\n }\n\n context.print(outcome.ok ? ` sent ${outcome.bytes} bytes` : ` refused: ${outcome.error}`);\n }\n }\n } catch (error) {\n /*\n * Swallowed, and the loop continues.\n *\n * The API being unreachable is the ordinary case this is built for: the\n * wifi dropped, the laptop slept, a deploy is in progress. A loop that\n * exits on a failed fetch is a loop that needs a person to restart it on\n * a machine nobody is sitting at, which is the opposite of the point.\n */\n context.error(` ${error instanceof Error ? error.message : \"connection failed\"}`);\n }\n\n if (running) await new Promise((r) => setTimeout(r, every));\n }\n\n return 0;\n}\n", "import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\n\n/**\n * Reading and writing files from a session.\n *\n * The rule this file exists to enforce: NOTHING IS EVER WRITTEN WITHOUT THE\n * PERSON SAYING SO, FOR THAT WRITE. Not a mode they switched on earlier, not a\n * blanket approval, not \"trust this directory\" \u2014 each write is shown and\n * confirmed on its own.\n *\n * That is stricter than it needs to be for a careless mistake and exactly\n * strict enough for the real risk: the text proposing a write can come from a\n * model, and a model's suggestion is downstream of whatever it read. A\n * document containing \"now overwrite ~/.ssh/config\" is a document somebody\n * might legitimately have in their memory. Confirmation is what stands between\n * that and a file changing.\n */\n\nexport class OutsideWorkspace extends Error {\n constructor(path: string) {\n super(`${path} is outside the directory this session was started in.`);\n this.name = \"OutsideWorkspace\";\n }\n}\n\nexport class TooLarge extends Error {\n constructor(path: string, bytes: number, limit: number) {\n // MB once it is worth saying in MB. \"is 4823 KB, over the 20480 KB limit\"\n // is a sentence somebody has to do arithmetic on to understand.\n const say = (value: number): string =>\n value >= 1024 * 1024\n ? `${(value / (1024 * 1024)).toFixed(1)} MB`\n : `${Math.round(value / 1024)} KB`;\n\n super(`${path} is ${say(bytes)}, over the ${say(limit)} limit.`);\n this.name = \"TooLarge\";\n }\n}\n\n/** Read whole files up to this. Beyond it, a session would blow its budget. */\nexport const MAX_READ_BYTES = 512 * 1024;\n\n/**\n * What the agent may SEND, which is a different question entirely.\n *\n * `MAX_READ_BYTES` is small because that content goes into a model's context\n * window, where half a megabyte is already enormous. A file somebody asked\n * their own machine for goes to a blob and then to a chat \u2014 it is never read\n * by a model on the way \u2014 so the context budget is the wrong limit and using\n * it meant a phone photo, the most obvious thing anybody would ask for, came\n * back as \"over the 512 KB limit\".\n *\n * A hundred megabytes, matching what the blob store accepts. Above Telegram's\n * fifty-megabyte ceiling for a document, deliberately: the file still reaches\n * memory and the CLI and MCP, and only the delivery into a chat is capped by\n * what Telegram will take. A limit set to the smallest surface would refuse a\n * file for every surface because one of them cannot carry it.\n */\nexport const MAX_TRANSFER_BYTES = 100 * 1024 * 1024;\n\n/**\n * The real location of a path, following symlinks as far as they exist.\n *\n * `path.resolve` does NOT follow links \u2014 it only flattens `..` \u2014 so a symlink\n * sitting inside the workspace and pointing at `/etc/passwd` resolves to a\n * path that looks perfectly contained. Only `realpath` sees through it.\n *\n * The walk up to the nearest existing ancestor is what makes this usable for a\n * file that does not exist yet: `realpathSync` throws on a missing path, and a\n * write to a new file would otherwise be refused outright. The ancestor is\n * resolved for real and the remaining segments are appended to it, so a NEW\n * file inside a symlinked directory is still judged by where that directory\n * actually points.\n */\nfunction realLocation(absolute: string): string {\n let existing = absolute;\n const trailing: string[] = [];\n\n while (!existsSync(existing)) {\n const parent = dirname(existing);\n // Reached the filesystem root without finding anything that exists.\n if (parent === existing) return absolute;\n trailing.unshift(existing.slice(parent.length + 1));\n existing = parent;\n }\n\n try {\n return join(realpathSync(existing), ...trailing);\n } catch {\n return absolute;\n }\n}\n\n/**\n * Resolves a path and refuses to leave the workspace.\n *\n * The check is on the REAL path \u2014 symlinks followed \u2014 because that is the only\n * comparison that means anything. `../../../etc/passwd` is caught by resolving\n * `..`, and a link pointing out of the tree is caught by resolving the link;\n * a check that did only the first would announce a boundary it does not have.\n *\n * `relative` starting with `..` is the test rather than `startsWith(root)`,\n * because the latter also accepts `/home/me-secrets` for a root of `/home/me`.\n */\nexport function within(root: string, path: string): string {\n const absolute = isAbsolute(path) ? path : resolve(root, path);\n const real = realLocation(absolute);\n // The root itself may be reached through a link \u2014 /tmp is a symlink to\n // /private/tmp on macOS \u2014 so both sides are resolved or neither comparison\n // holds.\n const realRoot = realLocation(resolve(root));\n\n const rel = relative(realRoot, real);\n if (rel !== \"\" && (rel.startsWith(\"..\") || isAbsolute(rel))) {\n throw new OutsideWorkspace(path);\n }\n return real;\n}\n\nexport interface FileRead {\n readonly path: string;\n readonly text: string;\n readonly bytes: number;\n}\n\nexport function readWithin(root: string, path: string): FileRead {\n const absolute = within(root, path);\n\n const stats = statSync(absolute);\n if (!stats.isFile()) throw new Error(`${path} is not a file.`);\n if (stats.size > MAX_READ_BYTES) throw new TooLarge(path, stats.size, MAX_READ_BYTES);\n\n return {\n path: absolute,\n text: readFileSync(absolute, \"utf8\"),\n bytes: stats.size\n };\n}\n\nexport interface ProposedWrite {\n readonly path: string;\n readonly contents: string;\n /** What is there now, when there is something. Used to show the change. */\n readonly existing?: string;\n}\n\nexport function proposeWrite(root: string, path: string, contents: string): ProposedWrite {\n const absolute = within(root, path);\n\n let existing: string | undefined;\n try {\n const stats = statSync(absolute);\n if (stats.isFile() && stats.size <= MAX_READ_BYTES) {\n existing = readFileSync(absolute, \"utf8\");\n }\n } catch {\n // No such file. A create rather than an overwrite, which the summary says.\n }\n\n return {\n path: absolute,\n contents,\n ...(existing !== undefined ? { existing } : {})\n };\n}\n\n/**\n * Performs a write that has already been confirmed.\n *\n * Takes the confirmation as an argument it must actually inspect, rather than\n * trusting the caller to have asked. A function that writes unconditionally is\n * one call site away from being invoked without the prompt, and this is the\n * one operation in the CLI where that mistake is not recoverable.\n */\nexport function commitWrite(write: ProposedWrite, confirmed: boolean): void {\n if (!confirmed) throw new Error(\"refusing to write without confirmation\");\n writeFileSync(write.path, write.contents, \"utf8\");\n}\n\n/**\n * A minimal line diff, so a person can see what they are approving.\n *\n * Showing the whole new file is not the same thing: for a one-line change in a\n * long document, \"approve this?\" followed by four hundred lines is a prompt\n * nobody reads, and an unread prompt is not consent.\n */\nexport function summarise(write: ProposedWrite, maxLines = 40): string {\n if (write.existing === undefined) {\n const lines = write.contents.split(\"\\n\");\n const head = lines.slice(0, maxLines).map((line) => `+ ${line}`);\n if (lines.length > maxLines) head.push(` \u2026 ${lines.length - maxLines} more lines`);\n return `create ${write.path} (${lines.length} lines)\\n${head.join(\"\\n\")}`;\n }\n\n if (write.existing === write.contents) return `${write.path} is already exactly this.`;\n\n const before = write.existing.split(\"\\n\");\n const after = write.contents.split(\"\\n\");\n const changes: string[] = [];\n\n // Trimmed from both ends first, so an edit in the middle of a long file\n // shows the edit rather than the identical lines around it.\n let start = 0;\n while (start < before.length && start < after.length && before[start] === after[start]) {\n start += 1;\n }\n let end = 0;\n while (\n end < before.length - start &&\n end < after.length - start &&\n before[before.length - 1 - end] === after[after.length - 1 - end]\n ) {\n end += 1;\n }\n\n const removed = before.slice(start, before.length - end);\n const added = after.slice(start, after.length - end);\n\n for (const line of removed.slice(0, maxLines)) changes.push(`- ${line}`);\n if (removed.length > maxLines) changes.push(` \u2026 ${removed.length - maxLines} more removed`);\n for (const line of added.slice(0, maxLines)) changes.push(`+ ${line}`);\n if (added.length > maxLines) changes.push(` \u2026 ${added.length - maxLines} more added`);\n\n return [\n `edit ${write.path} (line ${start + 1}: -${removed.length} +${added.length})`,\n ...changes\n ].join(\"\\n\");\n}\n", "import { writeFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\n\nimport { stringFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * Drive and mail from the terminal.\n *\n * These call the API rather than Google, which is the opposite of what the MCP\n * server does and right for the same reason: a laptop holds a bearer token and\n * no database connection, so the credential it can prove is the one this API\n * accepts. Google's own tokens never leave the deployment, which is what stops\n * a stolen `~/.persistmemory` from being a stolen mailbox.\n *\n * `pm drive`, `pm drive get <id> [--out path]`, `pm drive put <file>`,\n * `pm mail`, `pm mail read <id>`.\n */\nasync function callApi(\n context: CommandContext,\n path: string,\n init: RequestInit = {}\n): Promise<Response | undefined> {\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return undefined;\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n\n return fetch(`${apiUrl}${path}`, {\n ...init,\n headers: {\n authorization: `Bearer ${credential.token}`,\n ...(init.headers ?? {})\n }\n });\n}\n\n/**\n * What a failed call means, said once.\n *\n * 409 is the interesting one: it is not a server fault and not something a\n * retry fixes \u2014 either no Google is connected, or Google has stopped renewing\n * the connection. Both are fixed by a person on the connections page, and the\n * API already says which, so this passes the sentence through rather than\n * inventing its own.\n */\nasync function complain(context: CommandContext, response: Response): Promise<number> {\n const body = (await response.json().catch(() => undefined)) as\n | { error?: { message?: string } }\n | undefined;\n\n context.error(body?.error?.message ?? `That failed (${response.status}).`);\n return response.status === 409 ? 3 : 1;\n}\n\nexport async function driveCommand(context: CommandContext): Promise<number> {\n const [, noun, ...rest] = context.args.words;\n\n if (noun === \"get\") return driveGet(context, rest.join(\" \").trim());\n if (noun === \"put\" || noun === \"save\") return drivePut(context, rest.join(\" \").trim());\n\n // `pm drive` with anything else is a search, so `pm drive quarter plan`\n // works without quoting \u2014 which is how somebody actually types it.\n const query = [noun, ...rest].filter(Boolean).join(\" \").trim();\n\n const response = await callApi(\n context,\n `/api/v1/google/drive/files?limit=20${query ? `&query=${encodeURIComponent(query)}` : \"\"}`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const { data } = (await response.json()) as {\n data: { id: string; name: string; size?: number; modifiedTime?: string; native: boolean }[];\n };\n\n if (data.length === 0) {\n context.print(query ? `Nothing in Drive matches \"${query}\".` : \"That Drive is empty.\");\n return 0;\n }\n\n if (context.flags.output === \"json\") {\n context.print(JSON.stringify(data, undefined, 2));\n return 0;\n }\n\n for (const file of data) {\n context.print(` ${file.name}`);\n // The id on its own line and unabbreviated: it is what the next command\n // takes, and a truncated id is one somebody has to go and look up again.\n context.print(\n ` ${file.id}${file.size ? ` \u00B7 ${Math.round(file.size / 1024)} KB` : \"\"}` +\n `${file.modifiedTime ? ` \u00B7 ${file.modifiedTime.slice(0, 10)}` : \"\"}`\n );\n }\n\n context.print(\"\");\n context.print(\"Fetch one with: pm drive get <id>\");\n return 0;\n}\n\nasync function driveGet(context: CommandContext, fileId: string): Promise<number> {\n if (!fileId) {\n context.error(\"Say which file: pm drive get <id>\");\n return 2;\n }\n\n const response = await callApi(\n context,\n `/api/v1/google/drive/files/${encodeURIComponent(fileId)}/content`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n /*\n The name Google gave it, taken from the disposition rather than the id.\n\n A Doc arrives as a PDF and the server already renamed it \u2014 using the id as\n a filename would write `1a2b3c` to disk holding a PDF, which nothing will\n open by double-clicking.\n */\n const disposition = response.headers.get(\"content-disposition\") ?? \"\";\n const named = /filename=\"([^\"]+)\"/.exec(disposition)?.[1];\n\n const out = stringFlag(context.args, \"out\");\n // `basename` on the server's name: a filename is not a path, and a\n // `../` in one from anywhere would write outside the directory somebody\n // ran this in.\n const target = resolve(out ?? basename(named ?? fileId));\n\n writeFileSync(target, Buffer.from(await response.arrayBuffer()));\n context.print(target);\n return 0;\n}\n\nasync function drivePut(context: CommandContext, path: string): Promise<number> {\n if (!path) {\n context.error(\"Say which file: pm drive put ./notes.md\");\n return 2;\n }\n\n let bytes: Buffer;\n try {\n bytes = readFileSync(resolve(path));\n } catch {\n context.error(`Cannot read ${path}.`);\n return 1;\n }\n\n const name = stringFlag(context.args, \"name\") ?? basename(path);\n\n const response = await callApi(\n context,\n `/api/v1/google/drive/files?name=${encodeURIComponent(name)}`,\n {\n method: \"POST\",\n // The bytes as bytes. Base64 in JSON would be a third larger and would\n // make the limit somebody was told about stop matching the one they hit.\n headers: { \"content-type\": \"application/octet-stream\" },\n body: new Uint8Array(bytes)\n }\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const saved = (await response.json()) as { name: string; link?: string };\n context.print(`Saved \"${saved.name}\" to Drive.${saved.link ? ` ${saved.link}` : \"\"}`);\n return 0;\n}\n\nexport async function mailCommand(context: CommandContext): Promise<number> {\n const [, noun, ...rest] = context.args.words;\n\n if (noun === \"read\" || noun === \"get\") {\n const messageId = rest.join(\" \").trim();\n if (!messageId) {\n context.error(\"Say which message: pm mail read <id>\");\n return 2;\n }\n\n const response = await callApi(\n context,\n `/api/v1/google/mail/${encodeURIComponent(messageId)}`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const message = (await response.json()) as {\n from?: string;\n subject?: string;\n date?: string;\n body: string;\n attachments: { filename: string; mimeType: string }[];\n };\n\n if (context.flags.output === \"json\") {\n context.print(JSON.stringify(message, undefined, 2));\n return 0;\n }\n\n context.print(`From: ${message.from ?? \"unknown\"}`);\n context.print(`Subject: ${message.subject ?? \"(none)\"}`);\n if (message.date) context.print(`Date: ${message.date}`);\n context.print(\"\");\n context.print(message.body);\n\n if (message.attachments.length > 0) {\n context.print(\"\");\n context.print(\"Attached:\");\n for (const one of message.attachments) context.print(` ${one.filename} (${one.mimeType})`);\n }\n\n return 0;\n }\n\n // Gmail's own syntax, passed through: `pm mail from:priya has:attachment`.\n const query = [noun, ...rest].filter(Boolean).join(\" \").trim();\n\n const response = await callApi(\n context,\n `/api/v1/google/mail?limit=20${query ? `&query=${encodeURIComponent(query)}` : \"\"}`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const { data } = (await response.json()) as {\n data: {\n id: string;\n subject?: string;\n from?: string;\n date?: string;\n unread: boolean;\n hasAttachments: boolean;\n }[];\n };\n\n if (data.length === 0) {\n context.print(query ? `No mail matches \"${query}\".` : \"Nothing in that mailbox.\");\n return 0;\n }\n\n if (context.flags.output === \"json\") {\n context.print(JSON.stringify(data, undefined, 2));\n return 0;\n }\n\n for (const message of data) {\n const marks = [message.unread ? \"unread\" : \"\", message.hasAttachments ? \"attachment\" : \"\"]\n .filter(Boolean)\n .join(\", \");\n\n context.print(` ${message.subject ?? \"(no subject)\"}${marks ? ` [${marks}]` : \"\"}`);\n context.print(\n ` ${message.from ?? \"unknown\"}${message.date ? ` \u00B7 ${message.date.slice(0, 10)}` : \"\"}`\n );\n context.print(` ${message.id}`);\n }\n\n context.print(\"\");\n context.print(\"Read one with: pm mail read <id>\");\n return 0;\n}\n", "import { existsSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { stringFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * What is waiting for the person to approve.\n *\n * LISTS ONLY. There is no `pm requests approve`, and its absence is the design\n * rather than an unfinished edge.\n *\n * A file request exists because something chose a path \u2014 usually a model, with\n * an account's ingested email and shared documents in the same context that\n * chose it. The approval has to come from somewhere that thing cannot reach. A\n * terminal is not that place: this CLI is routinely driven by agents, and a\n * command an agent can run is a command an injected instruction can eventually\n * cause. An approval subcommand with a `--yes` flag would be exactly the\n * setting that gets turned on once and then never off.\n *\n * So this prints the paths and the link, and the decision happens in a browser\n * session belonging to a person.\n */\nexport async function requestsCommand(context: CommandContext): Promise<number> {\n // `pm requests get <id>` collects a finished one. Listing and collecting are\n // different verbs and the second is not an approval \u2014 see the note above for\n // why approving stays out of this program entirely.\n if (context.args.words[1] === \"get\") return collectCommand(context);\n\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return 1;\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n\n const response = await fetch(`${apiUrl}/api/v1/agent/awaiting`, {\n headers: { authorization: `Bearer ${credential.token}` }\n });\n\n if (response.status === 403) {\n // The session-only rule, reported as the fact it is rather than as a\n // failure. An API key genuinely cannot see or decide these.\n context.error(\n \"This credential cannot see the approval queue. It is visible only to you, signed in, at /dashboard/requests.\"\n );\n return 3;\n }\n\n if (!response.ok) {\n context.error(`Could not read the queue (${response.status}).`);\n return 1;\n }\n\n const { items } = (await response.json()) as {\n items: { id: string; path: string; askedBy?: string; createdAt: string }[];\n };\n\n if (items.length === 0) {\n context.print(\"Nothing is waiting. No app or chat has asked for a file from your computers.\");\n return 0;\n }\n\n context.print(\n `${items.length} request${items.length === 1 ? \"\" : \"s\"} waiting. Nothing has been read.`\n );\n context.print(\"\");\n\n for (const one of items) {\n // The path on its own line, unabbreviated. It is the only part of this that\n // distinguishes a request somebody wanted from one a stranger's email caused.\n context.print(` ${one.path}`);\n context.print(` asked by ${one.askedBy ?? \"something\"} \u00B7 ${one.id}`);\n context.print(\"\");\n }\n\n context.print(\"Approve or refuse them while signed in, at /dashboard/requests.\");\n context.print(\"They cannot be approved from here \u2014 see `pm help requests`.\");\n\n return 0;\n}\n\n/**\n * `pm requests get <id>` \u2014 writes a finished request's file to disk.\n *\n * NOT an approval. The decision has already been made by a person in a\n * browser; this collects what their own machine answered, which is the half of\n * the loop the terminal was missing. Somebody who asked for a file from their\n * laptop could see the request here and had no way to get the bytes.\n *\n * The signed URL is fetched and used immediately, never printed. It is a\n * bearer credential for one file, and a URL echoed to a terminal is a URL in\n * the scrollback, in the shell history of anyone who copies it, and in any\n * screen recording.\n */\nexport async function collectCommand(context: CommandContext): Promise<number> {\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return 1;\n }\n\n const id = context.args.words[2];\n if (!id) {\n context.error(\"Which request? `pm requests` lists them with their ids.\");\n return 2;\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n\n const link = await fetch(\n `${apiUrl}/api/v1/agent/request/${encodeURIComponent(id)}/download`,\n { headers: { authorization: `Bearer ${credential.token}` } }\n );\n\n if (!link.ok) {\n // The server's own sentence \u2014 it distinguishes \"not finished yet\" from\n // \"that is not your request\" from \"it failed\", and a status code does not.\n const body = (await link.json().catch(() => undefined)) as\n | { error?: { message?: string } }\n | undefined;\n context.error(body?.error?.message ?? `Could not prepare that file (${link.status}).`);\n return 1;\n }\n\n const { downloadUrl, filename } = (await link.json()) as {\n downloadUrl: string;\n filename: string;\n };\n\n // No credential on this one, deliberately: the URL is the authorisation, and\n // attaching a bearer token to a signed URL sends the session token to\n // whatever host the URL names.\n const file = await fetch(downloadUrl);\n if (!file.ok) {\n context.error(`The download refused it (${file.status}). Links expire in minutes \u2014 try again.`);\n return 1;\n }\n\n const name = stringFlag(context.args, \"output\", \"o\") ?? filename;\n const target = resolve(name);\n\n /*\n Refused rather than overwritten.\n\n The filename comes from a path somebody typed on another machine, and this\n writes into whatever directory the command was run in. Silently replacing\n `notes.md` in a repository because a file of that name came back is not a\n trade worth making for one saved keystroke.\n */\n if (existsSync(target)) {\n context.error(`${target} already exists. Pass --output to write somewhere else.`);\n return 1;\n }\n\n writeFileSync(target, new Uint8Array(await file.arrayBuffer()));\n\n context.print(`Wrote ${target}`);\n return 0;\n}\n", "import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve as resolvePath } from \"node:path\";\n\n/**\n * The space this FOLDER writes into.\n *\n * Separate from the profile in `~/.persistmemory`, and deliberately so. A\n * profile answers \"who am I\"; this answers \"what am I working on\", and those\n * change on different schedules \u2014 one person, many projects, and the memory\n * from a client's repository has no business landing in the same space as a\n * personal one.\n *\n * Found by walking up from the working directory, the way `git` finds its\n * root, so a command run three folders deep still writes into the project's\n * space rather than starting a new one.\n *\n * Committed or not is the user's call. It contains a space id and a name, no\n * credential and nothing secret \u2014 a colleague who clones the repository gets\n * the right space and still has to sign in as themselves.\n */\nexport const WORKSPACE_FILE = \".persistmemory.json\";\n\nexport interface WorkspaceSpace {\n readonly id: string;\n readonly name: string;\n}\n\nexport interface Workspace {\n readonly space?: WorkspaceSpace;\n}\n\nexport interface FoundWorkspace {\n readonly file: string;\n readonly dir: string;\n readonly config: Workspace;\n}\n\n/**\n * Walks up from `from` looking for a workspace file.\n *\n * Stops at the filesystem root rather than at a git root: a folder that is not\n * a repository is still a project, and refusing to look further would make\n * `pm` behave differently in the same directory depending on whether somebody\n * had run `git init` yet.\n */\nexport function findWorkspace(from: string = process.cwd()): FoundWorkspace | undefined {\n let dir = resolvePath(from);\n\n for (;;) {\n const file = join(dir, WORKSPACE_FILE);\n\n if (existsSync(file)) {\n const config = readWorkspace(file);\n // A file that cannot be read is treated as absent and the walk\n // continues. A corrupt file in a deep folder should not shadow a good\n // one at the project root.\n if (config) return { file, dir, config };\n }\n\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\nexport function readWorkspace(file: string): Workspace | undefined {\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as Partial<Workspace>;\n const space = parsed.space;\n\n if (\n space &&\n typeof space === \"object\" &&\n typeof space.id === \"string\" &&\n space.id !== \"\" &&\n typeof space.name === \"string\"\n ) {\n return { space: { id: space.id, name: space.name } };\n }\n\n return {};\n } catch {\n return undefined;\n }\n}\n\nexport function writeWorkspace(dir: string, config: Workspace): string {\n const file = join(dir, WORKSPACE_FILE);\n // Trailing newline, because this lands in people's repositories and a file\n // without one is a diff everybody's editor fights over.\n writeFileSync(file, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n return file;\n}\n", "import type { PersistMemory, Space } from \"@persistmemory/sdk\";\nimport { stringFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\nimport { login } from \"./auth\";\nimport { WORKSPACE_FILE, findWorkspace, writeWorkspace } from \"../workspace\";\n\n/**\n * `pm setup` \u2014 from nothing to a working folder, in one command.\n *\n * Written for the moment an assistant is being connected: a plugin's install\n * step runs this, and the person is signed in and pointed at a Space without\n * ever being told to go and read the docs. That is the whole reason it exists\n * as a command rather than as three paragraphs on a web page.\n *\n * It asks about the Space EVERY time, including when the folder already has\n * one. Adding PersistMemory to a second project from inside the first would\n * otherwise silently inherit that project's Space, and the person would find\n * out weeks later that a client's memory had been landing in another client's\n * space. Re-running in a folder that is already set up is cheap: the current\n * choice is offered as the default and Enter keeps it.\n */\nexport async function setupCommand(context: CommandContext): Promise<number> {\n const { print, error } = context;\n\n print(\"\");\n print(\" PersistMemory setup\");\n print(\"\");\n\n /* ------------------------------- signing in ------------------------------ */\n\n if (!context.resolved.credential) {\n print(\" You are not signed in yet. Opening your browser.\");\n print(\"\");\n\n const code = await login(context);\n if (code !== 0) {\n error(\"Setup stopped: signing in did not finish.\");\n return code;\n }\n } else {\n const how =\n context.resolved.credential.kind === \"api-key\" ? \"an API key\" : \"your browser sign-in\";\n print(` Already signed in to ${context.resolved.apiUrl} with ${how}.`);\n }\n\n /*\n Proves the credential rather than trusting the file.\n\n A stored token can be revoked, expired or for a different server, and every\n one of those looks identical to a working login until the first real call.\n Finding out here \u2014 while somebody is watching the output of a setup command\n \u2014 is far better than finding out inside an assistant three days later.\n */\n let client: PersistMemory;\n let spaces: readonly Space[];\n\n try {\n client = await context.client();\n const page = await client.spaces.list({ limit: 200 }).first();\n spaces = page.data;\n } catch (caught) {\n error(\n `Signed in, but the server would not answer: ${\n caught instanceof Error ? caught.message : String(caught)\n }`\n );\n error(\"Run `pm auth login` to sign in again.\");\n return 1;\n }\n\n print(\" Signed in and the server answered. \\u2713\");\n print(\"\");\n\n return chooseSpace(context, client, spaces);\n}\n\n/**\n * The Space half of setup, on its own so `pm auth login` can continue into it.\n *\n * Signing in and then stopping at a bare prompt leaves a person who has just\n * approved a consent screen with no idea what to do next, and \u2014 worse \u2014 with\n * everything landing in one undifferentiated pile until they happen to read\n * about Spaces. The two steps belong together.\n */\nexport async function chooseSpace(\n context: CommandContext,\n client: PersistMemory,\n spaces: readonly Space[]\n): Promise<number> {\n const { print, error } = context;\n\n const found = findWorkspace();\n const current = found?.config.space;\n\n // Non-interactive paths first, so a plugin's install script, a Dockerfile or\n // a CI job never reaches a prompt that nothing will answer.\n const named = stringFlag(context.args, \"space\");\n const creating = stringFlag(context.args, \"new-space\");\n\n if (creating !== undefined) {\n const space = await create(client, creating);\n return finish(context, space, current);\n }\n\n if (named !== undefined) {\n const match = byName(spaces, named);\n if (!match) {\n error(`No Space called \"${named}\". Use --new-space to create it.`);\n return 1;\n }\n return finish(context, match, current);\n }\n\n const interactive = context.args.flags[\"yes\"] !== true && context.isTty;\n\n if (!interactive) {\n // Nothing was asked and nobody can answer. Say what happened rather than\n // writing a file nobody chose.\n print(\" No Space chosen. Memories will go to your account's default.\");\n print(` Pass --space \"<name>\" or --new-space \"<name>\" to pick one.`);\n return 0;\n }\n\n if (current) {\n print(` This folder currently uses the Space \"${current.name}\".`);\n print(\"\");\n }\n\n print(\" Which Space should this folder use?\");\n print(\"\");\n\n spaces.forEach((space, index) => {\n const mark = current?.id === space.id ? \" (current)\" : \"\";\n const count = space.memoryCount === undefined ? \"\" : `, ${space.memoryCount} memories`;\n print(` ${index + 1}. ${space.name}${mark} ${space.kind}${count}`);\n });\n\n const createIndex = spaces.length + 1;\n const noneIndex = spaces.length + 2;\n\n print(` ${createIndex}. Create a new Space`);\n print(` ${noneIndex}. No Space \u2014 use everything in my account`);\n print(\"\");\n\n const fallback = current ? \"keep the current one\" : String(createIndex);\n const answer = await context.ask(` Choose 1-${noneIndex} [${fallback}]: `);\n\n if (answer === \"\") {\n if (current) {\n print(\"\");\n print(` Keeping \"${current.name}\".`);\n return 0;\n }\n return finish(context, await askForNewSpace(context, client), current);\n }\n\n const choice = Number(answer);\n\n if (!Number.isInteger(choice) || choice < 1 || choice > noneIndex) {\n error(`\"${answer}\" is not one of the choices. Nothing was changed.`);\n return 2;\n }\n\n if (choice === noneIndex) {\n if (found) {\n writeWorkspace(found.dir, {});\n print(\"\");\n print(` Cleared the Space in ${WORKSPACE_FILE}. This folder now uses everything.`);\n } else {\n print(\"\");\n print(\" No Space. This folder uses everything in your account.\");\n }\n return 0;\n }\n\n if (choice === createIndex) {\n return finish(context, await askForNewSpace(context, client), current);\n }\n\n return finish(context, spaces[choice - 1]!, current);\n}\n\nasync function askForNewSpace(\n context: CommandContext,\n client: PersistMemory\n): Promise<Space> {\n for (;;) {\n const name = await context.ask(\" Name for the new Space: \");\n if (name !== \"\") return create(client, name);\n context.print(\" A Space needs a name.\");\n }\n}\n\nasync function create(client: PersistMemory, name: string): Promise<Space> {\n // `project`, because that is what a folder is. The other kinds exist and are\n // reachable from `pm spaces create --kind`; guessing between them here would\n // be asking a question whose answer changes nothing a person can see.\n return client.spaces.create({ name, kind: \"project\" });\n}\n\nfunction byName(spaces: readonly Space[], name: string): Space | undefined {\n const wanted = name.trim().toLowerCase();\n return spaces.find((one) => one.name.trim().toLowerCase() === wanted) ??\n spaces.find((one) => one.id === name);\n}\n\nfunction finish(\n context: CommandContext,\n space: Space,\n previous: { id: string; name: string } | undefined\n): number {\n // Written into the folder the command was RUN in, not the one the old file\n // was found in: choosing a Space for this project should not rewrite the\n // parent project's file three directories up.\n const file = writeWorkspace(process.cwd(), {\n space: { id: space.id, name: space.name }\n });\n\n context.print(\"\");\n context.print(` This folder now uses the Space \"${space.name}\".`);\n if (previous && previous.id !== space.id) {\n context.print(` It used to use \"${previous.name}\". Existing memories were not moved.`);\n }\n context.print(` Saved to ${file}`);\n context.print(\"\");\n context.print(\" Try it:\");\n context.print(\"\");\n context.print(' pm remember \"we chose Postgres for the ledger\"');\n context.print(' pm search \"what did we choose\"');\n context.print(\"\");\n return 0;\n}\n", "import { DEFAULT_PROFILE, clearLogin, maskToken, readConfig, resolve, saveLogin } from \"../config\";\nimport { loginWithBrowser } from \"../auth/oauth\";\nimport { currentCredential } from \"../session\";\nimport { chooseSpace } from \"./setup\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * `pm auth login`, `pm auth status`, `pm auth logout`.\n *\n * Two ways in, and both are first-class:\n *\n * pm auth login a browser, PKCE, a refresh token that renews\n * pm auth login --api-key a pasted key, for CI and for headless machines\n *\n * The second exists because the first cannot work everywhere, and a CLI whose\n * only login needs a browser is a CLI that cannot run in a pipeline. It is\n * also why `PERSISTMEMORY_API_KEY` outranks the stored profile: a CI runner\n * sets one variable and never writes a file.\n */\nexport async function authCommand(context: CommandContext): Promise<number> {\n const action = context.args.words[1] ?? \"status\";\n\n switch (action) {\n case \"login\":\n return login(context);\n case \"logout\":\n return logout(context);\n case \"status\":\n return status(context);\n default:\n context.error(`Unknown command \"pm auth ${action}\". Try login, logout or status.`);\n return 2;\n }\n}\n\nconst SCOPE = \"memory:read memory:capture memory:write usage:read\";\n\n/**\n * Signing in, exported so `pm setup` can do it as a step rather than telling\n * somebody to run another command and come back.\n */\nexport async function login(context: CommandContext): Promise<number> {\n const { flags } = context;\n const profile = flags.profile ?? DEFAULT_PROFILE;\n const apiUrl = context.resolved.apiUrl;\n\n /**\n * A pasted key.\n *\n * `--api-key` with no value reads from stdin rather than from the argument,\n * so the key never appears in the shell history or in the process list \u2014\n * both of which are readable by anyone else on the machine. `--api-key=\u2026` is\n * still accepted because scripts need it, and a script's environment is a\n * problem the script owns.\n */\n if (flags.apiKey !== undefined) {\n const key = flags.apiKey === true ? await context.readSecret(\"API key: \") : flags.apiKey;\n if (!key) {\n context.error(\"No API key was given.\");\n return 2;\n }\n\n saveLogin({\n paths: context.paths,\n profile,\n apiUrl,\n credential: { kind: \"api-key\", token: key }\n });\n\n context.print(`Signed in to ${apiUrl} as profile \"${profile}\" with an API key.`);\n return 0;\n }\n\n try {\n const { credential, clientId } = await loginWithBrowser({\n apiUrl,\n scope: SCOPE,\n clientId: context.resolved.clientId,\n deps: context.oauth\n });\n\n saveLogin({\n paths: context.paths,\n profile,\n apiUrl,\n credential,\n clientId\n });\n\n context.print(`\\nSigned in to ${apiUrl} as profile \"${profile}\".`);\n\n /*\n And then keep going, rather than returning to a bare prompt.\n\n Signing in is never the thing somebody wanted; it is the step before it.\n Stopping here left a person who had just approved a consent screen with\n no idea what to do next, and everything they captured landing in one\n undifferentiated pile until they happened to read about Spaces.\n\n Only when a terminal is attached and only when the caller did not ask for\n the login on its own. `pm auth login` inside a script, a Dockerfile or a\n plugin's install step must still be exactly one thing.\n */\n if (context.args.flags[\"no-setup\"] === true || !context.isTty) return 0;\n\n return continueToSpace(context);\n } catch (error) {\n context.error(message(error));\n return 1;\n }\n}\n\n/**\n * The Space question, asked after a successful browser sign-in.\n *\n * Failure here is NOT a failed login. The credential is already saved and\n * works; being unable to list Spaces means the person can still use every\n * command, so this reports and returns success rather than making a signed-in\n * terminal look like a broken one.\n */\nasync function continueToSpace(context: CommandContext): Promise<number> {\n try {\n const client = await context.client();\n const { data } = await client.spaces.list({ limit: 200 }).first();\n return await chooseSpace(context, client, data);\n } catch (caught) {\n context.print(\"\");\n context.print(`Could not load your Spaces: ${message(caught)}`);\n context.print(\"You are signed in. Run `pm setup` to choose a Space.\");\n return 0;\n }\n}\n\nfunction logout(context: CommandContext): number {\n const profile = context.flags.profile ?? context.resolved.profile;\n const forgotten = clearLogin(context.paths, profile);\n\n context.print(\n forgotten\n ? `Signed out of profile \"${profile}\".`\n : `Profile \"${profile}\" was not signed in.`\n );\n\n /**\n * A reminder, not a failure.\n *\n * `logout` removes the stored credential and can do nothing about an\n * environment variable, so somebody who exported one stays authenticated and\n * would otherwise conclude that logging out silently did not work.\n */\n if (process.env[\"PERSISTMEMORY_API_KEY\"]) {\n context.print(\n \"PERSISTMEMORY_API_KEY is still set in this shell, and takes precedence. Unset it to finish signing out.\"\n );\n }\n return 0;\n}\n\nasync function status(context: CommandContext): Promise<number> {\n const config = readConfig(context.paths);\n const resolved = context.resolved;\n\n if (!resolved.credential) {\n context.print(`Not signed in. Run \\`pm auth login\\`.\\n\\n api url ${resolved.apiUrl}`);\n return 1;\n }\n\n const lines = [\n ` profile ${resolved.profile}${config.current === resolved.profile ? \" (current)\" : \"\"}`,\n ` api url ${resolved.apiUrl}`,\n ` method ${resolved.credential.kind === \"api-key\" ? \"API key\" : \"browser sign-in\"}`,\n ` token ${maskToken(resolved.credential.token)}`\n ];\n\n if (resolved.fromEnvironment) {\n lines.push(\" source PERSISTMEMORY_API_KEY (overrides the stored profile)\");\n }\n if (resolved.credential.expiresAt) {\n lines.push(` expires ${resolved.credential.expiresAt}`);\n }\n if (resolved.credential.scope) {\n lines.push(` scope ${resolved.credential.scope}`);\n }\n\n context.print(lines.join(\"\\n\"));\n\n /**\n * Then actually use it.\n *\n * A status that only reads a local file answers \"is there a token here\",\n * which is not the question anybody is asking when they run this. They are\n * asking \"why is my next command failing\", and a revoked key looks perfectly\n * healthy on disk.\n */\n try {\n await currentCredential(resolved, context.session);\n const client = await context.client();\n await client.health.ready();\n context.print(\"\\n The server accepted this credential.\");\n return 0;\n } catch (error) {\n context.print(`\\n The server did NOT accept this credential: ${message(error)}`);\n return 1;\n }\n}\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import { existsSync, rmSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { CommandContext } from \"../context\";\nimport { PACKAGE } from \"../help\";\n\n/**\n * Updating, removing, and forgetting everything.\n *\n * These exist because the alternative is a web page nobody reads. Somebody who\n * wants this program gone should be able to ask it to go, in the place they\n * are already typing, rather than being told to remember an npm incantation \u2014\n * and somebody handing a laptop back needs the credentials gone with one\n * command, not a path to delete by hand.\n */\n\n/** `pm update` \u2014 install the newest published version. */\nexport async function updateCommand(context: CommandContext): Promise<number> {\n const manager = installer();\n\n if (!manager) {\n context.error(\n \"This copy was not installed by npm, so `pm update` cannot replace it.\\n\" +\n \"Re-run the installer: curl -fsSL https://persistmemory.com/install.sh | sh\"\n );\n return 1;\n }\n\n context.print(`Installing the newest ${PACKAGE}\u2026`);\n\n // Inherited, so npm's own progress and errors go straight to the person.\n // Summarising them would hide the one line that says what went wrong.\n const result = spawnSync(manager, [\"install\", \"-g\", `${PACKAGE}@latest`], {\n stdio: \"inherit\"\n });\n\n if (result.status !== 0) {\n context.error(\n \"That did not work. If it failed on permissions, do NOT re-run it with sudo \u2014\\n\" +\n \"point npm at a directory you own instead:\\n\" +\n \" npm config set prefix ~/.npm-global\\n\" +\n \" export PATH=$HOME/.npm-global/bin:$PATH\"\n );\n return result.status ?? 1;\n }\n\n context.print(\"Done. `pm --version` will show the new one.\");\n return 0;\n}\n\n/** `pm uninstall` \u2014 remove the program. Offers to take its files too. */\nexport async function uninstallCommand(context: CommandContext): Promise<number> {\n const manager = installer();\n\n if (!manager) {\n context.error(\n \"This copy was not installed by npm, so it cannot uninstall itself.\\n\" +\n `Delete the file it runs from: ${processPath()}`\n );\n return 1;\n }\n\n // Asked BEFORE anything is removed. Afterwards there is no `pm` left to ask\n // with, and somebody who wanted their credentials gone would have to find\n // the directory themselves.\n const alsoData =\n context.args.flags[\"purge\"] === true ||\n (context.isTty\n ? /^y(es)?$/i.test(\n await context.ask(`Also delete your credentials and settings in ${context.paths.dir}? [y/N] `)\n )\n : false);\n\n const result = spawnSync(manager, [\"uninstall\", \"-g\", PACKAGE], { stdio: \"inherit\" });\n\n if (result.status !== 0) return result.status ?? 1;\n\n if (alsoData) removeEverything(context);\n\n context.print(\"Removed. Your memories are untouched \u2014 this only removed the program.\");\n return 0;\n}\n\n/**\n * `pm delete` \u2014 every file this program has written on this machine.\n *\n * NOT the account, and the difference is stated in the confirmation. A command\n * called `delete` that quietly destroyed somebody's memories would be the\n * worst possible reading of an ambiguous word, so this one is explicit about\n * being local-only and points at where the other thing lives.\n */\nexport async function deleteCommand(context: CommandContext): Promise<number> {\n if (!existsSync(context.paths.dir)) {\n context.print(`Nothing to delete: ${context.paths.dir} does not exist.`);\n return 0;\n }\n\n if (context.args.flags[\"yes\"] !== true) {\n if (!context.isTty) {\n context.error(\"Refusing to delete without confirmation. Pass --yes.\");\n return 2;\n }\n\n context.print(\"\");\n context.print(`This deletes everything in ${context.paths.dir}:`);\n context.print(\" \u2022 the credential you signed in with\");\n context.print(\" \u2022 your profiles and settings\");\n context.print(\" \u2022 transcripts of your `pm` sessions\");\n context.print(\"\");\n context.print(\"Your account and your memories are NOT touched. To delete those,\");\n context.print(\"go to https://persistmemory.com/settings.\");\n context.print(\"\");\n\n const answer = await context.ask(\"Type 'delete' to confirm: \");\n if (answer.trim().toLowerCase() !== \"delete\") {\n context.print(\"Nothing was deleted.\");\n return 1;\n }\n }\n\n removeEverything(context);\n context.print(`Deleted ${context.paths.dir}.`);\n return 0;\n}\n\nfunction removeEverything(context: CommandContext): void {\n // `resolve`, and a guard, because this deletes a directory recursively and\n // `PERSISTMEMORY_HOME` is settable. An empty or root-ish value would be a\n // command that eats a filesystem.\n const dir = resolve(context.paths.dir);\n if (dir === \"/\" || dir.split(\"/\").filter(Boolean).length < 2) {\n context.error(`Refusing to delete ${dir}: that does not look like a data directory.`);\n return;\n }\n rmSync(dir, { recursive: true, force: true });\n}\n\n/**\n * Which package manager put this here, if any.\n *\n * Decided from the path this file runs from rather than from configuration: a\n * global npm install lives under `node_modules`, and a copy someone built from\n * source or downloaded does not. Getting this wrong in the optimistic\n * direction means telling npm to uninstall something it never installed.\n */\nfunction installer(): \"npm\" | undefined {\n return processPath().includes(`node_modules`) ? \"npm\" : undefined;\n}\n\nfunction processPath(): string {\n try {\n return resolve(dirname(fileURLToPath(import.meta.url)));\n } catch {\n return process.argv[1] ?? \"\";\n }\n}\n", "import { createInterface } from \"node:readline\";\nimport { randomUUID } from \"node:crypto\";\nimport { relative } from \"node:path\";\nimport { stringFlag } from \"../args\";\nimport { openSessionLog, totalUsage, turnsFrom } from \"../events\";\nimport type { SessionEvent, SessionLog } from \"../events\";\nimport { commitWrite, proposeWrite, readWithin, summarise } from \"../files\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * The interactive session.\n *\n * A conversation with your own memory, in a terminal. What it is NOT is a\n * coding agent: nothing here plans, edits a project, or runs a command. It\n * reads, it answers from what you have recorded, and it writes a file only when\n * you say so for that file.\n *\n * THREE THINGS THIS BORROWS, deliberately, from harnesses built for coding\n * agents \u2014 the problems are the same even though the domain is not:\n *\n * A SMALL, COMPOSABLE TOOL SET. Six commands, not sixty. A sprawling toolkit\n * is harder for a person to remember and gives a model more ways to pick\n * wrong, and every one of these is something you could otherwise do by\n * leaving the session.\n *\n * AN EVENT LOG, written as it happens. Every prompt, reply, file read and\n * proposed write lands in `~/.persistmemory/sessions/<id>.jsonl` on the line\n * it occurs, so a session that dies with the terminal is still readable and\n * still resumable. See `events.ts` for why append-only.\n *\n * COST IN VIEW. Each reply reports what it cost and `/usage` totals the\n * session. A tool that spends someone's money silently is a tool they stop\n * trusting the first time they see the bill.\n *\n * The one thing it does not borrow is an approval MODE. Those harnesses have a\n * setting that grants writes for a whole session; this asks every time, because\n * the text proposing a write can come from a model, and a model's suggestion is\n * downstream of whatever it just read.\n */\n\nconst HELP = `\n Commands\n\n /read <path> read a file into the conversation\n /capture <path> read a file AND remember it\n /write <path> write the last reply to a file (asks first)\n /remember <text> remember something directly\n /usage what this session has cost\n /new start a fresh conversation\n /exit leave (Ctrl-D also works)\n\n Anything else is a question, answered from your memory.\n`;\n\nexport interface SessionState {\n conversationId?: string;\n /** The turns sent to the server, kept so a reply has its own context. */\n turns: { role: \"user\" | \"assistant\"; content: string }[];\n lastReply?: string;\n /** Files read this session, so a question can refer to them. */\n attached: { path: string; text: string }[];\n}\n\nexport async function sessionCommand(context: CommandContext): Promise<number> {\n const resumeId = stringFlag(context.args, \"resume\");\n const id = resumeId ?? randomUUID();\n const log = openSessionLog(context.paths, id);\n\n const state: SessionState = { turns: [], attached: [] };\n\n if (resumeId) {\n const previous = log.read();\n state.turns = turnsFrom(previous);\n if (state.turns.length === 0) {\n context.error(`No session \"${resumeId}\" to resume.`);\n return 1;\n }\n context.print(`Resumed session ${resumeId} \u2014 ${state.turns.length} turns.`);\n }\n\n // Checked before the prompt is drawn. Discovering you are not signed in\n // after typing a paragraph is a small cruelty a one-line check avoids.\n try {\n await context.client();\n } catch (error) {\n context.error(error instanceof Error ? error.message : String(error));\n return 3;\n }\n\n log.append({\n kind: \"session.started\",\n at: new Date().toISOString(),\n cwd: process.cwd(),\n apiUrl: context.resolved.apiUrl,\n profile: context.resolved.profile\n });\n\n context.print(`\\n PersistMemory \u2014 session ${id.slice(0, 8)}`);\n context.print(` Ask anything. /help for commands, /exit to leave.\\n`);\n\n const readline = createInterface({ input: process.stdin, output: process.stdout });\n const ask = (prompt: string): Promise<string | undefined> =>\n new Promise((resolve) => {\n readline.question(prompt, resolve);\n // Ctrl-D closes stdin, which resolves nothing above. Without this the\n // session hangs on a closed terminal instead of ending.\n readline.once(\"close\", () => resolve(undefined));\n });\n\n const root = process.cwd();\n let running = true;\n\n while (running) {\n const line = await ask(\"> \");\n if (line === undefined) break;\n\n const input = line.trim();\n if (input === \"\") continue;\n\n try {\n running = await handleInput({ input, context, state, log, root, ask });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.append({ kind: \"error\", at: new Date().toISOString(), message });\n context.error(` ${message}`);\n }\n }\n\n readline.close();\n\n const totals = totalUsage(log.read());\n log.append({ kind: \"session.ended\", at: new Date().toISOString(), turns: totals.turns });\n\n context.print(\n `\\n ${totals.turns} turn${totals.turns === 1 ? \"\" : \"s\"}` +\n (totals.inputTokens + totals.outputTokens > 0\n ? `, ${totals.inputTokens + totals.outputTokens} tokens`\n : \"\") +\n `\\n Transcript: ${log.path}` +\n `\\n Resume with: pm chat --resume ${id}\\n`\n );\n\n return 0;\n}\n\n/**\n * One line of input.\n *\n * Exported for tests. The loop above owns a real terminal and cannot be driven\n * from a test without one; this is where every decision actually lives, and it\n * takes `ask` as a parameter precisely so the confirmation prompt can be\n * answered by a function instead of a person.\n *\n * Returns false to end the session.\n */\nexport async function handleInput(args: {\n input: string;\n context: CommandContext;\n state: SessionState;\n log: SessionLog;\n root: string;\n ask: (prompt: string) => Promise<string | undefined>;\n}): Promise<boolean> {\n const { input, context, state, log, root } = args;\n\n if (!input.startsWith(\"/\")) {\n await answer(args);\n return true;\n }\n\n const [command, ...rest] = input.slice(1).split(/\\s+/);\n const argument = rest.join(\" \").trim();\n\n switch (command) {\n case \"exit\":\n case \"quit\":\n return false;\n\n case \"help\":\n context.print(HELP);\n return true;\n\n case \"usage\": {\n const totals = totalUsage(log.read());\n context.print(\n ` ${totals.turns} turns, ${totals.inputTokens} in / ${totals.outputTokens} out tokens`\n );\n return true;\n }\n\n case \"new\":\n // The conversation id is dropped, so the next turn starts a new one\n // server-side. The local log continues, because it is a log of this\n // SESSION and starting a new topic is a thing that happened in it.\n delete state.conversationId;\n state.turns = [];\n state.attached = [];\n delete state.lastReply;\n context.print(\" Starting a fresh conversation.\");\n return true;\n\n case \"read\":\n case \"capture\": {\n if (!argument) {\n context.error(` /${command} needs a path.`);\n return true;\n }\n\n const file = readWithin(root, argument);\n state.attached.push({ path: file.path, text: file.text });\n log.append({\n kind: \"file.read\",\n at: new Date().toISOString(),\n path: file.path,\n bytes: file.bytes\n });\n\n context.print(` read ${relative(root, file.path)} (${Math.round(file.bytes / 1024)} KB)`);\n\n if (command === \"capture\") {\n const client = await context.client();\n const result = await client.memories.remember(\n { text: file.text, title: relative(root, file.path) },\n { idempotencyKey: `cli:capture:${file.path}:${file.bytes}` }\n );\n log.append({\n kind: \"file.captured\",\n at: new Date().toISOString(),\n path: file.path,\n jobId: result.jobId\n });\n // 202, not \"created\". Extraction runs afterwards and may produce one\n // memory, several, or none.\n context.print(` queued for extraction (job ${result.jobId})`);\n }\n\n return true;\n }\n\n case \"remember\": {\n if (!argument) {\n context.error(\" /remember needs something to remember.\");\n return true;\n }\n const client = await context.client();\n const result = await client.memories.remember({ text: argument });\n context.print(` queued for extraction (job ${result.jobId})`);\n return true;\n }\n\n case \"write\":\n await write({ ...args, path: argument });\n return true;\n\n default:\n context.error(` Unknown command /${command ?? \"\"}. Try /help.`);\n return true;\n }\n}\n\n/**\n * A question, answered from memory.\n *\n * Files read with `/read` are attached to the turn rather than remembered, and\n * the distinction matters: reading a file to ask about it should not file it in\n * somebody's long-term memory. `/capture` is the command that does that, and it\n * says so.\n */\nasync function answer(args: {\n input: string;\n context: CommandContext;\n state: SessionState;\n log: SessionLog;\n}): Promise<void> {\n const { input, context, state, log } = args;\n\n const attached = state.attached\n .map((file) => `--- ${file.path} ---\\n${file.text}`)\n .join(\"\\n\\n\");\n\n const content = attached ? `${attached}\\n\\n---\\n\\n${input}` : input;\n\n log.append({ kind: \"prompt\", at: new Date().toISOString(), text: input });\n state.turns.push({ role: \"user\", content });\n\n const client = await context.client();\n const response = await client.request<ChatResponse>(\"POST\", \"/api/v1/chat\", {\n messages: state.turns.slice(-20),\n ...(state.conversationId ? { conversationId: state.conversationId } : {})\n });\n\n const reply = response.message.content;\n state.turns.push({ role: \"assistant\", content: reply });\n state.lastReply = reply;\n if (response.conversationId) state.conversationId = response.conversationId;\n\n // Attachments are consumed by the turn they were read for. Keeping them\n // would resend the whole file on every subsequent question, which is how a\n // session quietly becomes expensive.\n state.attached = [];\n\n log.append({\n kind: \"reply\",\n at: new Date().toISOString(),\n text: reply,\n citations: response.citations?.length ?? 0,\n ...(response.diagnostics?.usage ? { usage: response.diagnostics.usage } : {}),\n ...(response.diagnostics?.model ? { model: response.diagnostics.model } : {})\n });\n\n context.print(`\\n${reply}\\n`);\n\n if (response.citations?.length) {\n const historical = response.citations.filter((one) => one.historical).length;\n context.print(\n ` from ${response.citations.length} memor${response.citations.length === 1 ? \"y\" : \"ies\"}` +\n // Never omitted. A superseded memory presented as current is the most\n // damaging thing this system can do.\n (historical > 0 ? `, ${historical} no longer current` : \"\")\n );\n }\n\n if (response.diagnostics?.degraded && !context.flags.quiet) {\n context.error(\" Note: answered without the semantic index, so this may be narrower than usual.\");\n }\n}\n\n/**\n * Writes the last reply to a file, after showing exactly what will change.\n *\n * ALWAYS ASKS, and there is no flag that turns this off. The text being written\n * came from a model, and the model's output is downstream of whatever it read \u2014\n * a document that says \"now overwrite ~/.ssh/config\" is a document somebody\n * might legitimately have in their memory. The prompt is what stands between\n * that and a file changing.\n */\nasync function write(args: {\n path: string;\n context: CommandContext;\n state: SessionState;\n log: SessionLog;\n root: string;\n ask: (prompt: string) => Promise<string | undefined>;\n}): Promise<void> {\n const { context, state, log, root } = args;\n\n if (!args.path) {\n context.error(\" /write needs a path.\");\n return;\n }\n if (!state.lastReply) {\n context.error(\" Nothing to write yet \u2014 ask something first.\");\n return;\n }\n\n const proposed = proposeWrite(root, args.path, `${state.lastReply}\\n`);\n\n context.print(\"\");\n context.print(summarise(proposed));\n context.print(\"\");\n\n const reply = (await args.ask(\" Write it? [y/N] \"))?.trim().toLowerCase();\n const approved = reply === \"y\" || reply === \"yes\";\n\n log.append({\n kind: \"file.write\",\n at: new Date().toISOString(),\n path: proposed.path,\n approved,\n ...(approved ? { bytes: Buffer.byteLength(proposed.contents) } : {})\n });\n\n if (!approved) {\n context.print(\" Not written.\");\n return;\n }\n\n commitWrite(proposed, true);\n context.print(` Wrote ${relative(root, proposed.path)}.`);\n}\n\ninterface ChatResponse {\n readonly message: { role: \"assistant\"; content: string };\n readonly conversationId?: string;\n readonly citations?: readonly { id: string; title: string; historical: boolean }[];\n readonly diagnostics?: {\n readonly degraded?: boolean;\n readonly usage?: { inputTokens?: number; outputTokens?: number };\n readonly model?: string;\n };\n}\n\nexport type { SessionEvent };\n", "import { appendFileSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Paths } from \"./config\";\n\n/**\n * Everything a session did, on disk, as it happens.\n *\n * Append-only JSONL, one event per line, flushed on every write. That shape is\n * chosen for the failure it survives: a session ends by the terminal being\n * closed, the laptop sleeping, or Ctrl-C \u2014 never by a tidy shutdown \u2014 and a log\n * written at the end is a log that does not exist. Appending a line at a time\n * means the transcript of a session that died mid-sentence is complete up to\n * the sentence.\n *\n * This is deliberately the SECOND record rather than the only one. The\n * conversation itself is stored server-side, which is what makes it available\n * to every other client. This local log holds what the server has no business\n * knowing: which files were read off this machine, what was proposed as a\n * write, and what the person approved or refused. Sending that to a server\n * would be shipping a directory listing of somebody's laptop.\n *\n * JSONL rather than JSON, because a JSON array has to be rewritten to be\n * appended to \u2014 and a rewrite interrupted halfway loses the whole file rather\n * than the last line.\n */\n\nexport type SessionEvent =\n | { kind: \"session.started\"; at: string; cwd: string; apiUrl: string; profile: string }\n | { kind: \"prompt\"; at: string; text: string }\n | {\n kind: \"reply\";\n at: string;\n text: string;\n citations: number;\n /** What the turn cost, when the server reported it. */\n usage?: { inputTokens?: number; outputTokens?: number };\n model?: string;\n }\n | { kind: \"file.read\"; at: string; path: string; bytes: number }\n | { kind: \"file.captured\"; at: string; path: string; jobId?: string }\n /** Proposed, and what the person said. `approved: false` is the useful one. */\n | { kind: \"file.write\"; at: string; path: string; approved: boolean; bytes?: number }\n | { kind: \"error\"; at: string; message: string }\n | { kind: \"session.ended\"; at: string; turns: number };\n\nexport interface SessionLog {\n readonly id: string;\n readonly path: string;\n append(event: SessionEvent): void;\n read(): SessionEvent[];\n}\n\n/**\n * Opens (or resumes) a session log.\n *\n * The id is the file name, so resuming a session is opening the same file \u2014\n * there is no index to keep in step with the directory, and a log the user\n * deleted is simply gone rather than a dangling row.\n */\nexport function openSessionLog(paths: Paths, id: string): SessionLog {\n const directory = join(paths.dir, \"sessions\");\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n\n const path = join(directory, `${id}.jsonl`);\n\n return {\n id,\n path,\n\n append(event) {\n try {\n // 0600: this holds the text of what somebody asked their own memory and\n // the paths of files on their machine.\n appendFileSync(path, `${JSON.stringify(event)}\\n`, { mode: 0o600 });\n } catch {\n // A log that cannot be written must not end the session it is\n // describing. The transcript is a convenience; the conversation is the\n // thing the person came for.\n }\n },\n\n read() {\n if (!existsSync(path)) return [];\n return readFileSync(path, \"utf8\")\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\")\n .flatMap((line) => {\n try {\n return [JSON.parse(line) as SessionEvent];\n } catch {\n // One malformed line \u2014 a half-written final record after a crash \u2014\n // costs that line and not the transcript around it.\n return [];\n }\n });\n }\n };\n}\n\n/**\n * The turns, in the shape `/chat` wants, recovered from a log.\n *\n * This is what makes `pm chat --resume` work without the server: the local log\n * already holds every prompt and reply in order, so a resumed session starts\n * with its own history even when the conversation id has been lost.\n */\nexport function turnsFrom(events: readonly SessionEvent[]): {\n role: \"user\" | \"assistant\";\n content: string;\n}[] {\n const turns: { role: \"user\" | \"assistant\"; content: string }[] = [];\n\n for (const event of events) {\n if (event.kind === \"prompt\") turns.push({ role: \"user\", content: event.text });\n if (event.kind === \"reply\") turns.push({ role: \"assistant\", content: event.text });\n }\n\n return turns;\n}\n\n/** What a session cost, added up. Printed on exit. */\nexport function totalUsage(events: readonly SessionEvent[]): {\n turns: number;\n inputTokens: number;\n outputTokens: number;\n} {\n let turns = 0;\n let inputTokens = 0;\n let outputTokens = 0;\n\n for (const event of events) {\n if (event.kind !== \"reply\") continue;\n turns += 1;\n inputTokens += event.usage?.inputTokens ?? 0;\n outputTokens += event.usage?.outputTokens ?? 0;\n }\n\n return { turns, inputTokens, outputTokens };\n}\n", "import { readFileSync } from \"node:fs\";\nimport type { Memory, SearchResult, Space } from \"@persistmemory/sdk\";\nimport { listFlag, numberFlag, stringFlag } from \"../args\";\nimport type { Column } from \"../output\";\nimport { render, renderOne, shortDate } from \"../output\";\nimport { readStdin } from \"../context\";\nimport type { CommandContext } from \"../context\";\nimport { spacesFor } from \"../spaces\";\n\n/**\n * The commands that do the actual work.\n *\n * Every one of them goes through `@persistmemory/sdk` rather than calling\n * `fetch`. That is not code reuse for its own sake: the SDK already decides\n * retries, per-attempt timeouts, idempotency and how an error becomes a\n * message, and a CLI that reimplemented those would drift from the library the\n * same user's scripts are using \u2014 so a request that succeeds from their code\n * would fail from their terminal, or the other way round.\n */\n\nconst memoryColumns: readonly Column<Memory>[] = [\n { header: \"id\", value: (m) => m.id },\n { header: \"type\", value: (m) => m.type },\n { header: \"title\", value: (m) => m.title },\n { header: \"confidence\", value: (m) => m.confidence.toFixed(2) },\n { header: \"updated\", value: (m) => shortDate(m.updatedAt) }\n];\n\nconst memoryFields: readonly Column<Memory>[] = [\n { header: \"id\", value: (m) => m.id },\n { header: \"type\", value: (m) => m.type },\n { header: \"state\", value: (m) => m.state },\n { header: \"title\", value: (m) => m.title },\n { header: \"content\", value: (m) => m.content },\n { header: \"confidence\", value: (m) => m.confidence.toFixed(2) },\n { header: \"importance\", value: (m) => m.importance.toFixed(2) },\n { header: \"entities\", value: (m) => m.entities.map((e) => e.name).join(\", \") },\n { header: \"spaces\", value: (m) => (m.spaceIds ?? []).join(\", \") },\n { header: \"version\", value: (m) => String(m.version) },\n { header: \"created\", value: (m) => shortDate(m.createdAt) },\n { header: \"updated\", value: (m) => shortDate(m.updatedAt) }\n];\n\n/**\n * `pm remember <text>`, `pm remember -`, `pm remember --file notes.md`.\n *\n * Reading from stdin and from a file are not conveniences. The things worth\n * remembering are usually already in a file or coming out of another command,\n * and a capture tool that only accepts a quoted argument makes the user paste\n * multi-line text into a shell \u2014 where the shell then interprets it.\n */\nexport async function rememberCommand(context: CommandContext): Promise<number> {\n const positional = context.args.words.slice(1);\n const file = stringFlag(context.args, \"file\", \"f\");\n\n let text: string;\n if (file) {\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n context.error(`Could not read ${file}.`);\n return 1;\n }\n } else if (positional[0] === \"-\" || (positional.length === 0 && !process.stdin.isTTY)) {\n text = await readStdin();\n } else {\n text = positional.join(\" \");\n }\n\n if (text.trim() === \"\") {\n context.error(\"Nothing to remember. Pass text, a --file, or pipe something in.\");\n return 2;\n }\n\n const client = await context.client();\n // Resolves names as well as ids, and falls back to the folder's space.\n const spaceIds = await spacesFor(context, client);\n const title = stringFlag(context.args, \"title\");\n\n const result = await client.memories.remember(\n {\n text,\n ...(title ? { title } : {}),\n ...(spaceIds ? { spaceIds } : {})\n },\n {\n /**\n * A key derived from the CONTENT, not a random one.\n *\n * The SDK will not retry a POST without one, and a random value per\n * attempt would defeat the point: a request that timed out after the\n * server accepted it would be captured twice. Same text, same key, one\n * memory \u2014 which is what a person re-running a failed command expects.\n */\n idempotencyKey: `cli:remember:${hash(text)}`\n }\n );\n\n if (context.flags.output !== \"table\") {\n context.print(renderOne(result, [\n { header: \"status\", value: (r) => r.status },\n { header: \"jobId\", value: (r) => r.jobId },\n { header: \"note\", value: (r) => r.note }\n ], { format: context.flags.output }));\n return 0;\n }\n\n // Said plainly, because `remember` returns 202 and people reasonably assume\n // a memory now exists. It does not yet: extraction, deduplication and\n // conflict detection all run afterwards and may produce one, several or none.\n context.print(`Accepted for processing. Job ${result.jobId}.`);\n context.print(result.note);\n return 0;\n}\n\nexport async function searchCommand(context: CommandContext): Promise<number> {\n const query = context.args.words.slice(1).join(\" \").trim();\n if (query === \"\") {\n context.error('Nothing to search for. Try `pm search \"what did we decide about Postgres\"`.');\n return 2;\n }\n\n const limit = numberFlag(context.args, \"limit\", \"n\");\n if (limit === \"invalid\") {\n context.error(\"--limit must be a number.\");\n return 2;\n }\n\n const client = await context.client();\n const spaceIds = await spacesFor(context, client);\n\n const response = await client.search.query({\n query,\n ...(limit !== undefined ? { limit } : {}),\n ...(spaceIds ? { spaceIds } : {}),\n ...(stringFlag(context.args, \"as-of\") ? { asOf: stringFlag(context.args, \"as-of\") as string } : {})\n });\n\n if (context.flags.output === \"json\" || context.flags.output === \"yaml\") {\n // The whole response, diagnostics included. A script that wants to know\n // whether the answer was degraded cannot find that out from the rows.\n context.print(renderOne(response, [], { format: context.flags.output }));\n return 0;\n }\n\n const columns: readonly Column<SearchResult>[] = [\n { header: \"score\", value: (r) => r.score.toFixed(3) },\n { header: \"type\", value: (r) => r.memory.type },\n { header: \"title\", value: (r) => r.memory.title },\n { header: \"content\", value: (r) => r.memory.content },\n { header: \"id\", value: (r) => r.memory.id }\n ];\n\n if (response.results.length === 0) {\n context.print(`Nothing found for \"${response.query}\".`);\n } else {\n context.print(render(response.results, columns, { format: context.flags.output }));\n }\n\n /**\n * The degraded notice, always, and never only in verbose mode.\n *\n * Search falls back to deterministic retrieval when embeddings are\n * unavailable and still answers. A person who is not told that reads a\n * narrower result set as \"my memory is empty\" \u2014 which is the one conclusion\n * that would make them stop using the tool.\n */\n if (response.diagnostics.degraded && !context.flags.quiet) {\n const notice =\n response.diagnostics.notice ??\n `search ran without ${(response.diagnostics.unavailable ?? [\"some capabilities\"]).join(\", \")}`;\n context.error(`\\nNote: these results are narrower than usual \u2014 ${notice}`);\n }\n\n return 0;\n}\n\nexport async function listMemoriesCommand(context: CommandContext): Promise<number> {\n const limit = numberFlag(context.args, \"limit\", \"n\");\n if (limit === \"invalid\") {\n context.error(\"--limit must be a number.\");\n return 2;\n }\n\n const client = await context.client();\n const spaceIds = await spacesFor(context, client);\n const page = client.memories.list({\n ...(limit !== undefined ? { limit } : {}),\n ...(listFlag(context.args, \"type\") ? { type: listFlag(context.args, \"type\") as never } : {}),\n ...(spaceIds\n ? { spaceIds: [...spaceIds] }\n : {})\n });\n\n // One page. `--all` walks the cursor, because a memory store is unbounded\n // and printing all of it by default is a command nobody can interrupt.\n const rows = context.args.flags[\"all\"]\n ? await page.all(limit ?? 1000)\n : (await page.first()).data;\n\n if (rows.length === 0) {\n context.print(\"No memories yet.\");\n return 0;\n }\n\n context.print(render(rows, memoryColumns, { format: context.flags.output }));\n return 0;\n}\n\nexport async function getMemoryCommand(context: CommandContext): Promise<number> {\n const id = context.args.words[2];\n if (!id) {\n context.error(\"Which memory? Try `pm get memory <id>`.\");\n return 2;\n }\n\n const client = await context.client();\n const memory = await client.memories.get(id);\n context.print(renderOne(memory, memoryFields, { format: context.flags.output }));\n return 0;\n}\n\nexport async function listSpacesCommand(context: CommandContext): Promise<number> {\n const client = await context.client();\n const { data } = await client.spaces.list().first();\n\n if (data.length === 0) {\n context.print(\"No Spaces yet.\");\n return 0;\n }\n\n const columns: readonly Column<Space>[] = [\n { header: \"id\", value: (s) => s.id },\n { header: \"name\", value: (s) => s.name },\n { header: \"kind\", value: (s) => s.kind },\n { header: \"memories\", value: (s) => (s.memoryCount === undefined ? \"\" : String(s.memoryCount)) },\n { header: \"created\", value: (s) => shortDate(s.createdAt) }\n ];\n\n context.print(render(data, columns, { format: context.flags.output }));\n return 0;\n}\n\n/** `pm status` \u2014 is the service up, and does this credential work. */\nexport async function statusCommand(context: CommandContext): Promise<number> {\n const client = await context.client();\n const health = await client.health.ready();\n\n context.print(\n renderOne(health, [{ header: \"status\", value: (h) => JSON.stringify(h) }], {\n format: context.flags.output === \"table\" ? \"yaml\" : context.flags.output\n })\n );\n return 0;\n}\n\n/**\n * A short, stable digest of the captured text, for the idempotency key.\n *\n * FNV-1a rather than a crypto hash: this is a deduplication token the server\n * treats as opaque, not a security boundary, and it keeps the key short enough\n * to read in a log line.\n */\nfunction hash(text: string): string {\n let value = 0x811c9dc5;\n for (let index = 0; index < text.length; index += 1) {\n value ^= text.charCodeAt(index);\n value = Math.imul(value, 0x01000193) >>> 0;\n }\n return value.toString(16).padStart(8, \"0\");\n}\n\n/**\n * `pm spaces create \"Acme\"` \u2014 the command that did not exist.\n *\n * Spaces could be listed from here and created only through the SDK or a raw\n * curl, which made the first thing the README tells somebody to do impossible\n * from the tool the README is about.\n */\nexport async function createSpaceCommand(context: CommandContext): Promise<number> {\n const name = context.args.words.slice(2).join(\" \").trim();\n\n if (name === \"\") {\n context.error('A Space needs a name. Try `pm spaces create \"Acme\"`.');\n return 2;\n }\n\n const kind = stringFlag(context.args, \"kind\") ?? \"project\";\n const description = stringFlag(context.args, \"description\");\n\n const client = await context.client();\n const space = await client.spaces.create({\n name,\n kind: kind as Space[\"kind\"],\n ...(description ? { description } : {})\n });\n\n if (context.flags.output !== \"table\") {\n context.print(renderOne(space, spaceFields, { format: context.flags.output }));\n return 0;\n }\n\n context.print(`Created \"${space.name}\".`);\n // The id, because everything else that takes a Space takes this.\n context.print(` id ${space.id}`);\n context.print(` kind ${space.kind}`);\n context.print(\"\");\n context.print(`Use it here with: pm setup --space \"${space.name}\"`);\n return 0;\n}\n\nconst spaceFields: readonly Column<Space>[] = [\n { header: \"id\", value: (s) => s.id },\n { header: \"name\", value: (s) => s.name },\n { header: \"kind\", value: (s) => s.kind }\n];\n\n/**\n * `pm spaces delete \"Acme\" --memories keep|delete`.\n *\n * The flag has no default, here or in the API, and that is the whole design of\n * this command. \"Delete this Space\" means the label to some people and\n * everything inside it to others, and a client that guessed would destroy or\n * keep somebody's material without being asked. Refusing to guess costs one\n * flag; guessing wrong costs a corpus.\n */\nexport async function deleteSpaceCommand(context: CommandContext): Promise<number> {\n const named = context.args.words.slice(2).join(\" \").trim();\n\n if (named === \"\") {\n context.error('Which Space? Try `pm spaces delete \"Acme\" --memories keep`.');\n return 2;\n }\n\n const memories = stringFlag(context.args, \"memories\");\n if (memories !== \"keep\" && memories !== \"delete\") {\n context.error(\"Say what happens to what is in it \u2014 there is no default:\");\n context.error(\"\");\n context.error(` pm spaces delete \"${named}\" --memories keep the memories survive`);\n context.error(` pm spaces delete \"${named}\" --memories delete they go with it`);\n return 2;\n }\n\n const client = await context.client();\n const { data } = await client.spaces.list({ limit: 200 }).first();\n\n // A name, because that is what a person has. Ids are accepted too \u2014 the same\n // rule every other Space argument in this CLI follows.\n const found = named.startsWith(\"space_\")\n ? data.find((one) => one.id === named)\n : data.find((one) => one.name.toLowerCase() === named.toLowerCase());\n\n if (!found) {\n context.error(`No Space called \"${named}\". Run \\`pm spaces list\\` to see them.`);\n return 1;\n }\n\n const result = await client.spaces.delete(found.id, { memories });\n\n if (context.flags.output !== \"table\") {\n context.print(JSON.stringify({ id: found.id, ...result }, undefined, 2));\n return 0;\n }\n\n context.print(`Deleted \"${found.name}\".`);\n // Both numbers, always. A memory filed in another Space as well is detached\n // rather than destroyed, and \"deleted 4, kept 11\" is the only way to see it.\n context.print(` ${result.deleted} memories deleted, ${result.kept} kept`);\n return 0;\n}\n\n/**\n * `pm spaces merge \"Work\" \"Personal\" --name \"Everything\"`.\n *\n * Additive. A memory ends up in the sources AND the result, every search over\n * a source returns what it did before, and undoing it is deleting the Space\n * this makes. Said out loud in the output because \"merge\" everywhere else\n * means the sources stop existing.\n */\nexport async function mergeSpacesCommand(context: CommandContext): Promise<number> {\n const named = context.args.words.slice(2);\n const name = stringFlag(context.args, \"name\");\n\n if (named.length < 2 || !name) {\n context.error(\"Two or more Spaces, and a name for the one this makes:\");\n context.error(\"\");\n context.error(' pm spaces merge \"Work\" \"Personal\" --name \"Everything\"');\n return 2;\n }\n\n const client = await context.client();\n const { data } = await client.spaces.list({ limit: 200 }).first();\n\n const ids: string[] = [];\n for (const one of named) {\n const found = one.startsWith(\"space_\")\n ? data.find((space) => space.id === one)\n : data.find((space) => space.name.toLowerCase() === one.toLowerCase());\n\n if (!found) {\n context.error(`No Space called \"${one}\". Run \\`pm spaces list\\` to see them.`);\n return 1;\n }\n ids.push(found.id);\n }\n\n // `merge` answers with the new Space AND how many memories were filed into\n // it, which is the number worth printing: \"created\" alone does not say\n // whether it drew anything.\n const { space, added } = await client.spaces.merge({ sourceIds: ids, name });\n\n if (context.flags.output !== \"table\") {\n context.print(renderOne(space, spaceFields, { format: context.flags.output }));\n return 0;\n }\n\n context.print(`Created \"${space.name}\" from ${ids.length} Spaces, holding ${added} memories.`);\n context.print(` id ${space.id}`);\n context.print(\"\");\n context.print(\"The Spaces it drew from are unchanged \u2014 nothing was moved or deleted.\");\n return 0;\n}\n", "import type { PersistMemory, Space } from \"@persistmemory/sdk\";\nimport { listFlag } from \"./args\";\nimport type { CommandContext } from \"./context\";\nimport { findWorkspace } from \"./workspace\";\n\n/**\n * Which spaces this command should read from and write into.\n *\n * Precedence, highest first:\n *\n * --space work,acme an instruction for this one command\n * PERSISTMEMORY_SPACE what a CI job exports\n * .persistmemory.json what `pm setup` wrote for this folder\n * nothing everything the account has\n *\n * NAMES ARE ACCEPTED, not just ids. `--space` used to be passed through to the\n * API untouched, so `--space work` sent the literal word \"work\" as a space id\n * and silently matched nothing \u2014 a search that quietly looked in an empty\n * place, which is worse than an error because the answer looks like \"you have\n * no memories about this\".\n */\nexport async function spacesFor(\n context: CommandContext,\n client: PersistMemory,\n env: NodeJS.ProcessEnv = process.env\n): Promise<readonly string[] | undefined> {\n const asked =\n listFlag(context.args, \"space\", \"spaces\") ??\n splitList(env[\"PERSISTMEMORY_SPACE\"]) ??\n workspaceSpace();\n\n if (!asked || asked.length === 0) return undefined;\n\n // Only fetched when a name needs resolving. Somebody passing ids \u2014 a script,\n // or the workspace file this command wrote itself \u2014 should not pay for a\n // round trip to confirm what they already know.\n if (asked.every(looksLikeId)) return asked;\n\n const { data } = await client.spaces.list({ limit: 200 }).first();\n return asked.map((one) => (looksLikeId(one) ? one : resolveName(one, data)));\n}\n\nfunction workspaceSpace(): readonly string[] | undefined {\n const found = findWorkspace();\n return found?.config.space ? [found.config.space.id] : undefined;\n}\n\nfunction splitList(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined;\n const items = raw\n .split(\",\")\n .map((one) => one.trim())\n .filter((one) => one.length > 0);\n return items.length > 0 ? items : undefined;\n}\n\n/** The server's own prefix. Anything else is treated as a name to look up. */\nfunction looksLikeId(value: string): boolean {\n return value.startsWith(\"space_\");\n}\n\nfunction resolveName(name: string, spaces: readonly Space[]): string {\n const wanted = name.trim().toLowerCase();\n const matches = spaces.filter((one) => one.name.trim().toLowerCase() === wanted);\n\n if (matches.length === 1) return matches[0]!.id;\n\n if (matches.length === 0) {\n throw new Error(\n `No Space called \"${name}\". Run \\`pm list spaces\\` to see yours, or ` +\n `\\`pm spaces create \"${name}\"\\` to make it.`\n );\n }\n\n // Two spaces may share a name \u2014 nothing stops it, and picking one would put\n // memories somewhere the person did not choose.\n throw new Error(\n `More than one Space is called \"${name}\": ${matches\n .map((one) => one.id)\n .join(\", \")}. Name it by id.`\n );\n}\n", "import { PersistMemory } from \"@persistmemory/sdk\";\nimport { PersistMemoryError } from \"@persistmemory/sdk\";\nimport { boolFlag, numberFlag, parseArgs, stringFlag } from \"./args\";\nimport type { ParsedArgs } from \"./args\";\nimport { pathsFor, resolve } from \"./config\";\nimport type { Paths } from \"./config\";\nimport { isOutputFormat } from \"./output\";\nimport type { OutputFormat } from \"./output\";\nimport { HELP, VERSION } from \"./help\";\nimport { refreshUpdateCache, updateCacheFile, updateNotice } from \"./update\";\nimport { NotSignedIn, clientFor } from \"./session\";\nimport { askOnTty, readSecretFromTty } from \"./context\";\nimport type { CommandContext, GlobalFlags } from \"./context\";\nimport { agentCommand } from \"./commands/agent\";\nimport { driveCommand, mailCommand } from \"./commands/google\";\nimport { requestsCommand } from \"./commands/requests\";\nimport { authCommand } from \"./commands/auth\";\nimport { setupCommand } from \"./commands/setup\";\nimport { deleteCommand, uninstallCommand, updateCommand } from \"./commands/maintain\";\nimport { sessionCommand } from \"./commands/session\";\nimport {\n createSpaceCommand,\n deleteSpaceCommand,\n mergeSpacesCommand,\n getMemoryCommand,\n listMemoriesCommand,\n listSpacesCommand,\n rememberCommand,\n searchCommand,\n statusCommand\n} from \"./commands/memory\";\n\n/**\n * The entry point.\n *\n * Returns an exit code rather than calling `process.exit`, so the whole CLI is\n * callable from a test. Everything that touches the world \u2014 stdout, the home\n * directory, `fetch`, the browser \u2014 arrives through `Deps` for the same reason.\n */\nexport interface Deps {\n readonly argv: readonly string[];\n readonly env?: NodeJS.ProcessEnv;\n readonly paths?: Paths;\n readonly fetch?: typeof globalThis.fetch;\n readonly stdout?: (line: string) => void;\n readonly stderr?: (line: string) => void;\n readonly openBrowser?: (url: string) => Promise<void>;\n readonly readSecret?: (prompt: string) => Promise<string>;\n readonly ask?: (prompt: string) => Promise<string>;\n readonly isTty?: boolean;\n}\n\nexport async function run(deps: Deps): Promise<number> {\n const args = parseArgs(deps.argv);\n const print = deps.stdout ?? ((line: string) => process.stdout.write(`${line}\\n`));\n const error = deps.stderr ?? ((line: string) => process.stderr.write(`${line}\\n`));\n\n // `--version` BEFORE the bare-invocation check, not after. Both `pm` and\n // `pm --version` carry no positional words, so testing for \"no words\" first\n // made `--version` print the help page \u2014 which reads as the flag not\n // existing at all.\n if (boolFlag(args, \"version\", \"v\")) {\n print(VERSION);\n return 0;\n }\n if (boolFlag(args, \"help\", \"h\")) {\n print(HELP);\n return 0;\n }\n\n const flags = globalFlags(args, deps);\n if (flags === \"invalid-output\") {\n error(`--output must be one of table, json, yaml, csv, tsv.`);\n return 2;\n }\n if (flags === \"invalid-limit\") {\n error(\"--limit must be a number.\");\n return 2;\n }\n\n const paths = deps.paths ?? pathsFor();\n const resolved = resolve({\n paths,\n profileFlag: flags.profile,\n apiUrlFlag: flags.apiUrl,\n // A prompted key is not known yet; only a literal one participates here.\n apiKeyFlag: typeof flags.apiKey === \"string\" ? flags.apiKey : undefined,\n ...(deps.env ? { env: deps.env } : {})\n });\n\n const fetchImpl = deps.fetch ?? globalThis.fetch;\n const oauth = {\n fetch: fetchImpl,\n ...(deps.openBrowser ? { openBrowser: deps.openBrowser } : {}),\n print\n };\n const session = { ...oauth, paths, userAgent: `persistmemory-cli/${VERSION}` };\n\n const context: CommandContext = {\n args,\n flags,\n paths,\n resolved,\n oauth,\n session,\n client: () => clientFor(resolved, session),\n print,\n error,\n readSecret: deps.readSecret ?? readSecretFromTty,\n ask: deps.ask ?? askOnTty,\n isTty: deps.isTty ?? process.stdin.isTTY ?? false\n };\n\n /**\n * A bare `pm` on a terminal opens a session; piped, it prints help.\n *\n * The split is the same one `--output` makes: a person who typed `pm` and is\n * looking at a prompt wants to start talking, and a script that ran `pm` with\n * no arguments has made a mistake and needs to be told what the commands are\n * \u2014 not left holding an interactive prompt that will never be answered.\n */\n if (args.words.length === 0) {\n if (!(deps.isTty ?? process.stdin.isTTY ?? false)) {\n print(HELP);\n return 0;\n }\n return sessionCommand(context);\n }\n\n try {\n /*\n The update check, before the command and never in its way.\n\n Reads a cache written by the LAST run, so nothing here waits on the\n network; the refresh at the end of this function is what fills it. Silent\n unless there is something to say, and silent always in a script \u2014 a\n version notice on stdout would corrupt piped JSON, and one in a CI log\n helps nobody.\n */\n await offerUpdate(context, deps);\n\n const code = await dispatch(context);\n\n // After the command, so a slow registry cannot delay an answer. Not\n // awaited for its result \u2014 a failed check is not a failed command.\n void refreshUpdateCache(updateDeps(context, deps));\n\n return code;\n } catch (caught) {\n return report(caught, error);\n }\n}\n\n/**\n * Tells somebody a newer version exists, and offers to install it.\n *\n * Asked rather than done silently, with yes as the default: an update that\n * runs itself in the middle of an unrelated command surprises people, can take\n * ten seconds, and on a shared machine may fail on permissions halfway\n * through. `PERSISTMEMORY_AUTO_UPDATE=1` skips the question for anybody who\n * would rather never be asked.\n */\nasync function offerUpdate(context: CommandContext, deps: Deps): Promise<void> {\n // `pm update` and `pm uninstall` must not be interrupted by an offer to\n // update: one is already doing it and the other is removing the program.\n const verb = context.args.words[0];\n if (verb === \"update\" || verb === \"upgrade\" || verb === \"uninstall\") return;\n\n const notice = updateNotice(updateDeps(context, deps));\n if (!notice) return;\n\n const env = deps.env ?? process.env;\n\n if (env[\"PERSISTMEMORY_AUTO_UPDATE\"]) {\n context.print(notice.split(\"\\n\")[0] ?? \"\");\n await updateCommand(context);\n return;\n }\n\n // stderr, so a person sees it and a pipe does not.\n context.error(notice);\n}\n\nfunction updateDeps(context: CommandContext, deps: Deps) {\n return {\n file: updateCacheFile(context.paths.dir),\n current: VERSION,\n ...(deps.fetch ? { fetch: deps.fetch } : {}),\n ...(deps.env ? { env: deps.env } : {}),\n isTty: context.isTty,\n quiet: context.flags.quiet\n };\n}\n\nasync function dispatch(context: CommandContext): Promise<number> {\n const [verb, noun] = context.args.words;\n\n switch (verb) {\n case \"auth\":\n return authCommand(context);\n case \"setup\":\n case \"init\":\n return setupCommand(context);\n /*\n `pm version` as well as `--version`.\n\n It is what people type, and answering \"Unknown command\" to somebody\n asking which version they are running \u2014 while a flag two characters away\n answers it \u2014 is a needless dead end.\n */\n case \"version\":\n context.print(VERSION);\n return 0;\n\n case \"update\":\n case \"upgrade\":\n return updateCommand(context);\n case \"uninstall\":\n return uninstallCommand(context);\n case \"delete\":\n return deleteCommand(context);\n case \"agent\":\n return agentCommand(context);\n case \"chat\":\n case \"session\":\n return sessionCommand(context);\n case \"remember\":\n return rememberCommand(context);\n case \"search\":\n return searchCommand(context);\n case \"status\":\n return statusCommand(context);\n case \"requests\":\n return requestsCommand(context);\n\n /*\n Google, through the API rather than through Google.\n\n A laptop holds a bearer token and no database connection, so the\n credential it can prove is the one the API accepts. Google's own tokens\n never leave the deployment \u2014 which is what stops a stolen\n `~/.persistmemory` from being a stolen mailbox.\n */\n case \"drive\":\n return driveCommand(context);\n case \"mail\":\n return mailCommand(context);\n\n /**\n * `pm <verb> <noun>`, the grammar the Harness CLI uses.\n *\n * Worth copying rather than inventing: a person who has typed\n * `list pipelines` can guess `list memories` without opening the help, and\n * a consistent grammar is what lets a tool grow past the handful of\n * commands anybody can memorise.\n */\n case \"spaces\":\n case \"space\":\n if (noun === \"create\" || noun === \"new\") return createSpaceCommand(context);\n if (noun === \"delete\" || noun === \"remove\") return deleteSpaceCommand(context);\n if (noun === \"merge\") return mergeSpacesCommand(context);\n if (noun === undefined || noun === \"list\") return listSpacesCommand(context);\n context.error(`Cannot \"pm spaces ${noun}\". Try list, create, delete or merge.`);\n return 2;\n\n case \"list\":\n if (noun === \"memories\" || noun === \"memory\") return listMemoriesCommand(context);\n if (noun === \"spaces\" || noun === \"space\") return listSpacesCommand(context);\n context.error(`Cannot list \"${noun ?? \"\"}\". Try memories or spaces.`);\n return 2;\n\n case \"get\":\n if (noun === \"memory\") return getMemoryCommand(context);\n context.error(`Cannot get \"${noun ?? \"\"}\". Try memory.`);\n return 2;\n\n default:\n context.error(`Unknown command \"${verb ?? \"\"}\". Run \\`pm --help\\`.`);\n return 2;\n }\n}\n\nfunction globalFlags(\n args: ParsedArgs,\n deps: Deps\n): GlobalFlags | \"invalid-output\" | \"invalid-limit\" {\n const requested = stringFlag(args, \"output\", \"o\");\n if (requested !== undefined && !isOutputFormat(requested)) return \"invalid-output\";\n\n const limit = numberFlag(args, \"limit\", \"n\");\n if (limit === \"invalid\") return \"invalid-limit\";\n\n /**\n * Table for a person, JSON for a pipe.\n *\n * Chosen from whether stdout is a terminal rather than fixed, so\n * `pm search x` is readable and `pm search x | jq .` works without anyone\n * having to discover a flag. A fixed default makes one of those two\n * audiences worse off for no reason.\n */\n const isTty = deps.isTty ?? process.stdout.isTTY ?? false;\n const output: OutputFormat = (requested as OutputFormat) ?? (isTty ? \"table\" : \"json\");\n\n const apiKey = args.flags[\"api-key\"];\n // Bound to locals first. Spreading the call directly widens each field to\n // `string | undefined`, which `exactOptionalPropertyTypes` treats as a\n // different type from an absent one.\n const profile = stringFlag(args, \"profile\", \"p\");\n const apiUrl = stringFlag(args, \"api-url\");\n\n return {\n ...(profile !== undefined ? { profile } : {}),\n ...(apiUrl !== undefined ? { apiUrl } : {}),\n ...(apiKey === true || typeof apiKey === \"string\" ? { apiKey } : {}),\n output,\n quiet: boolFlag(args, \"quiet\", \"q\"),\n ...(limit !== undefined ? { limit } : {})\n };\n}\n\n/**\n * Turns a thrown thing into something a person can act on.\n *\n * Exit codes are distinguished because scripts read them: 2 for \"you typed\n * something wrong\", 3 for \"you are not signed in\", 1 for everything else. A\n * CLI that returns 1 for all three makes `pm search x || pm auth login`\n * impossible to write.\n */\nfunction report(caught: unknown, error: (line: string) => void): number {\n if (caught instanceof NotSignedIn) {\n error(caught.message);\n return 3;\n }\n\n if (caught instanceof PersistMemoryError) {\n // The SDK's message, which already excludes the credential \u2014 see `redact`\n // in its errors module. Re-serialising the whole error here is how a key\n // ends up in somebody's CI log.\n error(caught.message);\n return caught.status === 401 || caught.status === 403 ? 3 : 1;\n }\n\n error(caught instanceof Error ? caught.message : String(caught));\n return 1;\n}\n\nexport { PersistMemory };\n", "#!/usr/bin/env node\nimport { run } from \"./index\";\n\n/**\n * The executable.\n *\n * Thin on purpose: everything testable lives in `run`, and this file exists to\n * do the two things a test must never do \u2014 read the real argv and set the\n * process's exit code.\n */\nrun({ argv: process.argv.slice(2) }).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n }\n);\n"],
5
- "mappings": "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",
6
- "names": ["message", "status", "resolve", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "join", "resolve", "resolve", "resolve", "answer", "finish", "homedir", "join", "resolve", "existsSync", "readFileSync", "statSync", "writeFileSync", "existsSync", "readFileSync", "writeFileSync", "dirname", "join", "resolve", "write", "message", "resolve", "homedir", "existsSync", "existsSync", "statSync", "join", "writeFileSync", "readFileSync", "resolve", "homedir", "complain", "message", "writeFileSync", "basename", "resolve", "readFileSync", "resolve", "basename", "writeFileSync", "readFileSync", "response", "message", "existsSync", "writeFileSync", "resolve", "resolve", "existsSync", "writeFileSync", "existsSync", "readFileSync", "writeFileSync", "dirname", "join", "answer", "wanted", "existsSync", "dirname", "resolve", "existsSync", "answer", "resolve", "dirname", "createInterface", "relative", "existsSync", "mkdirSync", "readFileSync", "join", "HELP", "createInterface", "resolve", "message", "answer", "relative", "write", "readFileSync", "wanted", "readFileSync", "space"]
3
+ "sources": ["../node_modules/@persistmemory/sdk/src/query.ts", "../node_modules/@persistmemory/sdk/src/backoff.ts", "../node_modules/@persistmemory/sdk/src/errors.ts", "../node_modules/@persistmemory/sdk/src/http.ts", "../node_modules/@persistmemory/sdk/src/pagination.ts", "../node_modules/@persistmemory/sdk/src/resources/memories.ts", "../node_modules/@persistmemory/sdk/src/resources/search.ts", "../node_modules/@persistmemory/sdk/src/resources/spaces.ts", "../node_modules/@persistmemory/sdk/src/resources/ingestion.ts", "../node_modules/@persistmemory/sdk/src/resources/knowledge.ts", "../node_modules/@persistmemory/sdk/src/resources/conversations.ts", "../node_modules/@persistmemory/sdk/src/resources/integrations.ts", "../node_modules/@persistmemory/sdk/src/resources/health.ts", "../node_modules/@persistmemory/sdk/src/resources/agent.ts", "../node_modules/@persistmemory/sdk/src/client.ts", "../src/args.ts", "../src/config.ts", "../src/output.ts", "../src/help.ts", "../src/update.ts", "../src/auth/oauth.ts", "../src/auth/pkce.ts", "../src/auth/loopback.ts", "../src/session.ts", "../src/context.ts", "../src/commands/agent.ts", "../src/files.ts", "../src/commands/google.ts", "../src/commands/requests.ts", "../src/workspace.ts", "../src/commands/setup.ts", "../src/commands/auth.ts", "../src/commands/maintain.ts", "../src/commands/session.ts", "../src/events.ts", "../src/commands/memory.ts", "../src/spaces.ts", "../src/index.ts", "../src/bin.ts"],
4
+ "sourcesContent": ["/**\n * Turning parameters into a query string the API's parser reads the way we mean.\n *\n * Its own module because both the request loop and every list resource need\n * it, and putting it in either one would have the other importing a transport\n * to build a string.\n */\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | readonly number[]\n | undefined;\n\nexport type QueryParams = Readonly<Record<string, QueryValue>>;\n\n/**\n * Builds a query string the API's parser will read the way we mean it.\n *\n * Arrays repeat the key - `?spaceIds=a&spaceIds=b` - because that is what\n * Express hands to the schemas, which accept either one value or a list.\n * Comma-joining would arrive as a single id containing a comma and match\n * nothing, with no error to say why.\n *\n * Booleans are sent as `true`/`false` strings. The API parses those\n * explicitly, because `Boolean(\"false\")` is `true` and a flag written that way\n * can never be turned off.\n */\nexport function encodeQuery(params?: QueryParams): string {\n if (!params) return \"\";\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n // Undefined is dropped, never sent. `?cursor=undefined` is a string the\n // server tries to decode, and the 400 it produces names the cursor rather\n // than the caller who forgot to omit it.\n if (value === undefined) continue;\n\n if (Array.isArray(value)) {\n for (const one of value as readonly (string | number)[]) search.append(key, String(one));\n continue;\n }\n search.append(key, String(value));\n }\n\n const encoded = search.toString();\n return encoded ? `?${encoded}` : \"\";\n}\n\n/**\n * The two parameters every list shares, plus whatever the endpoint adds.\n *\n * Shared because the cursor rule is subtle enough to get wrong once per\n * resource: the PAGINATOR's cursor wins over the caller's. The caller's seeds\n * the first page - resuming from a bookmark - and the paginator supplies every\n * page after that. Letting the caller's win would re-read the same page\n * forever, which looks like an account that never ends.\n */\nexport function pageQuery(\n params: { readonly limit?: number; readonly cursor?: string },\n cursor: string | undefined,\n extra: QueryParams\n): QueryParams {\n return {\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(cursor !== undefined\n ? { cursor }\n : params.cursor !== undefined\n ? { cursor: params.cursor }\n : {}),\n ...extra\n };\n}\n", "/**\n * How long to wait before trying again.\n *\n * Exponential, capped, and jittered, for the reasons the rest of this repo\n * gives in `@persistmemory/async`:\n *\n * exponential a cause that has not cleared in 200ms may clear in two\n * seconds; hammering it every 200ms spends the attempts faster\n * without giving it time to recover.\n *\n * capped unbounded doubling reaches minutes, and a caller waiting\n * inside one function call cannot tell that from a hang.\n *\n * jittered the one that gets skipped, and the one that matters most. An\n * outage fails every in-flight request at once; without jitter\n * every client waits exactly two seconds and retries in the\n * same millisecond, so the recovering service is hit by the\n * whole fleet and knocked over again. The retry storm is caused\n * by the retry policy.\n *\n * Duplicated here rather than imported from `@persistmemory/async` on purpose:\n * this package is published to npm and installed by people who have no reason\n * to pull in a queue runtime, a Redis client and a dead-letter store to make\n * an HTTP request.\n */\nexport interface BackoffOptions {\n readonly baseMs?: number;\n readonly maxMs?: number;\n readonly factor?: number;\n /** 0 = none, 1 = full. Full is the right default; see below. */\n readonly jitter?: number;\n /** Injected so a test is not at the mercy of the random number generator. */\n readonly random?: () => number;\n}\n\n/**\n * Short by server standards.\n *\n * A queue worker can afford to come back in a minute. A caller is blocked\n * inside `await client.search(...)` and has a user watching, so the whole\n * retry budget has to fit inside a request timeout rather than outlast it.\n */\nexport const DEFAULT_BACKOFF = { baseMs: 250, maxMs: 8_000, factor: 2, jitter: 1 } as const;\n\n/**\n * The delay before attempt `attempt` (1-based).\n *\n * FULL jitter by default - a random point in [0, ceiling] rather than\n * ceiling plus or minus a wobble. It sounds worse and measures better:\n * partial jitter leaves the retries clustered around the same instant, which\n * is the thing that overwhelms a service coming back up.\n */\nexport function backoffMs(attempt: number, options: BackoffOptions = {}): number {\n const base = options.baseMs ?? DEFAULT_BACKOFF.baseMs;\n const max = options.maxMs ?? DEFAULT_BACKOFF.maxMs;\n const factor = options.factor ?? DEFAULT_BACKOFF.factor;\n const jitter = clamp01(options.jitter ?? DEFAULT_BACKOFF.jitter);\n const random = options.random ?? Math.random;\n\n // Clamped at 1: attempt 0 would give a negative exponent and a delay\n // shorter than the base, so the first retry would be the fastest one.\n const exponent = Math.max(0, Math.floor(attempt) - 1);\n // Capped BEFORE jitter. Capping after lets an un-jittered value of minutes\n // be scaled down to something that looks reasonable while the underlying\n // growth is still unbounded.\n const ceiling = Math.min(max, base * Math.pow(factor, exponent));\n\n if (jitter <= 0) return Math.round(ceiling);\n\n const fixed = ceiling * (1 - jitter);\n return Math.round(fixed + random() * (ceiling - fixed));\n}\n\n/**\n * The delay to actually use, honouring what the server asked for.\n *\n * `Retry-After` is taken as a FLOOR, not verbatim. Verbatim would let a\n * one-second hint on the fifth consecutive 429 undo the backoff entirely and\n * put us straight back into the limit; ignoring it would have us retry before\n * the window resets and spend an attempt learning what we were already told.\n *\n * A server asking for LONGER than our cap is believed. The cap exists to stop\n * our own growth running away, not to overrule a service that has told us\n * when it will be ready.\n */\nexport function delayFor(args: {\n attempt: number;\n retryAfterSeconds?: number;\n options?: BackoffOptions;\n}): number {\n const computed = backoffMs(args.attempt, args.options ?? {});\n if (args.retryAfterSeconds === undefined || !Number.isFinite(args.retryAfterSeconds)) {\n return computed;\n }\n return Math.max(computed, Math.max(0, args.retryAfterSeconds) * 1000);\n}\n\nfunction clamp01(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.min(1, Math.max(0, value));\n}\n", "/**\n * What went wrong, in a shape a caller can branch on.\n *\n * One class per thing a caller can DO about it, which is not the same as one\n * class per status code. `RateLimited` says wait, `Validation` says fix the\n * request, `NotFound` says the id is wrong or gone, `Conflict` says re-read\n * and try again. A code nobody branches on is a string that only looks like an\n * API, so 402 and 418 and anything else unmapped land on the base class rather\n * than growing a name each.\n *\n * The API's own error envelope is\n *\n * { error: { code, message, fields?, requestId } }\n *\n * and `code` is the stable part. Branch on the class or on `code`, never on\n * `message`: messages get rewritten for clarity, translated, and deliberately\n * made vaguer for security, and a client keyed to message text breaks silently\n * when any of that happens.\n *\n * NOTHING in here ever holds the API key. Errors are logged, serialised into\n * bug reports and posted into issue trackers, which is exactly how a\n * credential escapes - see `redact` at the bottom of this file, which every\n * message this module builds passes through.\n */\n\n/** The stable codes the API returns. Unknown strings are possible; see below. */\nexport type ErrorCode =\n | \"VALIDATION_ERROR\"\n | \"UNAUTHORIZED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"CONFLICT\"\n | \"IDEMPOTENCY_MISMATCH\"\n | \"RATE_LIMITED\"\n | \"PAYLOAD_TOO_LARGE\"\n | \"DEPENDENCY_UNAVAILABLE\"\n | \"PROCESSING_FAILED\"\n | \"INTERNAL_ERROR\"\n // Widened on purpose. A server that adds a code should not make an older\n // SDK throw a TypeError while parsing the error that explains the problem.\n | (string & {});\n\nexport interface ApiErrorInit {\n readonly status: number;\n readonly code: ErrorCode;\n readonly message: string;\n /** Which fields were rejected, for a validation failure. */\n readonly fields?: Readonly<Record<string, string>>;\n /** Ties this failure to the server's log lines. Quote it in support. */\n readonly requestId?: string;\n /** Seconds the server asked us to wait, when it said. */\n readonly retryAfterSeconds?: number;\n}\n\n/**\n * The base every failure from this SDK inherits from.\n *\n * `retryable` is the single question the request loop asks. It lives on the\n * error rather than in a table beside it because the two drift: a table says\n * 429 is retryable while the error that reaches the loop is a transport\n * failure nobody thought to add.\n */\nexport class PersistMemoryError extends Error {\n readonly status: number;\n readonly code: ErrorCode;\n readonly fields?: Readonly<Record<string, string>>;\n readonly requestId?: string;\n readonly retryAfterSeconds?: number;\n /** Retrying this exact request could plausibly succeed. */\n readonly retryable: boolean = false;\n\n constructor(init: ApiErrorInit) {\n super(redact(init.message));\n this.name = new.target.name;\n this.status = init.status;\n this.code = init.code;\n if (init.fields) this.fields = init.fields;\n if (init.requestId) this.requestId = init.requestId;\n if (init.retryAfterSeconds !== undefined) this.retryAfterSeconds = init.retryAfterSeconds;\n }\n\n /**\n * A one-line summary safe to log.\n *\n * Provided so callers reach for this instead of `JSON.stringify(error)`,\n * which walks own properties and would pick up anything a future field\n * holds. Everything here is already server-supplied and key-free.\n */\n override toString(): string {\n const id = this.requestId ? ` requestId=${this.requestId}` : \"\";\n return `${this.name}: [${this.status} ${this.code}] ${this.message}${id}`;\n }\n}\n\n/** 401. The key is missing, malformed, revoked, or the session expired. */\nexport class AuthenticationError extends PersistMemoryError {}\n\n/**\n * 403. Known caller, and this credential will never be enough.\n *\n * Distinct from `AuthenticationError` because the fix is different: 401 means\n * present a credential, 403 means this key's scopes are wrong and no amount of\n * retrying or re-signing will change it. A read-only key calling `remember`\n * lands here.\n */\nexport class PermissionDeniedError extends PersistMemoryError {}\n\n/** 404. Does not exist, or is not yours - the API answers both the same way. */\nexport class NotFoundError extends PersistMemoryError {}\n\n/** 400 and 422. The request was wrong; `fields` says where. */\nexport class ValidationError extends PersistMemoryError {}\n\n/** 409. Something changed underneath. Re-read, then try again. */\nexport class ConflictError extends PersistMemoryError {}\n\n/**\n * 429. Slow down.\n *\n * `retryAfterSeconds` comes from the `Retry-After` header, which the API\n * always sets on a 429. It is not advice - it is the only number that knows\n * when the window resets, and computing our own backoff instead means being\n * refused again and spending an attempt to learn what we were already told.\n */\nexport class RateLimitError extends PersistMemoryError {\n override readonly retryable = true;\n}\n\n/**\n * 5xx. Ours, not yours.\n *\n * Retryable, because a 500 or a 503 is usually a dependency that has fallen\n * over and will come back - and the alternative, giving up on the first one,\n * turns a three-second blip into a failed job. Retryable does not mean\n * REPEATED: a POST still needs an idempotency key before this client will send\n * it again, because a 500 may have been raised after the work was done.\n */\nexport class ServerError extends PersistMemoryError {\n override readonly retryable = true;\n}\n\n/**\n * The request never got an answer: DNS, connect, reset, or a body that died\n * mid-stream.\n *\n * Status 0, because there was no status. Retryable in general - but see\n * `isRetryable` in `client.ts`, which refuses to retry a POST that may already\n * have been processed, since a connection dying after the server accepted the\n * request looks identical from here.\n */\nexport class ConnectionError extends PersistMemoryError {\n override readonly retryable = true;\n\n constructor(message: string) {\n super({ status: 0, code: \"CONNECTION_ERROR\", message });\n }\n}\n\n/** The deadline passed. A distinct class because the fix is often a bigger one. */\nexport class TimeoutError extends PersistMemoryError {\n override readonly retryable = true;\n\n constructor(message: string) {\n super({ status: 0, code: \"TIMEOUT\", message });\n }\n}\n\n/**\n * The caller's own AbortSignal fired.\n *\n * NOT retryable, and not a timeout: someone asked for this to stop, and\n * retrying it is the one thing they have said they do not want.\n */\nexport class AbortError extends PersistMemoryError {\n constructor(message = \"The request was aborted by the caller.\") {\n super({ status: 0, code: \"ABORTED\", message });\n }\n}\n\ninterface ErrorEnvelope {\n readonly error?: {\n readonly code?: unknown;\n readonly message?: unknown;\n readonly fields?: unknown;\n readonly requestId?: unknown;\n };\n}\n\n/**\n * A response the server refused, turned into the right class.\n *\n * Keyed on the CODE first and the status second. The code is the API's own\n * vocabulary and is the more precise of the two - `IDEMPOTENCY_MISMATCH` is a\n * 422 that means \"you reused a key with a different body\", which is a\n * validation problem and not a generic unprocessable entity.\n *\n * The body is parsed defensively at every step. A 502 from a proxy in front of\n * the API returns HTML, and an SDK that assumes JSON turns a bad gateway into\n * an unhelpful SyntaxError thrown from inside the error handler.\n */\nexport function errorFromResponse(\n status: number,\n body: unknown,\n headers: { get(name: string): string | null }\n): PersistMemoryError {\n const envelope = (body ?? {}) as ErrorEnvelope;\n const code = typeof envelope.error?.code === \"string\" ? envelope.error.code : codeForStatus(status);\n const message =\n typeof envelope.error?.message === \"string\" && envelope.error.message.length > 0\n ? envelope.error.message\n : defaultMessage(status);\n\n // Read for 429 and 503 alike. A 503 with a `Retry-After` is a service\n // telling us when it will be back, and ignoring it because the status was\n // not 429 means retrying into an outage that has said it is not over.\n const retryAfterSeconds =\n status === 429 || status === 503 ? retryAfterOf(headers) : undefined;\n\n const init: ApiErrorInit = {\n status,\n code,\n message,\n ...(isFieldMap(envelope.error?.fields) ? { fields: envelope.error.fields } : {}),\n ...(typeof envelope.error?.requestId === \"string\"\n ? { requestId: envelope.error.requestId }\n : {}),\n ...(retryAfterSeconds !== undefined ? { retryAfterSeconds } : {})\n };\n\n if (status === 429 || code === \"RATE_LIMITED\") return new RateLimitError(init);\n if (status === 401 || code === \"UNAUTHORIZED\") return new AuthenticationError(init);\n if (status === 403 || code === \"FORBIDDEN\") return new PermissionDeniedError(init);\n if (status === 404 || code === \"NOT_FOUND\") return new NotFoundError(init);\n if (status === 409 || code === \"CONFLICT\") return new ConflictError(init);\n if (status === 400 || status === 413 || status === 422) return new ValidationError(init);\n if (status >= 500) return new ServerError(init);\n\n // Anything else - a 405 from a misconfigured proxy, a 402 the API grows\n // later. Named honestly rather than forced into the nearest class, because\n // a caller catching `ValidationError` should not be handed a payment\n // problem.\n return new PersistMemoryError(init);\n}\n\n/**\n * `Retry-After`, in seconds, when the header is one we can trust.\n *\n * Only the delta-seconds form is honoured. The HTTP-date form is also legal\n * and is parsed against the CLIENT's clock, which on a laptop that has been\n * asleep can be minutes out - and a negative delay computed from a skewed\n * clock is a retry storm aimed at a service that just asked for quiet.\n */\nfunction retryAfterOf(headers: { get(name: string): string | null }): number | undefined {\n const raw = headers.get(\"retry-after\");\n if (!raw) return undefined;\n\n const seconds = Number(raw.trim());\n if (!Number.isFinite(seconds) || seconds < 0) return undefined;\n // Capped. A header saying 86400 would otherwise park a caller's retry for a\n // day inside a call they expected to return.\n return Math.min(seconds, 300);\n}\n\nfunction isFieldMap(value: unknown): value is Record<string, string> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n return Object.values(value).every((one) => typeof one === \"string\");\n}\n\nfunction codeForStatus(status: number): ErrorCode {\n if (status === 401) return \"UNAUTHORIZED\";\n if (status === 403) return \"FORBIDDEN\";\n if (status === 404) return \"NOT_FOUND\";\n if (status === 409) return \"CONFLICT\";\n if (status === 429) return \"RATE_LIMITED\";\n if (status === 413) return \"PAYLOAD_TOO_LARGE\";\n if (status >= 500) return \"INTERNAL_ERROR\";\n return \"VALIDATION_ERROR\";\n}\n\nfunction defaultMessage(status: number): string {\n // Deliberately says the body was unreadable rather than inventing a reason.\n // A message claiming \"not found\" for a 404 that was actually an HTML error\n // page from a proxy sends whoever is debugging to the wrong system.\n return `The API returned ${status} with no readable error body.`;\n}\n\n/**\n * Removes anything key-shaped from a string bound for an error message.\n *\n * Every message this module produces goes through here, including the\n * server's own. It should never contain a key - we never send it in a body\n * and the API never echoes it - but \"should never\" is how credentials end up\n * in issue trackers. The cost is one regex on a path that has already failed.\n */\nexport function redact(text: string): string {\n return text.replace(/pm_(live|test)_[A-Za-z0-9_-]+/g, \"pm_$1_[redacted]\");\n}\n", "import type { BackoffOptions } from \"./backoff\";\nimport type { QueryParams } from \"./query\";\nimport { encodeQuery } from \"./query\";\nimport { delayFor } from \"./backoff\";\nimport {\n AbortError,\n ConnectionError,\n PersistMemoryError,\n TimeoutError,\n errorFromResponse,\n redact\n} from \"./errors\";\n\n/**\n * The one place a request is made, retried, timed out and turned into an error.\n *\n * Every resource in this package goes through `request`. That is deliberate:\n * an SDK where each resource calls `fetch` for itself is an SDK with six\n * slightly different retry policies, and the differences only show up during\n * an outage, which is the moment nobody wants to be reading six files.\n *\n * `fetch` is injected rather than imported. It is what makes a test of this\n * incapable of opening a socket by accident, and it is the same reason every\n * provider client in this repo takes one.\n */\nexport type { QueryParams, QueryValue } from \"./query\";\n\nexport interface ClientOptions {\n /**\n * A `pm_live_...` API key, or a session JWT.\n *\n * Held privately and never returned, logged, stringified or put in an error.\n * See `#apiKey` below and the `toJSON` next to it.\n */\n readonly apiKey: string;\n readonly baseUrl?: string;\n readonly fetch?: typeof globalThis.fetch;\n /**\n * Per-attempt deadline, not a budget for the whole call.\n *\n * Per attempt because a whole-call deadline interacts badly with backoff: a\n * request that spent nine seconds waiting between retries would get one\n * second to actually run, and the failure would look like a slow server.\n */\n readonly timeoutMs?: number;\n /** Attempts, not retries. 3 means the original and two more. */\n readonly maxAttempts?: number;\n readonly backoff?: BackoffOptions;\n /** Injected so tests do not spend real seconds asleep. */\n readonly sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n /** Sent on every request, for support and for server-side triage. */\n readonly userAgent?: string;\n}\n\nexport interface RequestOptions {\n /** Cancels the call. A caller's abort is never retried - they asked it to stop. */\n readonly signal?: AbortSignal;\n readonly timeoutMs?: number;\n readonly maxAttempts?: number;\n /**\n * Makes a POST safe to retry.\n *\n * The API deduplicates on this header, so a retry after a timeout finds the\n * first result rather than doing the work twice. Without one, this client\n * will NOT retry a POST that may already have been processed - see\n * `mayRetry`.\n *\n * Give it meaning: `remember:note-42`, not a fresh random value per call. A\n * random one makes every retry a new request, which is exactly what it\n * exists to prevent.\n */\n readonly idempotencyKey?: string;\n}\n\ninterface InternalRequest {\n readonly method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n readonly path: string;\n readonly query?: QueryParams;\n readonly body?: unknown;\n readonly options?: RequestOptions;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.persistmemory.com\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_ATTEMPTS = 3;\n\n/**\n * Methods this client will retry without being told it is safe to.\n *\n * PATCH and DELETE are in here because of what they are in THIS API and not\n * because the RFC calls them idempotent: `PATCH /spaces/{id}` sets named\n * fields to given values, and `DELETE /spaces/{id}/memories` removes a set of\n * memberships. Applying either twice lands in the same state as applying it\n * once. POST is the one that does not - `remember` queues a job every time.\n */\nconst RETRY_WITHOUT_ASKING = new Set([\"GET\", \"HEAD\", \"PATCH\", \"DELETE\"]);\n\nexport class HttpClient {\n /**\n * The credential, in a private field, and never anywhere else.\n *\n * Private (`#`) rather than `readonly`: a public field is enumerable, so\n * `JSON.stringify(client)` and every structured logger that walks own\n * properties would write the key into a log line. `toJSON` and the inspect\n * hook below close the two remaining paths - a bug report pasted from\n * `console.log(client)` is exactly how a key gets shared with strangers.\n */\n readonly #apiKey: string;\n readonly #baseUrl: string;\n readonly #fetch: typeof globalThis.fetch;\n readonly #timeoutMs: number;\n readonly #maxAttempts: number;\n readonly #backoff: BackoffOptions;\n readonly #sleep: (ms: number, signal?: AbortSignal) => Promise<void>;\n readonly #userAgent: string;\n\n constructor(options: ClientOptions) {\n if (typeof options.apiKey !== \"string\" || options.apiKey.trim().length === 0) {\n // Refused here rather than as a 401 from the server, because the server\n // cannot say WHICH of \"missing\", \"empty\" and \"undefined stringified\"\n // happened, and all three come from the same forgotten environment\n // variable.\n throw new PersistMemoryError({\n status: 0,\n code: \"VALIDATION_ERROR\",\n message: \"An API key is required. Pass `apiKey`, or set PERSISTMEMORY_API_KEY.\"\n });\n }\n\n // A newline in a credential is header injection, and the usual source is\n // a key read from a file with `readFileSync` and never trimmed. Trimmed\n // rather than rejected for whitespace, then checked for anything a header\n // value may not carry.\n const key = options.apiKey.trim();\n if (/[\\r\\n\\0]/.test(key)) {\n // The key itself is NOT in this message. It is the one string in the\n // whole package that must never reach an error.\n throw new PersistMemoryError({\n status: 0,\n code: \"VALIDATION_ERROR\",\n message: \"The API key contains characters that cannot go in a header.\"\n });\n }\n\n this.#apiKey = key;\n // Trailing slashes stripped once, here. Left alone, `baseUrl + path`\n // produces `//api/v1/...`, which some proxies normalise and some route to\n // a 404 - a difference that only appears in production.\n this.#baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n this.#fetch = options.fetch ?? globalThis.fetch;\n this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.#maxAttempts = Math.max(1, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS);\n this.#backoff = options.backoff ?? {};\n this.#sleep = options.sleep ?? defaultSleep;\n this.#userAgent = options.userAgent ?? \"persistmemory-sdk-js/0.1.0\";\n }\n\n /**\n * What this object looks like when something serialises it.\n *\n * Both hooks return the same key-free shape. `toJSON` covers\n * `JSON.stringify`, the inspect symbol covers `console.log` under Node, and\n * between them they cover how a credential actually escapes: not through a\n * deliberate log line, but through an object dumped into a bug report.\n */\n toJSON(): Record<string, unknown> {\n return { baseUrl: this.#baseUrl, apiKey: \"[redacted]\" };\n }\n\n [Symbol.for(\"nodejs.util.inspect.custom\")](): Record<string, unknown> {\n return this.toJSON();\n }\n\n async get<T>(path: string, query?: QueryParams, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"GET\",\n path,\n ...(query ? { query } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"POST\",\n path,\n ...(body !== undefined ? { body } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"PATCH\",\n path,\n ...(body !== undefined ? { body } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async delete<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.#request<T>({\n method: \"DELETE\",\n path,\n ...(body !== undefined ? { body } : {}),\n ...(options ? { options } : {})\n });\n }\n\n async #request<T>(request: InternalRequest): Promise<T> {\n const maxAttempts = Math.max(1, request.options?.maxAttempts ?? this.#maxAttempts);\n const url = this.#baseUrl + request.path + encodeQuery(request.query);\n\n let attempt = 0;\n // Unbounded `while` with the exit conditions inside, rather than a `for`\n // over attempts: every path out of here either returns or throws, and a\n // loop that can fall off the end would silently return undefined as `T`.\n for (;;) {\n attempt += 1;\n\n let error: PersistMemoryError;\n try {\n return await this.#attempt<T>(request, url);\n } catch (thrown) {\n // Anything that is not one of ours is a programming error in this\n // package - a bad URL, a body that will not serialise - and rethrowing\n // it unchanged is right. Wrapping it as a retryable transport failure\n // would make the request loop retry a defect that fails identically\n // every time.\n if (!(thrown instanceof PersistMemoryError)) throw thrown;\n error = thrown;\n }\n\n if (attempt >= maxAttempts) throw error;\n if (!mayRetry(error, request)) throw error;\n\n const delay = delayFor({\n attempt,\n ...(error.retryAfterSeconds !== undefined\n ? { retryAfterSeconds: error.retryAfterSeconds }\n : {}),\n options: this.#backoff\n });\n\n // The caller's signal is passed into the wait too. Without it an aborted\n // call still sits out its full backoff before noticing, which to a user\n // who pressed cancel is indistinguishable from the cancel not working.\n await this.#sleep(delay, request.options?.signal);\n }\n }\n\n async #attempt<T>(request: InternalRequest, url: string): Promise<T> {\n const timeoutMs = request.options?.timeoutMs ?? this.#timeoutMs;\n const deadline = new AbortController();\n const timer = setTimeout(() => deadline.abort(), timeoutMs);\n // Linked rather than AbortSignal.any: this package supports Node 18, where\n // `any` does not exist. The listener is removed in the `finally`, because\n // a long-lived caller signal that accumulated one listener per request is\n // a leak that only shows up under load.\n const onCallerAbort = () => deadline.abort();\n const caller = request.options?.signal;\n caller?.addEventListener(\"abort\", onCallerAbort, { once: true });\n\n try {\n if (caller?.aborted) throw new AbortError();\n\n // Raced against the deadline rather than left to `fetch` alone.\n // `fetch` is injected here, and not every implementation honours a\n // signal - a mocked one in someone's test suite, an older polyfill, a\n // wrapper that forgets to forward it. When one does not, an unanswered\n // request hangs forever and the timeout this client documents is a\n // promise it does not keep.\n const response = await untilAborted(\n this.#fetch(url, {\n method: request.method,\n headers: this.#headers(request),\n ...(request.body !== undefined ? { body: JSON.stringify(request.body) } : {}),\n signal: deadline.signal\n }),\n deadline.signal\n );\n\n const payload = await readBody(response);\n if (!response.ok) throw errorFromResponse(response.status, payload, response.headers);\n return payload as T;\n } catch (thrown) {\n if (thrown instanceof PersistMemoryError) throw thrown;\n\n // Three different things arrive here as one AbortError from fetch, and\n // they need three different answers: the caller cancelled (do not\n // retry), we ran out of time (retry), or the network failed (retry, but\n // not for a POST). Telling them apart by asking WHOSE signal fired is\n // the only reliable way - the DOMException looks the same either way.\n if (caller?.aborted) throw new AbortError();\n if (deadline.signal.aborted) {\n throw new TimeoutError(`The request did not complete within ${timeoutMs}ms.`);\n }\n\n const detail = thrown instanceof Error ? redact(thrown.message) : \"transport failure\";\n throw new ConnectionError(`Could not reach the API: ${detail}`);\n } finally {\n clearTimeout(timer);\n caller?.removeEventListener(\"abort\", onCallerAbort);\n }\n }\n\n #headers(request: InternalRequest): Record<string, string> {\n return {\n // The only place the key is ever read.\n authorization: `Bearer ${this.#apiKey}`,\n accept: \"application/json\",\n \"user-agent\": this.#userAgent,\n ...(request.body !== undefined ? { \"content-type\": \"application/json\" } : {}),\n ...(request.options?.idempotencyKey\n ? { \"idempotency-key\": request.options.idempotencyKey }\n : {})\n };\n }\n}\n\n/**\n * Whether this failure is worth another attempt.\n *\n * Two questions, and both have to say yes. The first is whether the failure\n * itself could clear - a 400 fails identically on every attempt, so retrying\n * spends two more calls to learn the same thing. The second is whether\n * repeating the REQUEST is safe, which is a different question and the one\n * that gets skipped.\n *\n * For a POST the honest answer is that we usually cannot tell. A connection\n * that died after the server accepted the request is indistinguishable from\n * one that died before, so retrying `remember` on a timeout would queue the\n * same note twice and the user would see it remembered twice. So a POST is\n * retried only when:\n *\n * an idempotency key was given the API deduplicates on it, so the retry\n * returns the first result rather than\n * repeating the work\n *\n * the status was 429 the request was refused BEFORE it was\n * processed. That is what a rate limit is,\n * and it is the one case where \"already\n * succeeded\" is not possible\n *\n * Every other retryable POST failure - a 500, a 503, a timeout, a reset - is\n * given back to the caller, who knows whether repeating it is safe and this\n * package does not.\n */\nexport function mayRetry(error: PersistMemoryError, request: InternalRequest): boolean {\n if (!error.retryable) return false;\n if (RETRY_WITHOUT_ASKING.has(request.method)) return true;\n if (request.options?.idempotencyKey) return true;\n return error.status === 429;\n}\n\n/**\n * The body, parsed if it is JSON and there is any.\n *\n * Never assumes JSON. A 502 from a load balancer in front of the API is an\n * HTML page, and an SDK that calls `response.json()` unconditionally turns a\n * bad gateway into a SyntaxError thrown from inside the error handler - which\n * hides the actual failure behind a parse error nobody can act on.\n */\nasync function readBody(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined;\n\n const text = await response.text().catch(() => \"\");\n if (text.length === 0) return undefined;\n\n const type = response.headers.get(\"content-type\") ?? \"\";\n if (!type.includes(\"json\")) return { raw: text.slice(0, 500) };\n\n try {\n return JSON.parse(text) as unknown;\n } catch {\n // Truncated, because a body that failed to parse can be megabytes of an\n // upstream error page and this string reaches an error message.\n return { raw: text.slice(0, 500) };\n }\n}\n\n/**\n * The response, or a rejection the moment the signal fires.\n *\n * The original promise is left with a `catch` attached: it may still settle\n * long after we have stopped waiting, and an unattended rejection from an\n * abandoned request takes the process down under Node's default handling.\n */\nclass SignalFired extends Error {\n constructor() {\n // Deliberately NOT one of this package's errors. It is raised before we\n // know WHICH signal fired, and the catch in `#attempt` is the only place\n // that can tell a caller's cancel from a deadline - a `TimeoutError`\n // thrown here would be a timeout reported for a user pressing stop.\n super(\"signal fired\");\n this.name = \"SignalFired\";\n }\n}\n\nfunction untilAborted<T>(work: Promise<T>, signal: AbortSignal): Promise<T> {\n work.catch(() => undefined);\n\n return new Promise<T>((resolve, reject) => {\n if (signal.aborted) {\n reject(new SignalFired());\n return;\n }\n\n const onAbort = () => reject(new SignalFired());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n\n work.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error instanceof Error ? error : new Error(String(error)));\n }\n );\n });\n}\n\n/**\n * A wait that can be cancelled.\n *\n * The default. Injected in tests so a retry test does not spend real seconds\n * asleep - a suite that actually waits out an exponential backoff is a suite\n * people stop running.\n */\nfunction defaultSleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new AbortError());\n return;\n }\n\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n\n function onAbort(): void {\n clearTimeout(timer);\n reject(new AbortError());\n }\n\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n", "import type { Page } from \"./types\";\n\n/**\n * Walking a cursor-paginated list.\n *\n * The list endpoints are keyset paginated: `?cursor=` carries where the last\n * page ended, and the response is `{ data, pagination: { nextCursor?, limit } }`\n * with `nextCursor` absent on the last page. The absence is the ONLY stop\n * signal - an empty `data` array is not the same thing, because a page can\n * come back empty when everything in it was filtered after the fetch while\n * more pages remain. A client that stops on an empty page silently truncates\n * the user's results and nothing anywhere reports an error.\n *\n * That rule is easy to state and easy to get wrong once per call site, which\n * is why every list method returns one of these instead of leaving the loop to\n * the caller.\n *\n * Not every list is paginated. `spaces/{id}/memories` and\n * `entities/{id}/memories` return a `pagination` block with no cursor at all,\n * so iterating them yields exactly one page and stops - which is correct, and\n * costs a caller nothing for using the same shape everywhere.\n */\nexport class Paginated<T> implements AsyncIterable<T> {\n readonly #fetchPage: (cursor: string | undefined) => Promise<Page<T>>;\n\n constructor(fetchPage: (cursor: string | undefined) => Promise<Page<T>>) {\n this.#fetchPage = fetchPage;\n }\n\n /** The first page, and nothing more. For a UI that renders one page at a time. */\n async first(): Promise<Page<T>> {\n return this.#fetchPage(undefined);\n }\n\n /**\n * Page by page, for a caller that wants the cursors or wants to stop early.\n *\n * A generator rather than an array of pages: fetching them all up front\n * would make \"show me the first ten\" cost every page in the account.\n */\n async *pages(): AsyncGenerator<Page<T>, void, undefined> {\n let cursor: string | undefined;\n const seen = new Set<string>();\n\n for (;;) {\n const page: Page<T> = await this.#fetchPage(cursor);\n yield page;\n\n const next = page.pagination.nextCursor;\n if (!next) return;\n\n // A cursor we have already followed means the server is handing back a\n // position that does not advance, and continuing is an infinite loop\n // that reads the same page forever while looking exactly like a slow\n // account. Stopping loses a page; looping loses the process.\n if (seen.has(next)) return;\n seen.add(next);\n cursor = next;\n }\n }\n\n /** Every item across every page. `for await (const memory of ...)`. */\n async *[Symbol.asyncIterator](): AsyncGenerator<T, void, undefined> {\n for await (const page of this.pages()) {\n for (const item of page.data) yield item;\n }\n }\n\n /**\n * Everything, in one array.\n *\n * `maxItems` is not optional, and that is the point. An unbounded `all()` on\n * an account with two hundred thousand memories is a request loop that runs\n * for minutes and an array that exhausts the heap, and the call site that\n * does it reads as innocently as any other. Ask for a number you can hold.\n */\n async all(maxItems: number): Promise<T[]> {\n const collected: T[] = [];\n if (maxItems <= 0) return collected;\n\n for await (const item of this) {\n collected.push(item);\n if (collected.length >= maxItems) break;\n }\n return collected;\n }\n}\n", "import type { HttpClient, QueryParams, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type { ListMemoriesParams, Memory, Page, RememberParams, RememberResult } from \"../types\";\n\n/**\n * Memories: browsing them, reading one, and handing over new material.\n *\n * Browsing is not searching. `list` is chronological and takes filters,\n * `search` ranks by relevance and takes a query - they are separate endpoints\n * because serving both from one would mean a caller who adds a filter silently\n * gets a differently ordered list.\n */\nexport class Memories {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /**\n * One page, plus the cursor loop.\n *\n * Returns a `Paginated`, so `await memories.list().first()` gets a page and\n * `for await (const memory of memories.list())` walks the lot. The filters\n * are carried into every page automatically - a caller re-passing them per\n * page is a caller who will eventually forget one, and the pages after that\n * come from a differently filtered list.\n */\n list(params: ListMemoriesParams = {}, options?: RequestOptions): Paginated<Memory> {\n return new Paginated<Memory>((cursor) =>\n this.#http.get<Page<Memory>>(\n \"/api/v1/memories\",\n pageQuery(params, cursor, toQuery(params)),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Memory> {\n return this.#http.get<Memory>(`/api/v1/memories/${encodeURIComponent(id)}`, undefined, options);\n }\n\n /**\n * Hands material to the ingestion pipeline. Needs a key with `write` scope.\n *\n * This does NOT create a memory, and the return type says so: it answers 202\n * with a job id. Extraction, entity resolution, deduplication and conflict\n * detection all run afterwards and may produce one memory, several, or none.\n * Poll `client.jobs.get(result.jobId)` to find out which.\n *\n * Pass an `idempotencyKey` if this can be retried by anything - a queue, a\n * user pressing a button twice, or this client's own retry loop, which\n * refuses to repeat a POST without one. `remember:note-42`, not a fresh\n * random value per call.\n */\n async remember(params: RememberParams, options?: RequestOptions): Promise<RememberResult> {\n return this.#http.post<RememberResult>(\"/api/v1/remember\", params, options);\n }\n}\n\nfunction toQuery(params: ListMemoriesParams): QueryParams {\n return {\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.state !== undefined ? { state: params.state } : {}),\n ...(params.scope !== undefined ? { scope: params.scope } : {}),\n ...(params.spaceIds !== undefined ? { spaceIds: params.spaceIds } : {}),\n ...(params.createdAfter !== undefined ? { createdAfter: params.createdAfter } : {}),\n ...(params.createdBefore !== undefined ? { createdBefore: params.createdBefore } : {}),\n ...(params.minConfidence !== undefined ? { minConfidence: params.minConfidence } : {}),\n ...(params.includeHistorical !== undefined\n ? { includeHistorical: params.includeHistorical }\n : {})\n };\n}\n", "import type { HttpClient, QueryParams, RequestOptions } from \"../http\";\nimport type { ContextParams, ContextResponse, SearchParams, SearchResponse } from \"../types\";\n\n/**\n * Asking the system what it knows.\n *\n * Two methods, and they answer different questions. `search` returns ranked\n * records for a person or a UI. `context` returns prose for a model, bounded\n * by TOKENS rather than by row count - which is the only bound that expresses\n * the real constraint, since ten long memories overflow a window that fifty\n * short ones fit inside.\n *\n * `search` is a GET and `context` is a POST, matching the API: a search is\n * linkable and cacheable, while a context request can carry two hundred\n * excluded ids and every proxy in between has its own idea of how long a URL\n * may be.\n */\nexport class Search {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /**\n * Ranked results, with an account of how they were found.\n *\n * Read `diagnostics.degraded` before showing the results. Search degrades\n * rather than fails - with embeddings unavailable it falls back to\n * deterministic retrieval and still answers - and a UI that cannot tell\n * degraded from healthy tells the user the system knows nothing when it is\n * merely looking with one eye.\n */\n async query(params: SearchParams, options?: RequestOptions): Promise<SearchResponse> {\n const query: QueryParams = {\n query: params.query,\n ...(params.limit !== undefined ? { limit: params.limit } : {}),\n ...(params.scope !== undefined ? { scope: params.scope } : {}),\n ...(params.spaceIds !== undefined ? { spaceIds: params.spaceIds } : {}),\n ...(params.types !== undefined ? { types: params.types } : {}),\n ...(params.minScore !== undefined ? { minScore: params.minScore } : {}),\n ...(params.asOf !== undefined ? { asOf: params.asOf } : {}),\n ...(params.includeHistorical !== undefined\n ? { includeHistorical: params.includeHistorical }\n : {}),\n ...(params.includeEvidence !== undefined\n ? { includeEvidence: params.includeEvidence }\n : {}),\n ...(params.explain !== undefined ? { explain: params.explain } : {})\n };\n\n return this.#http.get<SearchResponse>(\"/api/v1/search\", query, options);\n }\n\n /**\n * A context window, assembled and ready to paste into a prompt.\n *\n * A POST that is safe to repeat - it reads and returns, it writes nothing -\n * so this is one of the few places where retrying without an idempotency key\n * would be harmless. It still is not retried by default: the request loop\n * decides by METHOD, and a per-endpoint exception is a rule that holds until\n * someone adds a POST next to it that does write.\n */\n async context(params: ContextParams, options?: RequestOptions): Promise<ContextResponse> {\n return this.#http.post<ContextResponse>(\"/api/v1/context\", params, options);\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n CreateSpaceParams,\n ListSpacesParams,\n Memory,\n Page,\n Space,\n UpdateSpaceParams\n} from \"../types\";\n\n/**\n * Spaces: a boundary around a set of memories.\n *\n * They exist because \"everything I know\" is the wrong scope for most\n * questions. Work and personal contexts hold contradictory truths - two\n * different \"my manager\" - and answering from both at once is wrong in a way\n * that is hard to notice.\n *\n * Membership is a LINK, not ownership. `removeMemories` takes a memory out of\n * a Space; it does not delete it, and the same memory can belong to several.\n */\nexport class Spaces {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListSpacesParams = {}, options?: RequestOptions): Paginated<Space> {\n return new Paginated<Space>((cursor) =>\n this.#http.get<Page<Space>>(\n \"/api/v1/spaces\",\n pageQuery(params, cursor, {\n ...(params.includeArchived !== undefined\n ? { includeArchived: params.includeArchived }\n : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Space> {\n return this.#http.get<Space>(`/api/v1/spaces/${encodeURIComponent(id)}`, undefined, options);\n }\n\n /**\n * Creates a Space. Answers 201.\n *\n * Worth an idempotency key when a person is behind it: a double-clicked\n * \"create Space\" button makes two Spaces called Work, and nothing later can\n * tell which of them memories should have gone into.\n */\n async create(params: CreateSpaceParams, options?: RequestOptions): Promise<Space> {\n return this.#http.post<Space>(\"/api/v1/spaces\", params, options);\n }\n\n /**\n * Deletes a Space. You must say what happens to what is in it.\n *\n * There is no default, here or in the API, and that is deliberate: \"delete\n * this Space\" means the label to some people and everything inside it to\n * others, and a client that guessed would destroy or keep somebody's\n * material without being asked.\n *\n * `delete` never destroys a memory that is filed in another Space as well \u2014\n * that one is detached and left alone. `deleted` and `kept` come back so you\n * can say what actually happened.\n */\n async delete(\n id: string,\n params: { readonly memories: \"keep\" | \"delete\" },\n options?: RequestOptions\n ): Promise<{ deleted: number; kept: number }> {\n return this.#http.delete<{ deleted: number; kept: number }>(\n `/api/v1/spaces/${encodeURIComponent(id)}`,\n params,\n options\n );\n }\n\n /**\n * Merges Spaces into a NEW one, leaving every source exactly as it was.\n *\n * Additive, not destructive: a memory ends up in the sources AND the result,\n * every existing search over a source returns what it did before, and\n * undoing it is deleting the Space this returns. A memory in two sources is\n * filed once.\n */\n async merge(\n params: {\n readonly sourceIds: readonly string[];\n readonly name: string;\n readonly description?: string;\n },\n options?: RequestOptions\n ): Promise<{ space: Space; added: number }> {\n return this.#http.post<{ space: Space; added: number }>(\n \"/api/v1/spaces/merge\",\n params,\n options\n );\n }\n\n /**\n * The Space this account files into when a capture names none.\n *\n * `{}` \u2014 an object with no `space` \u2014 means there is no default, which is the\n * normal state rather than a gap. It is also what comes back after the Space\n * somebody chose has been deleted.\n */\n async getDefault(options?: RequestOptions): Promise<{ space?: Space }> {\n return this.#http.get<{ space?: Space }>(\"/api/v1/spaces/default\", undefined, options);\n }\n\n /** `null` clears it. Not the same as omitting it, which is why the type says so. */\n async setDefault(spaceId: string | null, options?: RequestOptions): Promise<{ space?: Space }> {\n return this.#http.patch<{ space?: Space }>(\n \"/api/v1/spaces/default\",\n { spaceId },\n options\n );\n }\n\n /** Renaming, retention, and archiving - `archived` is a field, not a verb. */\n async update(id: string, params: UpdateSpaceParams, options?: RequestOptions): Promise<Space> {\n return this.#http.patch<Space>(`/api/v1/spaces/${encodeURIComponent(id)}`, params, options);\n }\n\n /**\n * The memories filed in a Space.\n *\n * This endpoint answers `{ data, pagination: { limit } }` with no cursor: it\n * returns the first `limit` members and stops. Wrapped in a `Paginated`\n * anyway so it reads like every other list, and it simply yields one page -\n * a caller who needs more should filter `memories.list` by `spaceIds`, which\n * is the endpoint that actually pages.\n */\n memories(\n id: string,\n params: { readonly limit?: number } = {},\n options?: RequestOptions\n ): Paginated<Memory> {\n return new Paginated<Memory>(() =>\n this.#http.get<Page<Memory>>(\n `/api/v1/spaces/${encodeURIComponent(id)}/memories`,\n { ...(params.limit !== undefined ? { limit: params.limit } : {}) },\n options\n )\n );\n }\n\n async addMemories(\n id: string,\n memoryIds: readonly string[],\n options?: RequestOptions\n ): Promise<{ added: number }> {\n return this.#http.post<{ added: number }>(\n `/api/v1/spaces/${encodeURIComponent(id)}/memories`,\n { memoryIds },\n options\n );\n }\n\n /**\n * Removes memberships. The memories themselves are untouched.\n *\n * A body on a DELETE, which is unusual and is what the API takes: the\n * alternative is five hundred ids in a query string, and every proxy in\n * between has its own limit on how long a URL may be.\n */\n async removeMemories(\n id: string,\n memoryIds: readonly string[],\n options?: RequestOptions\n ): Promise<{ removed: number }> {\n return this.#http.delete<{ removed: number }>(\n `/api/v1/spaces/${encodeURIComponent(id)}/memories`,\n { memoryIds },\n options\n );\n }\n}\n", "import type { HttpClient, QueryParams, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n Document,\n Job,\n ListDocumentsParams,\n ListJobsParams,\n ListSourcesParams,\n Page,\n Source\n} from \"../types\";\n\n/**\n * Where material came from, what it became, and the work in between.\n *\n * Three resources rather than one because they answer three questions a caller\n * asks separately: a source is an ORIGIN, a document is the normalised form\n * that was kept, and a job is the work that is still running. Collapsing them\n * would make \"nothing has appeared yet\" indistinguishable from \"it silently\n * failed\", which is the whole reason jobs are visible at all.\n */\nexport class Sources {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListSourcesParams = {}, options?: RequestOptions): Paginated<Source> {\n return new Paginated<Source>((cursor) =>\n this.#http.get<Page<Source>>(\n \"/api/v1/sources\",\n pageQuery(params, cursor, {\n ...(params.provider !== undefined ? { provider: params.provider } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Source> {\n return this.#http.get<Source>(`/api/v1/sources/${encodeURIComponent(id)}`, undefined, options);\n }\n}\n\nexport class Documents {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListDocumentsParams = {}, options?: RequestOptions): Paginated<Document> {\n return new Paginated<Document>((cursor) =>\n this.#http.get<Page<Document>>(\n \"/api/v1/documents\",\n pageQuery(params, cursor, {\n ...(params.sourceId !== undefined ? { sourceId: params.sourceId } : {}),\n ...(params.status !== undefined ? { status: params.status } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Document> {\n return this.#http.get<Document>(\n `/api/v1/documents/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n}\n\nexport class Jobs {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListJobsParams = {}, options?: RequestOptions): Paginated<Job> {\n return new Paginated<Job>((cursor) =>\n this.#http.get<Page<Job>>(\n \"/api/v1/jobs\",\n pageQuery(params, cursor, {\n ...(params.status !== undefined ? { status: params.status } : {}),\n ...(params.type !== undefined ? { type: params.type } : {})\n }),\n options\n )\n );\n }\n\n /**\n * One job, by id. This is what `remember` hands back a reference to.\n *\n * `completed` is the terminal success state - the store's own word, not\n * `succeeded`. A caller polling for a state the API never writes waits\n * forever with nothing to show why.\n */\n async get(id: string, options?: RequestOptions): Promise<Job> {\n return this.#http.get<Job>(`/api/v1/jobs/${encodeURIComponent(id)}`, undefined, options);\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n Conflict,\n Entity,\n EntityMemoriesParams,\n EntityMention,\n GraphResponse,\n ListConflictsParams,\n ListEntitiesParams,\n Page,\n ResolveConflictParams,\n TraverseParams\n} from \"../types\";\n\n/**\n * The people, places and things memories are about.\n *\n * Entities are RESOLVED rather than stored as strings: \"Sam\", \"Sam Patel\" and\n * \"sam@work.com\" are one person, and a system that treats them as three cannot\n * answer \"what do I know about Sam\" - the most obvious question anyone asks a\n * memory system.\n */\nexport class Entities {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListEntitiesParams = {}, options?: RequestOptions): Paginated<Entity> {\n return new Paginated<Entity>((cursor) =>\n this.#http.get<Page<Entity>>(\n \"/api/v1/entities\",\n pageQuery(params, cursor, {\n ...(params.type !== undefined ? { type: params.type } : {}),\n ...(params.q !== undefined ? { q: params.q } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Entity> {\n return this.#http.get<Entity>(`/api/v1/entities/${encodeURIComponent(id)}`, undefined, options);\n }\n\n /**\n * Which memories mention this entity, and how.\n *\n * Returns MENTIONS - a memory id, a role and a confidence - not the memories\n * themselves. \"Memories about Sam\" and \"memories Sam appears in\" are\n * different questions, and `role` is what separates them.\n *\n * Like the Space membership list, this endpoint answers with a `pagination`\n * block that carries no cursor, so it yields one page and stops.\n */\n memories(\n id: string,\n params: EntityMemoriesParams = {},\n options?: RequestOptions\n ): Paginated<EntityMention> {\n return new Paginated<EntityMention>((cursor) =>\n this.#http.get<Page<EntityMention>>(\n `/api/v1/entities/${encodeURIComponent(id)}/memories`,\n pageQuery(params, cursor, {\n ...(params.role !== undefined ? { role: params.role } : {}),\n ...(params.minConfidence !== undefined ? { minConfidence: params.minConfidence } : {})\n }),\n options\n )\n );\n }\n}\n\n/**\n * Walking the graph out from an entity.\n *\n * Every bound has a server-side ceiling, and that is the point: an unbounded\n * traversal on a well-connected graph visits everything, and the request that\n * does it is indistinguishable from a denial of service. Read `truncated` -\n * silence would read as \"this is the whole graph\", and a conclusion drawn from\n * a subset nobody knew was a subset is worse than no answer.\n */\nexport class Graph {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n async traverse(params: TraverseParams, options?: RequestOptions): Promise<GraphResponse> {\n return this.#http.get<GraphResponse>(\n \"/api/v1/graph\",\n {\n from: params.from,\n ...(params.depth !== undefined ? { depth: params.depth } : {}),\n ...(params.maxNodes !== undefined ? { maxNodes: params.maxNodes } : {}),\n ...(params.memoryLimit !== undefined ? { memoryLimit: params.memoryLimit } : {})\n },\n options\n );\n }\n}\n\n/**\n * Two things the system believes that cannot both be true.\n *\n * Surfaced rather than settled silently, because the automatic answer is often\n * wrong: \"I moved to Berlin\" superseding \"I live in London\" is right, and \"the\n * deadline is Friday\" against \"the deadline is Monday\" is a question only the\n * user can answer.\n */\nexport class Conflicts {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListConflictsParams = {}, options?: RequestOptions): Paginated<Conflict> {\n return new Paginated<Conflict>((cursor) =>\n this.#http.get<Page<Conflict>>(\n \"/api/v1/conflicts\",\n pageQuery(params, cursor, {\n ...(params.includeResolved !== undefined\n ? { includeResolved: params.includeResolved }\n : {}),\n ...(params.type !== undefined ? { type: params.type } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Conflict> {\n return this.#http.get<Conflict>(\n `/api/v1/conflicts/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n /**\n * Settles one.\n *\n * `keep` names the winner and supersedes the loser; it does not delete it.\n * `dismiss` records that the detector was wrong, which is worth knowing when\n * the same pair trips it again.\n *\n * The parameter type is a union, so `keep` without a `keepId` does not\n * compile. The server rejects it too - this just moves the failure from a\n * 400 in production to a red squiggle.\n */\n async resolve(\n id: string,\n params: ResolveConflictParams,\n options?: RequestOptions\n ): Promise<{ status: string } & Record<string, unknown>> {\n return this.#http.post(\n `/api/v1/conflicts/${encodeURIComponent(id)}/resolve`,\n params,\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n AppendMessagesParams,\n AppendMessagesResult,\n Conversation,\n CreateConversationParams,\n ListConversationsParams,\n Message,\n Page\n} from \"../types\";\n\n/**\n * A running exchange the system remembers across sessions.\n *\n * A conversation is both a SOURCE of memories and a place to spend them: turns\n * appended here go through the same extraction pipeline as `remember`, so they\n * get consolidation and entity resolution rather than a second, drifting path.\n */\nexport class Conversations {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(\n params: ListConversationsParams = {},\n options?: RequestOptions\n ): Paginated<Conversation> {\n return new Paginated<Conversation>((cursor) =>\n this.#http.get<Page<Conversation>>(\n \"/api/v1/conversations\",\n pageQuery(params, cursor, {\n ...(params.channel !== undefined ? { channel: params.channel } : {})\n }),\n options\n )\n );\n }\n\n async get(id: string, options?: RequestOptions): Promise<Conversation> {\n return this.#http.get<Conversation>(\n `/api/v1/conversations/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n async create(\n params: CreateConversationParams = {},\n options?: RequestOptions\n ): Promise<Conversation> {\n return this.#http.post<Conversation>(\"/api/v1/conversations\", params, options);\n }\n\n messages(\n id: string,\n params: { readonly limit?: number; readonly cursor?: string } = {},\n options?: RequestOptions\n ): Paginated<Message> {\n return new Paginated<Message>((cursor) =>\n this.#http.get<Page<Message>>(\n `/api/v1/conversations/${encodeURIComponent(id)}/messages`,\n pageQuery(params, cursor, {}),\n options\n )\n );\n }\n\n /**\n * Appends turns, and by default extracts memories from them.\n *\n * Check `extracting` on the result. With no queue configured the turns are\n * stored and never become memory, and the API says so in `note` rather than\n * reporting a success - a caller that ignores it believes a memory is on its\n * way that never arrives.\n *\n * `system` and `tool` turns are stored but never extracted: a system prompt\n * is configuration, and remembering it would file our own instructions as\n * the user's facts.\n *\n * Give this an `idempotencyKey`. Appending the same turn twice is the most\n * likely duplicate in the whole API - a client reconnecting after a dropped\n * response has no other way to tell whether its last write landed.\n */\n async append(\n id: string,\n params: AppendMessagesParams,\n options?: RequestOptions\n ): Promise<AppendMessagesResult> {\n return this.#http.post<AppendMessagesResult>(\n `/api/v1/conversations/${encodeURIComponent(id)}/messages`,\n params,\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport { Paginated } from \"../pagination\";\nimport { pageQuery } from \"../query\";\nimport type {\n ConnectIntegrationParams,\n ConnectIntegrationResult,\n Integration,\n ListIntegrationsParams,\n Page,\n UpdateIntegrationParams\n} from \"../types\";\n\n/**\n * Live connections to somewhere material comes from.\n *\n * What is deliberately absent from every response: the access token, the\n * refresh token, and anything else that would let a caller act as the user on\n * the far side. They are held encrypted and never leave the server, so one\n * leaked API key does not become access to the user's Drive.\n *\n * `connect` returns a URL to send the user to. It does not take third-party\n * credentials, and no method here ever will - an endpoint that accepted a\n * password for another service would train users to hand them over, which is\n * the habit every phishing attack relies on.\n */\nexport class Integrations {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n list(params: ListIntegrationsParams = {}, options?: RequestOptions): Paginated<Integration> {\n return new Paginated<Integration>((cursor) =>\n this.#http.get<Page<Integration>>(\n \"/api/v1/integrations\",\n pageQuery(params, cursor, {\n ...(params.provider !== undefined ? { provider: params.provider } : {}),\n ...(params.status !== undefined ? { status: params.status } : {})\n }),\n options\n )\n );\n }\n\n /** Providers that can be connected at all. Not the user's own connections. */\n async available(options?: RequestOptions): Promise<unknown> {\n return this.#http.get<unknown>(\"/api/v1/integrations/available\", undefined, options);\n }\n\n async get(id: string, options?: RequestOptions): Promise<Integration> {\n return this.#http.get<Integration>(\n `/api/v1/integrations/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n async connect(\n params: ConnectIntegrationParams,\n options?: RequestOptions\n ): Promise<ConnectIntegrationResult> {\n return this.#http.post<ConnectIntegrationResult>(\n \"/api/v1/integrations/connect\",\n params,\n options\n );\n }\n\n async update(\n id: string,\n params: UpdateIntegrationParams,\n options?: RequestOptions\n ): Promise<Integration> {\n return this.#http.patch<Integration>(\n `/api/v1/integrations/${encodeURIComponent(id)}`,\n params,\n options\n );\n }\n\n /**\n * Asks for a sync now rather than waiting for the schedule. Answers 202.\n *\n * `full` re-reads everything and is deliberately opt-in: on a large Drive\n * that is thousands of documents and a real bill. The incremental default is\n * what should run almost always.\n */\n async sync(\n id: string,\n params: { readonly full?: boolean } = {},\n options?: RequestOptions\n ): Promise<{ status: string; full: boolean }> {\n return this.#http.post<{ status: string; full: boolean }>(\n `/api/v1/integrations/${encodeURIComponent(id)}/sync`,\n params,\n options\n );\n }\n\n /**\n * Destroys the credentials. The row stays.\n *\n * History still has to attribute the memories this connection produced, and\n * deleting the row would leave them pointing at nothing.\n */\n async disconnect(id: string, options?: RequestOptions): Promise<{ status: string }> {\n return this.#http.delete<{ status: string }>(\n `/api/v1/integrations/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport type { HealthResponse } from \"../types\";\n\n/**\n * Is it up, and is it ready.\n *\n * Two endpoints because they answer different questions and a load balancer\n * needs both: `live` says the process is running, `ready` says it can serve.\n * Answering `ready` from a liveness probe restarts a healthy process that was\n * merely waiting on a dependency.\n *\n * Neither is under `/api/v1`, and neither needs the key - but the key is sent\n * anyway, because a client that builds a second, credential-free request path\n * has a second path that can be wrong.\n */\nexport class Health {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n async live(options?: RequestOptions): Promise<HealthResponse> {\n return this.#http.get<HealthResponse>(\"/health/live\", undefined, options);\n }\n\n async ready(options?: RequestOptions): Promise<HealthResponse> {\n return this.#http.get<HealthResponse>(\"/health/ready\", undefined, options);\n }\n}\n", "import type { HttpClient, RequestOptions } from \"../http\";\nimport type { AgentDownloadLink, AgentRequest } from \"../types\";\n\n/**\n * Files fetched from the caller's own machine.\n *\n * A request is asked for on one surface, approved by a person, carried out by\n * an agent on their laptop, and finishes with the bytes in storage. Everything\n * up to that point was already visible through the API; `downloadLink` is what\n * makes the result retrievable rather than merely describable.\n */\nexport class Agent {\n readonly #http: HttpClient;\n\n constructor(http: HttpClient) {\n this.#http = http;\n }\n\n /** The row, including whether it finished and how large the result is. */\n async request(id: string, options?: RequestOptions): Promise<AgentRequest> {\n return this.#http.get<AgentRequest>(\n `/api/v1/agent/request/${encodeURIComponent(id)}`,\n undefined,\n options\n );\n }\n\n /**\n * A short-lived link to the bytes of a finished request.\n *\n * Returns the URL rather than the file, and that is a deliberate limit of\n * this package rather than an oversight. The transport under every other\n * method parses JSON, retries, and attaches the API key; none of those is\n * right for a hundred-megabyte binary body, and building a second request\n * path inside the SDK to serve one method is how a client ends up with two\n * retry policies that differ only during an outage. Fetch the URL with\n * whatever already streams in your runtime - it needs no credential, which\n * is the whole reason it is signed.\n *\n * Treat the URL as the file. It is a bearer credential for exactly one\n * object, it expires in minutes, and it should not be logged or stored.\n */\n async downloadLink(id: string, options?: RequestOptions): Promise<AgentDownloadLink> {\n return this.#http.get<AgentDownloadLink>(\n `/api/v1/agent/request/${encodeURIComponent(id)}/download`,\n undefined,\n options\n );\n }\n}\n", "import type { ClientOptions, RequestOptions } from \"./http\";\nimport { HttpClient } from \"./http\";\nimport { Memories } from \"./resources/memories\";\nimport { Search } from \"./resources/search\";\nimport { Spaces } from \"./resources/spaces\";\nimport { Documents, Jobs, Sources } from \"./resources/ingestion\";\nimport { Conflicts, Entities, Graph } from \"./resources/knowledge\";\nimport { Conversations } from \"./resources/conversations\";\nimport { Integrations } from \"./resources/integrations\";\nimport { Health } from \"./resources/health\";\nimport { Agent } from \"./resources/agent\";\n\n/**\n * The client.\n *\n * const client = new PersistMemory({ apiKey: process.env.PERSISTMEMORY_API_KEY! });\n * const found = await client.search.query({ query: \"what did we decide about Postgres\" });\n *\n * One transport underneath every resource, so retries, timeouts, error mapping\n * and the credential are decided once. Resources are plain objects hanging off\n * this one; they hold a reference to the transport and no state of their own,\n * which is what makes a client safe to share across a process.\n */\nexport class PersistMemory {\n readonly memories: Memories;\n readonly search: Search;\n readonly spaces: Spaces;\n readonly sources: Sources;\n readonly documents: Documents;\n readonly jobs: Jobs;\n readonly entities: Entities;\n readonly graph: Graph;\n readonly conflicts: Conflicts;\n readonly conversations: Conversations;\n readonly integrations: Integrations;\n readonly health: Health;\n readonly agent: Agent;\n\n readonly #http: HttpClient;\n\n constructor(options: ClientOptions) {\n this.#http = new HttpClient(options);\n\n this.memories = new Memories(this.#http);\n this.search = new Search(this.#http);\n this.spaces = new Spaces(this.#http);\n this.sources = new Sources(this.#http);\n this.documents = new Documents(this.#http);\n this.jobs = new Jobs(this.#http);\n this.entities = new Entities(this.#http);\n this.graph = new Graph(this.#http);\n this.conflicts = new Conflicts(this.#http);\n this.conversations = new Conversations(this.#http);\n this.integrations = new Integrations(this.#http);\n this.health = new Health(this.#http);\n this.agent = new Agent(this.#http);\n }\n\n /**\n * An escape hatch for an endpoint this package has not caught up with.\n *\n * Typed as `unknown` on purpose: a caller reaching past the typed surface is\n * taking responsibility for the shape, and handing them `any` would let that\n * responsibility spread silently through their codebase.\n */\n async request<T = unknown>(\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\",\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<T> {\n if (method === \"GET\") return this.#http.get<T>(path, undefined, options);\n if (method === \"POST\") return this.#http.post<T>(path, body, options);\n if (method === \"PATCH\") return this.#http.patch<T>(path, body, options);\n return this.#http.delete<T>(path, body, options);\n }\n\n /** Never the key. See `HttpClient.toJSON`, which this delegates to. */\n toJSON(): Record<string, unknown> {\n return this.#http.toJSON();\n }\n\n [Symbol.for(\"nodejs.util.inspect.custom\")](): Record<string, unknown> {\n return this.#http.toJSON();\n }\n}\n", "/**\n * Argument parsing, by hand and on purpose.\n *\n * A CLI is the one place in this repo where a dependency is a genuine cost to\n * the USER rather than to us: `npm i -g` pulls the whole tree onto their\n * machine, and an argument parser is fifty lines. Every other package here is\n * free to depend on what it needs; this one is not.\n *\n * The grammar is `pm <verb> <noun> [target] [flags]`, which is the shape the\n * Harness CLI uses and the reason it reads well: a person who has typed\n * `list pipelines` can guess `list memories` without opening the help.\n */\n\nexport interface ParsedArgs {\n /** Positional words, in order, with flags removed. */\n readonly words: readonly string[];\n /**\n * Flag values. An ARRAY when a flag was given more than once.\n *\n * `pm agent --root ~/Desktop --root ~/Downloads` is the documented way to\n * allow two folders \u2014 the help text shows exactly that \u2014 and a plain\n * assignment made the second overwrite the first. The agent then ran with\n * one root and refused everything in the other, saying so in a message that\n * named only the root it had kept, which reads as the folder never having\n * been allowed rather than as the flag having been dropped.\n */\n readonly flags: Readonly<Record<string, string | boolean | readonly string[]>>;\n /** Everything after a bare `--`, handed on untouched. */\n readonly rest: readonly string[];\n}\n\n/**\n * Splits argv.\n *\n * Supports `--flag`, `--flag=value`, `--flag value`, `--no-flag` and short\n * `-x`. A flag whose next token starts with `-` is treated as a boolean rather\n * than swallowing it, so `pm search --explain --limit 5` does not read\n * \"--limit\" as the value of \"--explain\" and then lose the limit entirely.\n */\nexport function parseArgs(argv: readonly string[]): ParsedArgs {\n const words: string[] = [];\n const flags: Record<string, string | boolean | string[]> = {};\n const rest: string[] = [];\n\n /*\n Repeated flags ACCUMULATE instead of overwriting.\n\n Only for string values: `--json --json` is still just true, because a\n boolean repeated says nothing new, and turning it into an array would make\n every `boolFlag` reader handle a shape it has no meaning for.\n */\n const set = (name: string, value: string | boolean): void => {\n const held = flags[name];\n\n if (typeof value === \"boolean\" || held === undefined || typeof held === \"boolean\") {\n flags[name] = value;\n return;\n }\n\n flags[name] = typeof held === \"string\" ? [held, value] : [...held, value];\n };\n\n let index = 0;\n while (index < argv.length) {\n const token = argv[index] as string;\n\n if (token === \"--\") {\n rest.push(...argv.slice(index + 1));\n break;\n }\n\n if (token.startsWith(\"--\")) {\n const body = token.slice(2);\n const equals = body.indexOf(\"=\");\n\n if (equals !== -1) {\n set(body.slice(0, equals), body.slice(equals + 1));\n index += 1;\n continue;\n }\n\n // `--no-colour` sets `colour` false rather than defining a flag called\n // \"no-colour\" that every reader has to remember to check for.\n if (body.startsWith(\"no-\")) {\n set(body.slice(3), false);\n index += 1;\n continue;\n }\n\n const next = argv[index + 1];\n if (next !== undefined && !next.startsWith(\"-\")) {\n set(body, next);\n index += 2;\n continue;\n }\n\n set(body, true);\n index += 1;\n continue;\n }\n\n // A single dash on its own is a filename meaning stdin, not a flag.\n if (token.startsWith(\"-\") && token.length > 1) {\n const body = token.slice(1);\n const next = argv[index + 1];\n if (next !== undefined && !next.startsWith(\"-\")) {\n set(body, next);\n index += 2;\n continue;\n }\n set(body, true);\n index += 1;\n continue;\n }\n\n words.push(token);\n index += 1;\n }\n\n return { words, flags, rest };\n}\n\n/** A flag's value as a string, or undefined. Booleans are not strings. */\nexport function stringFlag(\n args: ParsedArgs,\n ...names: readonly string[]\n): string | undefined {\n for (const name of names) {\n const value = args.flags[name];\n if (typeof value === \"string\") return value;\n // Repeated, and read by something that wants one. The LAST wins, which is\n // the convention every shell tool follows for a scalar option.\n if (Array.isArray(value) && value.length > 0) return value[value.length - 1];\n }\n return undefined;\n}\n\nexport function boolFlag(args: ParsedArgs, ...names: readonly string[]): boolean {\n for (const name of names) {\n const value = args.flags[name];\n if (Array.isArray(value)) continue;\n if (typeof value === \"boolean\") return value;\n // `--json=true` is not idiomatic, but somebody will type it and being\n // strict here produces a flag that silently does nothing.\n if (value === \"true\") return true;\n if (value === \"false\") return false;\n }\n return false;\n}\n\n/**\n * A numeric flag, or undefined.\n *\n * Refuses rather than coerces. `--limit abc` becoming `NaN` and then silently\n * becoming the server's default is how somebody gets ten results, believes\n * they asked for a thousand, and concludes the memory is empty.\n */\nexport function numberFlag(\n args: ParsedArgs,\n ...names: readonly string[]\n): number | undefined | \"invalid\" {\n for (const name of names) {\n const value = args.flags[name];\n if (value === undefined || typeof value === \"boolean\") continue;\n if (Array.isArray(value)) {\n const last = value[value.length - 1];\n if (last === undefined) continue;\n const parsed = Number(last);\n if (!Number.isFinite(parsed)) return \"invalid\";\n return parsed;\n }\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return \"invalid\";\n return parsed;\n }\n return undefined;\n}\n\n/**\n * A list flag, written either way.\n *\n * `--spaces a,b,c` AND `--root ~/one --root ~/two`, because both are natural\n * and the help text for `pm agent` documents the repeated form. This read\n * through `stringFlag`, which returns ONE value, so a repeated flag silently\n * kept a single entry \u2014 the agent was started with two roots and enforced one.\n */\nexport function listFlag(args: ParsedArgs, ...names: readonly string[]): string[] | undefined {\n const items: string[] = [];\n\n for (const name of names) {\n const value = args.flags[name];\n if (value === undefined || typeof value === \"boolean\") continue;\n\n // Each occurrence may itself be a comma-separated list, so the two forms\n // compose: `--root ~/a --root ~/b,~/c` means three roots.\n for (const one of Array.isArray(value) ? value : [value]) {\n for (const part of one.split(\",\")) {\n const trimmed = part.trim();\n if (trimmed.length > 0) items.push(trimmed);\n }\n }\n }\n\n return items.length > 0 ? items : undefined;\n}\n", "import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * Where the CLI keeps what it knows between runs.\n *\n * ~/.persistmemory/config.json profiles: which server, which account\n * ~/.persistmemory/credentials.json the tokens, mode 0600\n *\n * TWO FILES, and that split is the point rather than tidiness. People paste\n * their config into issues, screen-share it, and commit it to dotfile repos.\n * A credential in the same file as \"which API URL am I pointing at\" is a\n * credential that leaves the machine the first time somebody asks for help.\n * Keeping them apart means the file that gets shared is the harmless one.\n *\n * Modelled on the Harness CLI's `~/.harness/config.yaml` plus a separate\n * credentials file, for the same reason and with the same precedence: an\n * environment variable beats the stored profile, because that is what CI needs\n * and a CI runner should never have to write a config file to authenticate.\n */\n\nexport interface Profile {\n readonly apiUrl: string;\n /** Shown by `pm auth status` so a person can tell two accounts apart. */\n readonly account?: string;\n /**\n * This installation's registered OAuth client id for this server.\n *\n * Kept per profile rather than per credential because it survives logging\n * out: registering is rate-limited on the server, and a person who signs\n * out and back in should not consume a fresh registration each time. It is\n * an identifier, not a secret \u2014 there is no client secret to keep, by\n * design \u2014 so it belongs in the config file rather than beside the token.\n */\n readonly clientId?: string;\n}\n\nexport interface Credential {\n /**\n * How this credential was obtained, which decides whether it can be renewed.\n *\n * An API key is fixed and works until revoked. An OAuth access token expires\n * in an hour and is renewed with the refresh token beside it. Recording\n * which one this is means `pm` never tries to refresh something that has no\n * refresh token and reports \"session expired\" for a key that is simply\n * wrong.\n */\n readonly kind: \"api-key\" | \"oauth\";\n readonly token: string;\n readonly refreshToken?: string;\n /** ISO. Absent for an API key, which does not expire on a schedule. */\n readonly expiresAt?: string;\n readonly scope?: string;\n}\n\ninterface ConfigFile {\n readonly current: string;\n readonly profiles: Record<string, Profile>;\n}\n\ntype CredentialsFile = Record<string, Credential>;\n\nexport const DEFAULT_API_URL = \"https://api.persistmemory.com\";\nexport const DEFAULT_PROFILE = \"default\";\n\nexport interface Paths {\n readonly dir: string;\n readonly config: string;\n readonly credentials: string;\n}\n\nexport function pathsFor(home: string = homedir()): Paths {\n const dir = process.env[\"PERSISTMEMORY_HOME\"] ?? join(home, \".persistmemory\");\n return {\n dir,\n config: join(dir, \"config.json\"),\n credentials: join(dir, \"credentials.json\")\n };\n}\n\nexport function readConfig(paths: Paths): ConfigFile {\n const empty: ConfigFile = { current: DEFAULT_PROFILE, profiles: {} };\n if (!existsSync(paths.config)) return empty;\n\n try {\n const parsed = JSON.parse(readFileSync(paths.config, \"utf8\")) as Partial<ConfigFile>;\n return {\n current: typeof parsed.current === \"string\" ? parsed.current : DEFAULT_PROFILE,\n profiles: typeof parsed.profiles === \"object\" && parsed.profiles ? parsed.profiles : {}\n };\n } catch {\n // A corrupt config is not a reason to refuse to run. `pm auth login` is\n // the fix and it must be reachable, which it would not be if reading the\n // file threw on the way to every command.\n return empty;\n }\n}\n\nexport function readCredentials(paths: Paths): CredentialsFile {\n if (!existsSync(paths.credentials)) return {};\n try {\n return JSON.parse(readFileSync(paths.credentials, \"utf8\")) as CredentialsFile;\n } catch {\n return {};\n }\n}\n\n/**\n * Writes a file only its owner can read.\n *\n * Written to a temporary name and renamed, because `writeFileSync` truncates\n * first: a process killed midway through leaves an empty credentials file and\n * the person is silently logged out with no way to tell that from a token\n * having been revoked. Rename within a directory is atomic.\n *\n * The mode is set on the temporary file BEFORE the rename. Creating it 0600 in\n * the same call is not enough on its own \u2014 `writeFileSync`'s mode is subject\n * to the umask \u2014 so it is set explicitly afterwards and before the content is\n * reachable under its final name.\n */\nfunction writeSecurely(path: string, contents: string, mode: number): void {\n const temporary = `${path}.tmp`;\n writeFileSync(temporary, contents, { mode });\n chmodSync(temporary, mode);\n renameSync(temporary, path);\n}\n\nexport function writeConfig(paths: Paths, config: ConfigFile): void {\n mkdirSync(paths.dir, { recursive: true, mode: 0o700 });\n // 0600 as well. It holds no secret, but it does hold which servers this\n // person talks to, and there is no reason for that to be world-readable on a\n // shared machine.\n writeSecurely(paths.config, `${JSON.stringify(config, null, 2)}\\n`, 0o600);\n}\n\nexport function writeCredentials(paths: Paths, credentials: CredentialsFile): void {\n mkdirSync(paths.dir, { recursive: true, mode: 0o700 });\n writeSecurely(paths.credentials, `${JSON.stringify(credentials, null, 2)}\\n`, 0o600);\n}\n\nexport interface Resolved {\n readonly profile: string;\n readonly apiUrl: string;\n readonly credential?: Credential;\n readonly clientId?: string;\n /** True when the credential came from the environment, not the store. */\n readonly fromEnvironment: boolean;\n}\n\n/**\n * What this invocation should use, after everything has had its say.\n *\n * Precedence, highest first \u2014 flag, environment, stored profile, default:\n *\n * --api-key / --api-url an explicit instruction for this one command\n * PERSISTMEMORY_API_KEY what a CI job sets, and what a person exports\n * the named or current profile what `pm auth login` wrote\n * the public API so a fresh install points somewhere real\n *\n * The environment beating the stored profile is deliberate and matches the\n * Harness CLI. A CI runner has no interactive login and must not be made to\n * write a config file to authenticate; being able to export one variable is\n * the whole reason that path exists.\n */\nexport function resolve(args: {\n paths: Paths;\n profileFlag?: string | undefined;\n apiUrlFlag?: string | undefined;\n apiKeyFlag?: string | undefined;\n env?: NodeJS.ProcessEnv;\n}): Resolved {\n const env = args.env ?? process.env;\n const config = readConfig(args.paths);\n\n const profile =\n args.profileFlag ?? env[\"PERSISTMEMORY_PROFILE\"] ?? config.current ?? DEFAULT_PROFILE;\n\n const stored = config.profiles[profile];\n const apiUrl =\n args.apiUrlFlag ?? env[\"PERSISTMEMORY_API_URL\"] ?? stored?.apiUrl ?? DEFAULT_API_URL;\n\n const fromFlag = args.apiKeyFlag;\n const fromEnv = env[\"PERSISTMEMORY_API_KEY\"];\n\n const clientId = stored?.clientId;\n\n if (fromFlag) {\n return {\n profile,\n apiUrl,\n credential: { kind: \"api-key\", token: fromFlag },\n ...(clientId ? { clientId } : {}),\n fromEnvironment: true\n };\n }\n if (fromEnv) {\n return {\n profile,\n apiUrl,\n credential: { kind: \"api-key\", token: fromEnv },\n ...(clientId ? { clientId } : {}),\n fromEnvironment: true\n };\n }\n\n const credential = readCredentials(args.paths)[profile];\n return {\n profile,\n apiUrl,\n ...(credential ? { credential } : {}),\n ...(clientId ? { clientId } : {}),\n fromEnvironment: false\n };\n}\n\nexport function saveLogin(args: {\n paths: Paths;\n profile: string;\n apiUrl: string;\n credential: Credential;\n account?: string;\n clientId?: string;\n}): void {\n const config = readConfig(args.paths);\n writeConfig(args.paths, {\n // Logging in makes that profile the current one. Anything else means a\n // person logs in, runs a command, and is told they are not logged in.\n current: args.profile,\n profiles: {\n ...config.profiles,\n [args.profile]: {\n apiUrl: args.apiUrl,\n ...(args.account ? { account: args.account } : {}),\n // Kept from the existing profile when this login did not register a\n // new client, so an --api-key login does not erase the browser\n // client id and force a re-registration on the next `pm auth login`.\n ...(args.clientId ?? config.profiles[args.profile]?.clientId\n ? { clientId: args.clientId ?? (config.profiles[args.profile]?.clientId as string) }\n : {})\n }\n }\n });\n\n writeCredentials(args.paths, {\n ...readCredentials(args.paths),\n [args.profile]: args.credential\n });\n}\n\n/** Forgets one profile's credential. The profile itself is kept. */\nexport function clearLogin(paths: Paths, profile: string): boolean {\n const credentials = readCredentials(paths);\n if (!(profile in credentials)) return false;\n delete credentials[profile];\n writeCredentials(paths, credentials);\n return true;\n}\n\n/**\n * Enough of a token to recognise, never enough to use.\n *\n * Printed by `pm auth status`, which people run while screen-sharing to work\n * out why a command is failing. Showing the whole token there is how a\n * credential ends up in a recording.\n */\nexport function maskToken(token: string): string {\n if (token.length <= 8) return \"*\".repeat(token.length);\n return `${token.slice(0, 4)}\u2026${token.slice(-4)}`;\n}\n", "/**\n * How a result is printed.\n *\n * Four formats, because a CLI has two audiences that want opposite things: a\n * person reading a terminal wants columns, and a script wants something it can\n * pipe into `jq`. Serving only the first makes the tool unscriptable; serving\n * only the second makes it unreadable.\n *\n * The default is `table` when stdout is a terminal and `json` when it is not,\n * so `pm search x` is readable and `pm search x | jq` works without anyone\n * having to know a flag exists.\n */\n\nexport const OUTPUT_FORMATS = [\"table\", \"json\", \"yaml\", \"csv\", \"tsv\"] as const;\nexport type OutputFormat = (typeof OUTPUT_FORMATS)[number];\n\nexport function isOutputFormat(value: string): value is OutputFormat {\n return (OUTPUT_FORMATS as readonly string[]).includes(value);\n}\n\n/** A column: where the value comes from, and what to call it. */\nexport interface Column<T> {\n readonly header: string;\n readonly value: (row: T) => string;\n}\n\nexport interface RenderOptions {\n readonly format: OutputFormat;\n /** Terminal width, so a table can be narrowed rather than wrapped. */\n readonly width?: number;\n}\n\n/**\n * Renders rows.\n *\n * `json` and `yaml` print the RAW objects, not the columns. A person who asked\n * for JSON wants the record, and giving them the table's five stringified\n * columns would make the machine-readable format the lossy one.\n */\nexport function render<T>(\n rows: readonly T[],\n columns: readonly Column<T>[],\n options: RenderOptions\n): string {\n switch (options.format) {\n case \"json\":\n return JSON.stringify(rows, null, 2);\n case \"yaml\":\n return toYaml(rows);\n case \"csv\":\n return delimited(rows, columns, \",\");\n case \"tsv\":\n return delimited(rows, columns, \"\\t\");\n default:\n return table(rows, columns, options.width);\n }\n}\n\n/** A single object, for `get`-shaped commands. */\nexport function renderOne<T>(\n row: T,\n fields: readonly Column<T>[],\n options: RenderOptions\n): string {\n if (options.format === \"json\") return JSON.stringify(row, null, 2);\n if (options.format === \"yaml\") return toYaml(row);\n if (options.format === \"csv\" || options.format === \"tsv\") {\n return delimited([row], fields, options.format === \"csv\" ? \",\" : \"\\t\");\n }\n\n // Key on the left, value on the right. A `get` prints one record and a\n // one-row table forces the reader's eye across the screen to pair a heading\n // with its value.\n const width = Math.max(...fields.map((field) => field.header.length));\n return fields\n .map((field) => `${field.header.padEnd(width)} ${field.value(row)}`)\n .join(\"\\n\");\n}\n\nfunction table<T>(\n rows: readonly T[],\n columns: readonly Column<T>[],\n width = process.stdout.columns || 120\n): string {\n if (rows.length === 0) return \"\";\n\n const cells = rows.map((row) => columns.map((column) => oneLine(column.value(row))));\n const widths = columns.map((column, index) =>\n Math.max(column.header.length, ...cells.map((row) => (row[index] ?? \"\").length))\n );\n\n // Narrow the widest column until the table fits, rather than wrapping. A\n // wrapped row spans two lines and stops being greppable, which is most of\n // what a table in a terminal is for.\n const separator = 2;\n let total = widths.reduce((sum, one) => sum + one + separator, -separator);\n while (total > width && Math.max(...widths) > 8) {\n const widest = widths.indexOf(Math.max(...widths));\n widths[widest] = (widths[widest] as number) - 1;\n total -= 1;\n }\n\n const line = (values: readonly string[]): string =>\n values\n .map((value, index) => clip(value, widths[index] as number).padEnd(widths[index] as number))\n .join(\" \")\n .trimEnd();\n\n return [\n line(columns.map((column) => column.header.toUpperCase())),\n ...cells.map((row) => line(row))\n ].join(\"\\n\");\n}\n\nfunction delimited<T>(\n rows: readonly T[],\n columns: readonly Column<T>[],\n separator: string\n): string {\n const escape = (value: string): string => {\n const flat = oneLine(value);\n // Quoted only when it has to be. An always-quoted CSV is valid and is\n // needlessly hard to read in a terminal, which is where this one usually\n // ends up.\n if (!flat.includes(separator) && !flat.includes('\"') && !flat.includes(\"\\n\")) return flat;\n return `\"${flat.replace(/\"/g, '\"\"')}\"`;\n };\n\n return [\n columns.map((column) => escape(column.header)).join(separator),\n ...rows.map((row) => columns.map((column) => escape(column.value(row))).join(separator))\n ].join(\"\\n\");\n}\n\n/**\n * YAML, for the subset this CLI actually emits.\n *\n * Hand-written rather than a dependency, for the reason given in `args.ts`: a\n * global install pulls every dependency onto the user's machine. This handles\n * objects, arrays, strings, numbers, booleans and null, which is the whole of\n * what a JSON API response can be.\n */\nexport function toYaml(value: unknown, indent = 0): string {\n const pad = \" \".repeat(indent);\n\n if (value === null || value === undefined) return \"null\";\n if (typeof value === \"boolean\" || typeof value === \"number\") return String(value);\n if (typeof value === \"string\") return yamlString(value);\n\n if (Array.isArray(value)) {\n if (value.length === 0) return \"[]\";\n return value\n .map((item) => {\n const rendered = toYaml(item, indent + 2);\n // A nested block starts on the line after the dash; a scalar sits on it.\n return isBlock(item) ? `${pad}-\\n${rendered}` : `${pad}- ${rendered}`;\n })\n .join(\"\\n\");\n }\n\n if (typeof value === \"object\") {\n const entries = Object.entries(value as Record<string, unknown>);\n if (entries.length === 0) return \"{}\";\n return entries\n .map(([key, item]) => {\n const rendered = toYaml(item, indent + 2);\n return isBlock(item) ? `${pad}${key}:\\n${rendered}` : `${pad}${key}: ${rendered}`;\n })\n .join(\"\\n\");\n }\n\n return String(value);\n}\n\nfunction isBlock(value: unknown): boolean {\n if (Array.isArray(value)) return value.length > 0;\n return typeof value === \"object\" && value !== null && Object.keys(value).length > 0;\n}\n\n/**\n * Quotes a YAML scalar when leaving it bare would change its meaning.\n *\n * `yes`, `no`, `on`, `off`, `null` and anything that parses as a number are\n * the traps: a memory whose content is the single word \"No\" must not read back\n * as the boolean false.\n */\nfunction yamlString(value: string): string {\n if (value === \"\") return '\"\"';\n if (value.includes(\"\\n\")) {\n return `|-\\n${value\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\")}`;\n }\n const ambiguous =\n /^(y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF|null|Null|NULL|~)$/.test(\n value\n ) ||\n /^[-+]?[0-9]/.test(value) ||\n /^[\\s#&*!|>'\"%@`{}[\\],]/.test(value) ||\n value.includes(\": \") ||\n value.endsWith(\":\");\n\n return ambiguous ? `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"` : value;\n}\n\n/** Newlines flattened, so one record stays one row. */\nfunction oneLine(value: string): string {\n return value.replace(/\\s*\\n\\s*/g, \" \").trim();\n}\n\nfunction clip(value: string, width: number): string {\n if (value.length <= width) return value;\n return width <= 1 ? value.slice(0, width) : `${value.slice(0, width - 1)}\u2026`;\n}\n\n/** ISO timestamp to something short enough for a column. */\nexport function shortDate(iso: string | undefined): string {\n if (!iso) return \"\";\n const at = new Date(iso);\n return Number.isNaN(at.getTime()) ? \"\" : iso.slice(0, 16).replace(\"T\", \" \");\n}\n", "import { readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * The help, which is the only documentation most people will read.\n *\n * Written as a page rather than generated from a command table on purpose: a\n * generated help lists everything at equal weight, and the thing a new user\n * needs is the four commands that matter in the order they will need them.\n */\n/**\n * Replaced at build time from `package.json`, never edited here.\n *\n * This was a literal that had to be kept in step with the manifest by hand,\n * and it drifted \u2014 0.2.0 shipped with a binary reporting 0.1.2, so somebody\n * who upgraded was told the upgrade had not happened. Neither file was wrong\n * on its own, which is exactly why nobody caught it.\n *\n * The fallback is for `tsx`, which runs the source directly and performs no\n * substitution: it reads the manifest instead, so a development run reports\n * the truth too.\n */\ndeclare const __PM_VERSION__: string | undefined;\n\nexport const VERSION: string =\n typeof __PM_VERSION__ === \"string\" ? __PM_VERSION__ : versionFromManifest();\n\nfunction versionFromManifest(): string {\n try {\n const here = dirname(fileURLToPath(import.meta.url));\n const manifest = JSON.parse(readFileSync(join(here, \"..\", \"package.json\"), \"utf8\")) as {\n version?: string;\n };\n return manifest.version ?? \"0.0.0\";\n } catch {\n // Never fatal. A CLI that cannot start because it could not work out its\n // own version number is worse than one that reports it as unknown.\n return \"0.0.0\";\n }\n}\n\n/** The name to install, kept beside the version it belongs to. */\nexport const PACKAGE = \"@persistmemory/cli\";\n\nexport const HELP = `\n pm \u2014 PersistMemory from your terminal\n\n Memory that persists across every model, tool and session you use.\n\n GETTING STARTED\n\n pm setup sign in, then pick a Space for this folder\n pm auth login sign in with your browser\n pm auth logout sign out on this machine\n pm start a session and just ask\n pm remember \"we chose Postgres\" capture something\n pm search \"what did we choose\" ask for it back\n\n COMMANDS\n\n auth login sign in through the browser\n auth login --api-key sign in with a key, for CI and headless machines\n\n auth status who am I, and does the server still accept it\n auth logout forget the stored credential\n\n chat start an interactive session\n chat --resume <id> pick up an earlier session\n\n setup sign in and choose this folder's Space\n setup --space \"Acme\" choose one without being asked\n setup --new-space \"Acme\" create one and use it\n\n spaces list your Spaces\n spaces create \"Acme\" make a new one\n spaces delete \"Acme\" --memories keep|delete\n delete one \u2014 you must say what happens\n to what is in it\n spaces merge \"A\" \"B\" --name \"C\" a new Space holding both, originals kept\n\n remember <text> capture text\n remember - capture whatever is piped in\n remember --file <path> capture a file's contents\n\n agent --root <dir> [--root ...] answer file requests from this machine \u2014\n nothing outside those folders is read.\n It stays in the foreground. Background it,\n and stop it later, with:\n nohup pm agent --root ~/Desktop &\n pkill -f \"pm agent\"\n\n search <query> search your memory\n list memories the most recent memories\n list spaces your Spaces\n get memory <id> one memory, in full\n\n drive [name] search your Google Drive\n drive get <id> [--out path] download one file here\n drive put <file> [--name n] save a file into Drive\n mail [search] recent mail \u2014 from:priya, has:attachment\n mail read <id> one message, with its body\n\n status is the service healthy\n requests file requests waiting for you to approve\n requests get <id> write a finished one to a file here\n\n update install the newest version\n uninstall remove pm from this machine\n delete delete every file pm has written here\n\n FLAGS\n\n --output table|json|yaml|csv|tsv how to print (default: table on a\n terminal, json when piped)\n --profile <name> use a named account\n --api-url <url> talk to a different server\n --limit <n> how many results\n --space <a,b> restrict to Spaces, by name or id\n --quiet suppress notices\n --version print the version\n --help print this\n\n ENVIRONMENT\n\n PERSISTMEMORY_API_KEY a key, taking precedence over any stored\n login. This is what CI should set.\n PERSISTMEMORY_API_URL the server to talk to\n PERSISTMEMORY_PROFILE which stored profile to use\n PERSISTMEMORY_SPACE Spaces to use when --space is not given\n PERSISTMEMORY_HOME where config, credentials and session\n transcripts live (default: ~/.persistmemory)\n PERSISTMEMORY_CLIENT_ID override the OAuth client id, for a\n self-hosted deployment\n PERSISTMEMORY_AUTO_UPDATE update without asking when a newer\n version is published\n PERSISTMEMORY_NO_UPDATE never check for updates\n\n Docs: https://persistmemory.com/docs/cli\n`;\n", "import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * Noticing that a newer version exists, and saying so once.\n *\n * A CLI that never mentions its own updates is a CLI most people keep on the\n * version they first installed \u2014 and the bugs they hit were fixed months ago.\n * The whole design here is about being cheap and quiet enough that nobody\n * turns it off:\n *\n * never blocks the check runs after the command has printed, and the\n * answer is used on the NEXT run. A version check has no\n * business delaying `pm search`.\n * once a day the answer is cached with a timestamp.\n * never in a script no terminal, --quiet, CI, or PERSISTMEMORY_NO_UPDATE\n * all skip it. A notice in a log file helps nobody and a\n * notice on stdout would corrupt piped JSON.\n * stderr, always stdout is the command's output and belongs to whatever\n * is reading it.\n */\nconst REGISTRY = \"https://registry.npmjs.org/@persistmemory/cli/latest\";\nconst EVERY_MS = 24 * 60 * 60 * 1000;\n\nexport interface UpdateCheckDeps {\n readonly file: string;\n readonly current: string;\n readonly fetch?: typeof globalThis.fetch;\n readonly now?: () => number;\n readonly env?: NodeJS.ProcessEnv;\n readonly isTty?: boolean;\n readonly quiet?: boolean;\n}\n\ninterface Cached {\n readonly checkedAt: number;\n readonly latest: string;\n}\n\n/** The notice to print, or nothing. Reads the cache; never fetches. */\nexport function updateNotice(deps: UpdateCheckDeps): string | undefined {\n if (!wanted(deps)) return undefined;\n\n const cached = read(deps.file);\n if (!cached) return undefined;\n if (!isNewer(cached.latest, deps.current)) return undefined;\n\n return [\n `A newer PersistMemory CLI is available: ${deps.current} \u2192 ${cached.latest}`,\n `Run \\`pm update\\` to install it.`\n ].join(\"\\n\");\n}\n\n/**\n * Refreshes the cache, if it is stale. Never throws and never blocks anything\n * the person asked for.\n */\nexport async function refreshUpdateCache(deps: UpdateCheckDeps): Promise<void> {\n if (!wanted(deps)) return;\n\n const now = (deps.now ?? Date.now)();\n const cached = read(deps.file);\n if (cached && now - cached.checkedAt < EVERY_MS) return;\n\n const call = deps.fetch ?? globalThis.fetch;\n\n try {\n // Short, because this is a courtesy. A registry that is slow must not make\n // the CLI feel slow, and a missed check costs a day.\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 1500);\n\n const response = await call(REGISTRY, {\n signal: controller.signal,\n headers: { accept: \"application/vnd.npm.install-v1+json\" }\n }).finally(() => clearTimeout(timer));\n\n if (!response.ok) return;\n\n const body = (await response.json()) as { version?: unknown };\n if (typeof body.version !== \"string\") return;\n\n write(deps.file, { checkedAt: now, latest: body.version });\n } catch {\n // Offline, blocked, rate-limited, behind a proxy that hates us. None of\n // these are the person's problem and none of them are worth a word.\n }\n}\n\n/** Whether the person should be told about updates at all. */\nfunction wanted(deps: UpdateCheckDeps): boolean {\n const env = deps.env ?? process.env;\n\n if (deps.quiet === true) return false;\n if (deps.isTty === false) return false;\n if (env[\"PERSISTMEMORY_NO_UPDATE\"]) return false;\n // Every CI system sets this, and none of them can act on the notice.\n if (env[\"CI\"]) return false;\n\n return true;\n}\n\nfunction read(file: string): Cached | undefined {\n try {\n if (!existsSync(file)) return undefined;\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as Partial<Cached>;\n if (typeof parsed.checkedAt !== \"number\" || typeof parsed.latest !== \"string\") {\n return undefined;\n }\n return { checkedAt: parsed.checkedAt, latest: parsed.latest };\n } catch {\n return undefined;\n }\n}\n\nfunction write(file: string, value: Cached): void {\n try {\n mkdirSync(dirname(file), { recursive: true });\n writeFileSync(file, JSON.stringify(value), \"utf8\");\n } catch {\n // A read-only home directory is somebody's deliberate choice. It must not\n // fail a command that has already succeeded.\n }\n}\n\n/**\n * Compares two versions the way npm does, for the part that matters here.\n *\n * Numeric segment by segment, because \"0.10.0\" is newer than \"0.9.0\" and a\n * string comparison says the opposite \u2014 which would nag somebody forever about\n * an update they already have. A prerelease is never announced: somebody\n * running `0.2.0-rc.1` chose it.\n */\nexport function isNewer(candidate: string, current: string): boolean {\n if (candidate.includes(\"-\") || current.includes(\"-\")) return false;\n\n const a = candidate.split(\".\").map(Number);\n const b = current.split(\".\").map(Number);\n if (a.some(Number.isNaN) || b.some(Number.isNaN)) return false;\n\n for (let index = 0; index < Math.max(a.length, b.length); index += 1) {\n const left = a[index] ?? 0;\n const right = b[index] ?? 0;\n if (left !== right) return left > right;\n }\n\n return false;\n}\n\nexport function updateCacheFile(home: string): string {\n return join(home, \"update-check.json\");\n}\n", "import { spawn } from \"node:child_process\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type { Credential } from \"../config\";\nimport { createPkce, randomState } from \"./pkce\";\nimport { startLoopback } from \"./loopback\";\n\n/**\n * The browser sign-in, end to end.\n *\n * No new server endpoint was needed for any of this, which is worth stating\n * because the obvious plan was to build one. The API already implements\n * OAuth 2.1 with PKCE, dynamic client registration (RFC 7591) and the RFC 8252\n * loopback redirect rule \u2014 all of it built for the MCP server and all of it\n * exactly what a CLI needs. A device-code grant or a bespoke `/cli/login`\n * would have been a second authentication surface to harden, rate-limit and\n * keep in step with the first.\n *\n * discover \u2192 GET /.well-known/oauth-authorization-server\n * register \u2192 POST /oauth/register (public client, no secret)\n * authorize \u2192 browser to /oauth/authorize (PKCE challenge + state)\n * redeem \u2192 POST /oauth/token (code + verifier)\n */\n\nexport interface AuthorizationServer {\n readonly issuer: string;\n readonly authorizationEndpoint: string;\n readonly tokenEndpoint: string;\n readonly registrationEndpoint?: string;\n readonly scopesSupported?: readonly string[];\n /**\n * The RFC 8707 resource to ask a token FOR, when the server we are talking\n * to is not the one that issues them.\n */\n readonly resource?: string;\n}\n\n/**\n * Where the server we are talking to says its tokens come from. RFC 9728.\n *\n * This is what lets the CLI point at the command line's own service rather\n * than at the main API. That service issues nothing \u2014 it verifies \u2014 so asking\n * IT for OAuth metadata would find nothing. Instead it publishes a\n * protected-resource document naming its authorization server and its own\n * resource identifier, and the CLI follows that.\n *\n * Absent, and the URL is treated as the authorization server itself, which is\n * what pointing at the main API means. Both work, and neither needs the person\n * to know which kind of server they configured.\n */\nasync function protectedResource(\n apiUrl: string,\n deps: OAuthDeps\n): Promise<{ issuer: string; resource: string } | undefined> {\n try {\n const url = new URL(\"/.well-known/oauth-protected-resource\", apiUrl).toString();\n const response = await deps.fetch(url, { headers: { accept: \"application/json\" } });\n if (!response.ok) return undefined;\n\n const body = (await response.json()) as Record<string, unknown>;\n const servers = body[\"authorization_servers\"];\n const resource = body[\"resource\"];\n\n if (!Array.isArray(servers) || typeof servers[0] !== \"string\") return undefined;\n if (typeof resource !== \"string\") return undefined;\n\n return { issuer: servers[0], resource };\n } catch {\n // Not a protected resource, or unreachable. The caller falls back to\n // treating the URL as the authorization server, which is the main API.\n return undefined;\n }\n}\n\nexport interface OAuthDeps {\n readonly fetch: typeof globalThis.fetch;\n /** Injected so a test never opens a browser and never binds a port. */\n readonly openBrowser?: (url: string) => Promise<void>;\n readonly print?: (line: string) => void;\n}\n\nexport async function discover(\n apiUrl: string,\n deps: OAuthDeps\n): Promise<AuthorizationServer> {\n /**\n * Follow the protected-resource document first, when there is one.\n *\n * A service that only verifies tokens has no `/oauth/authorize` of its own,\n * so discovery has to be redirected to whoever issues for it. When there is\n * no such document the URL IS the authorization server.\n */\n const guarded = await protectedResource(apiUrl, deps);\n const issuerUrl = guarded?.issuer ?? apiUrl;\n\n const url = new URL(\"/.well-known/oauth-authorization-server\", issuerUrl).toString();\n const response = await deps.fetch(url, { headers: { accept: \"application/json\" } });\n\n if (!response.ok) {\n throw new Error(\n `${issuerUrl} does not look like a PersistMemory API: discovery answered ${response.status}.`\n );\n }\n\n const body = (await response.json()) as Record<string, unknown>;\n const required = (key: string): string => {\n const value = body[key];\n if (typeof value !== \"string\") {\n throw new Error(`the server's metadata is missing \"${key}\"`);\n }\n return value;\n };\n\n return {\n issuer: required(\"issuer\"),\n authorizationEndpoint: required(\"authorization_endpoint\"),\n tokenEndpoint: required(\"token_endpoint\"),\n // Carried through so the authorize request can name it. Absent when the\n // API is its own resource, in which case the server uses its default.\n ...(guarded?.resource ? { resource: guarded.resource } : {}),\n ...(typeof body[\"registration_endpoint\"] === \"string\"\n ? { registrationEndpoint: body[\"registration_endpoint\"] }\n : {}),\n ...(Array.isArray(body[\"scopes_supported\"])\n ? { scopesSupported: body[\"scopes_supported\"].map(String) }\n : {})\n };\n}\n\n/**\n * Registers this installation as a public client.\n *\n * Once per machine per server, and the resulting `client_id` is kept in the\n * credentials file. Registering on every login would leave a row per sign-in\n * on the server, and the registration endpoint is deliberately rate-limited.\n *\n * `token_endpoint_auth_method: \"none\"` because there is nowhere on a user's\n * laptop to keep a client secret that the user cannot read. Claiming\n * confidentiality we do not have is worse than not claiming it: the server\n * would then trust a secret that is sitting in a dotfile.\n */\nexport async function registerClient(\n server: AuthorizationServer,\n redirectUri: string,\n scope: string,\n deps: OAuthDeps\n): Promise<string> {\n if (!server.registrationEndpoint) {\n throw new Error(\n \"this server does not offer dynamic client registration. Use `pm auth login --api-key` instead.\"\n );\n }\n\n const response = await deps.fetch(server.registrationEndpoint, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\", accept: \"application/json\" },\n body: JSON.stringify({\n client_name: \"PersistMemory CLI\",\n client_uri: \"https://persistmemory.com/docs/cli\",\n // Registered WITHOUT a port. The server compares loopback redirects\n // ignoring the port (RFC 8252 \u00A77.3), so registering the one we happened\n // to bind this time would be noise \u2014 and would break the next login,\n // which binds a different one.\n redirect_uris: [\"http://127.0.0.1/callback\"],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n scope\n })\n });\n\n if (!response.ok) {\n throw new Error(`could not register with ${server.issuer}: ${await describe(response)}`);\n }\n\n const body = (await response.json()) as { client_id?: unknown };\n if (typeof body.client_id !== \"string\") {\n throw new Error(\"the server registered this client but returned no client_id\");\n }\n return body.client_id;\n}\n\n/**\n * The CLI's own client id, fixed and public.\n *\n * NOT obtained by registering. `/oauth/register` is open to anyone, and the\n * server now refuses to let any caller register under our own name precisely\n * because the consent screen renders that name \u2014 so a CLI that registered\n * itself would either be refused, or would have to call itself something\n * unrecognisable on the screen where a person decides whether to trust it.\n *\n * A public client id is not a secret. It appears in every authorize URL and is\n * baked into a program that runs on other people's machines. What matters is\n * that it is STABLE: consent is recorded against it, and a new id per install\n * would ask everybody to approve the CLI again.\n *\n * Overridable for a self-hosted deployment that seeded a different one.\n */\nexport const CLI_CLIENT_ID = \"persistmemory-cli\";\n\nexport interface LoginResult {\n readonly credential: Credential;\n readonly clientId: string;\n}\n\n/**\n * Is the seeded client actually there?\n *\n * Asked by starting an authorization request and reading the answer, because\n * there is no endpoint that discloses a client by id \u2014 and there should not\n * be, since that would let anyone enumerate what a deployment has registered.\n * A HEAD against `/oauth/authorize` with an unknown client answers 400 with\n * `invalid_client`, and with a known one answers a redirect or a consent\n * page. Either of those means it exists.\n *\n * Failure is treated as \"not there\", so a network problem falls back to\n * registration rather than stopping sign-in with a confusing error.\n */\nasync function knownClient(\n server: AuthorizationServer,\n clientId: string,\n deps: OAuthDeps\n): Promise<boolean> {\n try {\n const probe = new URL(server.authorizationEndpoint);\n probe.searchParams.set(\"client_id\", clientId);\n // Deliberately incomplete: this asks only whether the CLIENT is known, and\n // an incomplete request is refused for a missing parameter rather than for\n // an unknown client \u2014 which is exactly the distinction being read.\n probe.searchParams.set(\"response_type\", \"code\");\n\n const response = await deps.fetch(probe.toString(), {\n method: \"GET\",\n redirect: \"manual\"\n });\n\n if (response.status >= 500) return false;\n const body = await response.text().catch(() => \"\");\n return !body.includes(\"invalid_client\");\n } catch {\n return false;\n }\n}\n\nexport async function loginWithBrowser(args: {\n apiUrl: string;\n scope: string;\n clientId?: string | undefined;\n deps: OAuthDeps;\n timeoutMs?: number;\n}): Promise<LoginResult> {\n const { deps } = args;\n const print = deps.print ?? (() => undefined);\n\n const server = await discover(args.apiUrl, deps);\n const listener = await startLoopback(\n args.timeoutMs !== undefined ? { timeoutMs: args.timeoutMs } : {}\n );\n\n try {\n /**\n * The fixed first-party id, and registration only as a fallback.\n *\n * A deployment that has seeded the CLI client \u2014 every current one does, at\n * boot \u2014 is used directly. Dynamic registration remains for a self-hosted\n * server that has not, and it registers under a plain name because the\n * reserved ones are refused.\n */\n const clientId =\n args.clientId ??\n process.env[\"PERSISTMEMORY_CLIENT_ID\"] ??\n ((await knownClient(server, CLI_CLIENT_ID, deps))\n ? CLI_CLIENT_ID\n : await registerClient(server, listener.redirectUri, args.scope, deps));\n\n const pkce = createPkce();\n const state = randomState();\n\n const authorize = new URL(server.authorizationEndpoint);\n authorize.searchParams.set(\"response_type\", \"code\");\n authorize.searchParams.set(\"client_id\", clientId);\n authorize.searchParams.set(\"redirect_uri\", listener.redirectUri);\n authorize.searchParams.set(\"scope\", args.scope);\n authorize.searchParams.set(\"state\", state);\n authorize.searchParams.set(\"code_challenge\", pkce.challenge);\n authorize.searchParams.set(\"code_challenge_method\", pkce.method);\n /**\n * RFC 8707. Which service this token is FOR.\n *\n * Load-bearing when the CLI is pointed at the command line's own service:\n * a token minted for the default resource is refused there by the audience\n * check, and the refusal looks like a broken sign-in rather than a token\n * for the wrong place.\n */\n if (server.resource) authorize.searchParams.set(\"resource\", server.resource);\n\n print(\"Opening your browser to sign in.\");\n print(`If it does not open, visit:\\n\\n ${authorize.toString()}\\n`);\n\n // Failure to open a browser is NOT failure to log in. On a server over\n // SSH there is no browser at all, and the URL printed above is then the\n // whole flow \u2014 so this is attempted and its outcome ignored.\n await (deps.openBrowser ?? openBrowser)(authorize.toString()).catch(() => undefined);\n\n const callback = await listener.waitForCallback();\n\n if (callback.error) {\n throw new Error(\n `sign-in was refused: ${callback.errorDescription ?? callback.error}`\n );\n }\n if (!callback.code) {\n throw new Error(\"the browser came back without an authorization code\");\n }\n\n /**\n * The state check, in constant time.\n *\n * This is the CSRF defence: without it another site can send the user's\n * browser to a redirect carrying an authorization code the attacker\n * obtained, and the CLI would store a token for the ATTACKER'S account\n * while the user believes they are signed into their own. Everything they\n * then capture goes somewhere else.\n */\n if (!callback.state || !safeEqual(callback.state, state)) {\n throw new Error(\"the browser came back with the wrong state \u2014 sign-in was not completed\");\n }\n\n const credential = await redeem({\n server,\n clientId,\n code: callback.code,\n verifier: pkce.verifier,\n redirectUri: listener.redirectUri,\n deps\n });\n\n return { credential, clientId };\n } finally {\n // Always. A listener left bound holds the port and keeps the process\n // alive, and `pm auth login` would never return.\n listener.close();\n }\n}\n\nasync function redeem(args: {\n server: AuthorizationServer;\n clientId: string;\n code: string;\n verifier: string;\n redirectUri: string;\n deps: OAuthDeps;\n}): Promise<Credential> {\n const form = new URLSearchParams({\n grant_type: \"authorization_code\",\n code: args.code,\n redirect_uri: args.redirectUri,\n client_id: args.clientId,\n code_verifier: args.verifier,\n // Restated at redemption. The server compares it against the resource the\n // code was authorized for and refuses a mismatch, which is what stops a\n // code issued for one service being redeemed for a token against another.\n ...(args.server.resource ? { resource: args.server.resource } : {})\n });\n\n const response = await args.deps.fetch(args.server.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\"\n },\n body: form.toString()\n });\n\n if (!response.ok) {\n throw new Error(`the server refused to issue a token: ${await describe(response)}`);\n }\n\n return toCredential((await response.json()) as Record<string, unknown>);\n}\n\n/**\n * Trades a refresh token for a new access token.\n *\n * Exported because every command needs it, not just login: an access token\n * lasts an hour and a person who signed in yesterday should not be told to\n * sign in again to run `pm search`.\n */\nexport async function refresh(args: {\n apiUrl: string;\n clientId: string;\n refreshToken: string;\n deps: OAuthDeps;\n}): Promise<Credential> {\n const server = await discover(args.apiUrl, args.deps);\n\n const response = await args.deps.fetch(server.tokenEndpoint, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n accept: \"application/json\"\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: args.refreshToken,\n client_id: args.clientId\n }).toString()\n });\n\n if (!response.ok) {\n throw new Error(`could not renew the session: ${await describe(response)}`);\n }\n\n const credential = toCredential((await response.json()) as Record<string, unknown>);\n\n // A server that rotates refresh tokens returns a new one; one that does not\n // returns none, and the old one stays valid. Dropping the old one in that\n // second case would log the person out an hour later for no reason.\n return credential.refreshToken\n ? credential\n : { ...credential, refreshToken: args.refreshToken };\n}\n\nexport function toCredential(body: Record<string, unknown>): Credential {\n const token = body[\"access_token\"];\n if (typeof token !== \"string\") {\n throw new Error(\"the server's token response contained no access_token\");\n }\n\n const expiresIn = body[\"expires_in\"];\n const expiresAt =\n typeof expiresIn === \"number\" && Number.isFinite(expiresIn)\n ? new Date(Date.now() + expiresIn * 1000).toISOString()\n : undefined;\n\n return {\n kind: \"oauth\",\n token,\n ...(typeof body[\"refresh_token\"] === \"string\"\n ? { refreshToken: body[\"refresh_token\"] }\n : {}),\n ...(expiresAt ? { expiresAt } : {}),\n ...(typeof body[\"scope\"] === \"string\" ? { scope: body[\"scope\"] } : {})\n };\n}\n\n/** Compares two secrets without leaking their prefix through timing. */\nfunction safeEqual(a: string, b: string): boolean {\n const left = Buffer.from(a);\n const right = Buffer.from(b);\n if (left.length !== right.length) return false;\n return timingSafeEqual(left, right);\n}\n\n/**\n * Opens a URL in whatever the platform calls a browser.\n *\n * The URL is passed as an ARGUMENT, never through a shell. It contains a\n * client id and a code challenge and is assembled from a server's metadata; a\n * `sh -c` with that interpolated is a command injection with a remote source.\n */\nasync function openBrowser(url: string): Promise<void> {\n /**\n * Windows needs `cmd /c start`, not `start`.\n *\n * `start` is a cmd BUILTIN and not an executable, so spawning it directly\n * fails with ENOENT on every Windows machine \u2014 the browser never opens and\n * the person is left staring at a prompt. The empty string after it is not a\n * typo: `start` treats its first quoted argument as the window TITLE, so\n * without a placeholder a quoted URL is consumed as the title and nothing\n * opens.\n *\n * `windowsVerbatimArguments` is off, so Node quotes the URL for us \u2014 which\n * matters because an authorize URL is full of `&`, and an unquoted `&` in\n * cmd separates commands.\n */\n const [command, args] =\n process.platform === \"darwin\"\n ? [\"open\", [url]]\n : process.platform === \"win32\"\n ? [\"cmd\", [\"/c\", \"start\", \"\", url]]\n : [\"xdg-open\", [url]];\n\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command as string, args as string[], {\n stdio: \"ignore\",\n // Detached so closing the terminal does not close the browser, and so\n // this process can exit without waiting for it.\n detached: true\n });\n child.once(\"error\", reject);\n child.unref();\n resolve();\n });\n}\n\nasync function describe(response: Response): Promise<string> {\n try {\n const body = (await response.json()) as Record<string, unknown>;\n const error = body[\"error\"];\n const description = body[\"error_description\"];\n if (typeof description === \"string\") return `${String(error ?? response.status)} \u2014 ${description}`;\n if (typeof error === \"string\") return error;\n } catch {\n // Falls through to the status, which is all we have.\n }\n return `HTTP ${response.status}`;\n}\n", "import { createHash, randomBytes } from \"node:crypto\";\n\n/**\n * PKCE (RFC 7636), which is what makes a public client safe.\n *\n * The CLI cannot keep a secret \u2014 it is a file on the user's disk \u2014 so it\n * registers with `token_endpoint_auth_method: \"none\"` and proves possession a\n * different way: it invents a random verifier, sends only its hash with the\n * authorization request, and reveals the verifier when redeeming the code.\n *\n * That is the entire defence against an authorization code being stolen out of\n * a loopback redirect, which is a real risk on a shared machine: another\n * process can race to bind the port or read the URL out of a browser history.\n * A stolen code without the verifier is worthless.\n */\nexport interface Pkce {\n readonly verifier: string;\n readonly challenge: string;\n readonly method: \"S256\";\n}\n\nexport function createPkce(): Pkce {\n // 32 bytes, base64url. RFC 7636 requires 43-128 characters of the unreserved\n // set, and 32 random bytes encodes to 43 \u2014 the minimum that is also the full\n // entropy of the generator.\n const verifier = base64Url(randomBytes(32));\n return {\n verifier,\n challenge: base64Url(createHash(\"sha256\").update(verifier).digest()),\n // Never \"plain\". OAuth 2.1 removes it, and a plain challenge is the\n // verifier, which defends against nothing.\n method: \"S256\"\n };\n}\n\n/** A value a caller must not be able to guess or replay. */\nexport function randomState(): string {\n return base64Url(randomBytes(24));\n}\n\nfunction base64Url(bytes: Buffer): string {\n return bytes.toString(\"base64\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n", "import { createServer } from \"node:http\";\nimport type { Server } from \"node:http\";\n\n/**\n * The one-shot listener the browser is redirected back to.\n *\n * RFC 8252 \u00A77.3: a native app receives its authorization code on a loopback\n * address, binding whatever port happens to be free. This repo's redirect-URI\n * policy already implements the matching half of that rule \u2014 the port, and\n * only the port, is ignored when comparing against the registered URI \u2014 so the\n * CLI does not have to register a fixed port or ask the user to keep one free.\n *\n * Bound to 127.0.0.1 EXPLICITLY rather than to every interface. Binding 0.0.0.0\n * would put somebody's authorization code on a listener reachable from their\n * whole network, and on a laptop in a caf\u00E9 that is the entire attack.\n */\nexport interface Callback {\n readonly code?: string;\n readonly state?: string;\n readonly error?: string;\n readonly errorDescription?: string;\n}\n\nexport interface Listener {\n readonly port: number;\n readonly redirectUri: string;\n /** Resolves when the browser comes back, or rejects on timeout. */\n waitForCallback(): Promise<Callback>;\n close(): void;\n}\n\nexport const CALLBACK_PATH = \"/callback\";\n\nexport async function startLoopback(options: { timeoutMs?: number } = {}): Promise<Listener> {\n const timeoutMs = options.timeoutMs ?? 5 * 60 * 1000;\n\n let resolveCallback: ((value: Callback) => void) | undefined;\n let rejectCallback: ((reason: Error) => void) | undefined;\n\n const received = new Promise<Callback>((resolve, reject) => {\n resolveCallback = resolve;\n rejectCallback = reject;\n });\n\n const server: Server = createServer((request, response) => {\n const url = new URL(request.url ?? \"/\", \"http://127.0.0.1\");\n\n if (url.pathname !== CALLBACK_PATH) {\n response.writeHead(404, { \"content-type\": \"text/plain\" });\n response.end(\"Not found\");\n return;\n }\n\n const callback: Callback = {\n ...(url.searchParams.get(\"code\") ? { code: url.searchParams.get(\"code\") as string } : {}),\n ...(url.searchParams.get(\"state\") ? { state: url.searchParams.get(\"state\") as string } : {}),\n ...(url.searchParams.get(\"error\") ? { error: url.searchParams.get(\"error\") as string } : {}),\n ...(url.searchParams.get(\"error_description\")\n ? { errorDescription: url.searchParams.get(\"error_description\") as string }\n : {})\n };\n\n // The page the person is left looking at. Served from here rather than\n // redirecting to the web app, because a redirect would put the code in\n // another origin's referrer and because this must work offline against a\n // local API.\n response.writeHead(200, {\n \"content-type\": \"text/html; charset=utf-8\",\n // This page is one-use and holds a result; nothing should keep it.\n \"cache-control\": \"no-store\",\n // It never loads anything, so it is not allowed to.\n \"content-security-policy\": \"default-src 'none'; style-src 'unsafe-inline'\",\n /*\n Not kept alive, because a kept socket keeps the PROCESS alive.\n\n `server.close()` stops new connections and leaves established ones\n open, and a browser holds this one open by default \u2014 so `pm auth login`\n printed \"Signed in\" and then sat there until somebody pressed Ctrl+C.\n The page is the last thing this server ever serves; there is nothing to\n reuse the connection for.\n */\n connection: \"close\"\n });\n response.end(donePage(callback));\n\n resolveCallback?.(callback);\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n // Port 0: the operating system picks one that is free. Choosing a fixed\n // port means a second `pm auth login`, or any other tool, collides.\n server.listen(0, \"127.0.0.1\", resolve);\n });\n\n const address = server.address();\n if (address === null || typeof address === \"string\") {\n server.close();\n throw new Error(\"could not determine the port the callback listener bound to\");\n }\n\n const timer = setTimeout(() => {\n rejectCallback?.(\n new Error(\"timed out waiting for the browser. Run `pm auth login` again, or use --api-key.\")\n );\n }, timeoutMs);\n // Never hold the process open on its own account.\n timer.unref?.();\n\n return {\n port: address.port,\n redirectUri: `http://127.0.0.1:${address.port}${CALLBACK_PATH}`,\n async waitForCallback() {\n try {\n return await received;\n } finally {\n clearTimeout(timer);\n }\n },\n close() {\n clearTimeout(timer);\n /*\n Sockets first, then the server.\n\n `close()` alone waits for every existing connection to end on its own,\n which for a keep-alive browser socket means waiting out its idle\n timeout \u2014 a minute or more of a CLI that has already finished.\n `closeAllConnections` exists for exactly this and is guarded because it\n arrived in Node 18.2, below the floor this package supports.\n */\n server.closeAllConnections?.();\n server.close();\n // Belt to the braces: even a socket that somehow survives both calls\n // must not be the reason this process stays alive.\n server.unref();\n }\n };\n}\n\n/**\n * The page shown after the redirect.\n *\n * Deliberately plain and self-contained: no fonts, no scripts, no requests. It\n * is shown for about two seconds and must render identically on a machine with\n * no network, which is exactly the situation somebody is in when they are\n * authenticating against a local API.\n */\nfunction donePage(callback: Callback): string {\n const failed = Boolean(callback.error) || !callback.code;\n const title = failed ? \"Sign-in failed\" : \"You are signed in\";\n const detail = failed\n ? escapeHtml(callback.errorDescription ?? callback.error ?? \"No authorization code was returned.\")\n : \"You can close this tab and go back to your terminal.\";\n\n return `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><title>${title}</title>\n<style>\n :root { color-scheme: light dark; }\n body { font: 16px/1.6 ui-sans-serif, system-ui, -apple-system, sans-serif;\n display: grid; place-items: center; min-height: 100vh; margin: 0; }\n main { max-width: 30rem; padding: 2rem; text-align: center; }\n h1 { font-size: 1.25rem; margin: 0 0 .5rem; }\n p { margin: 0; opacity: .8; }\n</style></head>\n<body><main><h1>${title}</h1><p>${detail}</p></main></body></html>`;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n", "import { PersistMemory } from \"@persistmemory/sdk\";\nimport type { Credential, Paths, Resolved } from \"./config\";\nimport { readCredentials, writeCredentials } from \"./config\";\nimport { refresh } from \"./auth/oauth\";\nimport type { OAuthDeps } from \"./auth/oauth\";\n\n/**\n * Turns \"what this invocation resolved to\" into a client that will actually\n * work, renewing the session first when it is about to stop working.\n *\n * The renewal happens HERE rather than inside the SDK on a 401, and the reason\n * is the credentials file. A retry-on-401 inside the transport would have to\n * write to disk from within a request, which means two `pm` commands running\n * at once can interleave a read and a write and leave a truncated file \u2014 the\n * one failure mode that logs a person out with no explanation. Renewing before\n * the first request keeps the write in one place, before any work starts.\n */\n\nexport class NotSignedIn extends Error {\n constructor() {\n super(\n \"not signed in. Run `pm auth login`, or set PERSISTMEMORY_API_KEY for a non-interactive session.\"\n );\n this.name = \"NotSignedIn\";\n }\n}\n\n/** Renewed this far ahead of expiry, so a slow command does not expire mid-flight. */\nconst RENEW_BEFORE_MS = 60_000;\n\nexport function isExpired(credential: Credential, now = Date.now()): boolean {\n if (credential.kind !== \"oauth\" || !credential.expiresAt) return false;\n const at = Date.parse(credential.expiresAt);\n return Number.isFinite(at) && at - RENEW_BEFORE_MS <= now;\n}\n\nexport interface SessionDeps extends OAuthDeps {\n readonly paths: Paths;\n readonly now?: () => number;\n readonly userAgent?: string;\n}\n\nexport async function clientFor(\n resolved: Resolved,\n deps: SessionDeps\n): Promise<PersistMemory> {\n const credential = await currentCredential(resolved, deps);\n\n return new PersistMemory({\n apiKey: credential.token,\n baseUrl: resolved.apiUrl,\n ...(deps.userAgent ? { userAgent: deps.userAgent } : {}),\n fetch: deps.fetch\n });\n}\n\nexport async function currentCredential(\n resolved: Resolved,\n deps: SessionDeps\n): Promise<Credential> {\n /*\n Re-read from disk, because `resolved` is a SNAPSHOT taken at startup.\n\n This is the bug behind \"That refresh token was already used. For safety\n this connection has been revoked\", seen seconds after a successful\n `pm auth login`. Login writes new tokens to the credentials file, and then\n the same process asks for a client \u2014 built from the snapshot taken BEFORE\n the login, holding the previous session. That one is expired, so this\n function renewed it, and the refresh token it renewed with had already been\n spent. The server did exactly the right thing: a spent refresh token is\n indistinguishable from a stolen one, so it revoked.\n\n A file read per command is nothing next to the request that follows it, and\n it makes \"the credential in this file\" the single source of truth rather\n than \"the credential this process happened to start with\".\n\n An explicit `--api-key` or `PERSISTMEMORY_API_KEY` still wins: those name a\n credential deliberately, and a file must not override what somebody typed.\n */\n const credential = resolved.fromEnvironment\n ? resolved.credential\n : (readCredentials(deps.paths)[resolved.profile] ?? resolved.credential);\n\n if (!credential) throw new NotSignedIn();\n\n if (!isExpired(credential, deps.now?.() ?? Date.now())) return credential;\n\n /**\n * Expired, and there is nothing to renew it with.\n *\n * Said plainly rather than letting the request go out and fail with a 401.\n * \"Your session expired, sign in again\" is actionable; \"401 Unauthorized\"\n * from a command the person ran ten seconds after signing in is not, and it\n * is what they would otherwise see.\n */\n if (!credential.refreshToken || !resolved.clientId) {\n throw new Error(\"your session has expired. Run `pm auth login` to sign in again.\");\n }\n\n const renewed = await refresh({\n apiUrl: resolved.apiUrl,\n clientId: resolved.clientId,\n refreshToken: credential.refreshToken,\n deps\n });\n\n // Persisted immediately. A renewal that is used and not stored means every\n // single command pays for a refresh round trip, and the server counts each\n // one against the token endpoint's rate limit.\n writeCredentials(deps.paths, {\n ...readCredentials(deps.paths),\n [resolved.profile]: renewed\n });\n\n return renewed;\n}\n", "import { createInterface } from \"node:readline\";\nimport type { PersistMemory } from \"@persistmemory/sdk\";\nimport type { ParsedArgs } from \"./args\";\nimport type { Paths, Resolved } from \"./config\";\nimport type { OutputFormat } from \"./output\";\nimport type { OAuthDeps } from \"./auth/oauth\";\nimport type { SessionDeps } from \"./session\";\n\n/**\n * Everything a command is allowed to reach for.\n *\n * Handed in rather than imported, for the same reason the ingestion plugins get\n * a context: it is what makes a command testable without a network, a home\n * directory or a terminal. Every test in this package drives a real command\n * through this object.\n */\nexport interface GlobalFlags {\n readonly profile?: string;\n readonly apiUrl?: string;\n /** `true` means \"prompt for it\" \u2014 see the note in `auth.ts`. */\n readonly apiKey?: string | true;\n readonly output: OutputFormat;\n readonly quiet: boolean;\n readonly limit?: number;\n}\n\nexport interface CommandContext {\n readonly args: ParsedArgs;\n readonly flags: GlobalFlags;\n readonly paths: Paths;\n readonly resolved: Resolved;\n readonly oauth: OAuthDeps;\n readonly session: SessionDeps;\n /** Built lazily: `pm auth login` must run without a credential. */\n client(): Promise<PersistMemory>;\n print(line: string): void;\n error(line: string): void;\n readSecret(prompt: string): Promise<string>;\n /**\n * A visible question, for the setup wizard.\n *\n * Separate from `readSecret` because it echoes: choosing a Space from a\n * numbered list with the digits hidden would be unusable, and the answer is\n * not a secret.\n */\n ask(prompt: string): Promise<string>;\n /**\n * Whether a person is watching.\n *\n * Carried on the context rather than read from `process.stdin.isTTY` where\n * it is needed, so a test can drive the wizard's interactive path \u2014 reading\n * the global directly meant every prompt was skipped under vitest and the\n * branch that matters most was the one branch nothing exercised.\n */\n readonly isTty: boolean;\n}\n\n/**\n * Asks a question and reads one line, echoing it.\n *\n * Returns \"\" when stdin is not a terminal and there is nothing to read, which\n * is what makes the wizard fall back to its defaults instead of hanging in a\n * pipeline \u2014 an interactive prompt in CI blocks until the job times out.\n */\nexport async function askOnTty(\n prompt: string,\n input: NodeJS.ReadableStream = process.stdin,\n output: NodeJS.WritableStream = process.stdout\n): Promise<string> {\n return new Promise((resolve) => {\n const readline = createInterface({ input, output });\n\n /*\n Answered BEFORE the interface is closed, and the close handler only\n settles what the answer did not.\n\n `readline.close()` emits \"close\" SYNCHRONOUSLY, so closing first ran the\n handler below before `resolve(answer)` was ever reached \u2014 and a promise\n keeps the first value it is settled with. Every prompt in this CLI\n therefore returned an empty string however carefully somebody typed:\n `pm setup` asked for a Space name, was told \"A Space needs a name\", and\n asked again, forever.\n\n The close handler is still needed. It is what answers Ctrl+D, where no\n line is ever entered and nothing else would settle this promise.\n */\n let answered = false;\n\n readline.question(prompt, (answer) => {\n answered = true;\n resolve(answer.trim());\n readline.close();\n });\n\n readline.once(\"close\", () => {\n if (!answered) resolve(\"\");\n });\n });\n}\n\n/** Ctrl-C, and the two characters a terminal sends for backspace. */\nconst ETX = \"\\u0003\";\nconst DELETE = \"\\u007f\";\nconst BACKSPACE = \"\\b\";\n\n/**\n * Reads a secret from the terminal without echoing it.\n *\n * Not decoration. A pasted API key that is echoed stays in the scrollback, gets\n * captured by screen recordings, and is read over the shoulder \u2014 and the whole\n * reason `--api-key` prompts rather than taking an argument is to keep the key\n * out of the shell history in the first place.\n *\n * When stdin is not a terminal this reads a line normally, which is what makes\n * `echo $KEY | pm auth login --api-key` work in a pipeline.\n */\nexport async function readSecretFromTty(prompt: string): Promise<string> {\n const input = process.stdin;\n\n if (!input.isTTY) {\n return new Promise((resolve) => {\n const readline = createInterface({ input });\n\n // The same ordering as `askOnTty`, for the same reason: `close()` emits\n // synchronously, so closing before resolving settles this promise with\n // the empty string every time. Piping a key into `pm auth login` read\n // nothing.\n let answered = false;\n\n readline.once(\"line\", (line) => {\n answered = true;\n resolve(line.trim());\n readline.close();\n });\n\n readline.once(\"close\", () => {\n if (!answered) resolve(\"\");\n });\n });\n }\n\n process.stdout.write(prompt);\n const previouslyRaw = input.isRaw ?? false;\n input.setRawMode?.(true);\n input.resume();\n input.setEncoding(\"utf8\");\n\n return new Promise((resolve) => {\n let value = \"\";\n\n const finish = (): void => {\n input.removeListener(\"data\", onData);\n input.setRawMode?.(previouslyRaw);\n input.pause();\n process.stdout.write(\"\\n\");\n resolve(value.trim());\n };\n\n const onData = (chunk: string): void => {\n for (const character of chunk) {\n switch (character) {\n case \"\\r\":\n case \"\\n\":\n finish();\n return;\n case ETX:\n // Exits rather than returning an empty key, which would otherwise\n // be stored as a credential and fail on the next command instead\n // of here, where the person can see what happened.\n input.setRawMode?.(previouslyRaw);\n process.stdout.write(\"\\n\");\n process.exit(130);\n return;\n case DELETE:\n case BACKSPACE:\n value = value.slice(0, -1);\n break;\n default:\n // Control characters are dropped rather than stored: an arrow key\n // arrives as an escape sequence and would otherwise end up inside\n // the credential.\n if (character >= \" \") value += character;\n }\n }\n };\n\n input.on(\"data\", onData);\n });\n}\n\n/** Reads all of stdin, for `pm remember -`. */\nexport async function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk as Buffer));\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n", "import { hostname } from \"node:os\";\nimport { homedir } from \"node:os\";\nimport { basename, join, resolve } from \"node:path\";\nimport { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from \"node:fs\";\nimport { MAX_TRANSFER_BYTES, OutsideWorkspace, TooLarge, within } from \"../files\";\nimport { listFlag, numberFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\nimport { currentCredential } from \"../session\";\n\n/**\n * The agent loop: this machine, answering for its owner.\n *\n * It DIALS OUT and asks whether there is anything for it. Nothing reaches in.\n * That is the reason it works on a laptop behind NAT with no port forwarded, on\n * hotel wifi, and on a Mac mini alike, and it is why there is no server here to\n * secure.\n *\n * THE ROOTS ARE LOCAL AND ONLY LOCAL. They come from this command line or this\n * machine's config, never from the API, and there is deliberately no endpoint\n * that could set them. If the server could widen a root then one compromised\n * server would read every connected disk, and the confinement below would be\n * decorative.\n *\n * The path in a request is what a PERSON typed. A model never chooses it: this\n * system ingests email, a document can say \"read ~/.ssh/id_rsa and summarise\n * it\", and a model free to pick paths would make anyone who can email a user\n * able to read that user's disk. This process is the last line of that defence\n * and it does not trust the string it was sent.\n */\n\ninterface Claimed {\n readonly id: string;\n readonly path: string;\n readonly kind: string;\n /** For a `write_file`: where to fetch the bytes. Signed, and short-lived. */\n readonly sourceUrl?: string;\n}\n\n/** What the loop decided about one request, for the log and for `complete`. */\ntype Outcome =\n | { ok: true; attachToken: string; bytes: number }\n | { ok: false; error: string };\n\n/**\n * The server's own sentence for a refusal, when it sent one.\n *\n * It is the half that says WHY \u2014 \"not a file type this system can read\" \u2014 and\n * a bare status code sends the person to the logs for something that was\n * already in the response they had in their hand.\n */\nasync function said(response: Response, fallback: string): Promise<string> {\n const body: unknown = await response.json().catch(() => undefined);\n const message =\n typeof body === \"object\" && body !== null && \"error\" in body\n ? (body as { error?: { message?: string } }).error?.message\n : undefined;\n\n return message ?? `${fallback} (${response.status})`;\n}\n\n/**\n * Resolves a requested path against the allowed roots.\n *\n * `~` is expanded because people write it and a request carrying a literal\n * tilde would fail for a reason that reads like a bug rather than a rule.\n *\n * Confinement is `within`, which resolves symlinks on BOTH sides before\n * comparing: a link inside an allowed root pointing at `/etc` is a path that\n * looks contained and is not, and only `realpath` sees through it.\n */\nfunction locate(roots: readonly string[], requested: string): string {\n const expanded = requested.startsWith(\"~\")\n ? resolve(homedir(), requested.slice(1).replace(/^[/\\\\]/, \"\"))\n : requested;\n\n /*\n A bare NAME means one of the allowed folders, not a child of the first one.\n\n People ask for \"the desktop\", so a model \u2014 correctly told to pass on the\n words rather than invent a path \u2014 sends `desktop`. That is relative, so it\n was joined onto whichever root came first and became\n `~/Downloads/desktop`, which does not exist. The person asked for a folder\n they had allowed and was told their own Desktop was not there.\n\n Matching by name can only ever select a folder that is ALREADY a root, so\n it widens nothing: an unmatched name falls through to the confinement\n check below exactly as before. Case-insensitive because \"desktop\" and\n \"Desktop\" are the same folder to everyone except a filesystem.\n */\n if (!expanded.includes(\"/\") && !expanded.includes(\"\\\\\")) {\n const wanted = expanded.trim().toLowerCase();\n const named = roots.find((root) => basename(root).toLowerCase() === wanted);\n if (named) return within(named, named);\n }\n\n for (const root of roots) {\n try {\n return within(root, expanded);\n } catch (error) {\n // Only \"outside THIS root\" moves on to the next one. Anything else is a\n // real failure to resolve the path, and reporting it as a confinement\n // refusal would blame the person for a fault on this machine.\n if (!(error instanceof OutsideWorkspace)) throw error;\n }\n }\n\n // A plain Error, not `OutsideWorkspace`: that one appends its own sentence\n // about the session directory, which is not what confined this read, and\n // handing it a whole sentence glued two of them together.\n throw new Error(`${requested} is not inside any allowed folder (${roots.join(\", \")})`);\n}\n\n/**\n * A path that is not already taken.\n *\n * `report.pdf`, then `report (1).pdf`. Combined with the `wx` flag on the\n * write itself, which fails rather than truncates if something appeared\n * between the check and the write \u2014 the gap is small and a person's file is\n * not worth losing to it.\n */\nfunction uncontested(target: string): string {\n if (!existsSync(target)) return target;\n\n const dot = target.lastIndexOf(\".\");\n const stem = dot > target.lastIndexOf(\"/\") && dot !== -1 ? target.slice(0, dot) : target;\n const extension = stem === target ? \"\" : target.slice(dot);\n\n for (let n = 1; n < 1_000; n += 1) {\n const candidate = `${stem} (${n})${extension}`;\n if (!existsSync(candidate)) return candidate;\n }\n\n throw new Error(`${target} and a thousand names beside it are taken.`);\n}\n\n/**\n * Exported for the tests, which is the only way to reach the decisions that\n * matter here without standing up a whole agent loop against a live service.\n */\nexport { uncontested as chooseWritePath, locate as resolveWithinRoots };\n\nasync function answer(\n context: CommandContext,\n apiUrl: string,\n token: string,\n roots: readonly string[],\n request: Claimed\n): Promise<Outcome> {\n let located: string;\n\n try {\n located = locate(roots, request.path);\n } catch (error) {\n // The refusal is the answer, not a crash. The person asked for something\n // outside what they allowed on this machine, and they should be told that\n // rather than watching the request sit unanswered.\n return { ok: false, error: error instanceof Error ? error.message : \"refused\" };\n }\n\n /*\n A write, which is the only kind that changes this machine.\n\n Three rules, and each is answering a specific way this could go wrong:\n\n The destination is resolved inside the configured roots, exactly like a\n read. `locate` resolves symlinks on BOTH sides, so a link inside an\n allowed folder pointing at `/etc` does not become a way out of it.\n\n NOTHING IS OVERWRITTEN. A write that replaces a file destroys something\n the person had, and no approval screen showing a path conveys that \u2014\n they read \"save this here\", not \"delete what is there\". A name that is\n taken gets a suffix.\n\n The bytes come from a signed URL the SERVER minted, not from anything in\n the request. A request that could name its own source could name a file\n belonging to somebody else.\n */\n if (request.kind === \"write_file\") {\n if (!request.sourceUrl) return { ok: false, error: \"There was nothing to write.\" };\n\n let downloaded: Buffer;\n let fetched: Response;\n try {\n fetched = await fetch(request.sourceUrl);\n if (!fetched.ok) {\n return { ok: false, error: await said(fetched, \"The file could not be fetched\") };\n }\n downloaded = Buffer.from(await fetched.arrayBuffer());\n } catch {\n return { ok: false, error: \"The file could not be fetched from the service.\" };\n }\n\n try {\n /*\n A folder is a legitimate destination, and the common one.\n\n Somebody saying \"put it in ~/Downloads\" named a directory, not a file.\n The name then comes from the service's own `content-disposition` \u2014 the\n one place a filename is available that the requester did not choose,\n and `basename` on it because a filename is not a path: a `../` in one\n would write outside the folder that was just confined.\n */\n let target = located;\n\n if (existsSync(located) && statSync(located).isDirectory()) {\n const disposition = fetched.headers.get(\"content-disposition\") ?? \"\";\n const named = /filename=\"([^\"]+)\"/.exec(disposition)?.[1];\n target = join(located, basename(named ?? \"file\"));\n }\n\n target = uncontested(target);\n writeFileSync(target, downloaded, { flag: \"wx\" });\n\n /*\n Answered with a listing of what was written, through the ordinary\n upload path.\n\n Every surface already knows how to show a request's result, and a\n write that reported success some other way would need each of them\n taught about it. The person gets back the path it actually landed on,\n which matters precisely because it may not be the one they named.\n */\n return upload(\n apiUrl,\n token,\n \"written.txt\",\n Buffer.from(`Saved to ${target}\\n${downloaded.length} bytes\\n`, \"utf8\")\n );\n } catch (error) {\n return {\n ok: false,\n error: error instanceof Error ? error.message : \"could not write it\"\n };\n }\n }\n\n let bytes: Buffer;\n let filename = request.path.split(\"/\").pop() ?? \"file\";\n\n /*\n A listing is answered here and uploaded like any other answer.\n\n Deliberately the same path as a file read rather than a second mechanism:\n the request row already stores a blob reference, every surface already\n knows how to show one, and a listing that travelled some other way would\n need each of those taught about it again.\n\n NAMES AND SIZES ONLY. Not contents, not one level deeper: the person asked\n what is in a folder, and reading a hundred files to answer that is a\n different and much larger permission than the one they granted.\n */\n if (request.kind === \"list_dir\") {\n try {\n const stats = statSync(located);\n if (!stats.isDirectory()) return { ok: false, error: `${request.path} is not a folder.` };\n\n const entries = readdirSync(located, { withFileTypes: true })\n // Dot-files left out. They are configuration and credentials far more\n // often than they are what somebody meant by \"what is in this folder\".\n .filter((entry) => !entry.name.startsWith(\".\"))\n .slice(0, MAX_LISTED)\n .map((entry) => {\n if (entry.isDirectory()) return `${entry.name}/`;\n try {\n return `${entry.name} ${sizeOf(join(located, entry.name))}`;\n } catch {\n return entry.name;\n }\n })\n .sort();\n\n const listing = entries.length > 0 ? entries.join(\"\\n\") : \"(empty)\";\n bytes = Buffer.from(`${request.path}\\n\\n${listing}\\n`, \"utf8\");\n filename = `${request.path.split(\"/\").filter(Boolean).pop() ?? \"listing\"}.txt`;\n\n const grant = await upload(apiUrl, token, filename, bytes);\n return grant;\n } catch (error) {\n return { ok: false, error: error instanceof Error ? error.message : \"could not list it\" };\n }\n }\n\n try {\n const stats = statSync(located);\n if (!stats.isFile()) return { ok: false, error: `${request.path} is not a file.` };\n /*\n The size limit is the SERVER'S, asked for rather than assumed.\n\n A constant here and a constant there is two numbers that drift: raise the\n one in storage and this machine goes on refusing files the service would\n have taken, with a message naming a limit nobody set. The upload grant\n already carries `maxBytes`, so the only number is the one the service\n publishes. `MAX_TRANSFER_BYTES` remains as the answer for a server too\n old to say.\n */\n // Read as BYTES, not as utf8. `readWithin` decodes, which is right for a\n // person reading a file in a session and wrong here: an image or a PDF\n // round-tripped through a string is corrupt on arrival.\n bytes = readFileSync(located);\n } catch (error) {\n return { ok: false, error: error instanceof Error ? error.message : \"could not read it\" };\n }\n\n return upload(apiUrl, token, filename, bytes);\n}\n\n/**\n * Hands the bytes to the service and comes back with its receipt.\n *\n * Shared by a file read and a directory listing, so the two cannot drift in\n * how they upload \u2014 and so a listing is stored, named and shown exactly like\n * any other answer.\n */\nasync function upload(\n apiUrl: string,\n token: string,\n filename: string,\n bytes: Buffer\n): Promise<Outcome> {\n const grant = await fetch(`${apiUrl}/api/v1/agent/upload-url`, {\n method: \"POST\",\n headers: { authorization: `Bearer ${token}`, \"content-type\": \"application/json\" },\n body: JSON.stringify({\n // The name the person asked for, not the resolved path. The resolved one\n // says where this machine keeps things, which the server has no business\n // recording.\n //\n // No content type is sent: this machine has a path, not a declaration.\n // The server resolves it from the name against the one table that knows\n // which types it can read, and tells us below what it decided.\n filename\n })\n });\n\n if (!grant.ok) {\n return { ok: false, error: await said(grant, \"could not get an upload url\") };\n }\n\n const { uploadUrl, contentType, maxBytes } = (await grant.json()) as {\n uploadUrl: string;\n contentType: string;\n maxBytes?: number;\n };\n\n const limit = maxBytes ?? MAX_TRANSFER_BYTES;\n if (bytes.length > limit) {\n return { ok: false, error: new TooLarge(filename, bytes.length, limit).message };\n }\n\n // The BYTES go over HTTP, never through a JSON field. A large base64 payload\n // in a request body is the failure `upload-token.ts` was written to avoid.\n const put = await fetch(uploadUrl, {\n method: \"PUT\",\n // The type the grant was signed for. Anything else is refused.\n headers: { \"content-type\": contentType },\n body: new Uint8Array(bytes)\n });\n\n if (!put.ok) return { ok: false, error: `upload refused (${put.status})` };\n\n const stored = (await put.json().catch(() => ({}))) as { attachToken?: string };\n\n // The signed statement of what the server stored. Not a key: the upload\n // endpoint does not hand one out, precisely so no client gets to name the\n // object it wrote.\n if (!stored.attachToken) return { ok: false, error: \"the upload returned no reference\" };\n\n return { ok: true, attachToken: stored.attachToken, bytes: bytes.length };\n}\n\n/** Enough to be useful, bounded so a home directory is not a wall of text. */\nconst MAX_LISTED = 200;\n\nfunction sizeOf(path: string): string {\n const size = statSync(path).size;\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${Math.round(size / 1024)} KB`;\n return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nexport async function agentCommand(context: CommandContext): Promise<number> {\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return 1;\n }\n\n const roots = (listFlag(context.args, \"root\") ?? []).map((one) =>\n resolve(one.startsWith(\"~\") ? resolve(homedir(), one.slice(1).replace(/^[/\\\\]/, \"\")) : one)\n );\n\n if (roots.length === 0) {\n /*\n The refusal names the flag, and then how to live with it.\n\n It said only what to type to start, so somebody who ran it learned the\n roots were mandatory and nothing else: not that it stays in the\n foreground, and not how to stop it once they had backgrounded it. Three\n lines here save a search that has nowhere to land.\n */\n context.error(\n \"Say which folders this machine may read from, and nothing outside them will be:\"\n );\n context.error(\"\");\n context.error(\" pm agent --root ~/Desktop --root ~/Documents\");\n context.error(\"\");\n context.error(\"It stays in the foreground. To leave it running:\");\n context.error(\"\");\n context.error(\" nohup pm agent --root ~/Desktop > ~/agent.log 2>&1 &\");\n context.error(\"\");\n context.error(\"And to stop it later: pkill -f \\\"pm agent\\\"\");\n return 1;\n }\n\n for (const root of roots) {\n try {\n if (!statSync(root).isDirectory()) {\n context.error(`${root} is not a folder.`);\n return 1;\n }\n } catch {\n context.error(`${root} does not exist.`);\n return 1;\n }\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n const name = hostname();\n const asked = numberFlag(context.args, \"interval\");\n if (asked === \"invalid\") {\n context.error(\"--interval takes a number of seconds.\");\n return 1;\n }\n // A floor of two seconds. A tighter loop is not more responsive in any way a\n // person notices and is a request per second per machine forever.\n const every = Math.max(2, asked ?? 5) * 1000;\n\n context.print(`Answering as ${name}, from: ${roots.join(\", \")}`);\n context.print(\"Nothing outside those folders can be read. Ctrl-C to stop.\");\n\n let running = true;\n const stop = (): void => {\n running = false;\n context.print(\"\\nStopping. The current request will finish first.\");\n };\n process.on(\"SIGINT\", stop);\n process.on(\"SIGTERM\", stop);\n\n /*\n The token is fetched per pass, not captured once at startup.\n\n This loop runs for weeks and an access token lasts minutes. Holding the\n one it started with meant the agent worked for a quarter of an hour and\n then answered nothing forever \u2014 heartbeats rejected, the machine shown as\n \"not answering\", and a 401 in the service log every few seconds for as long\n as it was left running.\n\n `currentCredential` re-reads the credentials file and renews only when\n expiry is close, so this is a file read on almost every pass and a refresh\n on one in a few hundred. It also persists the rotation, which is what stops\n the NEXT command from presenting a token this loop has already replaced.\n */\n const authorization = async (): Promise<string> => {\n const held = await currentCredential(context.resolved, context.session);\n return held.token;\n };\n\n const call = async (path: string, body: unknown): Promise<Response> =>\n fetch(`${apiUrl}/api/v1/agent/${path}`, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${await authorization()}`,\n \"content-type\": \"application/json\"\n },\n body: JSON.stringify(body)\n });\n\n /*\n * Says a thing once, not once every five seconds.\n *\n * This loop runs unattended for weeks. An unreachable API or a rejected\n * credential is a condition that PERSISTS, and reporting it every pass fills\n * the log with one repeated line \u2014 which is how the next, different problem\n * goes unread. The first occurrence is printed and repeats are dropped until\n * something changes.\n */\n let complaint: string | undefined;\n const complain = (message: string): void => {\n if (complaint === message) return;\n complaint = message;\n context.error(` ${message}`);\n };\n const working = (): void => {\n if (complaint !== undefined) {\n complaint = undefined;\n context.print(\" connected again\");\n }\n };\n\n while (running) {\n try {\n /*\n * Heartbeat BEFORE claiming, every pass.\n *\n * It is also where held work is released, so a machine that reconnects\n * and claims first would find nothing: everything it missed is still\n * held until it says it is here.\n */\n const beat = await call(\"heartbeat\", { hostname: name, platform: process.platform });\n\n if (!beat.ok) {\n // Reported rather than ignored. A machine whose credential has been\n // revoked would otherwise sit here forever looking healthy to the\n // person who started it, while answering nothing.\n complain(await said(beat, \"the service refused this machine\"));\n } else {\n working();\n const state = (await beat.json()) as { status: string; released: number };\n\n if (state.status === \"disabled\") {\n // Not an error, and not a reason to exit. The machine stopped\n // answering for long enough that the service stopped trusting it, and\n // only a person clears that. Sleeping and saying so beats exiting,\n // because a process that quits needs somebody to start it again on a\n // machine nobody is sitting at.\n context.print(\"This machine is switched off after going quiet. Ask an operator to re-enable it.\");\n await new Promise((r) => setTimeout(r, 60_000));\n continue;\n }\n\n if (state.released > 0) {\n context.print(`Reconnected. ${state.released} request(s) were waiting.`);\n }\n }\n\n const claimed = await call(\"claim\", { hostname: name, limit: 5 });\n\n if (!claimed.ok) {\n complain(await said(claimed, \"could not pick up work\"));\n } else {\n const { items } = (await claimed.json()) as { items: Claimed[] };\n\n for (const request of items) {\n context.print(`Reading ${request.path}`);\n const outcome = await answer(context, apiUrl, await authorization(), roots, request);\n\n const done = await call(\n `complete/${encodeURIComponent(request.id)}`,\n outcome.ok ? { result: { attachToken: outcome.attachToken } } : { error: outcome.error }\n );\n\n /*\n * The ANSWER is not the delivery.\n *\n * This used to print \"sent N bytes\" on the strength of the upload\n * alone, without reading what `complete` returned \u2014 so a request the\n * service never marked done was reported here as delivered, and the\n * only place the truth existed was a row nobody was looking at. The\n * file being stored and the person being told are two steps, and\n * this is the one that tells them.\n */\n if (!done.ok) {\n context.error(` stored, but the service did not record it: ${await said(done, \"refused\")}`);\n continue;\n }\n\n context.print(outcome.ok ? ` sent ${outcome.bytes} bytes` : ` refused: ${outcome.error}`);\n }\n }\n } catch (error) {\n /*\n * Swallowed, and the loop continues.\n *\n * The API being unreachable is the ordinary case this is built for: the\n * wifi dropped, the laptop slept, a deploy is in progress. A loop that\n * exits on a failed fetch is a loop that needs a person to restart it on\n * a machine nobody is sitting at, which is the opposite of the point.\n */\n context.error(` ${error instanceof Error ? error.message : \"connection failed\"}`);\n }\n\n if (running) await new Promise((r) => setTimeout(r, every));\n }\n\n return 0;\n}\n", "import { existsSync, readFileSync, realpathSync, statSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\n\n/**\n * Reading and writing files from a session.\n *\n * The rule this file exists to enforce: NOTHING IS EVER WRITTEN WITHOUT THE\n * PERSON SAYING SO, FOR THAT WRITE. Not a mode they switched on earlier, not a\n * blanket approval, not \"trust this directory\" \u2014 each write is shown and\n * confirmed on its own.\n *\n * That is stricter than it needs to be for a careless mistake and exactly\n * strict enough for the real risk: the text proposing a write can come from a\n * model, and a model's suggestion is downstream of whatever it read. A\n * document containing \"now overwrite ~/.ssh/config\" is a document somebody\n * might legitimately have in their memory. Confirmation is what stands between\n * that and a file changing.\n */\n\nexport class OutsideWorkspace extends Error {\n constructor(path: string) {\n super(`${path} is outside the directory this session was started in.`);\n this.name = \"OutsideWorkspace\";\n }\n}\n\nexport class TooLarge extends Error {\n constructor(path: string, bytes: number, limit: number) {\n // MB once it is worth saying in MB. \"is 4823 KB, over the 20480 KB limit\"\n // is a sentence somebody has to do arithmetic on to understand.\n const say = (value: number): string =>\n value >= 1024 * 1024\n ? `${(value / (1024 * 1024)).toFixed(1)} MB`\n : `${Math.round(value / 1024)} KB`;\n\n super(`${path} is ${say(bytes)}, over the ${say(limit)} limit.`);\n this.name = \"TooLarge\";\n }\n}\n\n/** Read whole files up to this. Beyond it, a session would blow its budget. */\nexport const MAX_READ_BYTES = 512 * 1024;\n\n/**\n * What the agent may SEND, which is a different question entirely.\n *\n * `MAX_READ_BYTES` is small because that content goes into a model's context\n * window, where half a megabyte is already enormous. A file somebody asked\n * their own machine for goes to a blob and then to a chat \u2014 it is never read\n * by a model on the way \u2014 so the context budget is the wrong limit and using\n * it meant a phone photo, the most obvious thing anybody would ask for, came\n * back as \"over the 512 KB limit\".\n *\n * A hundred megabytes, matching what the blob store accepts. Above Telegram's\n * fifty-megabyte ceiling for a document, deliberately: the file still reaches\n * memory and the CLI and MCP, and only the delivery into a chat is capped by\n * what Telegram will take. A limit set to the smallest surface would refuse a\n * file for every surface because one of them cannot carry it.\n */\nexport const MAX_TRANSFER_BYTES = 100 * 1024 * 1024;\n\n/**\n * The real location of a path, following symlinks as far as they exist.\n *\n * `path.resolve` does NOT follow links \u2014 it only flattens `..` \u2014 so a symlink\n * sitting inside the workspace and pointing at `/etc/passwd` resolves to a\n * path that looks perfectly contained. Only `realpath` sees through it.\n *\n * The walk up to the nearest existing ancestor is what makes this usable for a\n * file that does not exist yet: `realpathSync` throws on a missing path, and a\n * write to a new file would otherwise be refused outright. The ancestor is\n * resolved for real and the remaining segments are appended to it, so a NEW\n * file inside a symlinked directory is still judged by where that directory\n * actually points.\n */\nfunction realLocation(absolute: string): string {\n let existing = absolute;\n const trailing: string[] = [];\n\n while (!existsSync(existing)) {\n const parent = dirname(existing);\n // Reached the filesystem root without finding anything that exists.\n if (parent === existing) return absolute;\n trailing.unshift(existing.slice(parent.length + 1));\n existing = parent;\n }\n\n try {\n return join(realpathSync(existing), ...trailing);\n } catch {\n return absolute;\n }\n}\n\n/**\n * Resolves a path and refuses to leave the workspace.\n *\n * The check is on the REAL path \u2014 symlinks followed \u2014 because that is the only\n * comparison that means anything. `../../../etc/passwd` is caught by resolving\n * `..`, and a link pointing out of the tree is caught by resolving the link;\n * a check that did only the first would announce a boundary it does not have.\n *\n * `relative` starting with `..` is the test rather than `startsWith(root)`,\n * because the latter also accepts `/home/me-secrets` for a root of `/home/me`.\n */\nexport function within(root: string, path: string): string {\n const absolute = isAbsolute(path) ? path : resolve(root, path);\n const real = realLocation(absolute);\n // The root itself may be reached through a link \u2014 /tmp is a symlink to\n // /private/tmp on macOS \u2014 so both sides are resolved or neither comparison\n // holds.\n const realRoot = realLocation(resolve(root));\n\n const rel = relative(realRoot, real);\n if (rel !== \"\" && (rel.startsWith(\"..\") || isAbsolute(rel))) {\n throw new OutsideWorkspace(path);\n }\n return real;\n}\n\nexport interface FileRead {\n readonly path: string;\n readonly text: string;\n readonly bytes: number;\n}\n\nexport function readWithin(root: string, path: string): FileRead {\n const absolute = within(root, path);\n\n const stats = statSync(absolute);\n if (!stats.isFile()) throw new Error(`${path} is not a file.`);\n if (stats.size > MAX_READ_BYTES) throw new TooLarge(path, stats.size, MAX_READ_BYTES);\n\n return {\n path: absolute,\n text: readFileSync(absolute, \"utf8\"),\n bytes: stats.size\n };\n}\n\nexport interface ProposedWrite {\n readonly path: string;\n readonly contents: string;\n /** What is there now, when there is something. Used to show the change. */\n readonly existing?: string;\n}\n\nexport function proposeWrite(root: string, path: string, contents: string): ProposedWrite {\n const absolute = within(root, path);\n\n let existing: string | undefined;\n try {\n const stats = statSync(absolute);\n if (stats.isFile() && stats.size <= MAX_READ_BYTES) {\n existing = readFileSync(absolute, \"utf8\");\n }\n } catch {\n // No such file. A create rather than an overwrite, which the summary says.\n }\n\n return {\n path: absolute,\n contents,\n ...(existing !== undefined ? { existing } : {})\n };\n}\n\n/**\n * Performs a write that has already been confirmed.\n *\n * Takes the confirmation as an argument it must actually inspect, rather than\n * trusting the caller to have asked. A function that writes unconditionally is\n * one call site away from being invoked without the prompt, and this is the\n * one operation in the CLI where that mistake is not recoverable.\n */\nexport function commitWrite(write: ProposedWrite, confirmed: boolean): void {\n if (!confirmed) throw new Error(\"refusing to write without confirmation\");\n writeFileSync(write.path, write.contents, \"utf8\");\n}\n\n/**\n * A minimal line diff, so a person can see what they are approving.\n *\n * Showing the whole new file is not the same thing: for a one-line change in a\n * long document, \"approve this?\" followed by four hundred lines is a prompt\n * nobody reads, and an unread prompt is not consent.\n */\nexport function summarise(write: ProposedWrite, maxLines = 40): string {\n if (write.existing === undefined) {\n const lines = write.contents.split(\"\\n\");\n const head = lines.slice(0, maxLines).map((line) => `+ ${line}`);\n if (lines.length > maxLines) head.push(` \u2026 ${lines.length - maxLines} more lines`);\n return `create ${write.path} (${lines.length} lines)\\n${head.join(\"\\n\")}`;\n }\n\n if (write.existing === write.contents) return `${write.path} is already exactly this.`;\n\n const before = write.existing.split(\"\\n\");\n const after = write.contents.split(\"\\n\");\n const changes: string[] = [];\n\n // Trimmed from both ends first, so an edit in the middle of a long file\n // shows the edit rather than the identical lines around it.\n let start = 0;\n while (start < before.length && start < after.length && before[start] === after[start]) {\n start += 1;\n }\n let end = 0;\n while (\n end < before.length - start &&\n end < after.length - start &&\n before[before.length - 1 - end] === after[after.length - 1 - end]\n ) {\n end += 1;\n }\n\n const removed = before.slice(start, before.length - end);\n const added = after.slice(start, after.length - end);\n\n for (const line of removed.slice(0, maxLines)) changes.push(`- ${line}`);\n if (removed.length > maxLines) changes.push(` \u2026 ${removed.length - maxLines} more removed`);\n for (const line of added.slice(0, maxLines)) changes.push(`+ ${line}`);\n if (added.length > maxLines) changes.push(` \u2026 ${added.length - maxLines} more added`);\n\n return [\n `edit ${write.path} (line ${start + 1}: -${removed.length} +${added.length})`,\n ...changes\n ].join(\"\\n\");\n}\n", "import { writeFileSync } from \"node:fs\";\nimport { basename, resolve } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\n\nimport { stringFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * Drive and mail from the terminal.\n *\n * These call the API rather than Google, which is the opposite of what the MCP\n * server does and right for the same reason: a laptop holds a bearer token and\n * no database connection, so the credential it can prove is the one this API\n * accepts. Google's own tokens never leave the deployment, which is what stops\n * a stolen `~/.persistmemory` from being a stolen mailbox.\n *\n * `pm drive`, `pm drive get <id> [--out path]`, `pm drive put <file>`,\n * `pm mail`, `pm mail read <id>`.\n */\nasync function callApi(\n context: CommandContext,\n path: string,\n init: RequestInit = {}\n): Promise<Response | undefined> {\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return undefined;\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n\n return fetch(`${apiUrl}${path}`, {\n ...init,\n headers: {\n authorization: `Bearer ${credential.token}`,\n ...(init.headers ?? {})\n }\n });\n}\n\n/**\n * What a failed call means, said once.\n *\n * 409 is the interesting one: it is not a server fault and not something a\n * retry fixes \u2014 either no Google is connected, or Google has stopped renewing\n * the connection. Both are fixed by a person on the connections page, and the\n * API already says which, so this passes the sentence through rather than\n * inventing its own.\n */\nasync function complain(context: CommandContext, response: Response): Promise<number> {\n const body = (await response.json().catch(() => undefined)) as\n | { error?: { message?: string } }\n | undefined;\n\n context.error(body?.error?.message ?? `That failed (${response.status}).`);\n return response.status === 409 ? 3 : 1;\n}\n\nexport async function driveCommand(context: CommandContext): Promise<number> {\n const [, noun, ...rest] = context.args.words;\n\n if (noun === \"get\") return driveGet(context, rest.join(\" \").trim());\n if (noun === \"put\" || noun === \"save\") return drivePut(context, rest.join(\" \").trim());\n\n // `pm drive` with anything else is a search, so `pm drive quarter plan`\n // works without quoting \u2014 which is how somebody actually types it.\n const query = [noun, ...rest].filter(Boolean).join(\" \").trim();\n\n const response = await callApi(\n context,\n `/api/v1/google/drive/files?limit=20${query ? `&query=${encodeURIComponent(query)}` : \"\"}`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const { data } = (await response.json()) as {\n data: { id: string; name: string; size?: number; modifiedTime?: string; native: boolean }[];\n };\n\n if (data.length === 0) {\n context.print(query ? `Nothing in Drive matches \"${query}\".` : \"That Drive is empty.\");\n return 0;\n }\n\n if (context.flags.output === \"json\") {\n context.print(JSON.stringify(data, undefined, 2));\n return 0;\n }\n\n for (const file of data) {\n context.print(` ${file.name}`);\n // The id on its own line and unabbreviated: it is what the next command\n // takes, and a truncated id is one somebody has to go and look up again.\n context.print(\n ` ${file.id}${file.size ? ` \u00B7 ${Math.round(file.size / 1024)} KB` : \"\"}` +\n `${file.modifiedTime ? ` \u00B7 ${file.modifiedTime.slice(0, 10)}` : \"\"}`\n );\n }\n\n context.print(\"\");\n context.print(\"Fetch one with: pm drive get <id>\");\n return 0;\n}\n\nasync function driveGet(context: CommandContext, fileId: string): Promise<number> {\n if (!fileId) {\n context.error(\"Say which file: pm drive get <id>\");\n return 2;\n }\n\n const response = await callApi(\n context,\n `/api/v1/google/drive/files/${encodeURIComponent(fileId)}/content`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n /*\n The name Google gave it, taken from the disposition rather than the id.\n\n A Doc arrives as a PDF and the server already renamed it \u2014 using the id as\n a filename would write `1a2b3c` to disk holding a PDF, which nothing will\n open by double-clicking.\n */\n const disposition = response.headers.get(\"content-disposition\") ?? \"\";\n const named = /filename=\"([^\"]+)\"/.exec(disposition)?.[1];\n\n const out = stringFlag(context.args, \"out\");\n // `basename` on the server's name: a filename is not a path, and a\n // `../` in one from anywhere would write outside the directory somebody\n // ran this in.\n const target = resolve(out ?? basename(named ?? fileId));\n\n writeFileSync(target, Buffer.from(await response.arrayBuffer()));\n context.print(target);\n return 0;\n}\n\nasync function drivePut(context: CommandContext, path: string): Promise<number> {\n if (!path) {\n context.error(\"Say which file: pm drive put ./notes.md\");\n return 2;\n }\n\n let bytes: Buffer;\n try {\n bytes = readFileSync(resolve(path));\n } catch {\n context.error(`Cannot read ${path}.`);\n return 1;\n }\n\n const name = stringFlag(context.args, \"name\") ?? basename(path);\n\n const response = await callApi(\n context,\n `/api/v1/google/drive/files?name=${encodeURIComponent(name)}`,\n {\n method: \"POST\",\n // The bytes as bytes. Base64 in JSON would be a third larger and would\n // make the limit somebody was told about stop matching the one they hit.\n headers: { \"content-type\": \"application/octet-stream\" },\n body: new Uint8Array(bytes)\n }\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const saved = (await response.json()) as { name: string; link?: string };\n context.print(`Saved \"${saved.name}\" to Drive.${saved.link ? ` ${saved.link}` : \"\"}`);\n return 0;\n}\n\nexport async function mailCommand(context: CommandContext): Promise<number> {\n const [, noun, ...rest] = context.args.words;\n\n if (noun === \"read\" || noun === \"get\") {\n const messageId = rest.join(\" \").trim();\n if (!messageId) {\n context.error(\"Say which message: pm mail read <id>\");\n return 2;\n }\n\n const response = await callApi(\n context,\n `/api/v1/google/mail/${encodeURIComponent(messageId)}`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const message = (await response.json()) as {\n from?: string;\n subject?: string;\n date?: string;\n body: string;\n attachments: { filename: string; mimeType: string }[];\n };\n\n if (context.flags.output === \"json\") {\n context.print(JSON.stringify(message, undefined, 2));\n return 0;\n }\n\n context.print(`From: ${message.from ?? \"unknown\"}`);\n context.print(`Subject: ${message.subject ?? \"(none)\"}`);\n if (message.date) context.print(`Date: ${message.date}`);\n context.print(\"\");\n context.print(message.body);\n\n if (message.attachments.length > 0) {\n context.print(\"\");\n context.print(\"Attached:\");\n for (const one of message.attachments) context.print(` ${one.filename} (${one.mimeType})`);\n }\n\n return 0;\n }\n\n // Gmail's own syntax, passed through: `pm mail from:priya has:attachment`.\n const query = [noun, ...rest].filter(Boolean).join(\" \").trim();\n\n const response = await callApi(\n context,\n `/api/v1/google/mail?limit=20${query ? `&query=${encodeURIComponent(query)}` : \"\"}`\n );\n if (!response) return 1;\n if (!response.ok) return complain(context, response);\n\n const { data } = (await response.json()) as {\n data: {\n id: string;\n subject?: string;\n from?: string;\n date?: string;\n unread: boolean;\n hasAttachments: boolean;\n }[];\n };\n\n if (data.length === 0) {\n context.print(query ? `No mail matches \"${query}\".` : \"Nothing in that mailbox.\");\n return 0;\n }\n\n if (context.flags.output === \"json\") {\n context.print(JSON.stringify(data, undefined, 2));\n return 0;\n }\n\n for (const message of data) {\n const marks = [message.unread ? \"unread\" : \"\", message.hasAttachments ? \"attachment\" : \"\"]\n .filter(Boolean)\n .join(\", \");\n\n context.print(` ${message.subject ?? \"(no subject)\"}${marks ? ` [${marks}]` : \"\"}`);\n context.print(\n ` ${message.from ?? \"unknown\"}${message.date ? ` \u00B7 ${message.date.slice(0, 10)}` : \"\"}`\n );\n context.print(` ${message.id}`);\n }\n\n context.print(\"\");\n context.print(\"Read one with: pm mail read <id>\");\n return 0;\n}\n", "import { existsSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { stringFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * What is waiting for the person to approve.\n *\n * LISTS ONLY. There is no `pm requests approve`, and its absence is the design\n * rather than an unfinished edge.\n *\n * A file request exists because something chose a path \u2014 usually a model, with\n * an account's ingested email and shared documents in the same context that\n * chose it. The approval has to come from somewhere that thing cannot reach. A\n * terminal is not that place: this CLI is routinely driven by agents, and a\n * command an agent can run is a command an injected instruction can eventually\n * cause. An approval subcommand with a `--yes` flag would be exactly the\n * setting that gets turned on once and then never off.\n *\n * So this prints the paths and the link, and the decision happens in a browser\n * session belonging to a person.\n */\nexport async function requestsCommand(context: CommandContext): Promise<number> {\n // `pm requests get <id>` collects a finished one. Listing and collecting are\n // different verbs and the second is not an approval \u2014 see the note above for\n // why approving stays out of this program entirely.\n if (context.args.words[1] === \"get\") return collectCommand(context);\n\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return 1;\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n\n const response = await fetch(`${apiUrl}/api/v1/agent/awaiting`, {\n headers: { authorization: `Bearer ${credential.token}` }\n });\n\n if (response.status === 403) {\n // The session-only rule, reported as the fact it is rather than as a\n // failure. An API key genuinely cannot see or decide these.\n context.error(\n \"This credential cannot see the approval queue. It is visible only to you, signed in, at /dashboard/requests.\"\n );\n return 3;\n }\n\n if (!response.ok) {\n context.error(`Could not read the queue (${response.status}).`);\n return 1;\n }\n\n const { items } = (await response.json()) as {\n items: { id: string; path: string; askedBy?: string; createdAt: string }[];\n };\n\n if (items.length === 0) {\n context.print(\"Nothing is waiting. No app or chat has asked for a file from your computers.\");\n return 0;\n }\n\n context.print(\n `${items.length} request${items.length === 1 ? \"\" : \"s\"} waiting. Nothing has been read.`\n );\n context.print(\"\");\n\n for (const one of items) {\n // The path on its own line, unabbreviated. It is the only part of this that\n // distinguishes a request somebody wanted from one a stranger's email caused.\n context.print(` ${one.path}`);\n context.print(` asked by ${one.askedBy ?? \"something\"} \u00B7 ${one.id}`);\n context.print(\"\");\n }\n\n context.print(\"Approve or refuse them while signed in, at /dashboard/requests.\");\n context.print(\"They cannot be approved from here \u2014 see `pm help requests`.\");\n\n return 0;\n}\n\n/**\n * `pm requests get <id>` \u2014 writes a finished request's file to disk.\n *\n * NOT an approval. The decision has already been made by a person in a\n * browser; this collects what their own machine answered, which is the half of\n * the loop the terminal was missing. Somebody who asked for a file from their\n * laptop could see the request here and had no way to get the bytes.\n *\n * The signed URL is fetched and used immediately, never printed. It is a\n * bearer credential for one file, and a URL echoed to a terminal is a URL in\n * the scrollback, in the shell history of anyone who copies it, and in any\n * screen recording.\n */\nexport async function collectCommand(context: CommandContext): Promise<number> {\n const credential = context.resolved.credential;\n if (!credential) {\n context.error(\"Sign in first: pm auth login\");\n return 1;\n }\n\n const id = context.args.words[2];\n if (!id) {\n context.error(\"Which request? `pm requests` lists them with their ids.\");\n return 2;\n }\n\n const apiUrl = context.resolved.apiUrl.replace(/\\/+$/, \"\");\n\n const link = await fetch(\n `${apiUrl}/api/v1/agent/request/${encodeURIComponent(id)}/download`,\n { headers: { authorization: `Bearer ${credential.token}` } }\n );\n\n if (!link.ok) {\n // The server's own sentence \u2014 it distinguishes \"not finished yet\" from\n // \"that is not your request\" from \"it failed\", and a status code does not.\n const body = (await link.json().catch(() => undefined)) as\n | { error?: { message?: string } }\n | undefined;\n context.error(body?.error?.message ?? `Could not prepare that file (${link.status}).`);\n return 1;\n }\n\n const { downloadUrl, filename } = (await link.json()) as {\n downloadUrl: string;\n filename: string;\n };\n\n // No credential on this one, deliberately: the URL is the authorisation, and\n // attaching a bearer token to a signed URL sends the session token to\n // whatever host the URL names.\n const file = await fetch(downloadUrl);\n if (!file.ok) {\n context.error(`The download refused it (${file.status}). Links expire in minutes \u2014 try again.`);\n return 1;\n }\n\n const name = stringFlag(context.args, \"output\", \"o\") ?? filename;\n const target = resolve(name);\n\n /*\n Refused rather than overwritten.\n\n The filename comes from a path somebody typed on another machine, and this\n writes into whatever directory the command was run in. Silently replacing\n `notes.md` in a repository because a file of that name came back is not a\n trade worth making for one saved keystroke.\n */\n if (existsSync(target)) {\n context.error(`${target} already exists. Pass --output to write somewhere else.`);\n return 1;\n }\n\n writeFileSync(target, new Uint8Array(await file.arrayBuffer()));\n\n context.print(`Wrote ${target}`);\n return 0;\n}\n", "import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve as resolvePath } from \"node:path\";\n\n/**\n * The space this FOLDER writes into.\n *\n * Separate from the profile in `~/.persistmemory`, and deliberately so. A\n * profile answers \"who am I\"; this answers \"what am I working on\", and those\n * change on different schedules \u2014 one person, many projects, and the memory\n * from a client's repository has no business landing in the same space as a\n * personal one.\n *\n * Found by walking up from the working directory, the way `git` finds its\n * root, so a command run three folders deep still writes into the project's\n * space rather than starting a new one.\n *\n * Committed or not is the user's call. It contains a space id and a name, no\n * credential and nothing secret \u2014 a colleague who clones the repository gets\n * the right space and still has to sign in as themselves.\n */\nexport const WORKSPACE_FILE = \".persistmemory.json\";\n\nexport interface WorkspaceSpace {\n readonly id: string;\n readonly name: string;\n}\n\nexport interface Workspace {\n readonly space?: WorkspaceSpace;\n}\n\nexport interface FoundWorkspace {\n readonly file: string;\n readonly dir: string;\n readonly config: Workspace;\n}\n\n/**\n * Walks up from `from` looking for a workspace file.\n *\n * Stops at the filesystem root rather than at a git root: a folder that is not\n * a repository is still a project, and refusing to look further would make\n * `pm` behave differently in the same directory depending on whether somebody\n * had run `git init` yet.\n */\nexport function findWorkspace(from: string = process.cwd()): FoundWorkspace | undefined {\n let dir = resolvePath(from);\n\n for (;;) {\n const file = join(dir, WORKSPACE_FILE);\n\n if (existsSync(file)) {\n const config = readWorkspace(file);\n // A file that cannot be read is treated as absent and the walk\n // continues. A corrupt file in a deep folder should not shadow a good\n // one at the project root.\n if (config) return { file, dir, config };\n }\n\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n}\n\nexport function readWorkspace(file: string): Workspace | undefined {\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as Partial<Workspace>;\n const space = parsed.space;\n\n if (\n space &&\n typeof space === \"object\" &&\n typeof space.id === \"string\" &&\n space.id !== \"\" &&\n typeof space.name === \"string\"\n ) {\n return { space: { id: space.id, name: space.name } };\n }\n\n return {};\n } catch {\n return undefined;\n }\n}\n\nexport function writeWorkspace(dir: string, config: Workspace): string {\n const file = join(dir, WORKSPACE_FILE);\n // Trailing newline, because this lands in people's repositories and a file\n // without one is a diff everybody's editor fights over.\n writeFileSync(file, `${JSON.stringify(config, null, 2)}\\n`, \"utf8\");\n return file;\n}\n", "import type { PersistMemory, Space } from \"@persistmemory/sdk\";\nimport { stringFlag } from \"../args\";\nimport type { CommandContext } from \"../context\";\nimport { login } from \"./auth\";\nimport { WORKSPACE_FILE, findWorkspace, writeWorkspace } from \"../workspace\";\n\n/**\n * `pm setup` \u2014 from nothing to a working folder, in one command.\n *\n * Written for the moment an assistant is being connected: a plugin's install\n * step runs this, and the person is signed in and pointed at a Space without\n * ever being told to go and read the docs. That is the whole reason it exists\n * as a command rather than as three paragraphs on a web page.\n *\n * It asks about the Space EVERY time, including when the folder already has\n * one. Adding PersistMemory to a second project from inside the first would\n * otherwise silently inherit that project's Space, and the person would find\n * out weeks later that a client's memory had been landing in another client's\n * space. Re-running in a folder that is already set up is cheap: the current\n * choice is offered as the default and Enter keeps it.\n */\nexport async function setupCommand(context: CommandContext): Promise<number> {\n const { print, error } = context;\n\n print(\"\");\n print(\" PersistMemory setup\");\n print(\"\");\n\n /* ------------------------------- signing in ------------------------------ */\n\n if (!context.resolved.credential) {\n print(\" You are not signed in yet. Opening your browser.\");\n print(\"\");\n\n const code = await login(context);\n if (code !== 0) {\n error(\"Setup stopped: signing in did not finish.\");\n return code;\n }\n } else {\n const how =\n context.resolved.credential.kind === \"api-key\" ? \"an API key\" : \"your browser sign-in\";\n print(` Already signed in to ${context.resolved.apiUrl} with ${how}.`);\n }\n\n /*\n Proves the credential rather than trusting the file.\n\n A stored token can be revoked, expired or for a different server, and every\n one of those looks identical to a working login until the first real call.\n Finding out here \u2014 while somebody is watching the output of a setup command\n \u2014 is far better than finding out inside an assistant three days later.\n */\n let client: PersistMemory;\n let spaces: readonly Space[];\n\n try {\n client = await context.client();\n const page = await client.spaces.list({ limit: 200 }).first();\n spaces = page.data;\n } catch (caught) {\n error(\n `Signed in, but the server would not answer: ${\n caught instanceof Error ? caught.message : String(caught)\n }`\n );\n error(\"Run `pm auth login` to sign in again.\");\n return 1;\n }\n\n print(\" Signed in and the server answered. \\u2713\");\n print(\"\");\n\n return chooseSpace(context, client, spaces);\n}\n\n/**\n * The Space half of setup, on its own so `pm auth login` can continue into it.\n *\n * Signing in and then stopping at a bare prompt leaves a person who has just\n * approved a consent screen with no idea what to do next, and \u2014 worse \u2014 with\n * everything landing in one undifferentiated pile until they happen to read\n * about Spaces. The two steps belong together.\n */\nexport async function chooseSpace(\n context: CommandContext,\n client: PersistMemory,\n spaces: readonly Space[]\n): Promise<number> {\n const { print, error } = context;\n\n const found = findWorkspace();\n const current = found?.config.space;\n\n // Non-interactive paths first, so a plugin's install script, a Dockerfile or\n // a CI job never reaches a prompt that nothing will answer.\n const named = stringFlag(context.args, \"space\");\n const creating = stringFlag(context.args, \"new-space\");\n\n if (creating !== undefined) {\n const space = await create(client, creating);\n return finish(context, space, current);\n }\n\n if (named !== undefined) {\n const match = byName(spaces, named);\n if (!match) {\n error(`No Space called \"${named}\". Use --new-space to create it.`);\n return 1;\n }\n return finish(context, match, current);\n }\n\n const interactive = context.args.flags[\"yes\"] !== true && context.isTty;\n\n if (!interactive) {\n // Nothing was asked and nobody can answer. Say what happened rather than\n // writing a file nobody chose.\n print(\" No Space chosen. Memories will go to your account's default.\");\n print(` Pass --space \"<name>\" or --new-space \"<name>\" to pick one.`);\n return 0;\n }\n\n if (current) {\n print(` This folder currently uses the Space \"${current.name}\".`);\n print(\"\");\n }\n\n print(\" Which Space should this folder use?\");\n print(\"\");\n\n spaces.forEach((space, index) => {\n const mark = current?.id === space.id ? \" (current)\" : \"\";\n const count = space.memoryCount === undefined ? \"\" : `, ${space.memoryCount} memories`;\n print(` ${index + 1}. ${space.name}${mark} ${space.kind}${count}`);\n });\n\n const createIndex = spaces.length + 1;\n const noneIndex = spaces.length + 2;\n\n print(` ${createIndex}. Create a new Space`);\n print(` ${noneIndex}. No Space \u2014 use everything in my account`);\n print(\"\");\n\n const fallback = current ? \"keep the current one\" : String(createIndex);\n const answer = await context.ask(` Choose 1-${noneIndex} [${fallback}]: `);\n\n if (answer === \"\") {\n if (current) {\n print(\"\");\n print(` Keeping \"${current.name}\".`);\n return 0;\n }\n return finish(context, await askForNewSpace(context, client), current);\n }\n\n const choice = Number(answer);\n\n if (!Number.isInteger(choice) || choice < 1 || choice > noneIndex) {\n error(`\"${answer}\" is not one of the choices. Nothing was changed.`);\n return 2;\n }\n\n if (choice === noneIndex) {\n if (found) {\n writeWorkspace(found.dir, {});\n print(\"\");\n print(` Cleared the Space in ${WORKSPACE_FILE}. This folder now uses everything.`);\n } else {\n print(\"\");\n print(\" No Space. This folder uses everything in your account.\");\n }\n return 0;\n }\n\n if (choice === createIndex) {\n return finish(context, await askForNewSpace(context, client), current);\n }\n\n return finish(context, spaces[choice - 1]!, current);\n}\n\nasync function askForNewSpace(\n context: CommandContext,\n client: PersistMemory\n): Promise<Space> {\n for (;;) {\n const name = await context.ask(\" Name for the new Space: \");\n if (name !== \"\") return create(client, name);\n context.print(\" A Space needs a name.\");\n }\n}\n\nasync function create(client: PersistMemory, name: string): Promise<Space> {\n // `project`, because that is what a folder is. The other kinds exist and are\n // reachable from `pm spaces create --kind`; guessing between them here would\n // be asking a question whose answer changes nothing a person can see.\n return client.spaces.create({ name, kind: \"project\" });\n}\n\nfunction byName(spaces: readonly Space[], name: string): Space | undefined {\n const wanted = name.trim().toLowerCase();\n return spaces.find((one) => one.name.trim().toLowerCase() === wanted) ??\n spaces.find((one) => one.id === name);\n}\n\nfunction finish(\n context: CommandContext,\n space: Space,\n previous: { id: string; name: string } | undefined\n): number {\n // Written into the folder the command was RUN in, not the one the old file\n // was found in: choosing a Space for this project should not rewrite the\n // parent project's file three directories up.\n const file = writeWorkspace(process.cwd(), {\n space: { id: space.id, name: space.name }\n });\n\n context.print(\"\");\n context.print(` This folder now uses the Space \"${space.name}\".`);\n if (previous && previous.id !== space.id) {\n context.print(` It used to use \"${previous.name}\". Existing memories were not moved.`);\n }\n context.print(` Saved to ${file}`);\n context.print(\"\");\n context.print(\" Try it:\");\n context.print(\"\");\n context.print(' pm remember \"we chose Postgres for the ledger\"');\n context.print(' pm search \"what did we choose\"');\n context.print(\"\");\n return 0;\n}\n", "import { DEFAULT_PROFILE, clearLogin, maskToken, readConfig, resolve, saveLogin } from \"../config\";\nimport { loginWithBrowser } from \"../auth/oauth\";\nimport { currentCredential } from \"../session\";\nimport { chooseSpace } from \"./setup\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * `pm auth login`, `pm auth status`, `pm auth logout`.\n *\n * Two ways in, and both are first-class:\n *\n * pm auth login a browser, PKCE, a refresh token that renews\n * pm auth login --api-key a pasted key, for CI and for headless machines\n *\n * The second exists because the first cannot work everywhere, and a CLI whose\n * only login needs a browser is a CLI that cannot run in a pipeline. It is\n * also why `PERSISTMEMORY_API_KEY` outranks the stored profile: a CI runner\n * sets one variable and never writes a file.\n */\nexport async function authCommand(context: CommandContext): Promise<number> {\n const action = context.args.words[1] ?? \"status\";\n\n switch (action) {\n case \"login\":\n return login(context);\n case \"logout\":\n return logout(context);\n case \"status\":\n return status(context);\n default:\n context.error(`Unknown command \"pm auth ${action}\". Try login, logout or status.`);\n return 2;\n }\n}\n\nconst SCOPE = \"memory:read memory:capture memory:write usage:read\";\n\n/**\n * Signing in, exported so `pm setup` can do it as a step rather than telling\n * somebody to run another command and come back.\n */\nexport async function login(context: CommandContext): Promise<number> {\n const { flags } = context;\n const profile = flags.profile ?? DEFAULT_PROFILE;\n const apiUrl = context.resolved.apiUrl;\n\n /**\n * A pasted key.\n *\n * `--api-key` with no value reads from stdin rather than from the argument,\n * so the key never appears in the shell history or in the process list \u2014\n * both of which are readable by anyone else on the machine. `--api-key=\u2026` is\n * still accepted because scripts need it, and a script's environment is a\n * problem the script owns.\n */\n if (flags.apiKey !== undefined) {\n const key = flags.apiKey === true ? await context.readSecret(\"API key: \") : flags.apiKey;\n if (!key) {\n context.error(\"No API key was given.\");\n return 2;\n }\n\n saveLogin({\n paths: context.paths,\n profile,\n apiUrl,\n credential: { kind: \"api-key\", token: key }\n });\n\n context.print(`Signed in to ${apiUrl} as profile \"${profile}\" with an API key.`);\n return 0;\n }\n\n try {\n const { credential, clientId } = await loginWithBrowser({\n apiUrl,\n scope: SCOPE,\n clientId: context.resolved.clientId,\n deps: context.oauth\n });\n\n saveLogin({\n paths: context.paths,\n profile,\n apiUrl,\n credential,\n clientId\n });\n\n context.print(`\\nSigned in to ${apiUrl} as profile \"${profile}\".`);\n\n /*\n And then keep going, rather than returning to a bare prompt.\n\n Signing in is never the thing somebody wanted; it is the step before it.\n Stopping here left a person who had just approved a consent screen with\n no idea what to do next, and everything they captured landing in one\n undifferentiated pile until they happened to read about Spaces.\n\n Only when a terminal is attached and only when the caller did not ask for\n the login on its own. `pm auth login` inside a script, a Dockerfile or a\n plugin's install step must still be exactly one thing.\n */\n if (context.args.flags[\"no-setup\"] === true || !context.isTty) return 0;\n\n return continueToSpace(context);\n } catch (error) {\n context.error(message(error));\n return 1;\n }\n}\n\n/**\n * The Space question, asked after a successful browser sign-in.\n *\n * Failure here is NOT a failed login. The credential is already saved and\n * works; being unable to list Spaces means the person can still use every\n * command, so this reports and returns success rather than making a signed-in\n * terminal look like a broken one.\n */\nasync function continueToSpace(context: CommandContext): Promise<number> {\n try {\n const client = await context.client();\n const { data } = await client.spaces.list({ limit: 200 }).first();\n return await chooseSpace(context, client, data);\n } catch (caught) {\n context.print(\"\");\n context.print(`Could not load your Spaces: ${message(caught)}`);\n context.print(\"You are signed in. Run `pm setup` to choose a Space.\");\n return 0;\n }\n}\n\nfunction logout(context: CommandContext): number {\n const profile = context.flags.profile ?? context.resolved.profile;\n const forgotten = clearLogin(context.paths, profile);\n\n context.print(\n forgotten\n ? `Signed out of profile \"${profile}\".`\n : `Profile \"${profile}\" was not signed in.`\n );\n\n /**\n * A reminder, not a failure.\n *\n * `logout` removes the stored credential and can do nothing about an\n * environment variable, so somebody who exported one stays authenticated and\n * would otherwise conclude that logging out silently did not work.\n */\n if (process.env[\"PERSISTMEMORY_API_KEY\"]) {\n context.print(\n \"PERSISTMEMORY_API_KEY is still set in this shell, and takes precedence. Unset it to finish signing out.\"\n );\n }\n return 0;\n}\n\nasync function status(context: CommandContext): Promise<number> {\n const config = readConfig(context.paths);\n const resolved = context.resolved;\n\n if (!resolved.credential) {\n context.print(`Not signed in. Run \\`pm auth login\\`.\\n\\n api url ${resolved.apiUrl}`);\n return 1;\n }\n\n const lines = [\n ` profile ${resolved.profile}${config.current === resolved.profile ? \" (current)\" : \"\"}`,\n ` api url ${resolved.apiUrl}`,\n ` method ${resolved.credential.kind === \"api-key\" ? \"API key\" : \"browser sign-in\"}`,\n ` token ${maskToken(resolved.credential.token)}`\n ];\n\n if (resolved.fromEnvironment) {\n lines.push(\" source PERSISTMEMORY_API_KEY (overrides the stored profile)\");\n }\n if (resolved.credential.expiresAt) {\n lines.push(` expires ${resolved.credential.expiresAt}`);\n }\n if (resolved.credential.scope) {\n lines.push(` scope ${resolved.credential.scope}`);\n }\n\n context.print(lines.join(\"\\n\"));\n\n /**\n * Then actually use it.\n *\n * A status that only reads a local file answers \"is there a token here\",\n * which is not the question anybody is asking when they run this. They are\n * asking \"why is my next command failing\", and a revoked key looks perfectly\n * healthy on disk.\n */\n try {\n await currentCredential(resolved, context.session);\n const client = await context.client();\n await client.health.ready();\n context.print(\"\\n The server accepted this credential.\");\n return 0;\n } catch (error) {\n context.print(`\\n The server did NOT accept this credential: ${message(error)}`);\n return 1;\n }\n}\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n", "import { existsSync, rmSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { CommandContext } from \"../context\";\nimport { PACKAGE } from \"../help\";\n\n/**\n * Updating, removing, and forgetting everything.\n *\n * These exist because the alternative is a web page nobody reads. Somebody who\n * wants this program gone should be able to ask it to go, in the place they\n * are already typing, rather than being told to remember an npm incantation \u2014\n * and somebody handing a laptop back needs the credentials gone with one\n * command, not a path to delete by hand.\n */\n\n/** `pm update` \u2014 install the newest published version. */\nexport async function updateCommand(context: CommandContext): Promise<number> {\n const manager = installer();\n\n if (!manager) {\n context.error(\n \"This copy was not installed by npm, so `pm update` cannot replace it.\\n\" +\n \"Re-run the installer: curl -fsSL https://persistmemory.com/install.sh | sh\"\n );\n return 1;\n }\n\n context.print(`Installing the newest ${PACKAGE}\u2026`);\n\n // Inherited, so npm's own progress and errors go straight to the person.\n // Summarising them would hide the one line that says what went wrong.\n const result = spawnSync(manager, [\"install\", \"-g\", `${PACKAGE}@latest`], {\n stdio: \"inherit\"\n });\n\n if (result.status !== 0) {\n context.error(\n \"That did not work. If it failed on permissions, do NOT re-run it with sudo \u2014\\n\" +\n \"point npm at a directory you own instead:\\n\" +\n \" npm config set prefix ~/.npm-global\\n\" +\n \" export PATH=$HOME/.npm-global/bin:$PATH\"\n );\n return result.status ?? 1;\n }\n\n context.print(\"Done. `pm --version` will show the new one.\");\n return 0;\n}\n\n/** `pm uninstall` \u2014 remove the program. Offers to take its files too. */\nexport async function uninstallCommand(context: CommandContext): Promise<number> {\n const manager = installer();\n\n if (!manager) {\n context.error(\n \"This copy was not installed by npm, so it cannot uninstall itself.\\n\" +\n `Delete the file it runs from: ${processPath()}`\n );\n return 1;\n }\n\n // Asked BEFORE anything is removed. Afterwards there is no `pm` left to ask\n // with, and somebody who wanted their credentials gone would have to find\n // the directory themselves.\n const alsoData =\n context.args.flags[\"purge\"] === true ||\n (context.isTty\n ? /^y(es)?$/i.test(\n await context.ask(`Also delete your credentials and settings in ${context.paths.dir}? [y/N] `)\n )\n : false);\n\n const result = spawnSync(manager, [\"uninstall\", \"-g\", PACKAGE], { stdio: \"inherit\" });\n\n if (result.status !== 0) return result.status ?? 1;\n\n if (alsoData) removeEverything(context);\n\n context.print(\"Removed. Your memories are untouched \u2014 this only removed the program.\");\n return 0;\n}\n\n/**\n * `pm delete` \u2014 every file this program has written on this machine.\n *\n * NOT the account, and the difference is stated in the confirmation. A command\n * called `delete` that quietly destroyed somebody's memories would be the\n * worst possible reading of an ambiguous word, so this one is explicit about\n * being local-only and points at where the other thing lives.\n */\nexport async function deleteCommand(context: CommandContext): Promise<number> {\n if (!existsSync(context.paths.dir)) {\n context.print(`Nothing to delete: ${context.paths.dir} does not exist.`);\n return 0;\n }\n\n if (context.args.flags[\"yes\"] !== true) {\n if (!context.isTty) {\n context.error(\"Refusing to delete without confirmation. Pass --yes.\");\n return 2;\n }\n\n context.print(\"\");\n context.print(`This deletes everything in ${context.paths.dir}:`);\n context.print(\" \u2022 the credential you signed in with\");\n context.print(\" \u2022 your profiles and settings\");\n context.print(\" \u2022 transcripts of your `pm` sessions\");\n context.print(\"\");\n context.print(\"Your account and your memories are NOT touched. To delete those,\");\n context.print(\"go to https://persistmemory.com/settings.\");\n context.print(\"\");\n\n const answer = await context.ask(\"Type 'delete' to confirm: \");\n if (answer.trim().toLowerCase() !== \"delete\") {\n context.print(\"Nothing was deleted.\");\n return 1;\n }\n }\n\n removeEverything(context);\n context.print(`Deleted ${context.paths.dir}.`);\n return 0;\n}\n\nfunction removeEverything(context: CommandContext): void {\n // `resolve`, and a guard, because this deletes a directory recursively and\n // `PERSISTMEMORY_HOME` is settable. An empty or root-ish value would be a\n // command that eats a filesystem.\n const dir = resolve(context.paths.dir);\n if (dir === \"/\" || dir.split(\"/\").filter(Boolean).length < 2) {\n context.error(`Refusing to delete ${dir}: that does not look like a data directory.`);\n return;\n }\n rmSync(dir, { recursive: true, force: true });\n}\n\n/**\n * Which package manager put this here, if any.\n *\n * Decided from the path this file runs from rather than from configuration: a\n * global npm install lives under `node_modules`, and a copy someone built from\n * source or downloaded does not. Getting this wrong in the optimistic\n * direction means telling npm to uninstall something it never installed.\n */\nfunction installer(): \"npm\" | undefined {\n return processPath().includes(`node_modules`) ? \"npm\" : undefined;\n}\n\nfunction processPath(): string {\n try {\n return resolve(dirname(fileURLToPath(import.meta.url)));\n } catch {\n return process.argv[1] ?? \"\";\n }\n}\n", "import { createInterface } from \"node:readline\";\nimport { randomUUID } from \"node:crypto\";\nimport { relative } from \"node:path\";\nimport { stringFlag } from \"../args\";\nimport { openSessionLog, totalUsage, turnsFrom } from \"../events\";\nimport type { SessionEvent, SessionLog } from \"../events\";\nimport { commitWrite, proposeWrite, readWithin, summarise } from \"../files\";\nimport type { CommandContext } from \"../context\";\n\n/**\n * The interactive session.\n *\n * A conversation with your own memory, in a terminal. What it is NOT is a\n * coding agent: nothing here plans, edits a project, or runs a command. It\n * reads, it answers from what you have recorded, and it writes a file only when\n * you say so for that file.\n *\n * THREE THINGS THIS BORROWS, deliberately, from harnesses built for coding\n * agents \u2014 the problems are the same even though the domain is not:\n *\n * A SMALL, COMPOSABLE TOOL SET. Six commands, not sixty. A sprawling toolkit\n * is harder for a person to remember and gives a model more ways to pick\n * wrong, and every one of these is something you could otherwise do by\n * leaving the session.\n *\n * AN EVENT LOG, written as it happens. Every prompt, reply, file read and\n * proposed write lands in `~/.persistmemory/sessions/<id>.jsonl` on the line\n * it occurs, so a session that dies with the terminal is still readable and\n * still resumable. See `events.ts` for why append-only.\n *\n * COST IN VIEW. Each reply reports what it cost and `/usage` totals the\n * session. A tool that spends someone's money silently is a tool they stop\n * trusting the first time they see the bill.\n *\n * The one thing it does not borrow is an approval MODE. Those harnesses have a\n * setting that grants writes for a whole session; this asks every time, because\n * the text proposing a write can come from a model, and a model's suggestion is\n * downstream of whatever it just read.\n */\n\nconst HELP = `\n Commands\n\n /read <path> read a file into the conversation\n /capture <path> read a file AND remember it\n /write <path> write the last reply to a file (asks first)\n /remember <text> remember something directly\n /usage what this session has cost\n /new start a fresh conversation\n /exit leave (Ctrl-D also works)\n\n Anything else is a question, answered from your memory.\n`;\n\nexport interface SessionState {\n conversationId?: string;\n /** The turns sent to the server, kept so a reply has its own context. */\n turns: { role: \"user\" | \"assistant\"; content: string }[];\n lastReply?: string;\n /** Files read this session, so a question can refer to them. */\n attached: { path: string; text: string }[];\n}\n\nexport async function sessionCommand(context: CommandContext): Promise<number> {\n const resumeId = stringFlag(context.args, \"resume\");\n const id = resumeId ?? randomUUID();\n const log = openSessionLog(context.paths, id);\n\n const state: SessionState = { turns: [], attached: [] };\n\n if (resumeId) {\n const previous = log.read();\n state.turns = turnsFrom(previous);\n if (state.turns.length === 0) {\n context.error(`No session \"${resumeId}\" to resume.`);\n return 1;\n }\n context.print(`Resumed session ${resumeId} \u2014 ${state.turns.length} turns.`);\n }\n\n // Checked before the prompt is drawn. Discovering you are not signed in\n // after typing a paragraph is a small cruelty a one-line check avoids.\n try {\n await context.client();\n } catch (error) {\n context.error(error instanceof Error ? error.message : String(error));\n return 3;\n }\n\n log.append({\n kind: \"session.started\",\n at: new Date().toISOString(),\n cwd: process.cwd(),\n apiUrl: context.resolved.apiUrl,\n profile: context.resolved.profile\n });\n\n context.print(`\\n PersistMemory \u2014 session ${id.slice(0, 8)}`);\n context.print(` Ask anything. /help for commands, /exit to leave.\\n`);\n\n const readline = createInterface({ input: process.stdin, output: process.stdout });\n const ask = (prompt: string): Promise<string | undefined> =>\n new Promise((resolve) => {\n readline.question(prompt, resolve);\n // Ctrl-D closes stdin, which resolves nothing above. Without this the\n // session hangs on a closed terminal instead of ending.\n readline.once(\"close\", () => resolve(undefined));\n });\n\n const root = process.cwd();\n let running = true;\n\n while (running) {\n const line = await ask(\"> \");\n if (line === undefined) break;\n\n const input = line.trim();\n if (input === \"\") continue;\n\n try {\n running = await handleInput({ input, context, state, log, root, ask });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n log.append({ kind: \"error\", at: new Date().toISOString(), message });\n context.error(` ${message}`);\n }\n }\n\n readline.close();\n\n const totals = totalUsage(log.read());\n log.append({ kind: \"session.ended\", at: new Date().toISOString(), turns: totals.turns });\n\n context.print(\n `\\n ${totals.turns} turn${totals.turns === 1 ? \"\" : \"s\"}` +\n (totals.inputTokens + totals.outputTokens > 0\n ? `, ${totals.inputTokens + totals.outputTokens} tokens`\n : \"\") +\n `\\n Transcript: ${log.path}` +\n `\\n Resume with: pm chat --resume ${id}\\n`\n );\n\n return 0;\n}\n\n/**\n * One line of input.\n *\n * Exported for tests. The loop above owns a real terminal and cannot be driven\n * from a test without one; this is where every decision actually lives, and it\n * takes `ask` as a parameter precisely so the confirmation prompt can be\n * answered by a function instead of a person.\n *\n * Returns false to end the session.\n */\nexport async function handleInput(args: {\n input: string;\n context: CommandContext;\n state: SessionState;\n log: SessionLog;\n root: string;\n ask: (prompt: string) => Promise<string | undefined>;\n}): Promise<boolean> {\n const { input, context, state, log, root } = args;\n\n if (!input.startsWith(\"/\")) {\n await answer(args);\n return true;\n }\n\n const [command, ...rest] = input.slice(1).split(/\\s+/);\n const argument = rest.join(\" \").trim();\n\n switch (command) {\n case \"exit\":\n case \"quit\":\n return false;\n\n case \"help\":\n context.print(HELP);\n return true;\n\n case \"usage\": {\n const totals = totalUsage(log.read());\n context.print(\n ` ${totals.turns} turns, ${totals.inputTokens} in / ${totals.outputTokens} out tokens`\n );\n return true;\n }\n\n case \"new\":\n // The conversation id is dropped, so the next turn starts a new one\n // server-side. The local log continues, because it is a log of this\n // SESSION and starting a new topic is a thing that happened in it.\n delete state.conversationId;\n state.turns = [];\n state.attached = [];\n delete state.lastReply;\n context.print(\" Starting a fresh conversation.\");\n return true;\n\n case \"read\":\n case \"capture\": {\n if (!argument) {\n context.error(` /${command} needs a path.`);\n return true;\n }\n\n const file = readWithin(root, argument);\n state.attached.push({ path: file.path, text: file.text });\n log.append({\n kind: \"file.read\",\n at: new Date().toISOString(),\n path: file.path,\n bytes: file.bytes\n });\n\n context.print(` read ${relative(root, file.path)} (${Math.round(file.bytes / 1024)} KB)`);\n\n if (command === \"capture\") {\n const client = await context.client();\n const result = await client.memories.remember(\n { text: file.text, title: relative(root, file.path) },\n { idempotencyKey: `cli:capture:${file.path}:${file.bytes}` }\n );\n log.append({\n kind: \"file.captured\",\n at: new Date().toISOString(),\n path: file.path,\n jobId: result.jobId\n });\n // 202, not \"created\". Extraction runs afterwards and may produce one\n // memory, several, or none.\n context.print(` queued for extraction (job ${result.jobId})`);\n }\n\n return true;\n }\n\n case \"remember\": {\n if (!argument) {\n context.error(\" /remember needs something to remember.\");\n return true;\n }\n const client = await context.client();\n const result = await client.memories.remember({ text: argument });\n context.print(` queued for extraction (job ${result.jobId})`);\n return true;\n }\n\n case \"write\":\n await write({ ...args, path: argument });\n return true;\n\n default:\n context.error(` Unknown command /${command ?? \"\"}. Try /help.`);\n return true;\n }\n}\n\n/**\n * A question, answered from memory.\n *\n * Files read with `/read` are attached to the turn rather than remembered, and\n * the distinction matters: reading a file to ask about it should not file it in\n * somebody's long-term memory. `/capture` is the command that does that, and it\n * says so.\n */\nasync function answer(args: {\n input: string;\n context: CommandContext;\n state: SessionState;\n log: SessionLog;\n}): Promise<void> {\n const { input, context, state, log } = args;\n\n const attached = state.attached\n .map((file) => `--- ${file.path} ---\\n${file.text}`)\n .join(\"\\n\\n\");\n\n const content = attached ? `${attached}\\n\\n---\\n\\n${input}` : input;\n\n log.append({ kind: \"prompt\", at: new Date().toISOString(), text: input });\n state.turns.push({ role: \"user\", content });\n\n const client = await context.client();\n const response = await client.request<ChatResponse>(\"POST\", \"/api/v1/chat\", {\n messages: state.turns.slice(-20),\n ...(state.conversationId ? { conversationId: state.conversationId } : {})\n });\n\n const reply = response.message.content;\n state.turns.push({ role: \"assistant\", content: reply });\n state.lastReply = reply;\n if (response.conversationId) state.conversationId = response.conversationId;\n\n // Attachments are consumed by the turn they were read for. Keeping them\n // would resend the whole file on every subsequent question, which is how a\n // session quietly becomes expensive.\n state.attached = [];\n\n log.append({\n kind: \"reply\",\n at: new Date().toISOString(),\n text: reply,\n citations: response.citations?.length ?? 0,\n ...(response.diagnostics?.usage ? { usage: response.diagnostics.usage } : {}),\n ...(response.diagnostics?.model ? { model: response.diagnostics.model } : {})\n });\n\n context.print(`\\n${reply}\\n`);\n\n if (response.citations?.length) {\n const historical = response.citations.filter((one) => one.historical).length;\n context.print(\n ` from ${response.citations.length} memor${response.citations.length === 1 ? \"y\" : \"ies\"}` +\n // Never omitted. A superseded memory presented as current is the most\n // damaging thing this system can do.\n (historical > 0 ? `, ${historical} no longer current` : \"\")\n );\n }\n\n if (response.diagnostics?.degraded && !context.flags.quiet) {\n context.error(\" Note: answered without the semantic index, so this may be narrower than usual.\");\n }\n}\n\n/**\n * Writes the last reply to a file, after showing exactly what will change.\n *\n * ALWAYS ASKS, and there is no flag that turns this off. The text being written\n * came from a model, and the model's output is downstream of whatever it read \u2014\n * a document that says \"now overwrite ~/.ssh/config\" is a document somebody\n * might legitimately have in their memory. The prompt is what stands between\n * that and a file changing.\n */\nasync function write(args: {\n path: string;\n context: CommandContext;\n state: SessionState;\n log: SessionLog;\n root: string;\n ask: (prompt: string) => Promise<string | undefined>;\n}): Promise<void> {\n const { context, state, log, root } = args;\n\n if (!args.path) {\n context.error(\" /write needs a path.\");\n return;\n }\n if (!state.lastReply) {\n context.error(\" Nothing to write yet \u2014 ask something first.\");\n return;\n }\n\n const proposed = proposeWrite(root, args.path, `${state.lastReply}\\n`);\n\n context.print(\"\");\n context.print(summarise(proposed));\n context.print(\"\");\n\n const reply = (await args.ask(\" Write it? [y/N] \"))?.trim().toLowerCase();\n const approved = reply === \"y\" || reply === \"yes\";\n\n log.append({\n kind: \"file.write\",\n at: new Date().toISOString(),\n path: proposed.path,\n approved,\n ...(approved ? { bytes: Buffer.byteLength(proposed.contents) } : {})\n });\n\n if (!approved) {\n context.print(\" Not written.\");\n return;\n }\n\n commitWrite(proposed, true);\n context.print(` Wrote ${relative(root, proposed.path)}.`);\n}\n\ninterface ChatResponse {\n readonly message: { role: \"assistant\"; content: string };\n readonly conversationId?: string;\n readonly citations?: readonly { id: string; title: string; historical: boolean }[];\n readonly diagnostics?: {\n readonly degraded?: boolean;\n readonly usage?: { inputTokens?: number; outputTokens?: number };\n readonly model?: string;\n };\n}\n\nexport type { SessionEvent };\n", "import { appendFileSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Paths } from \"./config\";\n\n/**\n * Everything a session did, on disk, as it happens.\n *\n * Append-only JSONL, one event per line, flushed on every write. That shape is\n * chosen for the failure it survives: a session ends by the terminal being\n * closed, the laptop sleeping, or Ctrl-C \u2014 never by a tidy shutdown \u2014 and a log\n * written at the end is a log that does not exist. Appending a line at a time\n * means the transcript of a session that died mid-sentence is complete up to\n * the sentence.\n *\n * This is deliberately the SECOND record rather than the only one. The\n * conversation itself is stored server-side, which is what makes it available\n * to every other client. This local log holds what the server has no business\n * knowing: which files were read off this machine, what was proposed as a\n * write, and what the person approved or refused. Sending that to a server\n * would be shipping a directory listing of somebody's laptop.\n *\n * JSONL rather than JSON, because a JSON array has to be rewritten to be\n * appended to \u2014 and a rewrite interrupted halfway loses the whole file rather\n * than the last line.\n */\n\nexport type SessionEvent =\n | { kind: \"session.started\"; at: string; cwd: string; apiUrl: string; profile: string }\n | { kind: \"prompt\"; at: string; text: string }\n | {\n kind: \"reply\";\n at: string;\n text: string;\n citations: number;\n /** What the turn cost, when the server reported it. */\n usage?: { inputTokens?: number; outputTokens?: number };\n model?: string;\n }\n | { kind: \"file.read\"; at: string; path: string; bytes: number }\n | { kind: \"file.captured\"; at: string; path: string; jobId?: string }\n /** Proposed, and what the person said. `approved: false` is the useful one. */\n | { kind: \"file.write\"; at: string; path: string; approved: boolean; bytes?: number }\n | { kind: \"error\"; at: string; message: string }\n | { kind: \"session.ended\"; at: string; turns: number };\n\nexport interface SessionLog {\n readonly id: string;\n readonly path: string;\n append(event: SessionEvent): void;\n read(): SessionEvent[];\n}\n\n/**\n * Opens (or resumes) a session log.\n *\n * The id is the file name, so resuming a session is opening the same file \u2014\n * there is no index to keep in step with the directory, and a log the user\n * deleted is simply gone rather than a dangling row.\n */\nexport function openSessionLog(paths: Paths, id: string): SessionLog {\n const directory = join(paths.dir, \"sessions\");\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n\n const path = join(directory, `${id}.jsonl`);\n\n return {\n id,\n path,\n\n append(event) {\n try {\n // 0600: this holds the text of what somebody asked their own memory and\n // the paths of files on their machine.\n appendFileSync(path, `${JSON.stringify(event)}\\n`, { mode: 0o600 });\n } catch {\n // A log that cannot be written must not end the session it is\n // describing. The transcript is a convenience; the conversation is the\n // thing the person came for.\n }\n },\n\n read() {\n if (!existsSync(path)) return [];\n return readFileSync(path, \"utf8\")\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\")\n .flatMap((line) => {\n try {\n return [JSON.parse(line) as SessionEvent];\n } catch {\n // One malformed line \u2014 a half-written final record after a crash \u2014\n // costs that line and not the transcript around it.\n return [];\n }\n });\n }\n };\n}\n\n/**\n * The turns, in the shape `/chat` wants, recovered from a log.\n *\n * This is what makes `pm chat --resume` work without the server: the local log\n * already holds every prompt and reply in order, so a resumed session starts\n * with its own history even when the conversation id has been lost.\n */\nexport function turnsFrom(events: readonly SessionEvent[]): {\n role: \"user\" | \"assistant\";\n content: string;\n}[] {\n const turns: { role: \"user\" | \"assistant\"; content: string }[] = [];\n\n for (const event of events) {\n if (event.kind === \"prompt\") turns.push({ role: \"user\", content: event.text });\n if (event.kind === \"reply\") turns.push({ role: \"assistant\", content: event.text });\n }\n\n return turns;\n}\n\n/** What a session cost, added up. Printed on exit. */\nexport function totalUsage(events: readonly SessionEvent[]): {\n turns: number;\n inputTokens: number;\n outputTokens: number;\n} {\n let turns = 0;\n let inputTokens = 0;\n let outputTokens = 0;\n\n for (const event of events) {\n if (event.kind !== \"reply\") continue;\n turns += 1;\n inputTokens += event.usage?.inputTokens ?? 0;\n outputTokens += event.usage?.outputTokens ?? 0;\n }\n\n return { turns, inputTokens, outputTokens };\n}\n", "import { readFileSync } from \"node:fs\";\nimport type { Memory, SearchResult, Space } from \"@persistmemory/sdk\";\nimport { listFlag, numberFlag, stringFlag } from \"../args\";\nimport type { Column } from \"../output\";\nimport { render, renderOne, shortDate } from \"../output\";\nimport { readStdin } from \"../context\";\nimport type { CommandContext } from \"../context\";\nimport { spacesFor } from \"../spaces\";\n\n/**\n * The commands that do the actual work.\n *\n * Every one of them goes through `@persistmemory/sdk` rather than calling\n * `fetch`. That is not code reuse for its own sake: the SDK already decides\n * retries, per-attempt timeouts, idempotency and how an error becomes a\n * message, and a CLI that reimplemented those would drift from the library the\n * same user's scripts are using \u2014 so a request that succeeds from their code\n * would fail from their terminal, or the other way round.\n */\n\nconst memoryColumns: readonly Column<Memory>[] = [\n { header: \"id\", value: (m) => m.id },\n { header: \"type\", value: (m) => m.type },\n { header: \"title\", value: (m) => m.title },\n { header: \"confidence\", value: (m) => m.confidence.toFixed(2) },\n { header: \"updated\", value: (m) => shortDate(m.updatedAt) }\n];\n\nconst memoryFields: readonly Column<Memory>[] = [\n { header: \"id\", value: (m) => m.id },\n { header: \"type\", value: (m) => m.type },\n { header: \"state\", value: (m) => m.state },\n { header: \"title\", value: (m) => m.title },\n { header: \"content\", value: (m) => m.content },\n { header: \"confidence\", value: (m) => m.confidence.toFixed(2) },\n { header: \"importance\", value: (m) => m.importance.toFixed(2) },\n { header: \"entities\", value: (m) => m.entities.map((e) => e.name).join(\", \") },\n { header: \"spaces\", value: (m) => (m.spaceIds ?? []).join(\", \") },\n { header: \"version\", value: (m) => String(m.version) },\n { header: \"created\", value: (m) => shortDate(m.createdAt) },\n { header: \"updated\", value: (m) => shortDate(m.updatedAt) }\n];\n\n/**\n * `pm remember <text>`, `pm remember -`, `pm remember --file notes.md`.\n *\n * Reading from stdin and from a file are not conveniences. The things worth\n * remembering are usually already in a file or coming out of another command,\n * and a capture tool that only accepts a quoted argument makes the user paste\n * multi-line text into a shell \u2014 where the shell then interprets it.\n */\nexport async function rememberCommand(context: CommandContext): Promise<number> {\n const positional = context.args.words.slice(1);\n const file = stringFlag(context.args, \"file\", \"f\");\n\n let text: string;\n if (file) {\n try {\n text = readFileSync(file, \"utf8\");\n } catch {\n context.error(`Could not read ${file}.`);\n return 1;\n }\n } else if (positional[0] === \"-\" || (positional.length === 0 && !process.stdin.isTTY)) {\n text = await readStdin();\n } else {\n text = positional.join(\" \");\n }\n\n if (text.trim() === \"\") {\n context.error(\"Nothing to remember. Pass text, a --file, or pipe something in.\");\n return 2;\n }\n\n const client = await context.client();\n // Resolves names as well as ids, and falls back to the folder's space.\n const spaceIds = await spacesFor(context, client);\n const title = stringFlag(context.args, \"title\");\n\n const result = await client.memories.remember(\n {\n text,\n ...(title ? { title } : {}),\n ...(spaceIds ? { spaceIds } : {})\n },\n {\n /**\n * A key derived from the CONTENT, not a random one.\n *\n * The SDK will not retry a POST without one, and a random value per\n * attempt would defeat the point: a request that timed out after the\n * server accepted it would be captured twice. Same text, same key, one\n * memory \u2014 which is what a person re-running a failed command expects.\n */\n idempotencyKey: `cli:remember:${hash(text)}`\n }\n );\n\n if (context.flags.output !== \"table\") {\n context.print(renderOne(result, [\n { header: \"status\", value: (r) => r.status },\n { header: \"jobId\", value: (r) => r.jobId },\n { header: \"note\", value: (r) => r.note }\n ], { format: context.flags.output }));\n return 0;\n }\n\n // Said plainly, because `remember` returns 202 and people reasonably assume\n // a memory now exists. It does not yet: extraction, deduplication and\n // conflict detection all run afterwards and may produce one, several or none.\n context.print(`Accepted for processing. Job ${result.jobId}.`);\n context.print(result.note);\n return 0;\n}\n\nexport async function searchCommand(context: CommandContext): Promise<number> {\n const query = context.args.words.slice(1).join(\" \").trim();\n if (query === \"\") {\n context.error('Nothing to search for. Try `pm search \"what did we decide about Postgres\"`.');\n return 2;\n }\n\n const limit = numberFlag(context.args, \"limit\", \"n\");\n if (limit === \"invalid\") {\n context.error(\"--limit must be a number.\");\n return 2;\n }\n\n const client = await context.client();\n const spaceIds = await spacesFor(context, client);\n\n const response = await client.search.query({\n query,\n ...(limit !== undefined ? { limit } : {}),\n ...(spaceIds ? { spaceIds } : {}),\n ...(stringFlag(context.args, \"as-of\") ? { asOf: stringFlag(context.args, \"as-of\") as string } : {})\n });\n\n if (context.flags.output === \"json\" || context.flags.output === \"yaml\") {\n // The whole response, diagnostics included. A script that wants to know\n // whether the answer was degraded cannot find that out from the rows.\n context.print(renderOne(response, [], { format: context.flags.output }));\n return 0;\n }\n\n const columns: readonly Column<SearchResult>[] = [\n { header: \"score\", value: (r) => r.score.toFixed(3) },\n { header: \"type\", value: (r) => r.memory.type },\n { header: \"title\", value: (r) => r.memory.title },\n { header: \"content\", value: (r) => r.memory.content },\n { header: \"id\", value: (r) => r.memory.id }\n ];\n\n if (response.results.length === 0) {\n context.print(`Nothing found for \"${response.query}\".`);\n } else {\n context.print(render(response.results, columns, { format: context.flags.output }));\n }\n\n /**\n * The degraded notice, always, and never only in verbose mode.\n *\n * Search falls back to deterministic retrieval when embeddings are\n * unavailable and still answers. A person who is not told that reads a\n * narrower result set as \"my memory is empty\" \u2014 which is the one conclusion\n * that would make them stop using the tool.\n */\n if (response.diagnostics.degraded && !context.flags.quiet) {\n const notice =\n response.diagnostics.notice ??\n `search ran without ${(response.diagnostics.unavailable ?? [\"some capabilities\"]).join(\", \")}`;\n context.error(`\\nNote: these results are narrower than usual \u2014 ${notice}`);\n }\n\n return 0;\n}\n\nexport async function listMemoriesCommand(context: CommandContext): Promise<number> {\n const limit = numberFlag(context.args, \"limit\", \"n\");\n if (limit === \"invalid\") {\n context.error(\"--limit must be a number.\");\n return 2;\n }\n\n const client = await context.client();\n const spaceIds = await spacesFor(context, client);\n const page = client.memories.list({\n ...(limit !== undefined ? { limit } : {}),\n ...(listFlag(context.args, \"type\") ? { type: listFlag(context.args, \"type\") as never } : {}),\n ...(spaceIds\n ? { spaceIds: [...spaceIds] }\n : {})\n });\n\n // One page. `--all` walks the cursor, because a memory store is unbounded\n // and printing all of it by default is a command nobody can interrupt.\n const rows = context.args.flags[\"all\"]\n ? await page.all(limit ?? 1000)\n : (await page.first()).data;\n\n if (rows.length === 0) {\n context.print(\"No memories yet.\");\n return 0;\n }\n\n context.print(render(rows, memoryColumns, { format: context.flags.output }));\n return 0;\n}\n\nexport async function getMemoryCommand(context: CommandContext): Promise<number> {\n const id = context.args.words[2];\n if (!id) {\n context.error(\"Which memory? Try `pm get memory <id>`.\");\n return 2;\n }\n\n const client = await context.client();\n const memory = await client.memories.get(id);\n context.print(renderOne(memory, memoryFields, { format: context.flags.output }));\n return 0;\n}\n\nexport async function listSpacesCommand(context: CommandContext): Promise<number> {\n const client = await context.client();\n const { data } = await client.spaces.list().first();\n\n if (data.length === 0) {\n context.print(\"No Spaces yet.\");\n return 0;\n }\n\n const columns: readonly Column<Space>[] = [\n { header: \"id\", value: (s) => s.id },\n { header: \"name\", value: (s) => s.name },\n { header: \"kind\", value: (s) => s.kind },\n { header: \"memories\", value: (s) => (s.memoryCount === undefined ? \"\" : String(s.memoryCount)) },\n { header: \"created\", value: (s) => shortDate(s.createdAt) }\n ];\n\n context.print(render(data, columns, { format: context.flags.output }));\n return 0;\n}\n\n/** `pm status` \u2014 is the service up, and does this credential work. */\nexport async function statusCommand(context: CommandContext): Promise<number> {\n const client = await context.client();\n const health = await client.health.ready();\n\n context.print(\n renderOne(health, [{ header: \"status\", value: (h) => JSON.stringify(h) }], {\n format: context.flags.output === \"table\" ? \"yaml\" : context.flags.output\n })\n );\n return 0;\n}\n\n/**\n * A short, stable digest of the captured text, for the idempotency key.\n *\n * FNV-1a rather than a crypto hash: this is a deduplication token the server\n * treats as opaque, not a security boundary, and it keeps the key short enough\n * to read in a log line.\n */\nfunction hash(text: string): string {\n let value = 0x811c9dc5;\n for (let index = 0; index < text.length; index += 1) {\n value ^= text.charCodeAt(index);\n value = Math.imul(value, 0x01000193) >>> 0;\n }\n return value.toString(16).padStart(8, \"0\");\n}\n\n/**\n * `pm spaces create \"Acme\"` \u2014 the command that did not exist.\n *\n * Spaces could be listed from here and created only through the SDK or a raw\n * curl, which made the first thing the README tells somebody to do impossible\n * from the tool the README is about.\n */\nexport async function createSpaceCommand(context: CommandContext): Promise<number> {\n const name = context.args.words.slice(2).join(\" \").trim();\n\n if (name === \"\") {\n context.error('A Space needs a name. Try `pm spaces create \"Acme\"`.');\n return 2;\n }\n\n const kind = stringFlag(context.args, \"kind\") ?? \"project\";\n const description = stringFlag(context.args, \"description\");\n\n const client = await context.client();\n const space = await client.spaces.create({\n name,\n kind: kind as Space[\"kind\"],\n ...(description ? { description } : {})\n });\n\n if (context.flags.output !== \"table\") {\n context.print(renderOne(space, spaceFields, { format: context.flags.output }));\n return 0;\n }\n\n context.print(`Created \"${space.name}\".`);\n // The id, because everything else that takes a Space takes this.\n context.print(` id ${space.id}`);\n context.print(` kind ${space.kind}`);\n context.print(\"\");\n context.print(`Use it here with: pm setup --space \"${space.name}\"`);\n return 0;\n}\n\nconst spaceFields: readonly Column<Space>[] = [\n { header: \"id\", value: (s) => s.id },\n { header: \"name\", value: (s) => s.name },\n { header: \"kind\", value: (s) => s.kind }\n];\n\n/**\n * `pm spaces delete \"Acme\" --memories keep|delete`.\n *\n * The flag has no default, here or in the API, and that is the whole design of\n * this command. \"Delete this Space\" means the label to some people and\n * everything inside it to others, and a client that guessed would destroy or\n * keep somebody's material without being asked. Refusing to guess costs one\n * flag; guessing wrong costs a corpus.\n */\nexport async function deleteSpaceCommand(context: CommandContext): Promise<number> {\n const named = context.args.words.slice(2).join(\" \").trim();\n\n if (named === \"\") {\n context.error('Which Space? Try `pm spaces delete \"Acme\" --memories keep`.');\n return 2;\n }\n\n const memories = stringFlag(context.args, \"memories\");\n if (memories !== \"keep\" && memories !== \"delete\") {\n context.error(\"Say what happens to what is in it \u2014 there is no default:\");\n context.error(\"\");\n context.error(` pm spaces delete \"${named}\" --memories keep the memories survive`);\n context.error(` pm spaces delete \"${named}\" --memories delete they go with it`);\n return 2;\n }\n\n const client = await context.client();\n const { data } = await client.spaces.list({ limit: 200 }).first();\n\n // A name, because that is what a person has. Ids are accepted too \u2014 the same\n // rule every other Space argument in this CLI follows.\n const found = named.startsWith(\"space_\")\n ? data.find((one) => one.id === named)\n : data.find((one) => one.name.toLowerCase() === named.toLowerCase());\n\n if (!found) {\n context.error(`No Space called \"${named}\". Run \\`pm spaces list\\` to see them.`);\n return 1;\n }\n\n const result = await client.spaces.delete(found.id, { memories });\n\n if (context.flags.output !== \"table\") {\n context.print(JSON.stringify({ id: found.id, ...result }, undefined, 2));\n return 0;\n }\n\n context.print(`Deleted \"${found.name}\".`);\n // Both numbers, always. A memory filed in another Space as well is detached\n // rather than destroyed, and \"deleted 4, kept 11\" is the only way to see it.\n context.print(` ${result.deleted} memories deleted, ${result.kept} kept`);\n return 0;\n}\n\n/**\n * `pm spaces merge \"Work\" \"Personal\" --name \"Everything\"`.\n *\n * Additive. A memory ends up in the sources AND the result, every search over\n * a source returns what it did before, and undoing it is deleting the Space\n * this makes. Said out loud in the output because \"merge\" everywhere else\n * means the sources stop existing.\n */\nexport async function mergeSpacesCommand(context: CommandContext): Promise<number> {\n const named = context.args.words.slice(2);\n const name = stringFlag(context.args, \"name\");\n\n if (named.length < 2 || !name) {\n context.error(\"Two or more Spaces, and a name for the one this makes:\");\n context.error(\"\");\n context.error(' pm spaces merge \"Work\" \"Personal\" --name \"Everything\"');\n return 2;\n }\n\n const client = await context.client();\n const { data } = await client.spaces.list({ limit: 200 }).first();\n\n const ids: string[] = [];\n for (const one of named) {\n const found = one.startsWith(\"space_\")\n ? data.find((space) => space.id === one)\n : data.find((space) => space.name.toLowerCase() === one.toLowerCase());\n\n if (!found) {\n context.error(`No Space called \"${one}\". Run \\`pm spaces list\\` to see them.`);\n return 1;\n }\n ids.push(found.id);\n }\n\n // `merge` answers with the new Space AND how many memories were filed into\n // it, which is the number worth printing: \"created\" alone does not say\n // whether it drew anything.\n const { space, added } = await client.spaces.merge({ sourceIds: ids, name });\n\n if (context.flags.output !== \"table\") {\n context.print(renderOne(space, spaceFields, { format: context.flags.output }));\n return 0;\n }\n\n context.print(`Created \"${space.name}\" from ${ids.length} Spaces, holding ${added} memories.`);\n context.print(` id ${space.id}`);\n context.print(\"\");\n context.print(\"The Spaces it drew from are unchanged \u2014 nothing was moved or deleted.\");\n return 0;\n}\n", "import type { PersistMemory, Space } from \"@persistmemory/sdk\";\nimport { listFlag } from \"./args\";\nimport type { CommandContext } from \"./context\";\nimport { findWorkspace } from \"./workspace\";\n\n/**\n * Which spaces this command should read from and write into.\n *\n * Precedence, highest first:\n *\n * --space work,acme an instruction for this one command\n * PERSISTMEMORY_SPACE what a CI job exports\n * .persistmemory.json what `pm setup` wrote for this folder\n * nothing everything the account has\n *\n * NAMES ARE ACCEPTED, not just ids. `--space` used to be passed through to the\n * API untouched, so `--space work` sent the literal word \"work\" as a space id\n * and silently matched nothing \u2014 a search that quietly looked in an empty\n * place, which is worse than an error because the answer looks like \"you have\n * no memories about this\".\n */\nexport async function spacesFor(\n context: CommandContext,\n client: PersistMemory,\n env: NodeJS.ProcessEnv = process.env\n): Promise<readonly string[] | undefined> {\n const asked =\n listFlag(context.args, \"space\", \"spaces\") ??\n splitList(env[\"PERSISTMEMORY_SPACE\"]) ??\n workspaceSpace();\n\n if (!asked || asked.length === 0) return undefined;\n\n // Only fetched when a name needs resolving. Somebody passing ids \u2014 a script,\n // or the workspace file this command wrote itself \u2014 should not pay for a\n // round trip to confirm what they already know.\n if (asked.every(looksLikeId)) return asked;\n\n const { data } = await client.spaces.list({ limit: 200 }).first();\n return asked.map((one) => (looksLikeId(one) ? one : resolveName(one, data)));\n}\n\nfunction workspaceSpace(): readonly string[] | undefined {\n const found = findWorkspace();\n return found?.config.space ? [found.config.space.id] : undefined;\n}\n\nfunction splitList(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined;\n const items = raw\n .split(\",\")\n .map((one) => one.trim())\n .filter((one) => one.length > 0);\n return items.length > 0 ? items : undefined;\n}\n\n/** The server's own prefix. Anything else is treated as a name to look up. */\nfunction looksLikeId(value: string): boolean {\n return value.startsWith(\"space_\");\n}\n\nfunction resolveName(name: string, spaces: readonly Space[]): string {\n const wanted = name.trim().toLowerCase();\n const matches = spaces.filter((one) => one.name.trim().toLowerCase() === wanted);\n\n if (matches.length === 1) return matches[0]!.id;\n\n if (matches.length === 0) {\n throw new Error(\n `No Space called \"${name}\". Run \\`pm list spaces\\` to see yours, or ` +\n `\\`pm spaces create \"${name}\"\\` to make it.`\n );\n }\n\n // Two spaces may share a name \u2014 nothing stops it, and picking one would put\n // memories somewhere the person did not choose.\n throw new Error(\n `More than one Space is called \"${name}\": ${matches\n .map((one) => one.id)\n .join(\", \")}. Name it by id.`\n );\n}\n", "import { PersistMemory } from \"@persistmemory/sdk\";\nimport { PersistMemoryError } from \"@persistmemory/sdk\";\nimport { boolFlag, numberFlag, parseArgs, stringFlag } from \"./args\";\nimport type { ParsedArgs } from \"./args\";\nimport { pathsFor, resolve } from \"./config\";\nimport type { Paths } from \"./config\";\nimport { isOutputFormat } from \"./output\";\nimport type { OutputFormat } from \"./output\";\nimport { HELP, VERSION } from \"./help\";\nimport { refreshUpdateCache, updateCacheFile, updateNotice } from \"./update\";\nimport { NotSignedIn, clientFor } from \"./session\";\nimport { askOnTty, readSecretFromTty } from \"./context\";\nimport type { CommandContext, GlobalFlags } from \"./context\";\nimport { agentCommand } from \"./commands/agent\";\nimport { driveCommand, mailCommand } from \"./commands/google\";\nimport { requestsCommand } from \"./commands/requests\";\nimport { authCommand } from \"./commands/auth\";\nimport { setupCommand } from \"./commands/setup\";\nimport { deleteCommand, uninstallCommand, updateCommand } from \"./commands/maintain\";\nimport { sessionCommand } from \"./commands/session\";\nimport {\n createSpaceCommand,\n deleteSpaceCommand,\n mergeSpacesCommand,\n getMemoryCommand,\n listMemoriesCommand,\n listSpacesCommand,\n rememberCommand,\n searchCommand,\n statusCommand\n} from \"./commands/memory\";\n\n/**\n * The entry point.\n *\n * Returns an exit code rather than calling `process.exit`, so the whole CLI is\n * callable from a test. Everything that touches the world \u2014 stdout, the home\n * directory, `fetch`, the browser \u2014 arrives through `Deps` for the same reason.\n */\nexport interface Deps {\n readonly argv: readonly string[];\n readonly env?: NodeJS.ProcessEnv;\n readonly paths?: Paths;\n readonly fetch?: typeof globalThis.fetch;\n readonly stdout?: (line: string) => void;\n readonly stderr?: (line: string) => void;\n readonly openBrowser?: (url: string) => Promise<void>;\n readonly readSecret?: (prompt: string) => Promise<string>;\n readonly ask?: (prompt: string) => Promise<string>;\n readonly isTty?: boolean;\n}\n\nexport async function run(deps: Deps): Promise<number> {\n const args = parseArgs(deps.argv);\n const print = deps.stdout ?? ((line: string) => process.stdout.write(`${line}\\n`));\n const error = deps.stderr ?? ((line: string) => process.stderr.write(`${line}\\n`));\n\n // `--version` BEFORE the bare-invocation check, not after. Both `pm` and\n // `pm --version` carry no positional words, so testing for \"no words\" first\n // made `--version` print the help page \u2014 which reads as the flag not\n // existing at all.\n if (boolFlag(args, \"version\", \"v\")) {\n print(VERSION);\n return 0;\n }\n if (boolFlag(args, \"help\", \"h\")) {\n print(HELP);\n return 0;\n }\n\n const flags = globalFlags(args, deps);\n if (flags === \"invalid-output\") {\n error(`--output must be one of table, json, yaml, csv, tsv.`);\n return 2;\n }\n if (flags === \"invalid-limit\") {\n error(\"--limit must be a number.\");\n return 2;\n }\n\n const paths = deps.paths ?? pathsFor();\n const resolved = resolve({\n paths,\n profileFlag: flags.profile,\n apiUrlFlag: flags.apiUrl,\n // A prompted key is not known yet; only a literal one participates here.\n apiKeyFlag: typeof flags.apiKey === \"string\" ? flags.apiKey : undefined,\n ...(deps.env ? { env: deps.env } : {})\n });\n\n const fetchImpl = deps.fetch ?? globalThis.fetch;\n const oauth = {\n fetch: fetchImpl,\n ...(deps.openBrowser ? { openBrowser: deps.openBrowser } : {}),\n print\n };\n const session = { ...oauth, paths, userAgent: `persistmemory-cli/${VERSION}` };\n\n const context: CommandContext = {\n args,\n flags,\n paths,\n resolved,\n oauth,\n session,\n client: () => clientFor(resolved, session),\n print,\n error,\n readSecret: deps.readSecret ?? readSecretFromTty,\n ask: deps.ask ?? askOnTty,\n isTty: deps.isTty ?? process.stdin.isTTY ?? false\n };\n\n /**\n * A bare `pm` on a terminal opens a session; piped, it prints help.\n *\n * The split is the same one `--output` makes: a person who typed `pm` and is\n * looking at a prompt wants to start talking, and a script that ran `pm` with\n * no arguments has made a mistake and needs to be told what the commands are\n * \u2014 not left holding an interactive prompt that will never be answered.\n */\n if (args.words.length === 0) {\n if (!(deps.isTty ?? process.stdin.isTTY ?? false)) {\n print(HELP);\n return 0;\n }\n return sessionCommand(context);\n }\n\n try {\n /*\n The update check, before the command and never in its way.\n\n Reads a cache written by the LAST run, so nothing here waits on the\n network; the refresh at the end of this function is what fills it. Silent\n unless there is something to say, and silent always in a script \u2014 a\n version notice on stdout would corrupt piped JSON, and one in a CI log\n helps nobody.\n */\n await offerUpdate(context, deps);\n\n const code = await dispatch(context);\n\n // After the command, so a slow registry cannot delay an answer. Not\n // awaited for its result \u2014 a failed check is not a failed command.\n void refreshUpdateCache(updateDeps(context, deps));\n\n return code;\n } catch (caught) {\n return report(caught, error);\n }\n}\n\n/**\n * Tells somebody a newer version exists, and offers to install it.\n *\n * Asked rather than done silently, with yes as the default: an update that\n * runs itself in the middle of an unrelated command surprises people, can take\n * ten seconds, and on a shared machine may fail on permissions halfway\n * through. `PERSISTMEMORY_AUTO_UPDATE=1` skips the question for anybody who\n * would rather never be asked.\n */\nasync function offerUpdate(context: CommandContext, deps: Deps): Promise<void> {\n // `pm update` and `pm uninstall` must not be interrupted by an offer to\n // update: one is already doing it and the other is removing the program.\n const verb = context.args.words[0];\n if (verb === \"update\" || verb === \"upgrade\" || verb === \"uninstall\") return;\n\n const notice = updateNotice(updateDeps(context, deps));\n if (!notice) return;\n\n const env = deps.env ?? process.env;\n\n if (env[\"PERSISTMEMORY_AUTO_UPDATE\"]) {\n context.print(notice.split(\"\\n\")[0] ?? \"\");\n await updateCommand(context);\n return;\n }\n\n // stderr, so a person sees it and a pipe does not.\n context.error(notice);\n}\n\nfunction updateDeps(context: CommandContext, deps: Deps) {\n return {\n file: updateCacheFile(context.paths.dir),\n current: VERSION,\n ...(deps.fetch ? { fetch: deps.fetch } : {}),\n ...(deps.env ? { env: deps.env } : {}),\n isTty: context.isTty,\n quiet: context.flags.quiet\n };\n}\n\nasync function dispatch(context: CommandContext): Promise<number> {\n const [verb, noun] = context.args.words;\n\n switch (verb) {\n case \"auth\":\n return authCommand(context);\n case \"setup\":\n case \"init\":\n return setupCommand(context);\n /*\n `pm version` as well as `--version`.\n\n It is what people type, and answering \"Unknown command\" to somebody\n asking which version they are running \u2014 while a flag two characters away\n answers it \u2014 is a needless dead end.\n */\n case \"version\":\n context.print(VERSION);\n return 0;\n\n case \"update\":\n case \"upgrade\":\n return updateCommand(context);\n case \"uninstall\":\n return uninstallCommand(context);\n case \"delete\":\n return deleteCommand(context);\n case \"agent\":\n return agentCommand(context);\n case \"chat\":\n case \"session\":\n return sessionCommand(context);\n case \"remember\":\n return rememberCommand(context);\n case \"search\":\n return searchCommand(context);\n case \"status\":\n return statusCommand(context);\n case \"requests\":\n return requestsCommand(context);\n\n /*\n Google, through the API rather than through Google.\n\n A laptop holds a bearer token and no database connection, so the\n credential it can prove is the one the API accepts. Google's own tokens\n never leave the deployment \u2014 which is what stops a stolen\n `~/.persistmemory` from being a stolen mailbox.\n */\n case \"drive\":\n return driveCommand(context);\n case \"mail\":\n return mailCommand(context);\n\n /**\n * `pm <verb> <noun>`, the grammar the Harness CLI uses.\n *\n * Worth copying rather than inventing: a person who has typed\n * `list pipelines` can guess `list memories` without opening the help, and\n * a consistent grammar is what lets a tool grow past the handful of\n * commands anybody can memorise.\n */\n case \"spaces\":\n case \"space\":\n if (noun === \"create\" || noun === \"new\") return createSpaceCommand(context);\n if (noun === \"delete\" || noun === \"remove\") return deleteSpaceCommand(context);\n if (noun === \"merge\") return mergeSpacesCommand(context);\n if (noun === undefined || noun === \"list\") return listSpacesCommand(context);\n context.error(`Cannot \"pm spaces ${noun}\". Try list, create, delete or merge.`);\n return 2;\n\n case \"list\":\n if (noun === \"memories\" || noun === \"memory\") return listMemoriesCommand(context);\n if (noun === \"spaces\" || noun === \"space\") return listSpacesCommand(context);\n context.error(`Cannot list \"${noun ?? \"\"}\". Try memories or spaces.`);\n return 2;\n\n case \"get\":\n if (noun === \"memory\") return getMemoryCommand(context);\n context.error(`Cannot get \"${noun ?? \"\"}\". Try memory.`);\n return 2;\n\n default:\n context.error(`Unknown command \"${verb ?? \"\"}\". Run \\`pm --help\\`.`);\n return 2;\n }\n}\n\nfunction globalFlags(\n args: ParsedArgs,\n deps: Deps\n): GlobalFlags | \"invalid-output\" | \"invalid-limit\" {\n const requested = stringFlag(args, \"output\", \"o\");\n if (requested !== undefined && !isOutputFormat(requested)) return \"invalid-output\";\n\n const limit = numberFlag(args, \"limit\", \"n\");\n if (limit === \"invalid\") return \"invalid-limit\";\n\n /**\n * Table for a person, JSON for a pipe.\n *\n * Chosen from whether stdout is a terminal rather than fixed, so\n * `pm search x` is readable and `pm search x | jq .` works without anyone\n * having to discover a flag. A fixed default makes one of those two\n * audiences worse off for no reason.\n */\n const isTty = deps.isTty ?? process.stdout.isTTY ?? false;\n const output: OutputFormat = (requested as OutputFormat) ?? (isTty ? \"table\" : \"json\");\n\n const apiKey = args.flags[\"api-key\"];\n // Bound to locals first. Spreading the call directly widens each field to\n // `string | undefined`, which `exactOptionalPropertyTypes` treats as a\n // different type from an absent one.\n const profile = stringFlag(args, \"profile\", \"p\");\n const apiUrl = stringFlag(args, \"api-url\");\n\n return {\n ...(profile !== undefined ? { profile } : {}),\n ...(apiUrl !== undefined ? { apiUrl } : {}),\n ...(apiKey === true || typeof apiKey === \"string\" ? { apiKey } : {}),\n output,\n quiet: boolFlag(args, \"quiet\", \"q\"),\n ...(limit !== undefined ? { limit } : {})\n };\n}\n\n/**\n * Turns a thrown thing into something a person can act on.\n *\n * Exit codes are distinguished because scripts read them: 2 for \"you typed\n * something wrong\", 3 for \"you are not signed in\", 1 for everything else. A\n * CLI that returns 1 for all three makes `pm search x || pm auth login`\n * impossible to write.\n */\nfunction report(caught: unknown, error: (line: string) => void): number {\n if (caught instanceof NotSignedIn) {\n error(caught.message);\n return 3;\n }\n\n if (caught instanceof PersistMemoryError) {\n // The SDK's message, which already excludes the credential \u2014 see `redact`\n // in its errors module. Re-serialising the whole error here is how a key\n // ends up in somebody's CI log.\n error(caught.message);\n return caught.status === 401 || caught.status === 403 ? 3 : 1;\n }\n\n error(caught instanceof Error ? caught.message : String(caught));\n return 1;\n}\n\nexport { PersistMemory };\n", "#!/usr/bin/env node\nimport { run } from \"./index\";\n\n/**\n * The executable.\n *\n * Thin on purpose: everything testable lives in `run`, and this file exists to\n * do the two things a test must never do \u2014 read the real argv and set the\n * process's exit code.\n */\nrun({ argv: process.argv.slice(2) }).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n }\n);\n"],
5
+ "mappings": "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",
6
+ "names": ["message", "status", "resolve", "parsed", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "join", "resolve", "resolve", "resolve", "answer", "finish", "homedir", "join", "resolve", "existsSync", "readFileSync", "statSync", "writeFileSync", "existsSync", "readFileSync", "writeFileSync", "dirname", "join", "resolve", "write", "message", "resolve", "homedir", "wanted", "existsSync", "existsSync", "statSync", "join", "writeFileSync", "readFileSync", "resolve", "homedir", "complain", "message", "writeFileSync", "basename", "resolve", "readFileSync", "resolve", "basename", "writeFileSync", "readFileSync", "response", "message", "existsSync", "writeFileSync", "resolve", "resolve", "existsSync", "writeFileSync", "existsSync", "readFileSync", "writeFileSync", "dirname", "join", "answer", "wanted", "existsSync", "dirname", "resolve", "existsSync", "answer", "resolve", "dirname", "createInterface", "relative", "existsSync", "mkdirSync", "readFileSync", "join", "HELP", "createInterface", "resolve", "message", "answer", "relative", "write", "readFileSync", "wanted", "readFileSync", "space"]
7
7
  }