@optimuslabs/harness-map-staging 1.5.29 → 1.5.30

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.
@@ -62,6 +62,7 @@ export function readClaudeSignedInTenant(env = process.env) {
62
62
  tenant_name: text('organizationName'),
63
63
  email: text('emailAddress'),
64
64
  account_uuid: text('accountUuid'),
65
+ plan: text('organizationType').toLowerCase().replace(/^claude_/, ''),
65
66
  };
66
67
  }
67
68
  catch {
@@ -69,14 +70,74 @@ export function readClaudeSignedInTenant(env = process.env) {
69
70
  return null;
70
71
  }
71
72
  }
72
- /** How to get out of a blocked tenant: Claude Desktop switches organization, Claude Code logs in. */
73
- function fix(agent, which) {
74
- return agent === 'claude_desktop'
75
- ? `Switch Claude Desktop to ${which} organization, or sign in to one.`
76
- : `Run /login to sign in to ${which} organization.`;
73
+ /**
74
+ * Block messages, one shape for every agent (Optimus Labs' prompt-block wording):
75
+ * "This device only allows <agent> <under/on/in> the <approved> <kind>. You're signed in to
76
+ * <what>. <how to switch>." With nothing approved yet: "This device doesn't allow <agent> signed in
77
+ * to <what>." and the same last sentence.
78
+ */
79
+ const TENANT_WORDS = {
80
+ claude: { name: 'Claude Code', kind: 'organization', prep: 'under' },
81
+ claude_desktop: { name: 'Claude Desktop', kind: 'organization', prep: 'under' },
82
+ cursor: { name: 'Cursor', kind: 'team', prep: 'on' },
83
+ codex: { name: 'Codex', kind: 'workspace', prep: 'in' },
84
+ };
85
+ /** A tenant's name as the admin approved it, or its id when it has none. */
86
+ function nameOf(t) {
87
+ return (t.tenant_name || '').trim() || t.tenant_id.trim();
88
+ }
89
+ function emailDomain(email) {
90
+ const address = (email ?? '').trim().toLowerCase();
91
+ const at = address.lastIndexOf('@');
92
+ return at >= 0 && at < address.length - 1 ? address.slice(at + 1) : '';
77
93
  }
78
- function label(name, id) {
79
- return name ? `${name} (${id})` : id;
94
+ function capitalised(word) {
95
+ return word ? word[0].toUpperCase() + word.slice(1) : word;
96
+ }
97
+ /** What to pick to get back in: the one approved tenant, one of several, or the company's own. */
98
+ function choice(approved, kind) {
99
+ if (approved.length === 1)
100
+ return approved[0];
101
+ return approved.length > 1 ? 'one of them' : `your company's ${kind}`;
102
+ }
103
+ function switchStep(agent, approved) {
104
+ const kind = TENANT_WORDS[agent].kind;
105
+ if (agent === 'claude_desktop')
106
+ return `Switch Claude Desktop to ${choice(approved, kind)}.`;
107
+ if (agent === 'codex')
108
+ return `Run codex logout, then codex login and choose ${choice(approved, kind)}.`;
109
+ if (agent === 'cursor') {
110
+ if (approved.length === 1)
111
+ return `Sign out of Cursor and sign in with your ${approved[0]} team account.`;
112
+ return approved.length > 1
113
+ ? 'Sign out of Cursor and sign in with an account on one of those teams.'
114
+ : "Sign out of Cursor and sign in with your company's team account.";
115
+ }
116
+ return `Run /login and choose ${choice(approved, kind)}.`;
117
+ }
118
+ /** The block message for `agent` signed in to `signedIn` (already worded) with these approved. */
119
+ export function tenantBlockMessage(agent, approved, signedIn) {
120
+ const w = TENANT_WORDS[agent];
121
+ const lead = approved.length
122
+ ? `This device only allows ${w.name} ${w.prep} the ${approved.join(' or ')} ${w.kind}. ` +
123
+ `You're signed in to ${signedIn}.`
124
+ : `This device doesn't allow ${w.name} signed in to ${signedIn}.`;
125
+ return `${lead} ${switchStep(agent, approved)}`;
126
+ }
127
+ const CLAUDE_PERSONAL_PLANS = new Set(['free', 'pro', 'max']);
128
+ /** "a personal Max account (gmail.com)" or "the Beta Corp organization". */
129
+ function claudeSignedInText(signedIn) {
130
+ const plan = (signedIn.plan ?? '').trim().toLowerCase();
131
+ const domain = emailDomain(signedIn.email);
132
+ const at = domain ? ` (${domain})` : '';
133
+ // A personal claude.ai org is named after its owner: "ada@gmail.com's Organization".
134
+ if (CLAUDE_PERSONAL_PLANS.has(plan) || /'s organization$/i.test(signedIn.tenant_name)) {
135
+ const planWord = CLAUDE_PERSONAL_PLANS.has(plan) ? `${capitalised(plan)} ` : '';
136
+ return `a personal ${planWord}account${at}`;
137
+ }
138
+ if (signedIn.tenant_name)
139
+ return `the ${signedIn.tenant_name} organization`;
140
+ return `an organization your company has not approved${at}`;
80
141
  }
81
142
  function tenantIds(tenants) {
82
143
  return (tenants ?? []).filter((t) => t && typeof t.tenant_id === 'string' && t.tenant_id.trim());
@@ -96,21 +157,11 @@ export function approvedTenantViolation(agent, approved, signedIn) {
96
157
  const unapprovedTenants = tenantIds(policy?.unapproved_tenants);
97
158
  const signedInId = signedIn.tenant_id.trim();
98
159
  const isIn = (list) => list.some((t) => t.tenant_id.trim() === signedInId);
99
- let reason;
100
- if (isIn(unapprovedTenants)) {
101
- reason = 'which your organization has marked unapproved';
102
- }
103
- else if ((policy?.enforced || approvedTenants.length > 0) && !isIn(approvedTenants)) {
104
- reason = 'which your organization has not approved';
105
- }
106
- else {
160
+ const blocked = isIn(unapprovedTenants) ||
161
+ ((policy?.enforced || approvedTenants.length > 0) && !isIn(approvedTenants));
162
+ if (!blocked)
107
163
  return null;
108
- }
109
- const allowed = approvedTenants.map((t) => label(t.tenant_name, t.tenant_id)).join(', ');
110
- return (`this session is signed into ${label(signedIn.tenant_name, signedIn.tenant_id)}, ${reason}. ` +
111
- (allowed
112
- ? `Approved: ${allowed}. ${fix(agent, 'an approved')}`
113
- : fix(agent, 'a different')));
164
+ return tenantBlockMessage(agent, approvedTenants.map(nameOf), claudeSignedInText(signedIn));
114
165
  }
115
166
  /**
116
167
  * The tenants a Cursor login is in: its teams, or, on no team, `@` and its email domain. Mirrors the
@@ -142,43 +193,61 @@ export function readCursorSignedInTeams(home = homedir()) {
142
193
  * the login; failing that, one marked unapproved is always blocked, and any other -- an unknown
143
194
  * tenant, or a personal account -- only once at least one tenant is approved for this agent.
144
195
  */
145
- function listedTenantViolation(policy, tenants, noun) {
196
+ function listedTenantViolation(policy, tenants) {
146
197
  const approvedList = tenantIds(policy?.tenants);
147
198
  if (tenants.some((id) => isListed(approvedList, id)))
148
199
  return null;
149
- const what = refusedTenantsText(tenants, noun, approvedList.length > 0 || Boolean(policy?.enforced), tenantIds(policy?.unapproved_tenants));
150
- if (what === null)
200
+ const enforced = approvedList.length > 0 || Boolean(policy?.enforced);
201
+ if (!isRefused(tenants, enforced, tenantIds(policy?.unapproved_tenants)))
151
202
  return null;
152
- return { what, allowed: approvedList.map((t) => label(t.tenant_name, t.tenant_id)).join(', ') };
203
+ return { approved: approvedList.map(nameOf) };
153
204
  }
154
205
  function isListed(list, id) {
155
206
  return list.some((t) => t.tenant_id.trim() === id);
156
207
  }
157
- function describeTenant(id, noun) {
158
- return id.startsWith('@') ? `a personal account with an ${id} email` : `${noun} ${id}`;
208
+ /** Whether a login in these tenants is refused: one marked unapproved always; any other only once
209
+ * the agent is enforced (an older backend that sends no flag, with nothing approved, lets it pass). */
210
+ function isRefused(tenants, enforced, unapprovedList) {
211
+ if (tenants.some((id) => isListed(unapprovedList, id)))
212
+ return true;
213
+ return enforced;
159
214
  }
160
- /** What the login is signed into and why that is refused, or null when it is not refused. */
161
- function refusedTenantsText(tenants, noun, enforced, unapprovedList) {
162
- const marked = tenants.find((id) => isListed(unapprovedList, id));
163
- if (marked)
164
- return `${describeTenant(marked, noun)}, which your organization has marked unapproved`;
165
- // Not enforced (an older backend that sends no flag) and nothing approved: shadow passes.
166
- if (!enforced)
167
- return null;
168
- if (tenants.length === 0)
169
- return `a personal account that is on no ${noun}, which your organization has not approved`;
170
- return `${tenants.map((id) => describeTenant(id, noun)).join(', ')}, which your organization has not approved`;
215
+ /** A tenant's name from the organization's lists, or '' when it has none there. */
216
+ function knownName(policy, id) {
217
+ const all = [...tenantIds(policy?.tenants), ...tenantIds(policy?.unapproved_tenants)];
218
+ const hit = all.find((t) => t.tenant_id.trim() === id);
219
+ return (hit?.tenant_name || '').trim();
220
+ }
221
+ /** "a personal account on no team (gmail.com)", "the Beta team" or "team 9876". */
222
+ function cursorSignedInText(signedIn, policy) {
223
+ const tenants = cursorTenants(signedIn);
224
+ if (!tenants.length || tenants[0].startsWith('@')) {
225
+ const domain = emailDomain(signedIn.email) || (tenants[0] ?? '').slice(1);
226
+ return `a personal account on no team${domain ? ` (${domain})` : ''}`;
227
+ }
228
+ return tenants
229
+ .map((id) => (knownName(policy, id) ? `the ${knownName(policy, id)} team` : `team ${id}`))
230
+ .join(' and ');
231
+ }
232
+ /** "a personal ChatGPT Plus account (gmail.com)", "the Beta workspace" or "workspace ws-1". */
233
+ function codexSignedInText(signedIn, tenants, policy) {
234
+ const tenant = tenants[0] ?? '';
235
+ if (!tenant || tenant.startsWith('@')) {
236
+ const plan = capitalised((signedIn.plan ?? '').trim().toLowerCase());
237
+ const domain = emailDomain(signedIn.email) || tenant.slice(1);
238
+ return `a personal ChatGPT ${plan ? `${plan} ` : ''}account${domain ? ` (${domain})` : ''}`;
239
+ }
240
+ const name = knownName(policy, tenant);
241
+ return name ? `the ${name} workspace` : `workspace ${tenant}`;
171
242
  }
172
243
  /** The block message when Cursor's login may not be used, else null. */
173
244
  export function cursorTeamViolation(approved, signedIn) {
174
245
  if (!signedIn)
175
246
  return null;
176
- const v = listedTenantViolation(approved?.cursor, cursorTenants(signedIn), 'team');
247
+ const v = listedTenantViolation(approved?.cursor, cursorTenants(signedIn));
177
248
  if (!v)
178
249
  return null;
179
- return (`this Cursor session is signed into ${v.what}. ` +
180
- (v.allowed ? `Approved: ${v.allowed}. ` : '') +
181
- 'Sign out of Cursor and sign in with an account on an approved team.');
250
+ return tenantBlockMessage('cursor', v.approved, cursorSignedInText(signedIn, approved?.cursor));
182
251
  }
183
252
  /**
184
253
  * Codex plans that are personal, mirroring the backend's `CodexPlans.PERSONAL`. On one of these
@@ -221,12 +290,10 @@ export function codexTenantViolation(approved, signedIn) {
221
290
  const tenants = signedIn ? codexTenants(signedIn) : null;
222
291
  if (!tenants)
223
292
  return null;
224
- const v = listedTenantViolation(approved?.codex, tenants, 'workspace');
293
+ const v = listedTenantViolation(approved?.codex, tenants);
225
294
  if (!v)
226
295
  return null;
227
- return (`this Codex session is signed into ${v.what}. ` +
228
- (v.allowed ? `Approved: ${v.allowed}. ` : '') +
229
- 'Run `codex logout`, then sign in to an approved workspace.');
296
+ return tenantBlockMessage('codex', v.approved, codexSignedInText(signedIn, tenants, approved?.codex));
230
297
  }
231
298
  /**
232
299
  * Whether a personal account's `@<domain>` tenant is on a team domain: an allowlisted domain that
@@ -276,6 +343,7 @@ export function readClaudeDesktopSignedInTenant(home = homedir(), env = process.
276
343
  tenant_name: same ? fromClaudeCode.tenant_name : '',
277
344
  email: same ? fromClaudeCode.email : '',
278
345
  account_uuid: account || (same ? fromClaudeCode.account_uuid : ''),
346
+ plan: same ? fromClaudeCode.plan : '',
279
347
  };
280
348
  }
281
349
  /**
@@ -293,8 +361,8 @@ export function unapprovedEmailDomainViolation(email, unapproved) {
293
361
  const hit = unapproved.find((d) => domain === d || domain.endsWith(`.${d}`));
294
362
  if (!hit)
295
363
  return null;
296
- return (`this session is signed in as ${address}, on @${hit}, which your organization has unapproved. ` +
297
- 'Sign in with an account on an approved email domain.');
364
+ return (`This device doesn't allow accounts on ${hit}. You're signed in as ${address}. ` +
365
+ 'Sign in with your work account.');
298
366
  }
299
367
  /**
300
368
  * The block message when a login's email is not on the organization's email allowlist, else null.
@@ -313,8 +381,8 @@ export function emailAllowlistViolation(email, allowed) {
313
381
  const domain = address.slice(at + 1);
314
382
  if (allowed.some((d) => domain === d || domain.endsWith(`.${d}`)))
315
383
  return null;
316
- return (`this session is signed in as ${address}, and @${domain} is not on your organization's email allowlist. ` +
317
- 'Sign in with an account on an allowed email domain.');
384
+ return (`This device only allows accounts on your organization's email domains. You're signed in as ${address}. ` +
385
+ 'Sign in with your work account.');
318
386
  }
319
387
  /** The id an agent is approved under on the Agents page: Desktop's Code tab runs Claude Code. */
320
388
  const APPROVAL_ID = { claude_desktop: 'claude' };
@@ -87,9 +87,10 @@ function printAllowWithAdvisory(ide, advisoryMessage) {
87
87
  }));
88
88
  }
89
89
  }
90
+ /** Every block reads as an Optimus Labs notice: a title line, then the message. */
91
+ const BLOCK_TITLE = 'Optimus Labs\n\n';
90
92
  function blockPayload(ide, violationMessage) {
91
- const prefix = 'Prompt blocked by Optimus: ';
92
- const text = prefix + violationMessage;
93
+ const text = BLOCK_TITLE + violationMessage;
93
94
  if (ide === 'claude' || ide === 'copilot' || ide === 'opencode') {
94
95
  return JSON.stringify({ decision: 'block', reason: text, systemMessage: text });
95
96
  }
@@ -100,7 +101,7 @@ function blockPayload(ide, violationMessage) {
100
101
  * warning, so the Claude-shaped payload (which carries both) prints the same sentence twice.
101
102
  */
102
103
  function codexBlockPayload(violationMessage) {
103
- return JSON.stringify({ decision: 'block', reason: 'Prompt blocked by Optimus: ' + violationMessage });
104
+ return JSON.stringify({ decision: 'block', reason: BLOCK_TITLE + violationMessage });
104
105
  }
105
106
  function getManifestStalenessMs() {
106
107
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optimuslabs/harness-map-staging",
3
- "version": "1.5.29",
3
+ "version": "1.5.30",
4
4
  "description": "CLI helpers for logging hardware UUIDs and posting startup payloads to Optimus Security.",
5
5
  "type": "module",
6
6
  "bin": {