@optima-chat/dev-skills 0.13.1 → 0.14.0
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/AGENTS.md
CHANGED
|
@@ -14,7 +14,7 @@ Prefer the installed CLI tools over reimplementing long shell workflows:
|
|
|
14
14
|
- `optima-product <create|update|add-channel|toggle-channel|show> [options]` — manage paid-plugin marketplace Products + Stripe channels (Wave 1.5 admin endpoints; stage default)
|
|
15
15
|
- `optima-entitlement <grant|revoke|list> [options]` — admin-grant / revoke / list paid-plugin entitlements (refuses revoke of PAYMENT / PARTNER source)
|
|
16
16
|
- `optima-cn-deploy <service> [--branch feat/xxx] [--no-wait]` — 云效 Flow 发布到 cn-stage(mirror 同步→构建→DB 迁移→SAE 发布→sha 校验;20 服务,凭证由云效变量组供给零配置)
|
|
17
|
-
- `optima-plugin <show|set-paid|set-default> [options]` — flip a plugin's skills-side paid/free state (isPaid) + defaultForUser (the user-facing gate; pairs with optima-product for the billing side)
|
|
17
|
+
- `optima-plugin <show|set-paid|set-default|set-status> [options]` — flip a plugin's skills-side paid/free state (isPaid) + defaultForUser (the user-facing gate; pairs with optima-product for the billing side) + lifecycle status (ACTIVE|BETA|DEPRECATED — retire/restore a marketplace plugin)
|
|
18
18
|
|
|
19
19
|
For code-reading tasks across Optima repositories, use `gh` commands against `Optima-Chat/<repo>`.
|
|
20
20
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { callSkills, validateEnvCnProd } from '../billing-http';
|
|
2
|
+
import { confirmIfProd } from '../confirm-prompt';
|
|
3
|
+
|
|
4
|
+
export const VALID_PLUGIN_STATUSES = ['ACTIVE', 'BETA', 'DEPRECATED'] as const;
|
|
5
|
+
export type PluginStatus = (typeof VALID_PLUGIN_STATUSES)[number];
|
|
6
|
+
|
|
7
|
+
// Aligned with agent-runtime skill-sync-handler's isValidSlug (and the
|
|
8
|
+
// deprecate-plugin workflow guard in optima-default-skills#40).
|
|
9
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
10
|
+
|
|
11
|
+
export interface SetStatusArgs {
|
|
12
|
+
slug: string;
|
|
13
|
+
status: PluginStatus;
|
|
14
|
+
yes: boolean;
|
|
15
|
+
env: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function parseSetStatusArgs(argv: string[]): SetStatusArgs {
|
|
19
|
+
if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
|
|
20
|
+
console.log(`Usage: optima-plugin set-status --slug <slug> --status ACTIVE|BETA|DEPRECATED [options]
|
|
21
|
+
|
|
22
|
+
Required:
|
|
23
|
+
--slug <slug>
|
|
24
|
+
--status <status> Sets Plugin.status (marketplace lifecycle gate).
|
|
25
|
+
DEPRECATED retires the plugin: registry sync stops
|
|
26
|
+
serving it and agents unload it on their next sync
|
|
27
|
+
(in-flight sessions keep it until then). ACTIVE
|
|
28
|
+
restores it. Fully reversible.
|
|
29
|
+
|
|
30
|
+
Optional:
|
|
31
|
+
--yes Skip prod confirmation prompt (no-op on stage)
|
|
32
|
+
--env <env> stage|prod|cn-prod|cn-stage (default: stage)
|
|
33
|
+
|
|
34
|
+
Note: this PATCH's 404 is the authoritative "slug has no marketplace row in
|
|
35
|
+
this env" signal. Don't use 'optima-plugin show' to check existence — it reads
|
|
36
|
+
the public endpoint, which also 404s for non-ACTIVE (e.g. already-DEPRECATED)
|
|
37
|
+
plugins.`);
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
const out: Partial<SetStatusArgs> = { env: 'stage', yes: false };
|
|
41
|
+
for (let i = 0; i < argv.length; i++) {
|
|
42
|
+
const a = argv[i];
|
|
43
|
+
const next = argv[i + 1];
|
|
44
|
+
switch (a) {
|
|
45
|
+
case '--slug': out.slug = next; i++; break;
|
|
46
|
+
case '--status': {
|
|
47
|
+
const upper = (next ?? '').toUpperCase();
|
|
48
|
+
if (!(VALID_PLUGIN_STATUSES as readonly string[]).includes(upper)) {
|
|
49
|
+
throw new Error(`--status must be one of: ${VALID_PLUGIN_STATUSES.join('|')}`);
|
|
50
|
+
}
|
|
51
|
+
out.status = upper as PluginStatus; i++; break;
|
|
52
|
+
}
|
|
53
|
+
case '--yes': out.yes = true; break;
|
|
54
|
+
case '--env': out.env = next; i++; break;
|
|
55
|
+
default: throw new Error(`Unknown arg: ${a}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!out.slug) throw new Error('--slug required');
|
|
59
|
+
if (!SLUG_RE.test(out.slug)) throw new Error(`--slug must match ${SLUG_RE} (lowercase slug, e.g. onboarding-research)`);
|
|
60
|
+
if (!out.status) throw new Error(`--status required (${VALID_PLUGIN_STATUSES.join('|')})`);
|
|
61
|
+
return out as SetStatusArgs;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function runSetStatus(argv: string[]): Promise<void> {
|
|
65
|
+
const args = parseSetStatusArgs(argv);
|
|
66
|
+
validateEnvCnProd(args.env);
|
|
67
|
+
|
|
68
|
+
await confirmIfProd(
|
|
69
|
+
args.env,
|
|
70
|
+
`Action: set status=${args.status} on plugin '${args.slug}' (${args.env.toUpperCase()})`,
|
|
71
|
+
args.yes,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
console.log(`\n🚦 Setting status=${args.status} on ${args.slug} (${args.env.toUpperCase()})...`);
|
|
75
|
+
const res = await callSkills(
|
|
76
|
+
args.env,
|
|
77
|
+
'PATCH',
|
|
78
|
+
`/api/admin/plugins/${encodeURIComponent(args.slug)}`,
|
|
79
|
+
{ status: args.status },
|
|
80
|
+
);
|
|
81
|
+
console.log(`✓ Updated plugin (HTTP ${res.status}):`);
|
|
82
|
+
console.log(JSON.stringify(res.body, null, 2));
|
|
83
|
+
if (args.status === 'DEPRECATED') {
|
|
84
|
+
console.log(`\nℹ️ Takes effect on each user's next skill sync (new session / billing event): registry stops serving the plugin and agents unload its skills. In-flight sessions keep it until then. Restore anytime with --status ACTIVE. Verify retirement end-to-end by confirming an agent session no longer loads the plugin's skills.`);
|
|
85
|
+
} else if (args.status === 'ACTIVE') {
|
|
86
|
+
console.log(`\nℹ️ Plugin restored: registry serves it again on each user's next skill sync.`);
|
|
87
|
+
} else if (args.status === 'BETA') {
|
|
88
|
+
console.log(`\n⚠️ BETA is NOT served either: registry sync / system load / user install all filter status='ACTIVE' (optima-skills internal.ts & user-plugins.ts). Users lose the plugin on their next sync, same as DEPRECATED — it's a pre-GA gate, not a soft-launch channel.`);
|
|
89
|
+
}
|
|
90
|
+
}
|
package/bin/helpers/plugin.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { runShow } from './plugin/show';
|
|
4
4
|
import { runSetPaid } from './plugin/set-paid';
|
|
5
5
|
import { runSetDefault } from './plugin/set-default';
|
|
6
|
+
import { runSetStatus } from './plugin/set-status';
|
|
6
7
|
|
|
7
8
|
function printHelp() {
|
|
8
9
|
console.log(`Usage: optima-plugin <subcommand> [options]
|
|
@@ -11,6 +12,7 @@ Subcommands:
|
|
|
11
12
|
show Show a plugin's marketplace state (isPaid, salesUrl, ... ACTIVE plugins only)
|
|
12
13
|
set-paid Flip a plugin's isPaid flag (the user-facing paid/free gate)
|
|
13
14
|
set-default Flip a plugin's defaultForUser flag
|
|
15
|
+
set-status Set a plugin's lifecycle status (ACTIVE|BETA|DEPRECATED — retire/restore)
|
|
14
16
|
|
|
15
17
|
Run 'optima-plugin <subcommand> --help' for subcommand-specific options.`);
|
|
16
18
|
}
|
|
@@ -22,6 +24,7 @@ async function main() {
|
|
|
22
24
|
case 'show': await runShow(rest); break;
|
|
23
25
|
case 'set-paid': await runSetPaid(rest); break;
|
|
24
26
|
case 'set-default': await runSetDefault(rest); break;
|
|
27
|
+
case 'set-status': await runSetStatus(rest); break;
|
|
25
28
|
default:
|
|
26
29
|
console.error(`Unknown subcommand: ${subcommand}`);
|
|
27
30
|
printHelp();
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VALID_PLUGIN_STATUSES = void 0;
|
|
4
|
+
exports.parseSetStatusArgs = parseSetStatusArgs;
|
|
5
|
+
exports.runSetStatus = runSetStatus;
|
|
6
|
+
const billing_http_1 = require("../billing-http");
|
|
7
|
+
const confirm_prompt_1 = require("../confirm-prompt");
|
|
8
|
+
exports.VALID_PLUGIN_STATUSES = ['ACTIVE', 'BETA', 'DEPRECATED'];
|
|
9
|
+
// Aligned with agent-runtime skill-sync-handler's isValidSlug (and the
|
|
10
|
+
// deprecate-plugin workflow guard in optima-default-skills#40).
|
|
11
|
+
const SLUG_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
12
|
+
function parseSetStatusArgs(argv) {
|
|
13
|
+
if (argv.length === 0 || argv[0] === '-h' || argv[0] === '--help') {
|
|
14
|
+
console.log(`Usage: optima-plugin set-status --slug <slug> --status ACTIVE|BETA|DEPRECATED [options]
|
|
15
|
+
|
|
16
|
+
Required:
|
|
17
|
+
--slug <slug>
|
|
18
|
+
--status <status> Sets Plugin.status (marketplace lifecycle gate).
|
|
19
|
+
DEPRECATED retires the plugin: registry sync stops
|
|
20
|
+
serving it and agents unload it on their next sync
|
|
21
|
+
(in-flight sessions keep it until then). ACTIVE
|
|
22
|
+
restores it. Fully reversible.
|
|
23
|
+
|
|
24
|
+
Optional:
|
|
25
|
+
--yes Skip prod confirmation prompt (no-op on stage)
|
|
26
|
+
--env <env> stage|prod|cn-prod|cn-stage (default: stage)
|
|
27
|
+
|
|
28
|
+
Note: this PATCH's 404 is the authoritative "slug has no marketplace row in
|
|
29
|
+
this env" signal. Don't use 'optima-plugin show' to check existence — it reads
|
|
30
|
+
the public endpoint, which also 404s for non-ACTIVE (e.g. already-DEPRECATED)
|
|
31
|
+
plugins.`);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
const out = { env: 'stage', yes: false };
|
|
35
|
+
for (let i = 0; i < argv.length; i++) {
|
|
36
|
+
const a = argv[i];
|
|
37
|
+
const next = argv[i + 1];
|
|
38
|
+
switch (a) {
|
|
39
|
+
case '--slug':
|
|
40
|
+
out.slug = next;
|
|
41
|
+
i++;
|
|
42
|
+
break;
|
|
43
|
+
case '--status': {
|
|
44
|
+
const upper = (next ?? '').toUpperCase();
|
|
45
|
+
if (!exports.VALID_PLUGIN_STATUSES.includes(upper)) {
|
|
46
|
+
throw new Error(`--status must be one of: ${exports.VALID_PLUGIN_STATUSES.join('|')}`);
|
|
47
|
+
}
|
|
48
|
+
out.status = upper;
|
|
49
|
+
i++;
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case '--yes':
|
|
53
|
+
out.yes = true;
|
|
54
|
+
break;
|
|
55
|
+
case '--env':
|
|
56
|
+
out.env = next;
|
|
57
|
+
i++;
|
|
58
|
+
break;
|
|
59
|
+
default: throw new Error(`Unknown arg: ${a}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (!out.slug)
|
|
63
|
+
throw new Error('--slug required');
|
|
64
|
+
if (!SLUG_RE.test(out.slug))
|
|
65
|
+
throw new Error(`--slug must match ${SLUG_RE} (lowercase slug, e.g. onboarding-research)`);
|
|
66
|
+
if (!out.status)
|
|
67
|
+
throw new Error(`--status required (${exports.VALID_PLUGIN_STATUSES.join('|')})`);
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
async function runSetStatus(argv) {
|
|
71
|
+
const args = parseSetStatusArgs(argv);
|
|
72
|
+
(0, billing_http_1.validateEnvCnProd)(args.env);
|
|
73
|
+
await (0, confirm_prompt_1.confirmIfProd)(args.env, `Action: set status=${args.status} on plugin '${args.slug}' (${args.env.toUpperCase()})`, args.yes);
|
|
74
|
+
console.log(`\n🚦 Setting status=${args.status} on ${args.slug} (${args.env.toUpperCase()})...`);
|
|
75
|
+
const res = await (0, billing_http_1.callSkills)(args.env, 'PATCH', `/api/admin/plugins/${encodeURIComponent(args.slug)}`, { status: args.status });
|
|
76
|
+
console.log(`✓ Updated plugin (HTTP ${res.status}):`);
|
|
77
|
+
console.log(JSON.stringify(res.body, null, 2));
|
|
78
|
+
if (args.status === 'DEPRECATED') {
|
|
79
|
+
console.log(`\nℹ️ Takes effect on each user's next skill sync (new session / billing event): registry stops serving the plugin and agents unload its skills. In-flight sessions keep it until then. Restore anytime with --status ACTIVE. Verify retirement end-to-end by confirming an agent session no longer loads the plugin's skills.`);
|
|
80
|
+
}
|
|
81
|
+
else if (args.status === 'ACTIVE') {
|
|
82
|
+
console.log(`\nℹ️ Plugin restored: registry serves it again on each user's next skill sync.`);
|
|
83
|
+
}
|
|
84
|
+
else if (args.status === 'BETA') {
|
|
85
|
+
console.log(`\n⚠️ BETA is NOT served either: registry sync / system load / user install all filter status='ACTIVE' (optima-skills internal.ts & user-plugins.ts). Users lose the plugin on their next sync, same as DEPRECATED — it's a pre-GA gate, not a soft-launch channel.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const show_1 = require("./plugin/show");
|
|
5
5
|
const set_paid_1 = require("./plugin/set-paid");
|
|
6
6
|
const set_default_1 = require("./plugin/set-default");
|
|
7
|
+
const set_status_1 = require("./plugin/set-status");
|
|
7
8
|
function printHelp() {
|
|
8
9
|
console.log(`Usage: optima-plugin <subcommand> [options]
|
|
9
10
|
|
|
@@ -11,6 +12,7 @@ Subcommands:
|
|
|
11
12
|
show Show a plugin's marketplace state (isPaid, salesUrl, ... ACTIVE plugins only)
|
|
12
13
|
set-paid Flip a plugin's isPaid flag (the user-facing paid/free gate)
|
|
13
14
|
set-default Flip a plugin's defaultForUser flag
|
|
15
|
+
set-status Set a plugin's lifecycle status (ACTIVE|BETA|DEPRECATED — retire/restore)
|
|
14
16
|
|
|
15
17
|
Run 'optima-plugin <subcommand> --help' for subcommand-specific options.`);
|
|
16
18
|
}
|
|
@@ -30,6 +32,9 @@ async function main() {
|
|
|
30
32
|
case 'set-default':
|
|
31
33
|
await (0, set_default_1.runSetDefault)(rest);
|
|
32
34
|
break;
|
|
35
|
+
case 'set-status':
|
|
36
|
+
await (0, set_status_1.runSetStatus)(rest);
|
|
37
|
+
break;
|
|
33
38
|
default:
|
|
34
39
|
console.error(`Unknown subcommand: ${subcommand}`);
|
|
35
40
|
printHelp();
|