@unisonlabs/sixminute-admin 0.1.1187-next → 0.1.1188-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.
- package/dist/sixminute-admin.mjs +214 -10
- package/package.json +1 -1
package/dist/sixminute-admin.mjs
CHANGED
|
@@ -21,7 +21,7 @@ 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.
|
|
24
|
+
var BUILT = { version: "0.1.1188-next", commit: "20f4bf99e8e3ce3d14dc7e52172b8cd5e9568924", surface: "9cd8ad25f1495c42" };
|
|
25
25
|
|
|
26
26
|
// tools/admin/src/run.ts
|
|
27
27
|
import { rmSync as rmSync3 } from "node:fs";
|
|
@@ -4895,7 +4895,8 @@ var TenantPolicySchema = exports_external.object({
|
|
|
4895
4895
|
excluded_bundles: exports_external.array(exports_external.string().min(1)).default([]),
|
|
4896
4896
|
security_tier: exports_external.enum(["standard", "confidential"]).default("standard"),
|
|
4897
4897
|
raw_archive: exports_external.boolean().default(false),
|
|
4898
|
-
research_export: exports_external.boolean().default(false)
|
|
4898
|
+
research_export: exports_external.boolean().default(false),
|
|
4899
|
+
context_retention_days: exports_external.number().int().min(0).max(365).default(30)
|
|
4899
4900
|
}).default({});
|
|
4900
4901
|
var NARRATIVE_GUIDANCE_MAX_CHARS = 1500;
|
|
4901
4902
|
var GUIDANCE_CONTROL = /[\u0000-\u0009\u000B-\u001F\u007F-\u009F]/;
|
|
@@ -5682,6 +5683,33 @@ var ResearchExportResultSchema = exports_external.discriminatedUnion("tier", [
|
|
|
5682
5683
|
ResearchExportConfidentialSchema,
|
|
5683
5684
|
ResearchExportSealedSchema
|
|
5684
5685
|
]);
|
|
5686
|
+
var ResearchContextExportSchema = exports_external.object({
|
|
5687
|
+
export_id: exports_external.string(),
|
|
5688
|
+
tenant_id: exports_external.string(),
|
|
5689
|
+
tenant_name: exports_external.string(),
|
|
5690
|
+
from: exports_external.string(),
|
|
5691
|
+
to: exports_external.string(),
|
|
5692
|
+
operator: exports_external.string(),
|
|
5693
|
+
contexts: exports_external.array(exports_external.object({
|
|
5694
|
+
member_id: exports_external.string(),
|
|
5695
|
+
recording_id: exports_external.string(),
|
|
5696
|
+
seq: exports_external.number().int(),
|
|
5697
|
+
t_start: exports_external.string(),
|
|
5698
|
+
t_end: exports_external.string(),
|
|
5699
|
+
context: exports_external.unknown()
|
|
5700
|
+
})),
|
|
5701
|
+
steps: exports_external.array(exports_external.object({
|
|
5702
|
+
run_id: exports_external.string(),
|
|
5703
|
+
kind: exports_external.string(),
|
|
5704
|
+
member_id: exports_external.string(),
|
|
5705
|
+
subject_from: exports_external.string(),
|
|
5706
|
+
name: exports_external.string(),
|
|
5707
|
+
prompt_fingerprint: exports_external.string().nullable(),
|
|
5708
|
+
usage: exports_external.unknown(),
|
|
5709
|
+
output: exports_external.unknown(),
|
|
5710
|
+
created_at: exports_external.string()
|
|
5711
|
+
}))
|
|
5712
|
+
});
|
|
5685
5713
|
// packages/contracts/src/admin-tenants.ts
|
|
5686
5714
|
var AdminTenantParamsSchema = exports_external.object({ tenant: TenantIdSchema });
|
|
5687
5715
|
var AdminSecurityTierSchema = exports_external.enum(["standard", "confidential"]);
|
|
@@ -5762,6 +5790,26 @@ var AdminEntriesPurgeResultSchema = exports_external.object({
|
|
|
5762
5790
|
rows: exports_external.object({ demo: exports_external.array(AdminPurgeRowSchema), unmatched: exports_external.array(AdminPurgeRowSchema) }),
|
|
5763
5791
|
deleted: exports_external.object({ demo: exports_external.number().int(), unmatched: exports_external.number().int(), total: exports_external.number().int() }).nullable()
|
|
5764
5792
|
});
|
|
5793
|
+
var AdminContextRetentionSetSchema = exports_external.object({ days: exports_external.number().int().min(1).max(365) });
|
|
5794
|
+
var AdminContextRetentionResultSchema = exports_external.object({
|
|
5795
|
+
tenant: exports_external.object({ id: TenantIdSchema, name: exports_external.string() }),
|
|
5796
|
+
days: exports_external.number().int(),
|
|
5797
|
+
previous: exports_external.number().int(),
|
|
5798
|
+
shifted: exports_external.object({
|
|
5799
|
+
interval_contexts: exports_external.number().int(),
|
|
5800
|
+
pipeline_runs: exports_external.number().int(),
|
|
5801
|
+
pipeline_steps: exports_external.number().int(),
|
|
5802
|
+
derivation_cache: exports_external.number().int(),
|
|
5803
|
+
intervals: exports_external.number().int()
|
|
5804
|
+
})
|
|
5805
|
+
});
|
|
5806
|
+
var AdminSealedBackfillResultSchema = exports_external.object({
|
|
5807
|
+
tenant: TenantIdSchema,
|
|
5808
|
+
decisions_sealed: exports_external.number().int(),
|
|
5809
|
+
intervals_aged: exports_external.number().int(),
|
|
5810
|
+
judged_sealed: exports_external.number().int(),
|
|
5811
|
+
done: exports_external.boolean()
|
|
5812
|
+
});
|
|
5765
5813
|
// packages/contracts/src/admin-firm-acting.ts
|
|
5766
5814
|
var ACTING_AS_HEADER = "X-Six-Minute-Acting-As";
|
|
5767
5815
|
var TeamApplyRequestSchema = exports_external.object({
|
|
@@ -5998,6 +6046,49 @@ var ServedConfigBundleSchema = ConfigBundleSchema.extend({
|
|
|
5998
6046
|
prompts: ServedConfigPromptsSchema,
|
|
5999
6047
|
vocabularies: ServedConfigVocabulariesSchema
|
|
6000
6048
|
});
|
|
6049
|
+
// packages/contracts/src/device.ts
|
|
6050
|
+
var DEVICE_CREDENTIAL_PREFIX = "smd_";
|
|
6051
|
+
var ENROLLMENT_CODE_PREFIX = "sme_";
|
|
6052
|
+
var EnrollmentCodeSchema = exports_external.object({
|
|
6053
|
+
code: exports_external.string().startsWith(ENROLLMENT_CODE_PREFIX),
|
|
6054
|
+
expires_at: TimestampSchema
|
|
6055
|
+
});
|
|
6056
|
+
var DeviceEnrollSchema = exports_external.object({
|
|
6057
|
+
code: exports_external.string().startsWith(ENROLLMENT_CODE_PREFIX).max(200),
|
|
6058
|
+
device_id: DeviceIdSchema,
|
|
6059
|
+
name: DeviceRegistrationSchema.shape.name,
|
|
6060
|
+
platform: DeviceSchema.shape.platform
|
|
6061
|
+
});
|
|
6062
|
+
var DeviceEnrolledSchema = exports_external.object({
|
|
6063
|
+
credential: exports_external.string().startsWith(DEVICE_CREDENTIAL_PREFIX),
|
|
6064
|
+
device: DeviceSchema
|
|
6065
|
+
});
|
|
6066
|
+
var DevicePolicySchema = exports_external.object({
|
|
6067
|
+
excluded_bundles: exports_external.array(exports_external.string()),
|
|
6068
|
+
raw_archive: exports_external.boolean(),
|
|
6069
|
+
swallow_short_pauses: exports_external.boolean().nullable(),
|
|
6070
|
+
unit_minutes: UnitMinutesSchema,
|
|
6071
|
+
context_retention_days: exports_external.number().int().nonnegative(),
|
|
6072
|
+
minimum_version: exports_external.string().nullable()
|
|
6073
|
+
});
|
|
6074
|
+
var RecordingStopSchema = exports_external.object({
|
|
6075
|
+
after_seq: exports_external.number().int().nonnegative(),
|
|
6076
|
+
at: TimestampSchema,
|
|
6077
|
+
reason: exports_external.enum(["person", "quit", "update", "sign-out", "roll"])
|
|
6078
|
+
});
|
|
6079
|
+
var RecordingSkipSchema = exports_external.object({ seq: exports_external.number().int().positive() });
|
|
6080
|
+
var RecordingClockSchema = exports_external.object({
|
|
6081
|
+
device_clock: TimestampSchema,
|
|
6082
|
+
last_witness_at: TimestampSchema.nullable(),
|
|
6083
|
+
silence_end_after: TimestampSchema.nullable()
|
|
6084
|
+
});
|
|
6085
|
+
var RecordingParamsSchema = exports_external.object({ id: RecordingIdSchema });
|
|
6086
|
+
var ContextAcceptedSchema = exports_external.object({
|
|
6087
|
+
accepted: exports_external.number().int().positive(),
|
|
6088
|
+
run_id: RunIdSchema.optional(),
|
|
6089
|
+
recording_id: RecordingIdSchema.optional()
|
|
6090
|
+
});
|
|
6091
|
+
var DeviceCredentialParamsSchema = exports_external.object({ id: DeviceIdSchema });
|
|
6001
6092
|
// packages/contracts/src/recording.ts
|
|
6002
6093
|
var RecordingSchema = exports_external.object({
|
|
6003
6094
|
id: RecordingIdSchema,
|
|
@@ -6392,6 +6483,32 @@ var LocalHostEventSchema = exports_external.discriminatedUnion("name", [
|
|
|
6392
6483
|
}).strict()
|
|
6393
6484
|
]);
|
|
6394
6485
|
var LocalMethodSchema = exports_external.enum(["GET", "POST", "PATCH", "DELETE"]);
|
|
6486
|
+
// packages/contracts/src/pipeline-status.ts
|
|
6487
|
+
var PipelineStatusQuerySchema = exports_external.object({
|
|
6488
|
+
since: exports_external.string().regex(/^\d{1,18}$/, "expected a version number").optional()
|
|
6489
|
+
});
|
|
6490
|
+
var PipelineRecordingStatusSchema = exports_external.object({
|
|
6491
|
+
recording_id: RecordingIdSchema,
|
|
6492
|
+
device_id: DeviceIdSchema,
|
|
6493
|
+
decided_through: TimestampSchema.nullable(),
|
|
6494
|
+
behind_seconds: exports_external.number().int().nonnegative(),
|
|
6495
|
+
stopped_at: TimestampSchema.nullable()
|
|
6496
|
+
});
|
|
6497
|
+
var PipelineStatusSchema = exports_external.object({
|
|
6498
|
+
version: exports_external.number().int().nonnegative(),
|
|
6499
|
+
recordings: exports_external.array(PipelineRecordingStatusSchema),
|
|
6500
|
+
deciding: exports_external.object({ recording_id: RecordingIdSchema, from: TimestampSchema, to: TimestampSchema }).nullable(),
|
|
6501
|
+
generate: exports_external.object({
|
|
6502
|
+
running: exports_external.object({
|
|
6503
|
+
run_id: RunIdSchema,
|
|
6504
|
+
kind: exports_external.enum(["generate", "regenerate", "propose"]),
|
|
6505
|
+
day: LocalDaySchema,
|
|
6506
|
+
step: exports_external.object({ name: exports_external.string(), at: TimestampSchema, entry_from: TimestampSchema.optional() })
|
|
6507
|
+
}).nullable(),
|
|
6508
|
+
pending: exports_external.array(exports_external.object({ day: LocalDaySchema, from: TimestampSchema, to: TimestampSchema })),
|
|
6509
|
+
failed: exports_external.object({ run_id: RunIdSchema, day: LocalDaySchema, error_class: exports_external.string() }).nullable()
|
|
6510
|
+
})
|
|
6511
|
+
});
|
|
6395
6512
|
// packages/contracts/src/pipeline.ts
|
|
6396
6513
|
var ContextStopReasonSchema = exports_external.enum(["person", "quit", "update", "sign-out", "roll"]);
|
|
6397
6514
|
var IntervalContextHeaderSchema = exports_external.object({
|
|
@@ -6763,23 +6880,23 @@ async function deviceLogin(io, environment) {
|
|
|
6763
6880
|
if (!started.ok) {
|
|
6764
6881
|
throw new AdminUsageError(`WorkOS answered ${started.status} to the sign-in request for ${environment.name}. CLI Auth must be enabled ` + "for this environment in the WorkOS dashboard.");
|
|
6765
6882
|
}
|
|
6766
|
-
const
|
|
6767
|
-
if (typeof
|
|
6883
|
+
const device2 = await started.json();
|
|
6884
|
+
if (typeof device2.device_code !== "string" || typeof device2.user_code !== "string") {
|
|
6768
6885
|
throw new Error("WorkOS answered the sign-in request without a device code");
|
|
6769
6886
|
}
|
|
6770
|
-
const url = typeof
|
|
6887
|
+
const url = typeof device2.verification_uri_complete === "string" ? device2.verification_uri_complete : typeof device2.verification_uri === "string" ? device2.verification_uri : null;
|
|
6771
6888
|
if (url === null)
|
|
6772
6889
|
throw new Error("WorkOS answered the sign-in request without a url to confirm it at");
|
|
6773
6890
|
io.say(`Sign in to ${environment.name} in your browser: ${url}`);
|
|
6774
|
-
io.say(`Confirm that it shows the code ${
|
|
6891
|
+
io.say(`Confirm that it shows the code ${device2.user_code}.`);
|
|
6775
6892
|
io.openBrowser(url);
|
|
6776
|
-
let interval = (typeof
|
|
6777
|
-
const deadline = io.now() + (typeof
|
|
6893
|
+
let interval = (typeof device2.interval === "number" && device2.interval > 0 ? device2.interval : 5) * 1000;
|
|
6894
|
+
const deadline = io.now() + (typeof device2.expires_in === "number" ? device2.expires_in : 300) * 1000;
|
|
6778
6895
|
for (;; ) {
|
|
6779
6896
|
await io.sleep(interval);
|
|
6780
6897
|
const answer = await authenticate(io, {
|
|
6781
6898
|
grant_type: DEVICE_GRANT,
|
|
6782
|
-
device_code:
|
|
6899
|
+
device_code: device2.device_code,
|
|
6783
6900
|
client_id: environment.clientId
|
|
6784
6901
|
});
|
|
6785
6902
|
if (answer.status === 200) {
|
|
@@ -7219,6 +7336,24 @@ is required; without one every command answers 403.
|
|
|
7219
7336
|
The unseal runs as you, with your own Google sign-in (gcloud auth
|
|
7220
7337
|
login); only the people granted the research key can open a card.
|
|
7221
7338
|
|
|
7339
|
+
sixminute-admin retention set --env <env> --tenant tenant_... --days <1-365> [--json]
|
|
7340
|
+
Sets how many days the cloud keeps the firm's interval contexts after
|
|
7341
|
+
each interval's day (30 unless its agreement says otherwise), and moves
|
|
7342
|
+
every stored expiry of the firm by the difference at once: a shorter
|
|
7343
|
+
setting deletes at the next hourly purge. Summaries, labels and entries
|
|
7344
|
+
are not affected.
|
|
7345
|
+
|
|
7346
|
+
sixminute-admin backfill sealed --env <env> --tenant tenant_... [--json]
|
|
7347
|
+
Seals the firm's interval summaries and labels and its entries' judged
|
|
7348
|
+
drafts under its own key, and gives intervals stored before the context
|
|
7349
|
+
store an age, a bounded pass at a time until nothing is left.
|
|
7350
|
+
|
|
7351
|
+
sixminute-admin research contexts --env <env> --tenant tenant_... --from YYYY-MM-DD --to YYYY-MM-DD --out <dir> [--json]
|
|
7352
|
+
A firm's research data (R10): its interval contexts and the step ledger
|
|
7353
|
+
over a day range, written as two jsonl files in --out (a new folder
|
|
7354
|
+
0700, as research export). Refused unless the firm instructed it in
|
|
7355
|
+
writing (research-export allow); the audit row is written first.
|
|
7356
|
+
|
|
7222
7357
|
sixminute-admin entries purge --env <env> --tenant tenant_... --author member_... (--demo | --unmatched | both) [--dry-run] [--yes] [--json]
|
|
7223
7358
|
Removes entry rows from one firm. A person may only soft-delete
|
|
7224
7359
|
their own draft (2026-09-25) and nothing but a merge removes a row
|
|
@@ -7595,6 +7730,12 @@ async function runAdmin(argv, deps) {
|
|
|
7595
7730
|
return runResearchExportFlag(run2, subcommand);
|
|
7596
7731
|
if (group === "research" && subcommand === "export")
|
|
7597
7732
|
return runResearchExport(run2);
|
|
7733
|
+
if (group === "research" && subcommand === "contexts")
|
|
7734
|
+
return runResearchContexts(run2);
|
|
7735
|
+
if (group === "retention" && subcommand === "set")
|
|
7736
|
+
return runRetentionSet(run2);
|
|
7737
|
+
if (group === "backfill" && subcommand === "sealed")
|
|
7738
|
+
return runBackfillSealed(run2);
|
|
7598
7739
|
if (group === "entries" && subcommand === "purge")
|
|
7599
7740
|
return runEntriesPurge(run2);
|
|
7600
7741
|
if (group === "connector")
|
|
@@ -7784,6 +7925,65 @@ async function runResearchExportFlag(run2, subcommand) {
|
|
|
7784
7925
|
allow ? "Research cards are stored for this firm from its next completion, for 30 days, sealed under the research key." : "No research card is stored for this firm from its next completion. Cards already stored stay until the 30-day purge."
|
|
7785
7926
|
]);
|
|
7786
7927
|
}
|
|
7928
|
+
async function runRetentionSet(run2) {
|
|
7929
|
+
const tenantId = required(run2.flags, "tenant", "whose retention");
|
|
7930
|
+
const days = Number(required(run2.flags, "days", "how many days after each interval's day its context is kept"));
|
|
7931
|
+
if (!Number.isInteger(days) || days < 1 || days > 365)
|
|
7932
|
+
throw new AdminUsageError("--days is a whole number from 1 to 365.");
|
|
7933
|
+
const done = AdminContextRetentionResultSchema.parse(expectOk(await call(run2.api, "PUT", tenantPath(tenantId, "/context-retention"), { days })));
|
|
7934
|
+
const moved = Object.entries(done.shifted).map(([table2, rows]) => `${table2} ${rows}`).join(", ");
|
|
7935
|
+
return render(run2, done, [
|
|
7936
|
+
`tenant ${done.tenant.id} ${done.tenant.name}`,
|
|
7937
|
+
`retention ${done.previous} -> ${done.days} days`,
|
|
7938
|
+
`moved ${moved}`
|
|
7939
|
+
]);
|
|
7940
|
+
}
|
|
7941
|
+
async function runBackfillSealed(run2) {
|
|
7942
|
+
const tenantId = required(run2.flags, "tenant", "whose rows to seal");
|
|
7943
|
+
const total = { decisions_sealed: 0, intervals_aged: 0, judged_sealed: 0 };
|
|
7944
|
+
for (;; ) {
|
|
7945
|
+
const pass = AdminSealedBackfillResultSchema.parse(expectOk(await call(run2.api, "POST", tenantPath(tenantId, "/backfill/sealed"))));
|
|
7946
|
+
total.decisions_sealed += pass.decisions_sealed;
|
|
7947
|
+
total.intervals_aged += pass.intervals_aged;
|
|
7948
|
+
total.judged_sealed += pass.judged_sealed;
|
|
7949
|
+
if (pass.done)
|
|
7950
|
+
break;
|
|
7951
|
+
}
|
|
7952
|
+
return render(run2, { tenant: tenantId, ...total }, [
|
|
7953
|
+
`tenant ${tenantId}`,
|
|
7954
|
+
`sealed ${total.decisions_sealed} interval decision(s), ${total.judged_sealed} judged draft(s)`,
|
|
7955
|
+
`aged ${total.intervals_aged} interval(s)`
|
|
7956
|
+
]);
|
|
7957
|
+
}
|
|
7958
|
+
async function runResearchContexts(run2) {
|
|
7959
|
+
const { flags } = run2;
|
|
7960
|
+
const tenantId = required(flags, "tenant", "an export is one firm's contexts and steps");
|
|
7961
|
+
const from = dayOf2(flags, "from", "the first day of the range");
|
|
7962
|
+
const to = dayOf2(flags, "to", "the day the range stops before; --to is not included");
|
|
7963
|
+
if (from >= to)
|
|
7964
|
+
throw new AdminUsageError("--from must be before --to; the range is half-open and an empty one exports nothing.");
|
|
7965
|
+
const out = resolve(required(flags, "out", "where to write the files; an export lives on this machine and nowhere else"));
|
|
7966
|
+
const claimed = claimExportDirectory(out);
|
|
7967
|
+
let done;
|
|
7968
|
+
try {
|
|
7969
|
+
done = ResearchContextExportSchema.parse(expectOk(await call(run2.api, "POST", tenantPath(tenantId, "/research-exports/contexts"), { from, to })));
|
|
7970
|
+
} catch (err) {
|
|
7971
|
+
releaseExportDirectory(out, claimed);
|
|
7972
|
+
throw err;
|
|
7973
|
+
}
|
|
7974
|
+
const contextsPath = join2(out, `contexts-${tenantId}-${from}-${to}.jsonl`);
|
|
7975
|
+
const stepsPath = join2(out, `steps-${tenantId}-${from}-${to}.jsonl`);
|
|
7976
|
+
writePrivateFile(contextsPath, jsonLines(done.contexts));
|
|
7977
|
+
writePrivateFile(stepsPath, jsonLines(done.steps));
|
|
7978
|
+
return render(run2, { tenant_id: tenantId, from: done.from, to: done.to, contexts: done.contexts.length, steps: done.steps.length, files: [contextsPath, stepsPath], operator: done.operator }, [
|
|
7979
|
+
`tenant ${tenantId} ${done.tenant_name}`,
|
|
7980
|
+
`range ${from} to ${to} (--to not included)`,
|
|
7981
|
+
`contexts ${done.contexts.length}`,
|
|
7982
|
+
`steps ${done.steps.length}`,
|
|
7983
|
+
`files ${contextsPath}`,
|
|
7984
|
+
` ${stepsPath}`
|
|
7985
|
+
]);
|
|
7986
|
+
}
|
|
7787
7987
|
async function runVersions(run2) {
|
|
7788
7988
|
const tenantId = required(run2.flags, "tenant", "whose devices");
|
|
7789
7989
|
const found = AdminDeviceVersionListSchema.parse(expectOk(await call(run2.api, "GET", tenantPath(tenantId, "/devices"))));
|
|
@@ -8439,7 +8639,11 @@ ${ADMIN_USAGE}`);
|
|
|
8439
8639
|
|
|
8440
8640
|
// tools/admin/src/surface.ts
|
|
8441
8641
|
import { createHash } from "node:crypto";
|
|
8442
|
-
var MACHINE_ADMIN_PATHS = [
|
|
8642
|
+
var MACHINE_ADMIN_PATHS = [
|
|
8643
|
+
"/v1/admin/research/purge",
|
|
8644
|
+
"/v1/admin/connectors/sync",
|
|
8645
|
+
"/v1/admin/context/purge"
|
|
8646
|
+
];
|
|
8443
8647
|
function canonicalJson(value) {
|
|
8444
8648
|
if (Array.isArray(value))
|
|
8445
8649
|
return `[${value.map((item) => item === undefined ? "null" : canonicalJson(item)).join(",")}]`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unisonlabs/sixminute-admin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1188-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": {
|