@302ai/media-studio-cli 0.1.0 → 0.1.1-beta.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/README.md +22 -8
- package/dist/index.js +353 -51
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,10 +42,12 @@ name:
|
|
|
42
42
|
```bash
|
|
43
43
|
msc chat "画一只猫" -r # -r/--show-reasoning = 展示模型推理过程
|
|
44
44
|
msc chat "hi" --json # machine-readable output
|
|
45
|
-
msc chat "hi" --session <id> #
|
|
45
|
+
msc chat "hi" --session <id> # 切换到已有会话(先校验存在)并设为默认
|
|
46
|
+
msc chat "hi" --new # 新建会话并设为默认(id 不复用)
|
|
46
47
|
msc sessions # 列出所有会话(标记当前默认 `(current)`)
|
|
47
48
|
msc sessions --json # 机器可读的原始 JSON 数组
|
|
48
|
-
msc sessions use <id> #
|
|
49
|
+
msc sessions use <id> # 校验存在后切换默认会话
|
|
50
|
+
msc sessions use --new # 新建会话并设为默认
|
|
49
51
|
msc skills # 列出技能库(--plaza 浏览技能广场)
|
|
50
52
|
msc skills add <slug> # 从广场安装技能(如 brainstorming,见 --plaza --json 的 slug)
|
|
51
53
|
msc skills rm <command> # 从技能库移除(-y/--yes 跳过确认)
|
|
@@ -79,10 +81,20 @@ whose browser can reach the loopback callback.
|
|
|
79
81
|
loses a live session.
|
|
80
82
|
- **Later chats** continue that session — upstream remembers the
|
|
81
83
|
conversation by session id, so no history is resent.
|
|
82
|
-
- If the session
|
|
83
|
-
fresh one and
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
- If the current session is gone **before a turn produces any output**, the CLI
|
|
85
|
+
transparently provisions a fresh one and re-runs the turn — a first-turn
|
|
86
|
+
failure never strands you.
|
|
87
|
+
- Once a turn has started producing output, a session failure is reported
|
|
88
|
+
instead: the partial result stands, nothing is re-run, and no replacement
|
|
89
|
+
session is created (a retry would replay output and re-dispatch tool calls or
|
|
90
|
+
generation tasks the first attempt may already have started).
|
|
91
|
+
- `--session <id>` switches to an existing session (including web-created
|
|
92
|
+
ones) and makes it the default. The id is verified upstream first: a missing
|
|
93
|
+
id fails with a hint, it never provisions a different session behind your
|
|
94
|
+
back.
|
|
95
|
+
- `--new` creates a fresh session with a newly generated id and makes it the
|
|
96
|
+
default for later runs. Ids are never reused or adopted: the CLI either uses
|
|
97
|
+
the id it generated or reports the refusal.
|
|
86
98
|
|
|
87
99
|
Manual proof of continuity:
|
|
88
100
|
|
|
@@ -317,8 +329,10 @@ msc chat "刚才的数字是几?" # answers 42
|
|
|
317
329
|
|
|
318
330
|
# Session management verification:
|
|
319
331
|
msc sessions # shows session list with (current) marker
|
|
320
|
-
msc chat "hi" --session <id> # switch to
|
|
321
|
-
msc
|
|
332
|
+
msc chat "hi" --session <id> # switch to an existing session
|
|
333
|
+
msc chat "hi" --new # start a new session
|
|
334
|
+
msc sessions use <id> # switch default pointer to an existing session
|
|
335
|
+
msc sessions use --new # create a new session and switch to it
|
|
322
336
|
```
|
|
323
337
|
|
|
324
338
|
Without the local server, point at production with
|
package/dist/index.js
CHANGED
|
@@ -4284,7 +4284,7 @@ var consola = createConsola2();
|
|
|
4284
4284
|
// package.json
|
|
4285
4285
|
var package_default = {
|
|
4286
4286
|
name: "@302ai/media-studio-cli",
|
|
4287
|
-
version: "0.1.0",
|
|
4287
|
+
version: "0.1.1-beta.0",
|
|
4288
4288
|
description: "CLI for AI Media Studio — let external agents drive the core media-studio features",
|
|
4289
4289
|
author: "302.AI",
|
|
4290
4290
|
license: "Apache-2.0",
|
|
@@ -9749,6 +9749,151 @@ function isString(value) {
|
|
|
9749
9749
|
return typeof value === "string";
|
|
9750
9750
|
}
|
|
9751
9751
|
// ../media-studio-contract/src/err-codes.ts
|
|
9752
|
+
var ErrCode = {
|
|
9753
|
+
MISSING_REQUIRED_PARAM: 10001,
|
|
9754
|
+
INVALID_PARAM_FORMAT: 10002,
|
|
9755
|
+
RESOURCE_NOT_FOUND: 10003,
|
|
9756
|
+
METHOD_NOT_ALLOWED: 10004,
|
|
9757
|
+
RATE_LIMITED: 10005,
|
|
9758
|
+
PAYLOAD_TOO_LARGE: 10006,
|
|
9759
|
+
UNSUPPORTED_MEDIA_TYPE: 10007,
|
|
9760
|
+
INTERNAL_ERROR: 10500,
|
|
9761
|
+
DEPENDENCY_UNAVAILABLE: 10501,
|
|
9762
|
+
DATABASE_ERROR: 10502,
|
|
9763
|
+
SERVICE_UNAVAILABLE: 10503,
|
|
9764
|
+
CACHE_UNAVAILABLE: 10504,
|
|
9765
|
+
UNAUTHORIZED: 20001,
|
|
9766
|
+
TOKEN_MISSING: 20002,
|
|
9767
|
+
TOKEN_INVALID: 20003,
|
|
9768
|
+
TOKEN_EXPIRED: 20004,
|
|
9769
|
+
TOKEN_REVOKED: 20005,
|
|
9770
|
+
REFRESH_TOKEN_INVALID: 20006,
|
|
9771
|
+
REFRESH_TOKEN_ROTATED: 20007,
|
|
9772
|
+
VERIFICATION_CODE_INVALID: 20101,
|
|
9773
|
+
VERIFICATION_CODE_EXPIRED: 20102,
|
|
9774
|
+
CODE_SEND_RATE_LIMITED: 20103,
|
|
9775
|
+
CODE_SEND_DAILY_LIMIT: 20104,
|
|
9776
|
+
EMAIL_SEND_FAILED: 20105,
|
|
9777
|
+
EMAIL_ALREADY_REGISTERED: 20106,
|
|
9778
|
+
EMAIL_NOT_REGISTERED: 20107,
|
|
9779
|
+
OAUTH_STATE_INVALID: 20201,
|
|
9780
|
+
OAUTH_CALLBACK_FAILED: 20202,
|
|
9781
|
+
OAUTH_ACCOUNT_ALREADY_BOUND: 20203,
|
|
9782
|
+
SSO_INFO_CONFLICT: 20204,
|
|
9783
|
+
FORBIDDEN: 20301,
|
|
9784
|
+
ADMIN_REQUIRED: 20302,
|
|
9785
|
+
ACCOUNT_DEACTIVATED: 20303,
|
|
9786
|
+
INSUFFICIENT_BALANCE: 30001,
|
|
9787
|
+
CREDIT_FREEZE_FAILED: 30002,
|
|
9788
|
+
FREEZE_RECORD_NOT_FOUND: 30003,
|
|
9789
|
+
FREEZE_ALREADY_SETTLED: 30004,
|
|
9790
|
+
CREDIT_SETTLE_FAILED: 30005,
|
|
9791
|
+
SETTLE_EXCEEDS_FREEZE: 30006,
|
|
9792
|
+
UNFREEZE_FAILED: 30007,
|
|
9793
|
+
CREDIT_BATCH_EXPIRED: 30008,
|
|
9794
|
+
CREDIT_BATCH_NOT_FOUND: 30009,
|
|
9795
|
+
CONCURRENT_MODIFICATION: 30010,
|
|
9796
|
+
PRICING_RULE_NOT_FOUND: 30101,
|
|
9797
|
+
MODEL_PRICE_MISSING: 30102,
|
|
9798
|
+
USAGE_RECORD_DUPLICATED: 30103,
|
|
9799
|
+
BALANCE_CACHE_REBUILD_FAILED: 30104,
|
|
9800
|
+
LEDGER_WRITE_FAILED: 30105,
|
|
9801
|
+
UPSTREAM_ERROR: 40001,
|
|
9802
|
+
UPSTREAM_TIMEOUT: 40002,
|
|
9803
|
+
UPSTREAM_RATE_LIMITED: 40003,
|
|
9804
|
+
UPSTREAM_UNAVAILABLE: 40004,
|
|
9805
|
+
UPSTREAM_AUTH_FAILED: 40005,
|
|
9806
|
+
UPSTREAM_DATA_INVALID: 40006,
|
|
9807
|
+
MODEL_UNSUPPORTED: 40101,
|
|
9808
|
+
MODEL_LABEL_INVALID: 40102,
|
|
9809
|
+
MODEL_PRICE_NOT_CONFIGURED: 40103,
|
|
9810
|
+
MODEL_LABEL_DEPRECATED: 40104,
|
|
9811
|
+
SANDBOX_TOKEN_INVALID: 40201,
|
|
9812
|
+
SANDBOX_TOKEN_EXPIRED: 40202,
|
|
9813
|
+
OSS_TRANSFER_FAILED: 40301,
|
|
9814
|
+
OSS_URL_PRESIGN_FAILED: 40302,
|
|
9815
|
+
PLAN_NOT_FOUND: 50001,
|
|
9816
|
+
PLAN_UNAVAILABLE: 50002,
|
|
9817
|
+
PLAN_PRICE_MISSING: 50003,
|
|
9818
|
+
ORDER_NOT_FOUND: 50101,
|
|
9819
|
+
ORDER_ALREADY_PAID: 50102,
|
|
9820
|
+
ORDER_EXPIRED: 50103,
|
|
9821
|
+
ORDER_AMOUNT_MISMATCH: 50104,
|
|
9822
|
+
ORDER_STATUS_NOT_ALLOWED: 50105,
|
|
9823
|
+
ORDER_CANCEL_FAILED: 50106,
|
|
9824
|
+
ORDER_PENDING_EXISTS: 50107,
|
|
9825
|
+
PAYMENT_FAILED: 50201,
|
|
9826
|
+
PAYMENT_REJECTED: 50202,
|
|
9827
|
+
PAYMENT_METHOD_NOT_FOUND: 50203,
|
|
9828
|
+
WEBHOOK_SIGNATURE_INVALID: 50204,
|
|
9829
|
+
WEBHOOK_EVENT_UNKNOWN: 50205,
|
|
9830
|
+
STRIPE_API_ERROR: 50206,
|
|
9831
|
+
SUBSCRIPTION_NOT_FOUND: 50301,
|
|
9832
|
+
SUBSCRIPTION_STATUS_NOT_ALLOWED: 50302,
|
|
9833
|
+
SUBSCRIPTION_CANCELED: 50303,
|
|
9834
|
+
UPGRADE_PRORATION_FAILED: 50304,
|
|
9835
|
+
DOWNGRADE_NOT_ALLOWED: 50305,
|
|
9836
|
+
AUTO_RENEW_FAILED: 50306,
|
|
9837
|
+
SAVED_CARD_INVALID: 50307,
|
|
9838
|
+
REFUND_NOT_ELIGIBLE: 50401,
|
|
9839
|
+
REFUND_WINDOW_EXPIRED: 50402,
|
|
9840
|
+
REFUND_THRESHOLD_EXCEEDED: 50403,
|
|
9841
|
+
REFUND_FAILED: 50404,
|
|
9842
|
+
TOPUP_SUBSCRIPTION_ONLY: 50501,
|
|
9843
|
+
TOPUP_FROZEN: 50502,
|
|
9844
|
+
TOPUP_NOT_FOUND: 50503,
|
|
9845
|
+
SESSION_NOT_FOUND: 60001,
|
|
9846
|
+
SESSION_ALREADY_EXISTS: 60002,
|
|
9847
|
+
SESSION_STATUS_NOT_ALLOWED: 60003,
|
|
9848
|
+
CHAT_SESSION_EXPIRED: 60004,
|
|
9849
|
+
CHAT_CONTEXT_MISSING: 60005,
|
|
9850
|
+
PROMPT_SUGGESTION_FAILED: 60006,
|
|
9851
|
+
TITLE_GENERATION_FAILED: 60007,
|
|
9852
|
+
CHAT_TASK_NOT_FOUND: 60101,
|
|
9853
|
+
CHAT_TASK_IN_PROGRESS: 60102,
|
|
9854
|
+
CHAT_TASK_CANCELED: 60103,
|
|
9855
|
+
CHAT_TASK_STATUS_NOT_ALLOWED: 60104,
|
|
9856
|
+
SANDBOX_CREATE_FAILED: 60201,
|
|
9857
|
+
SANDBOX_WARMUP_FAILED: 60202,
|
|
9858
|
+
SANDBOX_TIMEOUT: 60203,
|
|
9859
|
+
SANDBOX_UNAVAILABLE: 60204,
|
|
9860
|
+
SANDBOX_COMMAND_FAILED: 60205,
|
|
9861
|
+
SKILL_NOT_FOUND: 60301,
|
|
9862
|
+
SKILL_FILE_INVALID: 60302,
|
|
9863
|
+
SKILL_BUILTIN_IMMUTABLE: 60303,
|
|
9864
|
+
SKILL_UPLOAD_INVALID: 60304,
|
|
9865
|
+
ASSET_NOT_FOUND: 70001,
|
|
9866
|
+
ASSET_GROUP_NOT_FOUND: 70002,
|
|
9867
|
+
ASSET_GROUP_NAME_EXISTS: 70003,
|
|
9868
|
+
ASSET_UPLOAD_FAILED: 70004,
|
|
9869
|
+
ASSET_TOO_LARGE: 70005,
|
|
9870
|
+
ASSET_TYPE_NOT_ALLOWED: 70006,
|
|
9871
|
+
ASSET_GROUP_INVALID: 70007,
|
|
9872
|
+
OSS_UPLOAD_FAILED: 70101,
|
|
9873
|
+
OSS_DOWNLOAD_FAILED: 70102,
|
|
9874
|
+
COVER_UPLOAD_FAILED: 70103,
|
|
9875
|
+
OSS_DELETE_FAILED: 70104,
|
|
9876
|
+
FILE_NOT_FOUND: 70201,
|
|
9877
|
+
FILE_READ_FAILED: 70202,
|
|
9878
|
+
FILE_WRITE_FAILED: 70203,
|
|
9879
|
+
FILE_FORMAT_INVALID: 70204,
|
|
9880
|
+
FILE_FORMAT_TEXT_FILE_ONLY: 70205,
|
|
9881
|
+
FILE_OPERATION_INVALID: 70206,
|
|
9882
|
+
FILE_TARGET_PATH_REQUIRED: 70207,
|
|
9883
|
+
FILE_PATH_COUNT_MISMATCH: 70208,
|
|
9884
|
+
FILE_RENAME_BATCH_UNSUPPORTED: 70209,
|
|
9885
|
+
ADMIN_NOT_LOGGED_IN: 90001,
|
|
9886
|
+
ADMIN_2FA_REQUIRED: 90002,
|
|
9887
|
+
ADMIN_2FA_CODE_INVALID: 90003,
|
|
9888
|
+
ADMIN_2FA_RATE_LIMITED: 90004,
|
|
9889
|
+
ADMIN_FORBIDDEN: 90005,
|
|
9890
|
+
ADMIN_NOT_FOUND: 90006,
|
|
9891
|
+
RISK_CONTROL_TRIGGERED: 90101,
|
|
9892
|
+
RISK_CONTROL_RATE_LIMITED: 90102,
|
|
9893
|
+
RECONCILIATION_MISMATCH: 90103,
|
|
9894
|
+
RECONCILIATION_TASK_FAILED: 90104,
|
|
9895
|
+
AUDIT_LOG_WRITE_FAILED: 90105
|
|
9896
|
+
};
|
|
9752
9897
|
var ERR_NEXT_STEP = {
|
|
9753
9898
|
10001: "fix_input",
|
|
9754
9899
|
10002: "fix_input",
|
|
@@ -10027,6 +10172,15 @@ function attempt2(func) {
|
|
|
10027
10172
|
return [error, null];
|
|
10028
10173
|
}
|
|
10029
10174
|
}
|
|
10175
|
+
|
|
10176
|
+
// ../../node_modules/es-toolkit/dist/util/attemptAsync.mjs
|
|
10177
|
+
async function attemptAsync(func) {
|
|
10178
|
+
try {
|
|
10179
|
+
return [null, await func()];
|
|
10180
|
+
} catch (error) {
|
|
10181
|
+
return [error, null];
|
|
10182
|
+
}
|
|
10183
|
+
}
|
|
10030
10184
|
// ../../node_modules/ts-pattern/dist/index.js
|
|
10031
10185
|
var t2 = Symbol.for("@ts-pattern/matcher");
|
|
10032
10186
|
var e2 = Symbol.for("@ts-pattern/isVariadic");
|
|
@@ -16969,6 +17123,15 @@ class ClientSessions {
|
|
|
16969
17123
|
const url = `${this.baseUrl}/api/sessions${search ? `?${search}` : ""}`;
|
|
16970
17124
|
return requestJson(this.customFetch, url, { method: "GET", headers: this.authHeaders() }, ListSessionsResponseSchema, (status) => `Failed to fetch sessions with status ${status}`);
|
|
16971
17125
|
}
|
|
17126
|
+
async exists(sessionId) {
|
|
17127
|
+
const params = new URLSearchParams({ sessionId, limit: "1" });
|
|
17128
|
+
const [err] = await attemptAsync(() => requestJson(this.customFetch, `${this.baseUrl}/api/sessions/detail?${params.toString()}`, { method: "GET", headers: this.authHeaders() }, unknown2(), (status) => `Failed to verify session ${sessionId} with status ${status}`));
|
|
17129
|
+
if (!err)
|
|
17130
|
+
return true;
|
|
17131
|
+
if (err instanceof ChatUpstreamError && err.status === 404)
|
|
17132
|
+
return false;
|
|
17133
|
+
throw err;
|
|
17134
|
+
}
|
|
16972
17135
|
async artifacts(query) {
|
|
16973
17136
|
const params = new URLSearchParams({ sessionId: query.sessionId });
|
|
16974
17137
|
if (query.taskId !== undefined)
|
|
@@ -17006,12 +17169,17 @@ class ClientSessions {
|
|
|
17006
17169
|
signal
|
|
17007
17170
|
});
|
|
17008
17171
|
if (!response.ok) {
|
|
17009
|
-
await response.
|
|
17010
|
-
return;
|
|
17011
|
-
});
|
|
17172
|
+
const body = await response.text().catch(() => "");
|
|
17012
17173
|
const retryable = response.status >= 500 || response.status === 429;
|
|
17013
|
-
if (!retryable)
|
|
17174
|
+
if (!retryable) {
|
|
17175
|
+
if (!state.sessionReady) {
|
|
17176
|
+
state.outcome = {
|
|
17177
|
+
status: "failed",
|
|
17178
|
+
error: new ChatUpstreamError(`Session prewarm was rejected with status ${response.status}`, response.status, body)
|
|
17179
|
+
};
|
|
17180
|
+
}
|
|
17014
17181
|
break;
|
|
17182
|
+
}
|
|
17015
17183
|
continue;
|
|
17016
17184
|
}
|
|
17017
17185
|
await this.consumePrewarmStream(response, state, {
|
|
@@ -17030,7 +17198,10 @@ class ClientSessions {
|
|
|
17030
17198
|
}
|
|
17031
17199
|
if (state.outcome)
|
|
17032
17200
|
return state.outcome;
|
|
17033
|
-
return state.sessionReady ? { status: "fallback", session: state.sessionReady } : {
|
|
17201
|
+
return state.sessionReady ? { status: "fallback", session: state.sessionReady } : {
|
|
17202
|
+
status: "failed",
|
|
17203
|
+
error: new ChatUpstreamError("Session prewarm never completed: no session_ready event (request retries exhausted or timed out).", 0, "")
|
|
17204
|
+
};
|
|
17034
17205
|
}
|
|
17035
17206
|
async consumePrewarmStream(response, state, callbacks) {
|
|
17036
17207
|
if (!response.body)
|
|
@@ -17061,12 +17232,18 @@ class ClientSessions {
|
|
|
17061
17232
|
}
|
|
17062
17233
|
case "done": {
|
|
17063
17234
|
PrewarmDoneSchema.parse(data);
|
|
17064
|
-
state.outcome = state.sessionReady ? { status: "ready", session: state.sessionReady } : {
|
|
17235
|
+
state.outcome = state.sessionReady ? { status: "ready", session: state.sessionReady } : {
|
|
17236
|
+
status: "failed",
|
|
17237
|
+
error: new ChatUpstreamError("Session prewarm ended before the session was created upstream.", 0, "")
|
|
17238
|
+
};
|
|
17065
17239
|
return;
|
|
17066
17240
|
}
|
|
17067
17241
|
case "error": {
|
|
17068
|
-
PrewarmErrorSchema.parse(data);
|
|
17069
|
-
state.outcome = state.sessionReady ? { status: "fallback", session: state.sessionReady } : {
|
|
17242
|
+
const payload = PrewarmErrorSchema.parse(data);
|
|
17243
|
+
state.outcome = state.sessionReady ? { status: "fallback", session: state.sessionReady } : {
|
|
17244
|
+
status: "failed",
|
|
17245
|
+
error: new ChatUpstreamError(payload.message, 0, JSON.stringify({ error: payload }))
|
|
17246
|
+
};
|
|
17070
17247
|
return;
|
|
17071
17248
|
}
|
|
17072
17249
|
default:
|
|
@@ -17812,29 +17989,56 @@ async function resolvePromptAttachments(options) {
|
|
|
17812
17989
|
}
|
|
17813
17990
|
|
|
17814
17991
|
// src/services/session.ts
|
|
17992
|
+
var SESSION_GONE_ERR_CODES = [
|
|
17993
|
+
ErrCode.SESSION_NOT_FOUND,
|
|
17994
|
+
ErrCode.CHAT_SESSION_EXPIRED
|
|
17995
|
+
];
|
|
17815
17996
|
function isSessionGoneError(err) {
|
|
17816
17997
|
if (!(err instanceof ChatUpstreamError))
|
|
17817
17998
|
return false;
|
|
17999
|
+
if (err.errCode !== null) {
|
|
18000
|
+
return SESSION_GONE_ERR_CODES.includes(err.errCode);
|
|
18001
|
+
}
|
|
17818
18002
|
if (err.status === 404)
|
|
17819
18003
|
return true;
|
|
17820
18004
|
return err.body.includes(ERR_SESSION_EXPIRED);
|
|
17821
18005
|
}
|
|
18006
|
+
async function ensureSessionExists(options) {
|
|
18007
|
+
const client = new MediaStudioClient({
|
|
18008
|
+
baseUrl: options.apiBaseUrl,
|
|
18009
|
+
apiKey: options.apiKey
|
|
18010
|
+
});
|
|
18011
|
+
if (await client.sessions.exists(options.sessionId))
|
|
18012
|
+
return;
|
|
18013
|
+
throw new Error(`Session ${options.sessionId} does not exist.
|
|
18014
|
+
` + ' → Create one: `msc sessions use --new`, or `msc chat --new "<prompt>"` to also send a prompt.');
|
|
18015
|
+
}
|
|
18016
|
+
function finalizeProvision(result, spinner) {
|
|
18017
|
+
spinner?.stop();
|
|
18018
|
+
if (result.status === "failed") {
|
|
18019
|
+
throw result.error;
|
|
18020
|
+
}
|
|
18021
|
+
if (result.status === "fallback") {
|
|
18022
|
+
consola.warn("Session created, but sandbox/skill setup did not fully complete. Plain-text chat still works.");
|
|
18023
|
+
}
|
|
18024
|
+
return result.sessionId;
|
|
18025
|
+
}
|
|
17822
18026
|
async function provisionSession(options) {
|
|
17823
|
-
const sessionId = nanoid3();
|
|
17824
18027
|
const client = new MediaStudioClient({
|
|
17825
18028
|
baseUrl: options.apiBaseUrl,
|
|
17826
18029
|
apiKey: options.apiKey
|
|
17827
18030
|
});
|
|
18031
|
+
const sessionId = nanoid3();
|
|
17828
18032
|
const outcome = await client.sessions.prewarm({
|
|
17829
18033
|
sessionId,
|
|
17830
18034
|
source: "cli",
|
|
17831
18035
|
onSessionReady: () => saveLastSessionId(sessionId),
|
|
17832
|
-
|
|
18036
|
+
onStageChange: options.onStageChange
|
|
17833
18037
|
});
|
|
17834
|
-
|
|
17835
|
-
status,
|
|
17836
|
-
|
|
17837
|
-
|
|
18038
|
+
if (outcome.status === "failed") {
|
|
18039
|
+
return { status: "failed", error: outcome.error };
|
|
18040
|
+
}
|
|
18041
|
+
return { status: outcome.status, sessionId };
|
|
17838
18042
|
}
|
|
17839
18043
|
|
|
17840
18044
|
// src/lib/skill-refs.ts
|
|
@@ -17963,34 +18167,34 @@ function printTerminalMediaAssets(mediaAssets, fullText) {
|
|
|
17963
18167
|
process.stdout.write(`====================
|
|
17964
18168
|
`);
|
|
17965
18169
|
}
|
|
17966
|
-
function
|
|
17967
|
-
spinner.
|
|
17968
|
-
|
|
17969
|
-
|
|
17970
|
-
|
|
17971
|
-
|
|
17972
|
-
|
|
17973
|
-
|
|
17974
|
-
return result.sessionId;
|
|
18170
|
+
async function provisionNewSession(options) {
|
|
18171
|
+
const onStageChange = options.quiet ? undefined : (stage) => options.spinner.start(PROVISION_STAGE_LABELS[stage]);
|
|
18172
|
+
const result = await provisionSession({
|
|
18173
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
18174
|
+
apiKey: options.apiKey,
|
|
18175
|
+
onStageChange
|
|
18176
|
+
});
|
|
18177
|
+
return finalizeProvision(result, options.spinner);
|
|
17975
18178
|
}
|
|
17976
18179
|
async function resolveChatSession(options) {
|
|
18180
|
+
if (options.newSession) {
|
|
18181
|
+
return {
|
|
18182
|
+
sessionId: await provisionNewSession(options),
|
|
18183
|
+
recreateOnGone: false
|
|
18184
|
+
};
|
|
18185
|
+
}
|
|
17977
18186
|
if (options.sessionFlag) {
|
|
17978
18187
|
saveLastSessionId(options.sessionFlag);
|
|
17979
|
-
return { sessionId: options.sessionFlag, recreateOnGone:
|
|
18188
|
+
return { sessionId: options.sessionFlag, recreateOnGone: false };
|
|
17980
18189
|
}
|
|
17981
18190
|
const pointer = readLastSessionId();
|
|
17982
18191
|
if (pointer) {
|
|
17983
18192
|
return { sessionId: pointer, recreateOnGone: true };
|
|
17984
18193
|
}
|
|
17985
|
-
|
|
17986
|
-
|
|
17987
|
-
|
|
17988
|
-
|
|
17989
|
-
onStageChange: (stage) => options.spinner.start(PROVISION_STAGE_LABELS[stage])
|
|
17990
|
-
}
|
|
17991
|
-
});
|
|
17992
|
-
const sessionId = finalizeProvision(result, options.spinner);
|
|
17993
|
-
return { sessionId, recreateOnGone: false };
|
|
18194
|
+
return {
|
|
18195
|
+
sessionId: await provisionNewSession(options),
|
|
18196
|
+
recreateOnGone: false
|
|
18197
|
+
};
|
|
17994
18198
|
}
|
|
17995
18199
|
async function streamTurn(options) {
|
|
17996
18200
|
const { args, sessionId, spinner, autoEnabled, attachments } = options;
|
|
@@ -18012,6 +18216,9 @@ async function streamTurn(options) {
|
|
|
18012
18216
|
const mediaAssets = [];
|
|
18013
18217
|
let hasFinished = false;
|
|
18014
18218
|
for await (const ev of stream) {
|
|
18219
|
+
if (ev.type !== "finish" && ev.type !== "error") {
|
|
18220
|
+
options.progress.emitted = true;
|
|
18221
|
+
}
|
|
18015
18222
|
M(ev).with({ type: "text-delta", delta: z2.string }, ({ delta }) => {
|
|
18016
18223
|
isThinking = false;
|
|
18017
18224
|
spinner.stop();
|
|
@@ -18113,17 +18320,28 @@ async function runTurn(options) {
|
|
|
18113
18320
|
try {
|
|
18114
18321
|
await streamTurn(options);
|
|
18115
18322
|
} catch (err) {
|
|
18116
|
-
|
|
18323
|
+
const sessionGone = isSessionGoneError(err);
|
|
18324
|
+
if (sessionGone && options.progress.emitted) {
|
|
18325
|
+
throw new Error(`Session ${options.sessionId} failed after this turn had already started.
|
|
18326
|
+
` + " → The partial result above stands; re-run the same prompt to continue in a new session.");
|
|
18327
|
+
}
|
|
18328
|
+
if (sessionGone && !options.recreateOnGone) {
|
|
18329
|
+
throw new Error(`Session ${options.sessionId} does not exist.
|
|
18330
|
+
` + ' → Create one: `msc sessions use --new`, or `msc chat --new "<prompt>"` to also send a prompt.');
|
|
18331
|
+
}
|
|
18332
|
+
if (sessionGone) {
|
|
18117
18333
|
consola.warn(`Session ${options.sessionId} is no longer available. Provisioning a new one...`);
|
|
18118
|
-
const
|
|
18334
|
+
const sessionId = await provisionNewSession({
|
|
18119
18335
|
apiBaseUrl: options.apiBaseUrl,
|
|
18120
18336
|
apiKey: resolveApiKey(),
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
|
|
18337
|
+
spinner: options.spinner,
|
|
18338
|
+
quiet: options.args.json === true
|
|
18339
|
+
});
|
|
18340
|
+
await streamTurn({
|
|
18341
|
+
...options,
|
|
18342
|
+
sessionId,
|
|
18343
|
+
apiKey: resolveApiKey()
|
|
18124
18344
|
});
|
|
18125
|
-
const sessionId = finalizeProvision(result, options.spinner);
|
|
18126
|
-
await streamTurn({ ...options, sessionId, apiKey: resolveApiKey() });
|
|
18127
18345
|
return;
|
|
18128
18346
|
}
|
|
18129
18347
|
throw err;
|
|
@@ -18147,7 +18365,11 @@ var chatCommand = defineCommand({
|
|
|
18147
18365
|
},
|
|
18148
18366
|
session: {
|
|
18149
18367
|
type: "string",
|
|
18150
|
-
description: "
|
|
18368
|
+
description: "Chat in an existing session id (verified upstream); becomes the default session. A missing id fails — create one with --new"
|
|
18369
|
+
},
|
|
18370
|
+
new: {
|
|
18371
|
+
type: "boolean",
|
|
18372
|
+
description: "Create a new session and chat in it; becomes the default session"
|
|
18151
18373
|
},
|
|
18152
18374
|
"show-reasoning": {
|
|
18153
18375
|
type: "boolean",
|
|
@@ -18159,6 +18381,16 @@ var chatCommand = defineCommand({
|
|
|
18159
18381
|
const spinner = new AgentSpinner;
|
|
18160
18382
|
try {
|
|
18161
18383
|
const apiBaseUrl = resolveApiBaseUrl();
|
|
18384
|
+
if (args.new && args.session) {
|
|
18385
|
+
throw new Error("--new and --session cannot be combined: --session selects an existing session, --new creates one.");
|
|
18386
|
+
}
|
|
18387
|
+
if (args.session) {
|
|
18388
|
+
await ensureSessionExists({
|
|
18389
|
+
apiBaseUrl,
|
|
18390
|
+
apiKey: resolveApiKey(),
|
|
18391
|
+
sessionId: args.session
|
|
18392
|
+
});
|
|
18393
|
+
}
|
|
18162
18394
|
const { text, skillUrls, autoEnabled } = await resolvePromptSkills({
|
|
18163
18395
|
prompt: args.prompt,
|
|
18164
18396
|
apiBaseUrl,
|
|
@@ -18177,6 +18409,7 @@ var chatCommand = defineCommand({
|
|
|
18177
18409
|
});
|
|
18178
18410
|
const resolved = await resolveChatSession({
|
|
18179
18411
|
sessionFlag: args.session,
|
|
18412
|
+
newSession: args.new,
|
|
18180
18413
|
apiBaseUrl,
|
|
18181
18414
|
apiKey: resolveApiKey(),
|
|
18182
18415
|
spinner,
|
|
@@ -18187,6 +18420,7 @@ var chatCommand = defineCommand({
|
|
|
18187
18420
|
prompt: promptWithAttachments,
|
|
18188
18421
|
sessionId: resolved.sessionId,
|
|
18189
18422
|
recreateOnGone: resolved.recreateOnGone,
|
|
18423
|
+
progress: { emitted: false },
|
|
18190
18424
|
apiBaseUrl,
|
|
18191
18425
|
apiKey: resolveApiKey(),
|
|
18192
18426
|
spinner,
|
|
@@ -18285,8 +18519,16 @@ ${getAvailableRegions().map((r) => ` ${r.key.padEnd(8)} - ${r.url} (${r.des
|
|
|
18285
18519
|
"no such file". Remote URLs are not attachments and there is no @url form.
|
|
18286
18520
|
|
|
18287
18521
|
Session Switching:
|
|
18288
|
-
Pass \`--session <id>\` to direct a prompt to
|
|
18289
|
-
|
|
18522
|
+
Pass \`--session <id>\` to direct a prompt to an existing session and make it
|
|
18523
|
+
your new active session. The id is verified against the server first: the
|
|
18524
|
+
CLI only ever selects sessions that exist, so an unknown id fails with a
|
|
18525
|
+
hint instead of silently starting a different conversation.
|
|
18526
|
+
|
|
18527
|
+
Pass \`--new\` to start a fresh session (new id, never reused) and chat in
|
|
18528
|
+
it, ignoring the current default. \`--new\` and \`--session\` are mutually
|
|
18529
|
+
exclusive.
|
|
18530
|
+
msc chat "start over" --new # new session, new context
|
|
18531
|
+
msc sessions # pick an existing id for --session
|
|
18290
18532
|
|
|
18291
18533
|
4. USING SKILLS
|
|
18292
18534
|
|
|
@@ -18327,7 +18569,13 @@ ${getAvailableRegions().map((r) => ` ${r.key.padEnd(8)} - ${r.url} (${r.des
|
|
|
18327
18569
|
including download URLs and model metadata.
|
|
18328
18570
|
|
|
18329
18571
|
msc sessions use <session-id>
|
|
18330
|
-
Switch your active session pointer
|
|
18572
|
+
Switch your active session pointer to an existing session. The id is
|
|
18573
|
+
verified against the server; an unknown id fails here and leaves the
|
|
18574
|
+
pointer untouched.
|
|
18575
|
+
|
|
18576
|
+
msc sessions use --new
|
|
18577
|
+
Create a new session upstream and switch the pointer to it, without sending
|
|
18578
|
+
a prompt.
|
|
18331
18579
|
|
|
18332
18580
|
Session deletion is not available in the CLI. Open the corresponding session
|
|
18333
18581
|
in the Media Studio web app and delete it there manually.
|
|
@@ -18380,6 +18628,13 @@ ${getAvailableRegions().map((r) => ` ${r.key.padEnd(8)} - ${r.url}`).join(`
|
|
|
18380
18628
|
"nextStep": "relogin" // recommended action keyword
|
|
18381
18629
|
}
|
|
18382
18630
|
|
|
18631
|
+
Session commands:
|
|
18632
|
+
msc sessions --json # list: [{ sessionId, note, ... }]
|
|
18633
|
+
msc sessions use <id> --json # { "sessionId": "string" }
|
|
18634
|
+
msc sessions use --new --json # { "sessionId": "string" } (newly created)
|
|
18635
|
+
\`--session\`/\`use <id>\` verify the id upstream; an unknown id exits 1 with
|
|
18636
|
+
the \`--new\` hint and leaves the default session untouched.
|
|
18637
|
+
|
|
18383
18638
|
Recommended next steps:
|
|
18384
18639
|
relogin Session expired or missing; run \`msc login\`
|
|
18385
18640
|
retry_later Rate limit reached; wait before re-sending
|
|
@@ -20372,18 +20627,63 @@ var artifactsCommand = defineCommand({
|
|
|
20372
20627
|
var useSessionCommand = defineCommand({
|
|
20373
20628
|
meta: {
|
|
20374
20629
|
name: "use",
|
|
20375
|
-
description: "Switch default session
|
|
20630
|
+
description: "Switch the default session to an existing session, or create a fresh one with --new"
|
|
20376
20631
|
},
|
|
20377
20632
|
args: {
|
|
20378
20633
|
sessionId: {
|
|
20379
20634
|
type: "positional",
|
|
20380
|
-
required:
|
|
20381
|
-
description: "
|
|
20635
|
+
required: false,
|
|
20636
|
+
description: "Existing session id to set as default"
|
|
20637
|
+
},
|
|
20638
|
+
new: {
|
|
20639
|
+
type: "boolean",
|
|
20640
|
+
description: "Create a new session and make it the default"
|
|
20641
|
+
},
|
|
20642
|
+
json: {
|
|
20643
|
+
type: "boolean",
|
|
20644
|
+
alias: "j",
|
|
20645
|
+
description: "Output machine-readable JSON: { sessionId }"
|
|
20382
20646
|
}
|
|
20383
20647
|
},
|
|
20384
|
-
run: ({ args }) => {
|
|
20385
|
-
|
|
20386
|
-
|
|
20648
|
+
run: async ({ args }) => {
|
|
20649
|
+
try {
|
|
20650
|
+
const sessionId = args.sessionId;
|
|
20651
|
+
const apiBaseUrl = resolveApiBaseUrl();
|
|
20652
|
+
if (args.new) {
|
|
20653
|
+
if (sessionId) {
|
|
20654
|
+
throw new Error("--new and <session-id> cannot be combined: pass one, not both.");
|
|
20655
|
+
}
|
|
20656
|
+
const result = await provisionSession({
|
|
20657
|
+
apiBaseUrl,
|
|
20658
|
+
apiKey: resolveApiKey()
|
|
20659
|
+
});
|
|
20660
|
+
const created = finalizeProvision(result);
|
|
20661
|
+
if (args.json) {
|
|
20662
|
+
process.stdout.write(`${JSON.stringify({ sessionId: created })}
|
|
20663
|
+
`);
|
|
20664
|
+
return;
|
|
20665
|
+
}
|
|
20666
|
+
consola.success(`Created and switched to session ${created}`);
|
|
20667
|
+
return;
|
|
20668
|
+
}
|
|
20669
|
+
if (!sessionId) {
|
|
20670
|
+
throw new Error("Pass the session id to switch to, or --new to create a new session.");
|
|
20671
|
+
}
|
|
20672
|
+
await ensureSessionExists({
|
|
20673
|
+
apiBaseUrl,
|
|
20674
|
+
apiKey: resolveApiKey(),
|
|
20675
|
+
sessionId
|
|
20676
|
+
});
|
|
20677
|
+
saveLastSessionId(sessionId);
|
|
20678
|
+
if (args.json) {
|
|
20679
|
+
process.stdout.write(`${JSON.stringify({ sessionId })}
|
|
20680
|
+
`);
|
|
20681
|
+
return;
|
|
20682
|
+
}
|
|
20683
|
+
consola.success(`Switched default session to ${sessionId}`);
|
|
20684
|
+
} catch (err) {
|
|
20685
|
+
reportCommandError(err, { json: args.json });
|
|
20686
|
+
}
|
|
20387
20687
|
}
|
|
20388
20688
|
});
|
|
20389
20689
|
var sessionsCommand = defineCommand({
|
|
@@ -20763,6 +21063,8 @@ AGENT QUICKSTART
|
|
|
20763
21063
|
1. msc login # a human must finish this in a browser; instant if
|
|
20764
21064
|
# that browser is already signed in to the web app
|
|
20765
21065
|
2. msc chat "a red car" --json # one turn; the conversation continues across runs
|
|
21066
|
+
# (--new starts a fresh session, --session <id> picks
|
|
21067
|
+
# an existing one; both are verified)
|
|
20766
21068
|
3. msc skills --plaza --json # find a skill, then reference it by leading the
|
|
20767
21069
|
# prompt with /name or %%/name%%
|
|
20768
21070
|
|
package/package.json
CHANGED