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