@unisonlabs/sixminute-admin 0.1.1262-next → 0.1.1264-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 +162 -13
- package/package.json +1 -1
package/dist/sixminute-admin.mjs
CHANGED
|
@@ -16,12 +16,15 @@ 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
|
|
19
|
+
import { readFileSync as readFileSync5 } 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.
|
|
24
|
+
var BUILT = { version: "0.1.1264-next", commit: "4aaa4ffa41cba442a9d68c410a786df3dc27cb77", surface: "301dc344f2374600" };
|
|
25
|
+
|
|
26
|
+
// tools/admin/src/run.ts
|
|
27
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
25
28
|
|
|
26
29
|
// node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
27
30
|
var exports_external = {};
|
|
@@ -4102,6 +4105,53 @@ var OperatorAuditQuerySchema = exports_external.object({
|
|
|
4102
4105
|
limit: exports_external.coerce.number().int().min(1).max(1000).default(100)
|
|
4103
4106
|
});
|
|
4104
4107
|
var OperatorAuditListSchema = exports_external.object({ actions: exports_external.array(OperatorActionSchema) });
|
|
4108
|
+
// packages/contracts/src/narrative-activities.ts
|
|
4109
|
+
var NARRATIVE_PRIMARY_LANGUAGES = ["nl", "en", "de", "fr", "es", "it", "pt", "pl", "sv", "da"];
|
|
4110
|
+
var NarrativePrimaryLanguageSchema = exports_external.enum(NARRATIVE_PRIMARY_LANGUAGES);
|
|
4111
|
+
var NarrativeActivitySchema = exports_external.object({
|
|
4112
|
+
key: exports_external.string().regex(/^[a-z][a-z0-9_]{0,39}$/, "a key of lowercase letters, digits and underscores, starting with a letter"),
|
|
4113
|
+
when: exports_external.string().trim().min(1).max(800),
|
|
4114
|
+
patterns: exports_external.object(Object.fromEntries(NARRATIVE_PRIMARY_LANGUAGES.map((tag) => [tag, exports_external.string().trim().min(1).max(200).optional()]))).strict().refine((patterns) => Object.values(patterns).some((pattern) => pattern !== undefined), "at least one pattern")
|
|
4115
|
+
});
|
|
4116
|
+
var NarrativeActivitiesSchema = exports_external.array(NarrativeActivitySchema).min(1).max(40).refine((rows) => new Set(rows.map((row) => row.key)).size === rows.length, "every key once");
|
|
4117
|
+
var PUBLIC_MAIL_DOMAINS = new Set([
|
|
4118
|
+
"gmail.com",
|
|
4119
|
+
"googlemail.com",
|
|
4120
|
+
"outlook.com",
|
|
4121
|
+
"hotmail.com",
|
|
4122
|
+
"live.com",
|
|
4123
|
+
"msn.com",
|
|
4124
|
+
"icloud.com",
|
|
4125
|
+
"me.com",
|
|
4126
|
+
"mac.com",
|
|
4127
|
+
"yahoo.com",
|
|
4128
|
+
"aol.com",
|
|
4129
|
+
"mail.com",
|
|
4130
|
+
"proton.me",
|
|
4131
|
+
"protonmail.com",
|
|
4132
|
+
"gmx.com",
|
|
4133
|
+
"gmx.de",
|
|
4134
|
+
"gmx.net",
|
|
4135
|
+
"web.de",
|
|
4136
|
+
"t-online.de",
|
|
4137
|
+
"hotmail.nl",
|
|
4138
|
+
"live.nl",
|
|
4139
|
+
"outlook.nl",
|
|
4140
|
+
"ziggo.nl",
|
|
4141
|
+
"kpnmail.nl",
|
|
4142
|
+
"planet.nl",
|
|
4143
|
+
"home.nl",
|
|
4144
|
+
"xs4all.nl",
|
|
4145
|
+
"telenet.be",
|
|
4146
|
+
"skynet.be",
|
|
4147
|
+
"orange.fr",
|
|
4148
|
+
"free.fr",
|
|
4149
|
+
"wanadoo.fr",
|
|
4150
|
+
"laposte.net",
|
|
4151
|
+
"libero.it",
|
|
4152
|
+
"virgilio.it"
|
|
4153
|
+
]);
|
|
4154
|
+
|
|
4105
4155
|
// packages/contracts/src/vocabulary.ts
|
|
4106
4156
|
var AttributeKeySchema = exports_external.string().regex(/^[a-z][a-z0-9_]{0,39}$/, "an attribute key is a lower-case machine name: a letter, then letters, digits or underscores, at most 40");
|
|
4107
4157
|
var RESERVED_ATTRIBUTE_KEYS = ["utbms_task", "utbms_activity"];
|
|
@@ -4228,8 +4278,20 @@ var ClientSchema = exports_external.object({
|
|
|
4228
4278
|
created_at: TimestampSchema,
|
|
4229
4279
|
updated_at: TimestampSchema
|
|
4230
4280
|
});
|
|
4231
|
-
var
|
|
4232
|
-
var NarrativeLanguageSchema = exports_external.
|
|
4281
|
+
var NARRATIVE_LANGUAGES = [...NARRATIVE_PRIMARY_LANGUAGES, "en-GB", "pt-PT"];
|
|
4282
|
+
var NarrativeLanguageSchema = exports_external.enum(NARRATIVE_LANGUAGES);
|
|
4283
|
+
var STORED_TAG = /^[a-z]{2,3}(-[A-Z][a-z]{3})?(-([A-Z]{2}|[0-9]{3}))?$/;
|
|
4284
|
+
var heldLanguage = (value) => {
|
|
4285
|
+
const read = NarrativeLanguageSchema.safeParse(value);
|
|
4286
|
+
if (read.success)
|
|
4287
|
+
return read.data;
|
|
4288
|
+
if (typeof value !== "string" || !STORED_TAG.test(value))
|
|
4289
|
+
return;
|
|
4290
|
+
const primary = NarrativeLanguageSchema.safeParse(value.split("-", 1)[0]);
|
|
4291
|
+
return primary.success ? primary.data : undefined;
|
|
4292
|
+
};
|
|
4293
|
+
var StoredNarrativeLanguageSchema = exports_external.preprocess((value) => heldLanguage(value) ?? null, NarrativeLanguageSchema.nullable());
|
|
4294
|
+
var StoredFirmLanguageSchema = exports_external.preprocess((value) => heldLanguage(value), NarrativeLanguageSchema.default("en"));
|
|
4233
4295
|
var MatterAttributeRequiredSchema = exports_external.record(AttributeKeySchema.refine((key) => !key.includes("__"), {
|
|
4234
4296
|
message: "an attribute key here carries no double underscore"
|
|
4235
4297
|
}), exports_external.boolean());
|
|
@@ -4279,7 +4341,7 @@ var MatterSchema = exports_external.object({
|
|
|
4279
4341
|
billing: MatterBillingSchema,
|
|
4280
4342
|
attribute_sets: MatterAttributeSetsSchema.default({}),
|
|
4281
4343
|
attribute_required: MatterAttributeRequiredSchema.default({}),
|
|
4282
|
-
narrative_language:
|
|
4344
|
+
narrative_language: StoredNarrativeLanguageSchema,
|
|
4283
4345
|
sync_source: SyncSourceSchema.default("manual"),
|
|
4284
4346
|
created_at: TimestampSchema,
|
|
4285
4347
|
updated_at: TimestampSchema
|
|
@@ -5919,7 +5981,7 @@ var FirmSettingsSchema = exports_external.object({
|
|
|
5919
5981
|
unit_minutes: UnitMinutesSchema.default(6),
|
|
5920
5982
|
narrative: exports_external.object({
|
|
5921
5983
|
max_chars: NarrativeMaxCharsSchema.nullable().default(null),
|
|
5922
|
-
language:
|
|
5984
|
+
language: StoredFirmLanguageSchema,
|
|
5923
5985
|
guidance: NarrativeGuidanceSchema.default(""),
|
|
5924
5986
|
lowered_to_system: exports_external.object({ kind: ConnectorKindSchema, at: TimestampSchema }).nullable().default(null)
|
|
5925
5987
|
}).default({}),
|
|
@@ -5964,7 +6026,7 @@ var MemberSchema = exports_external.object({
|
|
|
5964
6026
|
user_id: UserIdSchema,
|
|
5965
6027
|
role: RoleSchema,
|
|
5966
6028
|
active: exports_external.boolean().default(true),
|
|
5967
|
-
narrative_language:
|
|
6029
|
+
narrative_language: StoredNarrativeLanguageSchema,
|
|
5968
6030
|
entry_size: EntrySizeSchema.nullable().default(null),
|
|
5969
6031
|
created_at: TimestampSchema,
|
|
5970
6032
|
updated_at: TimestampSchema
|
|
@@ -6006,7 +6068,7 @@ var MeSystemLinkSchema = exports_external.object({
|
|
|
6006
6068
|
code: exports_external.string().min(1).nullable(),
|
|
6007
6069
|
status: exports_external.enum(["connected", "needs_reconnect"]).optional(),
|
|
6008
6070
|
synced: exports_external.boolean().optional(),
|
|
6009
|
-
narrative_language:
|
|
6071
|
+
narrative_language: StoredNarrativeLanguageSchema.optional(),
|
|
6010
6072
|
approval: ApprovalModeSchema.optional()
|
|
6011
6073
|
});
|
|
6012
6074
|
var MeSchema = exports_external.object({
|
|
@@ -6117,7 +6179,7 @@ var MatterPatchSchema = MatterSchema.omit({
|
|
|
6117
6179
|
updated_at: true,
|
|
6118
6180
|
attribute_required: true,
|
|
6119
6181
|
firm_internal: true
|
|
6120
|
-
}).partial();
|
|
6182
|
+
}).extend({ narrative_language: NarrativeLanguageSchema.nullable() }).partial();
|
|
6121
6183
|
var FirmInternalPutSchema = exports_external.object({ firm_internal: exports_external.boolean() });
|
|
6122
6184
|
var AttributeSetPutSchema = AttributeSetSchema.omit({ updated_at: true });
|
|
6123
6185
|
var AttributeSetsQuerySchema = exports_external.object({ attribute: AttributeKeySchema.optional() });
|
|
@@ -6648,6 +6710,17 @@ var AdminSealedBackfillResultSchema = exports_external.object({
|
|
|
6648
6710
|
judged_sealed: exports_external.number().int(),
|
|
6649
6711
|
done: exports_external.boolean()
|
|
6650
6712
|
});
|
|
6713
|
+
var AdminNarrativeInstructionsSetSchema = exports_external.object({ instructions: NarrativeGuidanceSchema });
|
|
6714
|
+
var AdminNarrativeInstructionsSchema = exports_external.object({
|
|
6715
|
+
tenant: exports_external.object({ id: TenantIdSchema, name: exports_external.string() }),
|
|
6716
|
+
instructions: exports_external.string()
|
|
6717
|
+
});
|
|
6718
|
+
var AdminNarrativeActivitiesSetSchema = exports_external.object({ activities: NarrativeActivitiesSchema });
|
|
6719
|
+
var AdminNarrativeActivitiesSchema = exports_external.object({
|
|
6720
|
+
tenant: exports_external.object({ id: TenantIdSchema, name: exports_external.string() }),
|
|
6721
|
+
language: NarrativeLanguageSchema,
|
|
6722
|
+
activities: exports_external.array(NarrativeActivitySchema)
|
|
6723
|
+
});
|
|
6651
6724
|
// packages/contracts/src/admin-firm-acting.ts
|
|
6652
6725
|
var ACTING_AS_HEADER = "X-Six-Minute-Acting-As";
|
|
6653
6726
|
var TeamApplyRequestSchema = exports_external.object({
|
|
@@ -6853,6 +6926,13 @@ var COMPAT_MARKERS = [
|
|
|
6853
6926
|
"services/api/test/t42-intervals.test.ts",
|
|
6854
6927
|
"services/api/test/t53-bundle.test.ts"
|
|
6855
6928
|
]),
|
|
6929
|
+
...markers("frozen-short", [
|
|
6930
|
+
"services/api/src/platform/models/bundle.ts",
|
|
6931
|
+
"services/api/src/platform/models/compat/activity-types.ts",
|
|
6932
|
+
"services/api/src/platform/models/compat/narrative-short.md",
|
|
6933
|
+
"services/api/test/compat-180.test.ts",
|
|
6934
|
+
"services/api/test/t53-bundle.test.ts"
|
|
6935
|
+
]),
|
|
6856
6936
|
...markers("narrative-languages", ["services/api/src/app.ts", "services/api/src/features/update/legacy-languages.ts"]),
|
|
6857
6937
|
...markers("pr4", [
|
|
6858
6938
|
"boundaries.ts",
|
|
@@ -8149,16 +8229,16 @@ function syncLines(report) {
|
|
|
8149
8229
|
|
|
8150
8230
|
// tools/admin/src/sets.ts
|
|
8151
8231
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
8152
|
-
function readDocument(path, schema, what) {
|
|
8232
|
+
function readDocument(path, schema, what, flag = "from-file") {
|
|
8153
8233
|
let raw;
|
|
8154
8234
|
try {
|
|
8155
8235
|
raw = JSON.parse(readFileSync2(path, "utf8"));
|
|
8156
8236
|
} catch (err) {
|
|
8157
|
-
throw new AdminUsageError(
|
|
8237
|
+
throw new AdminUsageError(`--${flag} ${path} is not readable JSON: ${err.message}`);
|
|
8158
8238
|
}
|
|
8159
8239
|
const parsed = schema.safeParse(raw);
|
|
8160
8240
|
if (!parsed.success) {
|
|
8161
|
-
throw new AdminUsageError(
|
|
8241
|
+
throw new AdminUsageError(`--${flag} ${path} is not ${what}: ` + parsed.error.issues.slice(0, 4).map((i) => `${i.path.join(".") || "(root)"} ${i.message}`).join("; "));
|
|
8162
8242
|
}
|
|
8163
8243
|
return { raw, parsed: parsed.data };
|
|
8164
8244
|
}
|
|
@@ -8557,6 +8637,23 @@ is required; without one every command answers 403.
|
|
|
8557
8637
|
setting deletes at the next hourly purge. Summaries, labels and entries
|
|
8558
8638
|
are not affected.
|
|
8559
8639
|
|
|
8640
|
+
sixminute-admin narrative show --env <env> --tenant tenant_... [--file <path>] [--json]
|
|
8641
|
+
sixminute-admin narrative set --env <env> --tenant tenant_... --file <path> [--json]
|
|
8642
|
+
The firm's narrative instructions: the text every narrative of the firm
|
|
8643
|
+
follows, over every default, at most 1,500 characters. show prints it,
|
|
8644
|
+
or writes it to --file; set replaces it with the text of --file (an
|
|
8645
|
+
empty file clears it).
|
|
8646
|
+
|
|
8647
|
+
sixminute-admin narrative activities show --env <env> --tenant tenant_... [--file <path>] [--json]
|
|
8648
|
+
sixminute-admin narrative activities set --env <env> --tenant tenant_... --file <path> [--json]
|
|
8649
|
+
The firm's narrative activities, by rank: the first row whose "when"
|
|
8650
|
+
the evidence meets opens the line. show prints the ranks and keys, or
|
|
8651
|
+
writes the whole table to --file as a JSON array; set replaces the
|
|
8652
|
+
firm's rows with the array in --file, in its order. Edit by show to a
|
|
8653
|
+
file, edit, set. set is refused, and the rows stay as they were, for an
|
|
8654
|
+
empty table, a repeated key, or a table where no row has a pattern in
|
|
8655
|
+
the firm's default narrative language.
|
|
8656
|
+
|
|
8560
8657
|
sixminute-admin pipeline shadow-report --env <env> --day YYYY-MM-DD [--json]
|
|
8561
8658
|
The cloud pipeline's shadow against the device for one local day, for
|
|
8562
8659
|
every person of an internal firm with a shadow recording: intervals
|
|
@@ -8919,6 +9016,7 @@ async function runAdmin(argv, deps) {
|
|
|
8919
9016
|
const oneWord = ["login", "logout", "whoami", "doctor", "versions", "audit"].includes(group);
|
|
8920
9017
|
const vocabulary2 = group === "attribute" || group === "matter" && subcommand === "sets";
|
|
8921
9018
|
const threeDeep = group === "tenant" && subcommand === "internal";
|
|
9019
|
+
const narrativeTable = group === "narrative" && subcommand === "activities";
|
|
8922
9020
|
let flagArgv;
|
|
8923
9021
|
const positionals = [];
|
|
8924
9022
|
if (oneWord)
|
|
@@ -8928,6 +9026,11 @@ async function runAdmin(argv, deps) {
|
|
|
8928
9026
|
if (verb !== "set")
|
|
8929
9027
|
throw new AdminUsageError(`unknown command: tenant internal ${verb ?? ""}`.trim());
|
|
8930
9028
|
flagArgv = more;
|
|
9029
|
+
} else if (narrativeTable) {
|
|
9030
|
+
const [verb, ...more] = rest;
|
|
9031
|
+
if (verb !== "show" && verb !== "set")
|
|
9032
|
+
throw new AdminUsageError(`unknown command: narrative activities ${verb ?? ""}`.trim());
|
|
9033
|
+
flagArgv = more;
|
|
8931
9034
|
} else if (vocabulary2) {
|
|
8932
9035
|
const argvOf = group === "attribute" && subcommand === "set" ? rest.slice(1) : rest;
|
|
8933
9036
|
const forFlags = [];
|
|
@@ -8993,6 +9096,10 @@ async function runAdmin(argv, deps) {
|
|
|
8993
9096
|
return runRawArchive(run2, subcommand);
|
|
8994
9097
|
if (group === "retention" && subcommand === "set")
|
|
8995
9098
|
return runRetentionSet(run2);
|
|
9099
|
+
if (narrativeTable)
|
|
9100
|
+
return runNarrativeActivities(run2, rest[0] === "set");
|
|
9101
|
+
if (group === "narrative" && (subcommand === "show" || subcommand === "set"))
|
|
9102
|
+
return runNarrativeInstructions(run2, subcommand === "set");
|
|
8996
9103
|
if (group === "backfill" && subcommand === "sealed")
|
|
8997
9104
|
return runBackfillSealed(run2);
|
|
8998
9105
|
if (group === "scrub" && subcommand === "plaintext")
|
|
@@ -9182,6 +9289,48 @@ async function runRetentionSet(run2) {
|
|
|
9182
9289
|
`moved ${moved}`
|
|
9183
9290
|
]);
|
|
9184
9291
|
}
|
|
9292
|
+
async function runNarrativeInstructions(run2, set) {
|
|
9293
|
+
const tenantId = required(run2.flags, "tenant", "whose narrative instructions");
|
|
9294
|
+
const file = set ? required(run2.flags, "file", "the instructions are the text of a file") : optional(run2.flags, "file");
|
|
9295
|
+
let body;
|
|
9296
|
+
if (set) {
|
|
9297
|
+
try {
|
|
9298
|
+
body = { instructions: readFileSync4(file, "utf8") };
|
|
9299
|
+
} catch (err) {
|
|
9300
|
+
throw new AdminUsageError(`--file ${file} is not readable: ${err.message}`);
|
|
9301
|
+
}
|
|
9302
|
+
}
|
|
9303
|
+
const answer = await call(run2.api, set ? "PUT" : "GET", tenantPath(tenantId, "/narrative-instructions"), body);
|
|
9304
|
+
if (answer.status !== 200)
|
|
9305
|
+
return refused(run2, answer, [actingHead(tenantId, answer)]);
|
|
9306
|
+
const done = AdminNarrativeInstructionsSchema.parse(answer.body);
|
|
9307
|
+
const lead = [actingHead(tenantId, answer), `instructions ${done.instructions.length} characters${set ? ", set" : ""}`];
|
|
9308
|
+
if (!set && file !== undefined) {
|
|
9309
|
+
writeFileSync2(file, done.instructions);
|
|
9310
|
+
return render(run2, { ...done, file }, [...lead, `written ${file}`]);
|
|
9311
|
+
}
|
|
9312
|
+
return render(run2, done, set || done.instructions === "" ? lead : [...lead, "", ...done.instructions.split(`
|
|
9313
|
+
`)]);
|
|
9314
|
+
}
|
|
9315
|
+
async function runNarrativeActivities(run2, set) {
|
|
9316
|
+
const tenantId = required(run2.flags, "tenant", "whose narrative activities");
|
|
9317
|
+
const file = set ? required(run2.flags, "file", "the table is a JSON array of rows, by rank, in a file") : optional(run2.flags, "file");
|
|
9318
|
+
const body = set ? { activities: readDocument(file, NarrativeActivitiesSchema, "a narrative activity table (a JSON array of rows, by rank)", "file").raw } : undefined;
|
|
9319
|
+
const answer = await call(run2.api, set ? "PUT" : "GET", tenantPath(tenantId, "/narrative-activities"), body);
|
|
9320
|
+
if (answer.status !== 200)
|
|
9321
|
+
return refused(run2, answer, [actingHead(tenantId, answer)]);
|
|
9322
|
+
const done = AdminNarrativeActivitiesSchema.parse(answer.body);
|
|
9323
|
+
if (!set && file !== undefined)
|
|
9324
|
+
writeFileSync2(file, `${JSON.stringify(done.activities, null, 2)}
|
|
9325
|
+
`);
|
|
9326
|
+
return render(run2, !set && file !== undefined ? { ...done, file } : done, [
|
|
9327
|
+
actingHead(tenantId, answer),
|
|
9328
|
+
`language ${done.language}`,
|
|
9329
|
+
`activities ${done.activities.length}${set ? ", set" : ""}`,
|
|
9330
|
+
...done.activities.map((row, i) => ` ${String(i + 1).padStart(2)} ${row.key} ${Object.keys(row.patterns).join(", ")}`),
|
|
9331
|
+
...!set && file !== undefined ? [`written ${file}`] : []
|
|
9332
|
+
]);
|
|
9333
|
+
}
|
|
9185
9334
|
async function runBackfillSealed(run2) {
|
|
9186
9335
|
const tenantId = required(run2.flags, "tenant", "whose rows to seal");
|
|
9187
9336
|
const total = { decisions_sealed: 0, intervals_aged: 0, judged_sealed: 0 };
|
|
@@ -9813,7 +9962,7 @@ function adminSurfaceOf(document) {
|
|
|
9813
9962
|
// tools/admin/src/main.ts
|
|
9814
9963
|
function sourceBuild() {
|
|
9815
9964
|
const document = fileURLToPath(new URL("../../../services/api/openapi.json", import.meta.url));
|
|
9816
|
-
const surface = adminSurfaceOf(JSON.parse(
|
|
9965
|
+
const surface = adminSurfaceOf(JSON.parse(readFileSync5(document, "utf8")));
|
|
9817
9966
|
return { version: "0.0.0-dev", commit: "source", surface };
|
|
9818
9967
|
}
|
|
9819
9968
|
function openBrowser(url) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unisonlabs/sixminute-admin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1264-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": {
|