pairit 0.1.8 → 0.1.9
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/README.md +19 -0
- package/dist/index.js +52 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ A lightweight command line utility for working with Pairit experiment configurat
|
|
|
12
12
|
- `media list` — list media objects in Cloud Storage
|
|
13
13
|
- `media delete` — delete a media object from Cloud Storage
|
|
14
14
|
- `data export` — export sessions, events, and chat messages for a config as CSV/JSON/JSONL
|
|
15
|
+
- `admin add-user` / `admin remove-user` / `admin list-users` — manage the manager allowlist (admin role required)
|
|
15
16
|
|
|
16
17
|
## Install
|
|
17
18
|
|
|
@@ -77,6 +78,24 @@ bun run apps/manager/cli/src/index.ts media delete onboarding/logo.png --force
|
|
|
77
78
|
|
|
78
79
|
`config compile` writes `configs/simple-survey-basic.json` next to the source YAML. `config upload` defaults the config id to a 16-character base64url string derived from the SHA-256 hash of the compiled JSON (unless `--config-id` overrides it).
|
|
79
80
|
|
|
81
|
+
## Manager allowlist (admin)
|
|
82
|
+
|
|
83
|
+
Manager sign-ins are gated on a Mongo allowlist. Anyone who isn't on it lands on `/access-denied` after Google sign-in. Use these commands to manage who can sign in. The calling CLI user must be an admin.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pairit admin list-users # Show everyone on the allowlist
|
|
87
|
+
pairit admin add-user alice@example.com # Add as researcher
|
|
88
|
+
pairit admin add-user bob@example.com --admin # Add as admin (can manage the allowlist)
|
|
89
|
+
pairit admin remove-user alice@example.com # Remove and revoke their sessions
|
|
90
|
+
pairit admin remove-user alice@example.com --force # Skip confirmation prompt
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Notes:
|
|
94
|
+
- Bootstrap: `MANAGER_BOOTSTRAP_ADMIN_EMAIL` is seeded as admin on every manager boot. Set it before the first deploy or you'll have no admins.
|
|
95
|
+
- Day-1 migration: on first boot, existing config owners are backfilled as researchers (not the entire user collection, which is shared with lab participants).
|
|
96
|
+
- Self-removal is blocked.
|
|
97
|
+
- The rejection page contact is set by `MANAGER_ADMIN_CONTACT_EMAIL` (defaults to `harang@pairium.ai`).
|
|
98
|
+
|
|
80
99
|
## Per-experiment LLM credentials
|
|
81
100
|
|
|
82
101
|
If your config uses AI agents, attach provider credentials when uploading:
|
package/dist/index.js
CHANGED
|
@@ -9666,7 +9666,7 @@ async function loadKeytar() {
|
|
|
9666
9666
|
|
|
9667
9667
|
// src/index.ts
|
|
9668
9668
|
var program2 = new Command;
|
|
9669
|
-
program2.name("pairit").description("CLI for Pairit experiment configs").version("0.1.
|
|
9669
|
+
program2.name("pairit").description("CLI for Pairit experiment configs").version("0.1.9");
|
|
9670
9670
|
program2.command("login").description("Login to Pairit Manager").action(async () => {
|
|
9671
9671
|
try {
|
|
9672
9672
|
await login();
|
|
@@ -9817,6 +9817,57 @@ dataCommand.command("export").argument("<configId>", "Config ID to export data f
|
|
|
9817
9817
|
reportCliError("Export failed", error);
|
|
9818
9818
|
}
|
|
9819
9819
|
});
|
|
9820
|
+
var adminCommand = program2.command("admin").description("Manage manager allowlist (admin only)");
|
|
9821
|
+
adminCommand.command("add-user").argument("<email>", "Email to allow").option("--admin", "Grant admin privileges").description("Add a user to the manager allowlist").action(async (email, options) => {
|
|
9822
|
+
try {
|
|
9823
|
+
const response = await callFunctions("/admin/users", {
|
|
9824
|
+
method: "POST",
|
|
9825
|
+
headers: { "Content-Type": "application/json" },
|
|
9826
|
+
body: JSON.stringify({ email, isAdmin: Boolean(options.admin) })
|
|
9827
|
+
});
|
|
9828
|
+
const entry = response?.user;
|
|
9829
|
+
if (!entry)
|
|
9830
|
+
throw new Error("No user returned");
|
|
9831
|
+
console.log(`✓ Added ${entry.email} (${entry.isAdmin ? "admin" : "researcher"})`);
|
|
9832
|
+
} catch (error) {
|
|
9833
|
+
reportCliError("Add user failed", error);
|
|
9834
|
+
}
|
|
9835
|
+
});
|
|
9836
|
+
adminCommand.command("remove-user").argument("<email>", "Email to remove").option("--force", "Skip confirmation").description("Remove a user from the manager allowlist and revoke sessions").action(async (email, options) => {
|
|
9837
|
+
try {
|
|
9838
|
+
if (!options.force) {
|
|
9839
|
+
const confirmed = await promptConfirm(`Remove ${email} from allowlist? (y/N)`);
|
|
9840
|
+
if (!confirmed) {
|
|
9841
|
+
console.log("Removal aborted");
|
|
9842
|
+
return;
|
|
9843
|
+
}
|
|
9844
|
+
}
|
|
9845
|
+
await callFunctions(`/admin/users/${encodeURIComponent(email)}`, {
|
|
9846
|
+
method: "DELETE"
|
|
9847
|
+
});
|
|
9848
|
+
console.log(`✓ Removed ${email}`);
|
|
9849
|
+
} catch (error) {
|
|
9850
|
+
reportCliError("Remove user failed", error);
|
|
9851
|
+
}
|
|
9852
|
+
});
|
|
9853
|
+
adminCommand.command("list-users").description("List users on the manager allowlist").action(async () => {
|
|
9854
|
+
try {
|
|
9855
|
+
const response = await callFunctions("/admin/users", {
|
|
9856
|
+
method: "GET"
|
|
9857
|
+
});
|
|
9858
|
+
const users = response?.users ?? [];
|
|
9859
|
+
if (!users.length) {
|
|
9860
|
+
console.log("No users on the allowlist");
|
|
9861
|
+
return;
|
|
9862
|
+
}
|
|
9863
|
+
users.forEach((u) => {
|
|
9864
|
+
const role = u.isAdmin ? "admin" : "researcher";
|
|
9865
|
+
console.log(`${u.email} | ${role} | addedBy=${u.addedBy} | addedAt=${u.addedAt}`);
|
|
9866
|
+
});
|
|
9867
|
+
} catch (error) {
|
|
9868
|
+
reportCliError("List users failed", error);
|
|
9869
|
+
}
|
|
9870
|
+
});
|
|
9820
9871
|
program2.parseAsync(process9.argv).catch((err) => {
|
|
9821
9872
|
console.error(err);
|
|
9822
9873
|
process9.exit(1);
|