@unisonlabs/sixminute-admin 0.1.1236 → 0.1.1237-next

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.
@@ -16,12 +16,12 @@ var __export = (target, all) => {
16
16
 
17
17
  // tools/admin/src/main.ts
18
18
  import { spawn } from "node:child_process";
19
- import { readFileSync as readFileSync3 } from "node:fs";
19
+ import { readFileSync as readFileSync4 } from "node:fs";
20
20
  import { homedir } from "node:os";
21
21
  import { fileURLToPath } from "node:url";
22
22
 
23
23
  // tools/admin/src/build-info.ts
24
- var BUILT = { version: "0.1.1236", commit: "e9471c769e8799b7718544270c264cc208c3856f", surface: "dd0676dc61078cce" };
24
+ var BUILT = { version: "0.1.1237-next", commit: "fbfe48a89dd45b61d2677caa1981d41796a47ad4", surface: "3b2db9633e846531" };
25
25
 
26
26
  // tools/admin/src/run.ts
27
27
  import { rmSync as rmSync3 } from "node:fs";
@@ -5054,7 +5054,8 @@ var TenantPolicySchema = exports_external.object({
5054
5054
  security_tier: exports_external.enum(["standard", "confidential"]).default("standard"),
5055
5055
  raw_archive: exports_external.boolean().default(false),
5056
5056
  research_export: exports_external.boolean().default(false),
5057
- context_retention_days: exports_external.number().int().min(0).max(365).default(30)
5057
+ context_retention_days: exports_external.number().int().min(0).max(365).default(30),
5058
+ demo: exports_external.object({ enabled: exports_external.boolean() }).optional()
5058
5059
  }).default({});
5059
5060
  var NARRATIVE_GUIDANCE_MAX_CHARS = 1500;
5060
5061
  var GUIDANCE_CONTROL = /[\u0000-\u0009\u000B-\u001F\u007F-\u009F]/;
@@ -5962,6 +5963,10 @@ var AdminResearchExportSetSchema = exports_external.object({ research_export: ex
5962
5963
  var AdminResearchExportFlagSchema = exports_external.object({
5963
5964
  tenant: exports_external.object({ id: TenantIdSchema, name: exports_external.string(), research_export: exports_external.boolean() })
5964
5965
  });
5966
+ var AdminDemoSetSchema = exports_external.object({ enabled: exports_external.boolean() });
5967
+ var AdminDemoFlagSchema = exports_external.object({
5968
+ tenant: exports_external.object({ id: TenantIdSchema, name: exports_external.string(), demo: exports_external.boolean() })
5969
+ });
5965
5970
  var AdminDeviceVersionSchema = exports_external.object({
5966
5971
  id: DeviceIdSchema,
5967
5972
  name: exports_external.string(),
@@ -6256,6 +6261,140 @@ var ServedConfigBundleSchema = ConfigBundleSchema.extend({
6256
6261
  prompts: ServedConfigPromptsSchema,
6257
6262
  vocabularies: ServedConfigVocabulariesSchema
6258
6263
  });
6264
+ // packages/contracts/src/demo.ts
6265
+ var ClockSchema = exports_external.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "a local clock time, HH:MM");
6266
+ var KeySchema = exports_external.string().regex(/^[a-z0-9][a-z0-9_-]{0,63}$/i, "a key: letters, digits, _ and -");
6267
+ var DemoObservationSchema = exports_external.object({
6268
+ from: ClockSchema,
6269
+ to: ClockSchema,
6270
+ app: exports_external.string().min(1),
6271
+ bundle: exports_external.string().min(1),
6272
+ title: exports_external.string(),
6273
+ typed: exports_external.string().default(""),
6274
+ url: exports_external.string().nullable().default(null),
6275
+ files: exports_external.array(exports_external.string().min(1)).default([]),
6276
+ screen: exports_external.string().optional()
6277
+ }).strict();
6278
+ var DemoDecisionSchema = exports_external.object({ summary: exports_external.string().min(1), activity: exports_external.string().min(1).nullable(), matter: KeySchema.nullable() }).strict();
6279
+ var DemoIntervalSchema = exports_external.object({ from: ClockSchema, to: ClockSchema, observations: exports_external.array(DemoObservationSchema).default([]), decision: DemoDecisionSchema.optional() }).strict();
6280
+ var DemoEntrySchema = exports_external.object({ from: ClockSchema, to: ClockSchema, matter: KeySchema.nullable(), narrative: exports_external.string().min(1), codes: exports_external.record(exports_external.string().min(1)).default({}) }).strict();
6281
+ var DemoRecordingSchema = exports_external.object({ start: ClockSchema, stop: ClockSchema, intervals: exports_external.array(DemoIntervalSchema).min(1) }).strict();
6282
+ var minutes = (clock) => Number(clock.slice(0, 2)) * 60 + Number(clock.slice(3));
6283
+ function problemsOf(s) {
6284
+ const out = [];
6285
+ const clients = new Set(s.clients.map((c) => c.key));
6286
+ const matters = new Set(s.matters.map((m) => m.key));
6287
+ if (clients.size !== s.clients.length)
6288
+ out.push([["clients"], "a client key is used twice"]);
6289
+ if (matters.size !== s.matters.length)
6290
+ out.push([["matters"], "a matter key is used twice"]);
6291
+ s.matters.forEach((m, i) => clients.has(m.client) || out.push([["matters", i, "client"], `no client ${m.client}`]));
6292
+ const all = [];
6293
+ let previousStop = -1;
6294
+ s.recordings.forEach((rec, r) => {
6295
+ const [start, stop] = [minutes(rec.start), minutes(rec.stop)];
6296
+ if (stop <= start)
6297
+ out.push([["recordings", r, "stop"], "a recording stops after it starts"]);
6298
+ if (start < previousStop)
6299
+ out.push([["recordings", r, "start"], "recordings are in order and do not overlap"]);
6300
+ previousStop = stop;
6301
+ rec.intervals.forEach((one, i) => {
6302
+ const [from, to] = [minutes(one.from), minutes(one.to)];
6303
+ const at = ["recordings", r, "intervals", i];
6304
+ if (from % s.unit_minutes !== 0 || to - from !== s.unit_minutes)
6305
+ out.push([at, `an interval is one unit of ${s.unit_minutes} minutes on the grid`]);
6306
+ if (from < start || to > stop)
6307
+ out.push([at, "an interval lies inside its recording"]);
6308
+ if (i > 0 && minutes(rec.intervals[i - 1].to) !== from)
6309
+ out.push([at, "intervals are contiguous"]);
6310
+ one.observations.forEach((o, k) => {
6311
+ if (minutes(o.from) < from || minutes(o.to) > to || minutes(o.to) <= minutes(o.from))
6312
+ out.push([[...at, "observations", k], "an observation lies inside its interval"]);
6313
+ });
6314
+ const matter = one.decision?.matter ?? null;
6315
+ if (matter !== null && !matters.has(matter))
6316
+ out.push([[...at, "decision", "matter"], `no matter ${matter}`]);
6317
+ const work = one.decision === undefined || one.decision.activity === null ? null : JSON.stringify([one.decision.activity, matter]);
6318
+ all.push({ r, from, to, work, matter });
6319
+ });
6320
+ });
6321
+ const covered = new Set;
6322
+ s.entries.forEach((e, i) => {
6323
+ const at = ["entries", i];
6324
+ if (e.matter !== null && !matters.has(e.matter))
6325
+ out.push([[...at, "matter"], `no matter ${e.matter}`]);
6326
+ const first = all.findIndex((one) => one.from === minutes(e.from));
6327
+ const last = all.findIndex((one) => one.to === minutes(e.to));
6328
+ if (first < 0 || last < first || all[first].r !== all[last].r) {
6329
+ out.push([at, "an entry starts and ends on interval bounds of one recording"]);
6330
+ return;
6331
+ }
6332
+ const inside = all.slice(first, last + 1);
6333
+ if (inside.some((one, k) => one.work === null || one.matter !== e.matter || k > 0 && inside[k - 1].to !== one.from)) {
6334
+ out.push([at, "an entry covers only contiguous decided work on its own matter"]);
6335
+ }
6336
+ const [before, after] = [all[first - 1], all[last + 1]];
6337
+ const joins = (a, b) => a !== undefined && a.r === b.r && a.to === b.from && a.work === b.work;
6338
+ if (joins(before, inside[0]) || after !== undefined && joins(inside.at(-1), after))
6339
+ out.push([at, "an entry starts and ends where an activity block does"]);
6340
+ for (let k = first;k <= last; k++)
6341
+ covered.has(k) ? out.push([at, "entries do not overlap"]) : covered.add(k);
6342
+ });
6343
+ const clock = (m) => `${String(Math.floor(m / 60)).padStart(2, "0")}:${String(m % 60).padStart(2, "0")}`;
6344
+ if (s.entries.length > 0)
6345
+ all.forEach((one, k) => one.work !== null && !covered.has(k) && out.push([["entries"], `the work at ${clock(one.from)} is in no entry`]));
6346
+ return out;
6347
+ }
6348
+ var DemoScenarioSchema = exports_external.object({
6349
+ format: exports_external.literal(1),
6350
+ name: KeySchema,
6351
+ description: exports_external.string().default(""),
6352
+ time_zone: exports_external.string().min(1),
6353
+ unit_minutes: exports_external.number().int().min(1).max(60),
6354
+ clients: exports_external.array(exports_external.object({ key: KeySchema, name: exports_external.string().min(1) }).strict()),
6355
+ matters: exports_external.array(exports_external.object({ key: KeySchema, client: KeySchema, number: exports_external.string().min(1), name: exports_external.string().min(1) }).strict()),
6356
+ codes: exports_external.object({ set: exports_external.union([exports_external.string().min(1), exports_external.array(exports_external.string().min(1)).min(1)]) }).strict().optional(),
6357
+ recordings: exports_external.array(DemoRecordingSchema).min(1),
6358
+ entries: exports_external.array(DemoEntrySchema).default([])
6359
+ }).strict().superRefine((s, ctx) => {
6360
+ for (const [path, message] of problemsOf(s))
6361
+ ctx.addIssue({ code: exports_external.ZodIssueCode.custom, path, message });
6362
+ });
6363
+ function replayGap(s) {
6364
+ if (s.recordings.some((r) => r.intervals.some((i) => i.decision === undefined)))
6365
+ return "every interval needs its decision";
6366
+ return s.entries.length === 0 ? "a replay needs the scenario's entries" : null;
6367
+ }
6368
+ var AdminDemoSeedSchema = exports_external.object({
6369
+ scenario: DemoScenarioSchema,
6370
+ day: LocalDaySchema.optional(),
6371
+ replay: exports_external.boolean().default(false),
6372
+ generate: exports_external.boolean().default(false)
6373
+ });
6374
+ var AdminDemoDaySchema = exports_external.object({ day: LocalDaySchema, generate: exports_external.boolean().default(false) });
6375
+ var counts = { member_id: MemberIdSchema, day: LocalDaySchema };
6376
+ var AdminDemoSeedResultSchema = exports_external.object({
6377
+ ...counts,
6378
+ mode: exports_external.enum(["live", "replay"]),
6379
+ recordings: exports_external.number().int(),
6380
+ contexts: exports_external.object({ stored: exports_external.number().int(), repeated: exports_external.number().int() }),
6381
+ created: exports_external.object({ clients: exports_external.number().int(), matters: exports_external.number().int() }),
6382
+ generate_run: exports_external.string().nullable()
6383
+ });
6384
+ var AdminDemoResetResultSchema = exports_external.object({
6385
+ ...counts,
6386
+ runs_deleted: exports_external.number().int(),
6387
+ drafts_deleted: exports_external.number().int(),
6388
+ released_kept: exports_external.number().int(),
6389
+ generate_run: exports_external.string().nullable()
6390
+ });
6391
+ var AdminDemoRemoveResultSchema = exports_external.object({ ...counts, recordings_deleted: exports_external.number().int(), entries_deleted: exports_external.number().int() });
6392
+ var AdminDemoStatusSchema = exports_external.object({
6393
+ tenant: exports_external.object({ id: TenantIdSchema, name: exports_external.string(), demo: exports_external.boolean() }),
6394
+ member_id: MemberIdSchema,
6395
+ caps: exports_external.object({ calls_per_day: exports_external.number().int(), cost_usd_per_day: exports_external.number() }),
6396
+ days: exports_external.array(exports_external.object({ day: LocalDaySchema, mode: exports_external.enum(["live", "replay"]), recordings: exports_external.number().int(), entries: exports_external.number().int() }))
6397
+ });
6259
6398
  // packages/contracts/src/device.ts
6260
6399
  var DEVICE_CREDENTIAL_PREFIX = "smd_";
6261
6400
  var ENROLLMENT_CODE_PREFIX = "sme_";
@@ -6384,7 +6523,7 @@ var LocalSettingsSchema = exports_external.object({
6384
6523
  capture_enabled: exports_external.boolean(),
6385
6524
  excluded_bundles: exports_external.array(exports_external.string().min(1)),
6386
6525
  excluded_sites: exports_external.array(SiteSchema).default([]),
6387
- policy: TenantPolicySchema,
6526
+ policy: TenantPolicySchema.removeDefault().omit({ demo: true }).default({}),
6388
6527
  lists_revision: exports_external.string().min(1).nullable().default(null),
6389
6528
  raw_archive: exports_external.object({
6390
6529
  allowed: exports_external.boolean(),
@@ -7316,11 +7455,11 @@ function fieldLines(summary) {
7316
7455
  ];
7317
7456
  }
7318
7457
  function summaryLines(summary) {
7319
- const counts = summary.counts;
7458
+ const counts2 = summary.counts;
7320
7459
  return [
7321
7460
  `connector ${summary.kind} ${summary.status}`,
7322
7461
  `team ${summary.team_bound} bound, ${summary.team_unbound} unbound`,
7323
- `lists ${counts.matters} matters, ${counts.clients} clients, ` + `${counts.timekeepers} timekeepers, ${counts.options} options`,
7462
+ `lists ${counts2.matters} matters, ${counts2.clients} clients, ` + `${counts2.timekeepers} timekeepers, ${counts2.options} options`,
7324
7463
  `last sync ${summary.last_sync_at ?? "never"}`,
7325
7464
  `last error ${summary.last_error ?? "none"}`,
7326
7465
  ...summary.capabilities.accepts_by === "approval" ? [`reviewer ${reviewerLine(summary)}`, `approval ${approvalLine(summary)}`] : []
@@ -7480,6 +7619,84 @@ function googleAccessToken(env, platform) {
7480
7619
  throw new UnsealError("no Google access token: set GOOGLE_OAUTH_ACCESS_TOKEN, or install the gcloud CLI and run " + "`gcloud auth login` as yourself. The unseal runs as YOU, never as a service account.");
7481
7620
  }
7482
7621
 
7622
+ // tools/admin/src/demo.ts
7623
+ import { readFileSync as readFileSync3 } from "node:fs";
7624
+ function readScenario(path) {
7625
+ let raw;
7626
+ try {
7627
+ raw = JSON.parse(readFileSync3(path, "utf8"));
7628
+ } catch (err) {
7629
+ throw new AdminUsageError(`${path} is not readable JSON: ${err.message}`);
7630
+ }
7631
+ const parsed = DemoScenarioSchema.safeParse(raw);
7632
+ if (!parsed.success) {
7633
+ throw new AdminUsageError(`${path} is not a demo scenario:
7634
+ ${parsed.error.issues.map((i) => ` ${i.path.join(".") || "(root)"}: ${i.message}`).join(`
7635
+ `)}`);
7636
+ }
7637
+ return parsed.data;
7638
+ }
7639
+ function validateScenario(argv) {
7640
+ const [path, ...rest] = argv;
7641
+ if (path === undefined || path.startsWith("--") || rest.some((arg) => arg !== "--json"))
7642
+ throw new AdminUsageError("demo validate takes one scenario file, and --json");
7643
+ const s = readScenario(path);
7644
+ const facts = {
7645
+ name: s.name,
7646
+ recordings: s.recordings.length,
7647
+ intervals: s.recordings.reduce((n, r) => n + r.intervals.length, 0),
7648
+ entries: s.entries.length,
7649
+ replay: replayGap(s) ?? "yes"
7650
+ };
7651
+ if (rest.includes("--json"))
7652
+ return { code: 0, lines: [JSON.stringify({ valid: true, ...facts }, null, 2)] };
7653
+ return { code: 0, lines: [`valid ${facts.name}`, `recordings ${facts.recordings}, ${facts.intervals} intervals, ${facts.entries} entries`, `replay ${facts.replay}`] };
7654
+ }
7655
+ async function runDemo(run2, subcommand) {
7656
+ if (run2.environment.name === "production")
7657
+ throw new AdminUsageError("demo commands run on staging (or local) only: production never enters demo mode");
7658
+ const tenantId = required(run2.flags, "tenant", "which firm, an internal one");
7659
+ const path = (rest) => tenantPath(tenantId, rest);
7660
+ if (subcommand === "on" || subcommand === "off") {
7661
+ const { tenant } = AdminDemoFlagSchema.parse(expectOk(await call(run2.api, "PUT", path("/demo"), { enabled: subcommand === "on" })));
7662
+ return render(run2, { tenant }, [`tenant ${tenant.id} ${tenant.name}`, `demo ${tenant.demo}`]);
7663
+ }
7664
+ if (subcommand === "status") {
7665
+ const status = AdminDemoStatusSchema.parse(expectOk(await call(run2.api, "GET", path("/demo"))));
7666
+ return render(run2, status, [
7667
+ `tenant ${status.tenant.id} ${status.tenant.name} demo ${status.tenant.demo}`,
7668
+ `member ${status.member_id}`,
7669
+ `caps ${status.caps.calls_per_day} calls, ${status.caps.cost_usd_per_day} USD per UTC day`,
7670
+ ...status.days.length === 0 ? ["no seeded day"] : status.days.map((d) => `${d.day} ${d.mode} ${d.recordings} recordings, ${d.entries} entries`)
7671
+ ]);
7672
+ }
7673
+ if (subcommand === "seed") {
7674
+ const scenario = readScenario(required(run2.flags, "scenario", "the scenario file to seed"));
7675
+ const day = run2.flags.values.has("day") ? dayOf2(run2.flags, "day", "the day to seed on") : undefined;
7676
+ const body = { scenario, ...day === undefined ? {} : { day }, replay: switched(run2.flags, "replay"), generate: switched(run2.flags, "generate") };
7677
+ const done = AdminDemoSeedResultSchema.parse(expectOk(await call(run2.api, "POST", path("/demo/seed"), body)));
7678
+ return render(run2, done, [
7679
+ `seeded ${scenario.name} on ${done.day}, ${done.mode}, into ${done.member_id}`,
7680
+ `contexts ${done.contexts.stored} stored, ${done.contexts.repeated} already there, over ${done.recordings} recordings`,
7681
+ `created ${done.created.clients} clients, ${done.created.matters} matters`,
7682
+ done.generate_run === null ? "Generate the day from the app, or run demo reset --generate." : `generate ${done.generate_run}`
7683
+ ]);
7684
+ }
7685
+ if (subcommand === "reset" || subcommand === "remove") {
7686
+ const day = dayOf2(run2.flags, "day", `the seeded day to ${subcommand}`);
7687
+ if (subcommand === "remove") {
7688
+ const done2 = AdminDemoRemoveResultSchema.parse(expectOk(await call(run2.api, "POST", path("/demo/remove"), { day })));
7689
+ return render(run2, done2, [`removed ${done2.day}: ${done2.recordings_deleted} recordings, ${done2.entries_deleted} entries`]);
7690
+ }
7691
+ const done = AdminDemoResetResultSchema.parse(expectOk(await call(run2.api, "POST", path("/demo/reset"), { day, generate: switched(run2.flags, "generate") })));
7692
+ return render(run2, done, [
7693
+ `reset ${done.day}: ${done.runs_deleted} Generate runs, ${done.drafts_deleted} drafts deleted, ${done.released_kept} released kept`,
7694
+ ...done.generate_run === null ? [] : [`generate ${done.generate_run}`]
7695
+ ]);
7696
+ }
7697
+ throw new AdminUsageError(`unknown command: demo ${subcommand ?? ""}`.trim());
7698
+ }
7699
+
7483
7700
  // tools/admin/src/run.ts
7484
7701
  var ROLE_SLUGS = FIRM_ROLE_SLUGS;
7485
7702
  var CONFIDENTIAL_EXIT_CODE = 3;
@@ -7630,6 +7847,27 @@ is required; without one every command answers 403.
7630
7847
  --dry-run prints every row it would remove and writes nothing; without
7631
7848
  it and without --yes the command prints the same list and refuses.
7632
7849
 
7850
+ sixminute-admin demo on --env staging --tenant tenant_... [--json]
7851
+ sixminute-admin demo off --env staging --tenant tenant_... [--json]
7852
+ The firm's demo mode: its members' runs get the demo caps (50,000 calls
7853
+ and 100 USD a day), and the demo commands below work on it. Internal
7854
+ firms only, on staging only: every demo command refuses production.
7855
+ sixminute-admin demo status --env staging --tenant tenant_... [--json]
7856
+ The flag, the caps in force, and your own seeded days, live or replay.
7857
+ sixminute-admin demo validate tools/demo-scenarios/example-small.json [--json]
7858
+ Checks a scenario file offline: its shape, its times and every reference.
7859
+ sixminute-admin demo seed --env staging --tenant tenant_... --scenario <file> [--day YYYY-MM-DD] [--replay] [--generate] [--json]
7860
+ Seeds the scenario into YOUR OWN account of the firm (accept an
7861
+ invitation with the same address first), on its own Scenario device.
7862
+ Without --day, the most recent day it lies wholly in the past on, with
7863
+ nothing captured. --replay makes the day's Generate answer from the
7864
+ scenario with no model; --generate starts that Generate.
7865
+ sixminute-admin demo reset --env staging --tenant tenant_... --day YYYY-MM-DD [--generate] [--json]
7866
+ Drops the seeded day's Generate runs and drafts, so Generate runs
7867
+ again over the same activity. Released entries stay.
7868
+ sixminute-admin demo remove --env staging --tenant tenant_... --day YYYY-MM-DD [--json]
7869
+ Deletes the seeded day entirely. Captured time is never touched.
7870
+
7633
7871
  sixminute-admin attribute add --env <env> --tenant tenant_... --key utbms_task --label "UTBMS task" [--required] [--proposed] [--default-set aset_a,aset_b] [--json]
7634
7872
  Writes one attribute, whole: a bounded single-select field on an entry,
7635
7873
  which is what a firm calls its codes. --default-set names the sets a
@@ -7805,7 +8043,9 @@ var BOOLEAN_FLAGS = new Set([
7805
8043
  "on",
7806
8044
  "off",
7807
8045
  "auto",
7808
- "review"
8046
+ "review",
8047
+ "replay",
8048
+ "generate"
7809
8049
  ]);
7810
8050
  function parseFlags(argv, offset) {
7811
8051
  const values = new Map;
@@ -7909,6 +8149,8 @@ async function runAdmin(argv, deps) {
7909
8149
  if (group === "--version") {
7910
8150
  return { code: 0, lines: [`sixminute-admin ${deps.build.version} (API ${deps.build.commit}, operator surface ${deps.build.surface})`] };
7911
8151
  }
8152
+ if (group === "demo" && subcommand === "validate")
8153
+ return validateScenario(rest);
7912
8154
  const oneWord = ["login", "logout", "whoami", "doctor", "versions", "audit"].includes(group);
7913
8155
  const vocabulary2 = group === "attribute" || group === "matter" && subcommand === "sets";
7914
8156
  const threeDeep = group === "tenant" && subcommand === "internal";
@@ -8000,6 +8242,8 @@ async function runAdmin(argv, deps) {
8000
8242
  return runEntriesPurge(run2);
8001
8243
  if (group === "connector")
8002
8244
  return runConnector(run2, subcommand);
8245
+ if (group === "demo")
8246
+ return runDemo(run2, subcommand);
8003
8247
  if (group === "firm" || group === "invite")
8004
8248
  return runFirm(run2, group, subcommand);
8005
8249
  throw new AdminUsageError(`unknown command ${JSON.stringify([group, subcommand].filter(Boolean).join(" "))}.
@@ -8264,9 +8508,9 @@ async function runVersions(run2) {
8264
8508
  async function runEntriesPurge(run2) {
8265
8509
  const { flags } = run2;
8266
8510
  const tenantId = required(flags, "tenant", "which firm's rows are being removed");
8267
- const demo = switched(flags, "demo");
8511
+ const demo2 = switched(flags, "demo");
8268
8512
  const unmatched = switched(flags, "unmatched");
8269
- if (!demo && !unmatched) {
8513
+ if (!demo2 && !unmatched) {
8270
8514
  throw new AdminUsageError("name what to remove: --demo (the rows tools/demo-seed minted) or --unmatched " + "(engine-written rows charged to no matter), or both. This command never guesses a selector.");
8271
8515
  }
8272
8516
  const author = optional(flags, "author");
@@ -8275,15 +8519,15 @@ async function runEntriesPurge(run2) {
8275
8519
  }
8276
8520
  const dryRun = switched(flags, "dry-run");
8277
8521
  const yes = switched(flags, "yes");
8278
- const purge = async (dry) => AdminEntriesPurgeResultSchema.parse(expectOk(await call(run2.api, "POST", tenantPath(tenantId, "/entries/purge"), { author, demo, unmatched, dry_run: dry })));
8522
+ const purge = async (dry) => AdminEntriesPurgeResultSchema.parse(expectOk(await call(run2.api, "POST", tenantPath(tenantId, "/entries/purge"), { author, demo: demo2, unmatched, dry_run: dry })));
8279
8523
  const done = await purge(dryRun || !yes);
8280
8524
  const total = done.rows.demo.length + done.rows.unmatched.length;
8281
8525
  const listing = [
8282
8526
  `tenant ${tenantId}`,
8283
8527
  `author ${author} (user ${done.user})`,
8284
8528
  "",
8285
- ...demo ? purgeSection("demo entries (entry_demo-)", done.rows.demo) : [],
8286
- ...demo && unmatched ? [""] : [],
8529
+ ...demo2 ? purgeSection("demo entries (entry_demo-)", done.rows.demo) : [],
8530
+ ...demo2 && unmatched ? [""] : [],
8287
8531
  ...unmatched ? purgeSection("unmatched captured entries (no matter, engine-written)", done.rows.unmatched) : [],
8288
8532
  ""
8289
8533
  ];
@@ -8937,7 +9181,7 @@ function adminSurfaceOf(document) {
8937
9181
  // tools/admin/src/main.ts
8938
9182
  function sourceBuild() {
8939
9183
  const document = fileURLToPath(new URL("../../../services/api/openapi.json", import.meta.url));
8940
- const surface = adminSurfaceOf(JSON.parse(readFileSync3(document, "utf8")));
9184
+ const surface = adminSurfaceOf(JSON.parse(readFileSync4(document, "utf8")));
8941
9185
  return { version: "0.0.0-dev", commit: "source", surface };
8942
9186
  }
8943
9187
  function openBrowser(url) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unisonlabs/sixminute-admin",
3
- "version": "0.1.1236",
3
+ "version": "0.1.1237-next",
4
4
  "description": "Sixminute operator tool: the admin commands of the Sixminute API, run with your own operator sign-in.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {