@optima-chat/dev-skills 0.16.6 → 0.16.7

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.
@@ -1,12 +1,14 @@
1
1
  import { callBilling, validateEnvCnProd } from '../billing-http';
2
2
  import { confirmIfProd } from '../confirm-prompt';
3
3
  import { resolveTargetUser } from '../grant-subscription';
4
+ import { operatorActorId } from '../operator';
4
5
 
5
6
  interface GrantArgs {
6
7
  identifier: string;
7
8
  productKey: string;
8
9
  justification: string;
9
10
  yes: boolean;
11
+ operator?: string;
10
12
  env: string;
11
13
  }
12
14
 
@@ -21,6 +23,7 @@ Required:
21
23
 
22
24
  Optional:
23
25
  --yes Skip prod/cn-prod confirmation prompt (no-op on stage / cn-stage)
26
+ --operator <name> Operator self-report for billing audit (default: local username)
24
27
  --env stage|prod|cn-prod|cn-stage (default: stage)
25
28
 
26
29
  Hardcoded server-side: source=ADMIN_GRANT, priceCents=0, currency=USD, grantedBy=<clientId>.`);
@@ -35,6 +38,7 @@ Hardcoded server-side: source=ADMIN_GRANT, priceCents=0, currency=USD, grantedBy
35
38
  case '--product-key': out.productKey = next; i++; break;
36
39
  case '--justification': out.justification = next; i++; break;
37
40
  case '--yes': out.yes = true; break;
41
+ case '--operator': out.operator = next; i++; break;
38
42
  case '--env': out.env = next; i++; break;
39
43
  default:
40
44
  if (a.startsWith('--')) throw new Error(`Unknown arg: ${a}`);
@@ -67,6 +71,7 @@ export async function runGrant(argv: string[]): Promise<void> {
67
71
  userId,
68
72
  productKey: args.productKey,
69
73
  justification: args.justification,
74
+ actorUserId: operatorActorId(args.operator ?? null),
70
75
  });
71
76
  console.log(`✓ Granted entitlement (HTTP ${res.status}):`);
72
77
  console.log(JSON.stringify(res.body, null, 2));
@@ -1,12 +1,14 @@
1
1
  import { callBilling, validateEnvCnProd } from '../billing-http';
2
2
  import { confirmIfProd } from '../confirm-prompt';
3
3
  import { resolveTargetUser } from '../grant-subscription';
4
+ import { operatorActorId } from '../operator';
4
5
 
5
6
  interface RevokeArgs {
6
7
  identifier: string;
7
8
  productKey: string;
8
9
  reason: string;
9
10
  yes: boolean;
11
+ operator?: string;
10
12
  env: string;
11
13
  }
12
14
 
@@ -28,6 +30,7 @@ Required:
28
30
 
29
31
  Optional:
30
32
  --yes Skip prod/cn-prod confirmation prompt (no-op on stage / cn-stage)
33
+ --operator <name> Operator self-report for billing audit (default: local username)
31
34
  --env stage|prod|cn-prod|cn-stage (default: stage)
32
35
 
33
36
  Refuses non-ADMIN_GRANT sources (PAYMENT, PARTNER) with source-specific
@@ -43,6 +46,7 @@ error pointing to the right reversal flow.`);
43
46
  case '--product-key': out.productKey = next; i++; break;
44
47
  case '--reason': out.reason = next; i++; break;
45
48
  case '--yes': out.yes = true; break;
49
+ case '--operator': out.operator = next; i++; break;
46
50
  case '--env': out.env = next; i++; break;
47
51
  default:
48
52
  if (a.startsWith('--')) throw new Error(`Unknown arg: ${a}`);
@@ -111,6 +115,7 @@ export async function runRevoke(argv: string[]): Promise<void> {
111
115
  entitlementId: target.id,
112
116
  refundReason: args.reason,
113
117
  refundAmountCents: 0,
118
+ actorUserId: operatorActorId(args.operator ?? null),
114
119
  });
115
120
  console.log(`✓ Revoked entitlement (HTTP ${res.status}):`);
116
121
  console.log(JSON.stringify(res.body, null, 2));
@@ -10,6 +10,7 @@
10
10
  import { basename } from 'path';
11
11
  import { randomUUID } from 'crypto';
12
12
  import { callBilling, validateEnvCnProd } from './billing-http';
13
+ import { operatorActorId } from './operator';
13
14
  import { resolveTargetUser } from './grant-subscription';
14
15
 
15
16
  const CREDITS_PER_USD = 700;
@@ -19,6 +20,7 @@ interface Parsed {
19
20
  credits: number | null;
20
21
  amountUsd: number | null;
21
22
  description: string | null;
23
+ operator: string | null;
22
24
  env: string;
23
25
  }
24
26
 
@@ -36,6 +38,7 @@ Options:
36
38
  --credits <n> Credits to grant (integer >= 1). Primary unit.
37
39
  --amount <usd> Alt: grant by USD ($1 = ${CREDITS_PER_USD} credits). Provide exactly one of --credits / --amount.
38
40
  --description <text> Description for audit trail (optional)
41
+ --operator <name> Operator self-report for billing audit (default: local username)
39
42
  --env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
40
43
  -h, --help Show this help
41
44
 
@@ -50,12 +53,14 @@ Examples:
50
53
  let credits: number | null = null;
51
54
  let amountUsd: number | null = null;
52
55
  let description: string | null = null;
56
+ let operator: string | null = null;
53
57
  let env = 'stage';
54
58
 
55
59
  for (let i = 1; i < args.length; i++) {
56
60
  if (args[i] === '--credits' && args[i + 1]) { credits = parseInt(args[++i], 10); }
57
61
  else if (args[i] === '--amount' && args[i + 1]) { amountUsd = parseFloat(args[++i]); }
58
62
  else if (args[i] === '--description' && args[i + 1]) { description = args[++i]; }
63
+ else if (args[i] === '--operator' && args[i + 1]) { operator = args[++i]; }
59
64
  else if (args[i] === '--env' && args[i + 1]) { env = args[++i]; }
60
65
  }
61
66
 
@@ -74,7 +79,7 @@ Examples:
74
79
  }
75
80
  validateEnvCnProd(env);
76
81
 
77
- return { identifier, credits, amountUsd, description, env };
82
+ return { identifier, credits, amountUsd, description, operator, env };
78
83
  }
79
84
 
80
85
  async function main() {
@@ -83,7 +88,7 @@ async function main() {
83
88
  console.warn('⚠️ optima-grant-balance 已更名为 optima-grant-credits(P15 钱包退役后回归积分)。请改用 `optima-grant-credits --credits <n>`;本别名仍可用,后续弃用。\n');
84
89
  }
85
90
 
86
- const { identifier, credits, amountUsd, description, env } = parseArgs(process.argv.slice(2));
91
+ const { identifier, credits, amountUsd, description, operator, env } = parseArgs(process.argv.slice(2));
87
92
 
88
93
  const creditsDisplay = credits ?? Math.round((amountUsd as number) * CREDITS_PER_USD);
89
94
  console.log(`\n🎁 Granting ${creditsDisplay} credits${amountUsd !== null ? ` ($${amountUsd.toFixed(2)})` : ''} to ${identifier} [${env.toUpperCase()}]\n`);
@@ -105,6 +110,7 @@ async function main() {
105
110
  userId,
106
111
  ...amountField,
107
112
  description: description ?? undefined,
113
+ actorUserId: operatorActorId(operator),
108
114
  idempotencyKey: `dev-skills-grant:${randomUUID()}`,
109
115
  },
110
116
  );
@@ -11,6 +11,7 @@ import {
11
11
  getUserById,
12
12
  validateEnvCnProd,
13
13
  } from './billing-http';
14
+ import { operatorActorId } from './operator';
14
15
 
15
16
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
16
17
 
@@ -76,7 +77,7 @@ const PLANS_BY_ENV: Record<string, string[]> = {
76
77
  'cn-stage': ['trial', 'starter', 'pro', 'enterprise', 'free'],
77
78
  };
78
79
 
79
- function parseArgs(args: string[]): { identifier: string; plan: string; months: number; env: string } {
80
+ function parseArgs(args: string[]): { identifier: string; plan: string; months: number; operator: string | null; env: string } {
80
81
  if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
81
82
  console.log(`Usage: optima-grant-subscription <email|phone|userId> [options]
82
83
 
@@ -85,6 +86,7 @@ Options:
85
86
  cn-prod/cn-stage additionally allow: free
86
87
  (legacy *-cn ids are accepted and normalized to canonical)
87
88
  --months <n> Duration in months (default: 1)
89
+ --operator <name> Operator self-report for billing audit (default: local username)
88
90
  --env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
89
91
  -h, --help Show this help`);
90
92
  process.exit(0);
@@ -93,11 +95,13 @@ Options:
93
95
  const identifier = args[0];
94
96
  let plan: string | null = null;
95
97
  let months = 1;
98
+ let operator: string | null = null;
96
99
  let env = 'stage';
97
100
 
98
101
  for (let i = 1; i < args.length; i++) {
99
102
  if (args[i] === '--plan' && args[i + 1]) { plan = args[++i]; }
100
103
  else if (args[i] === '--months' && args[i + 1]) { months = parseInt(args[++i], 10); }
104
+ else if (args[i] === '--operator' && args[i + 1]) { operator = args[++i]; }
101
105
  else if (args[i] === '--env' && args[i + 1]) { env = args[++i]; }
102
106
  }
103
107
 
@@ -113,7 +117,7 @@ Options:
113
117
  }
114
118
  if (months < 1) { console.error('Months must be >= 1'); process.exit(1); }
115
119
 
116
- return { identifier, plan, months, env };
120
+ return { identifier, plan, months, operator, env };
117
121
  }
118
122
 
119
123
  /**
@@ -181,7 +185,7 @@ export async function resolveTargetUser(
181
185
  }
182
186
 
183
187
  async function main() {
184
- const { identifier, plan, months, env } = parseArgs(process.argv.slice(2));
188
+ const { identifier, plan, months, operator, env } = parseArgs(process.argv.slice(2));
185
189
 
186
190
  console.log(`\n🎁 Granting ${plan} subscription to ${identifier} (${classifyIdentifier(identifier)}) for ${months} month(s) [${env.toUpperCase()}]\n`);
187
191
 
@@ -198,7 +202,7 @@ async function main() {
198
202
  weeklyTokenLimit: number;
199
203
  expiresAt: string;
200
204
  warning?: string;
201
- }>(env, 'POST', '/api/billing/admin/grant-subscription', { userId, planId: plan, months });
205
+ }>(env, 'POST', '/api/billing/admin/grant-subscription', { userId, planId: plan, months, actorUserId: operatorActorId(operator) });
202
206
 
203
207
  console.log(`✓ Subscription ${body.subscriptionId} (${body.planId})`);
204
208
  console.log(`✓ Credits: ${body.credits.toLocaleString()} (expires ${body.expiresAt})`);
@@ -0,0 +1,9 @@
1
+ import { userInfo } from 'os';
2
+
3
+ // #429(Owner 拍板 3):CLI 发放族自报操作者——informational,billing 信任 allowlist client
4
+ // 自述(actor 不参与授权);不带 --operator 时回退本机用户名。缺省链最终兜底在 billing
5
+ // 侧(channel=client_id)。格式:dev-skills:<name>。
6
+ export function operatorActorId(operatorFlag?: string | null): string {
7
+ const name = (operatorFlag ?? '').trim() || userInfo().username;
8
+ return `dev-skills:${name}`;
9
+ }
@@ -4,6 +4,7 @@ exports.runGrant = runGrant;
4
4
  const billing_http_1 = require("../billing-http");
5
5
  const confirm_prompt_1 = require("../confirm-prompt");
6
6
  const grant_subscription_1 = require("../grant-subscription");
7
+ const operator_1 = require("../operator");
7
8
  function parseArgs(argv) {
8
9
  if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
9
10
  console.log(`Usage: optima-entitlement grant <email|phone|userId> --product-key <slug> --justification "..." [options]
@@ -15,6 +16,7 @@ Required:
15
16
 
16
17
  Optional:
17
18
  --yes Skip prod/cn-prod confirmation prompt (no-op on stage / cn-stage)
19
+ --operator <name> Operator self-report for billing audit (default: local username)
18
20
  --env stage|prod|cn-prod|cn-stage (default: stage)
19
21
 
20
22
  Hardcoded server-side: source=ADMIN_GRANT, priceCents=0, currency=USD, grantedBy=<clientId>.`);
@@ -40,6 +42,10 @@ Hardcoded server-side: source=ADMIN_GRANT, priceCents=0, currency=USD, grantedBy
40
42
  case '--yes':
41
43
  out.yes = true;
42
44
  break;
45
+ case '--operator':
46
+ out.operator = next;
47
+ i++;
48
+ break;
43
49
  case '--env':
44
50
  out.env = next;
45
51
  i++;
@@ -72,6 +78,7 @@ async function runGrant(argv) {
72
78
  userId,
73
79
  productKey: args.productKey,
74
80
  justification: args.justification,
81
+ actorUserId: (0, operator_1.operatorActorId)(args.operator ?? null),
75
82
  });
76
83
  console.log(`✓ Granted entitlement (HTTP ${res.status}):`);
77
84
  console.log(JSON.stringify(res.body, null, 2));
@@ -4,6 +4,7 @@ exports.runRevoke = runRevoke;
4
4
  const billing_http_1 = require("../billing-http");
5
5
  const confirm_prompt_1 = require("../confirm-prompt");
6
6
  const grant_subscription_1 = require("../grant-subscription");
7
+ const operator_1 = require("../operator");
7
8
  function parseArgs(argv) {
8
9
  if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
9
10
  console.log(`Usage: optima-entitlement revoke <email|phone|userId> --product-key <slug> --reason "..." [options]
@@ -15,6 +16,7 @@ Required:
15
16
 
16
17
  Optional:
17
18
  --yes Skip prod/cn-prod confirmation prompt (no-op on stage / cn-stage)
19
+ --operator <name> Operator self-report for billing audit (default: local username)
18
20
  --env stage|prod|cn-prod|cn-stage (default: stage)
19
21
 
20
22
  Refuses non-ADMIN_GRANT sources (PAYMENT, PARTNER) with source-specific
@@ -41,6 +43,10 @@ error pointing to the right reversal flow.`);
41
43
  case '--yes':
42
44
  out.yes = true;
43
45
  break;
46
+ case '--operator':
47
+ out.operator = next;
48
+ i++;
49
+ break;
44
50
  case '--env':
45
51
  out.env = next;
46
52
  i++;
@@ -102,6 +108,7 @@ async function runRevoke(argv) {
102
108
  entitlementId: target.id,
103
109
  refundReason: args.reason,
104
110
  refundAmountCents: 0,
111
+ actorUserId: (0, operator_1.operatorActorId)(args.operator ?? null),
105
112
  });
106
113
  console.log(`✓ Revoked entitlement (HTTP ${res.status}):`);
107
114
  console.log(JSON.stringify(res.body, null, 2));
@@ -11,6 +11,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
11
11
  const path_1 = require("path");
12
12
  const crypto_1 = require("crypto");
13
13
  const billing_http_1 = require("./billing-http");
14
+ const operator_1 = require("./operator");
14
15
  const grant_subscription_1 = require("./grant-subscription");
15
16
  const CREDITS_PER_USD = 700;
16
17
  function parseArgs(args) {
@@ -27,6 +28,7 @@ Options:
27
28
  --credits <n> Credits to grant (integer >= 1). Primary unit.
28
29
  --amount <usd> Alt: grant by USD ($1 = ${CREDITS_PER_USD} credits). Provide exactly one of --credits / --amount.
29
30
  --description <text> Description for audit trail (optional)
31
+ --operator <name> Operator self-report for billing audit (default: local username)
30
32
  --env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
31
33
  -h, --help Show this help
32
34
 
@@ -40,6 +42,7 @@ Examples:
40
42
  let credits = null;
41
43
  let amountUsd = null;
42
44
  let description = null;
45
+ let operator = null;
43
46
  let env = 'stage';
44
47
  for (let i = 1; i < args.length; i++) {
45
48
  if (args[i] === '--credits' && args[i + 1]) {
@@ -51,6 +54,9 @@ Examples:
51
54
  else if (args[i] === '--description' && args[i + 1]) {
52
55
  description = args[++i];
53
56
  }
57
+ else if (args[i] === '--operator' && args[i + 1]) {
58
+ operator = args[++i];
59
+ }
54
60
  else if (args[i] === '--env' && args[i + 1]) {
55
61
  env = args[++i];
56
62
  }
@@ -69,14 +75,14 @@ Examples:
69
75
  process.exit(1);
70
76
  }
71
77
  (0, billing_http_1.validateEnvCnProd)(env);
72
- return { identifier, credits, amountUsd, description, env };
78
+ return { identifier, credits, amountUsd, description, operator, env };
73
79
  }
74
80
  async function main() {
75
81
  // Deprecation notice when invoked via the legacy alias `optima-grant-balance`.
76
82
  if ((0, path_1.basename)(process.argv[1] || '').includes('grant-balance')) {
77
83
  console.warn('⚠️ optima-grant-balance 已更名为 optima-grant-credits(P15 钱包退役后回归积分)。请改用 `optima-grant-credits --credits <n>`;本别名仍可用,后续弃用。\n');
78
84
  }
79
- const { identifier, credits, amountUsd, description, env } = parseArgs(process.argv.slice(2));
85
+ const { identifier, credits, amountUsd, description, operator, env } = parseArgs(process.argv.slice(2));
80
86
  const creditsDisplay = credits ?? Math.round(amountUsd * CREDITS_PER_USD);
81
87
  console.log(`\n🎁 Granting ${creditsDisplay} credits${amountUsd !== null ? ` ($${amountUsd.toFixed(2)})` : ''} to ${identifier} [${env.toUpperCase()}]\n`);
82
88
  if (description)
@@ -93,6 +99,7 @@ async function main() {
93
99
  userId,
94
100
  ...amountField,
95
101
  description: description ?? undefined,
102
+ actorUserId: (0, operator_1.operatorActorId)(operator),
96
103
  idempotencyKey: `dev-skills-grant:${(0, crypto_1.randomUUID)()}`,
97
104
  });
98
105
  console.log(`✓ Granted ${body.credits} credits (lot ${body.lotId})`);
@@ -10,6 +10,7 @@ exports.resolveTargetUser = resolveTargetUser;
10
10
  // 业务体:supersede 旧授予 + 实得 credits + token quota,重试双发不双倍)。
11
11
  const db_utils_1 = require("./db-utils");
12
12
  const billing_http_1 = require("./billing-http");
13
+ const operator_1 = require("./operator");
13
14
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14
15
  /**
15
16
  * Auto-detect what kind of identifier the operator passed. gateway#923: a
@@ -79,6 +80,7 @@ Options:
79
80
  cn-prod/cn-stage additionally allow: free
80
81
  (legacy *-cn ids are accepted and normalized to canonical)
81
82
  --months <n> Duration in months (default: 1)
83
+ --operator <name> Operator self-report for billing audit (default: local username)
82
84
  --env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
83
85
  -h, --help Show this help`);
84
86
  process.exit(0);
@@ -86,6 +88,7 @@ Options:
86
88
  const identifier = args[0];
87
89
  let plan = null;
88
90
  let months = 1;
91
+ let operator = null;
89
92
  let env = 'stage';
90
93
  for (let i = 1; i < args.length; i++) {
91
94
  if (args[i] === '--plan' && args[i + 1]) {
@@ -94,6 +97,9 @@ Options:
94
97
  else if (args[i] === '--months' && args[i + 1]) {
95
98
  months = parseInt(args[++i], 10);
96
99
  }
100
+ else if (args[i] === '--operator' && args[i + 1]) {
101
+ operator = args[++i];
102
+ }
97
103
  else if (args[i] === '--env' && args[i + 1]) {
98
104
  env = args[++i];
99
105
  }
@@ -112,7 +118,7 @@ Options:
112
118
  console.error('Months must be >= 1');
113
119
  process.exit(1);
114
120
  }
115
- return { identifier, plan, months, env };
121
+ return { identifier, plan, months, operator, env };
116
122
  }
117
123
  /**
118
124
  * Resolve a CLI identifier (`<email|phone|userId>`) to a userId + verified
@@ -167,12 +173,12 @@ async function resolveTargetUser(env, identifier) {
167
173
  return { userId, kind, identity: { phone: null, email: identifier } };
168
174
  }
169
175
  async function main() {
170
- const { identifier, plan, months, env } = parseArgs(process.argv.slice(2));
176
+ const { identifier, plan, months, operator, env } = parseArgs(process.argv.slice(2));
171
177
  console.log(`\n🎁 Granting ${plan} subscription to ${identifier} (${classifyIdentifier(identifier)}) for ${months} month(s) [${env.toUpperCase()}]\n`);
172
178
  // Shared resolver: classify → resolve → reverse-verify echo → phone-assert
173
179
  // (cn-prod/cn-stage), or email-only via SSH tunnel (AWS). See resolveTargetUser.
174
180
  const { userId, identity } = await resolveTargetUser(env, identifier);
175
- const { body } = await (0, billing_http_1.callBilling)(env, 'POST', '/api/billing/admin/grant-subscription', { userId, planId: plan, months });
181
+ const { body } = await (0, billing_http_1.callBilling)(env, 'POST', '/api/billing/admin/grant-subscription', { userId, planId: plan, months, actorUserId: (0, operator_1.operatorActorId)(operator) });
176
182
  console.log(`✓ Subscription ${body.subscriptionId} (${body.planId})`);
177
183
  console.log(`✓ Credits: ${body.credits.toLocaleString()} (expires ${body.expiresAt})`);
178
184
  console.log(`✓ Token limits: session ${body.sessionTokenLimit.toLocaleString()} / weekly ${body.weeklyTokenLimit.toLocaleString()}`);
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.operatorActorId = operatorActorId;
4
+ const os_1 = require("os");
5
+ // #429(Owner 拍板 3):CLI 发放族自报操作者——informational,billing 信任 allowlist client
6
+ // 自述(actor 不参与授权);不带 --operator 时回退本机用户名。缺省链最终兜底在 billing
7
+ // 侧(channel=client_id)。格式:dev-skills:<name>。
8
+ function operatorActorId(operatorFlag) {
9
+ const name = (operatorFlag ?? '').trim() || (0, os_1.userInfo)().username;
10
+ return `dev-skills:${name}`;
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/dev-skills",
3
- "version": "0.16.6",
3
+ "version": "0.16.7",
4
4
  "description": "Claude Code Skills for Optima development team - cross-environment collaboration tools",
5
5
  "main": "index.js",
6
6
  "bin": {