@wji.ai/cli 0.6.0 → 0.6.1
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/dist/commands/agent.js +28 -8
- package/dist/commands/backreel.js +61 -1
- package/dist/commands/workspace.js +74 -1
- package/dist/index.js +6 -0
- package/package.json +1 -1
- package/skill/wji/SKILL.md +9 -0
- package/skill/wji/reference/commands.md +20 -3
package/dist/commands/agent.js
CHANGED
|
@@ -15,6 +15,21 @@ function skillRefLabel(ref) {
|
|
|
15
15
|
return String(ref);
|
|
16
16
|
return ref.kind === 'system' ? `system:${ref.key}` : `user:${ref.id}`;
|
|
17
17
|
}
|
|
18
|
+
/** Backend DEFAULT_MAX_STEPS / MAX_STEPS_LIMIT (src/ai/_/constant.ts). */
|
|
19
|
+
const DEFAULT_MAX_STEPS = 40;
|
|
20
|
+
const MAX_STEPS_LIMIT = 200;
|
|
21
|
+
/** `--max-steps`: an integer in range, or "default" to clear back to the site default. */
|
|
22
|
+
function parseMaxSteps(value) {
|
|
23
|
+
if (value === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
if (['default', 'none', 'null'].includes(value.trim().toLowerCase()))
|
|
26
|
+
return null;
|
|
27
|
+
const n = Number(value);
|
|
28
|
+
if (!Number.isInteger(n) || n < 1 || n > MAX_STEPS_LIMIT) {
|
|
29
|
+
throw new Error(`--max-steps must be an integer from 1 to ${MAX_STEPS_LIMIT} (or "default")`);
|
|
30
|
+
}
|
|
31
|
+
return n;
|
|
32
|
+
}
|
|
18
33
|
export function agentCommand(globals) {
|
|
19
34
|
const agent = new Command('agent').description('Manage AI agents');
|
|
20
35
|
agent
|
|
@@ -59,7 +74,7 @@ export function agentCommand(globals) {
|
|
|
59
74
|
});
|
|
60
75
|
agent
|
|
61
76
|
.command('get <id>')
|
|
62
|
-
.description('Show an agent (instructions
|
|
77
|
+
.description('Show an agent (private agents: creator only; instructions only when you own it)')
|
|
63
78
|
.action(async (id) => {
|
|
64
79
|
const client = new WjiClient(globals());
|
|
65
80
|
const a = await client.get(`/ai/agent/list/${id}`);
|
|
@@ -72,6 +87,7 @@ export function agentCommand(globals) {
|
|
|
72
87
|
['category', a.category],
|
|
73
88
|
['tags', (a.tags || []).join(', ')],
|
|
74
89
|
['greeting', a.greeting],
|
|
90
|
+
['maxSteps', a.maxSteps ?? color.dim(`default (${DEFAULT_MAX_STEPS})`)],
|
|
75
91
|
['creator', a.creator?.name || a.creator?.id || a.creator],
|
|
76
92
|
['organization', a.organization?.id || a.organization || 'personal'],
|
|
77
93
|
['skills', (a.skills || []).map(skillRefLabel).join(', ')],
|
|
@@ -80,7 +96,7 @@ export function agentCommand(globals) {
|
|
|
80
96
|
});
|
|
81
97
|
agent
|
|
82
98
|
.command('create <name>')
|
|
83
|
-
.description('Create an agent')
|
|
99
|
+
.description('Create an agent (needs the agent-create permission on your account)')
|
|
84
100
|
.requiredOption('-d, --description <text>', 'short description')
|
|
85
101
|
.option('-i, --instructions <text>', 'system prompt (@file / - supported)')
|
|
86
102
|
.option('-m, --model <name>', 'backing model')
|
|
@@ -89,7 +105,8 @@ export function agentCommand(globals) {
|
|
|
89
105
|
.option('-t, --tag <tag...>', 'tags')
|
|
90
106
|
.option('--greeting <text>', 'opening message')
|
|
91
107
|
.option('--skill <ref...>', 'attach skills: system:<key> or user:<skillId>')
|
|
92
|
-
.option('--
|
|
108
|
+
.option('--max-steps <n>', `model calls allowed per chat turn, 1-${MAX_STEPS_LIMIT} (default ${DEFAULT_MAX_STEPS})`)
|
|
109
|
+
.option('--set <key=value...>', 'arbitrary field (admin-only fields are dropped by the server)')
|
|
93
110
|
.action(async (name, opts) => {
|
|
94
111
|
const client = new WjiClient(globals());
|
|
95
112
|
const created = await client.post('/ai/agent/create', {
|
|
@@ -102,13 +119,14 @@ export function agentCommand(globals) {
|
|
|
102
119
|
tags: opts.tag,
|
|
103
120
|
greeting: opts.greeting,
|
|
104
121
|
skills: opts.skill?.length ? opts.skill.map(parseSkillRef) : undefined,
|
|
122
|
+
maxSteps: parseMaxSteps(opts.maxSteps),
|
|
105
123
|
...parseKeyValues(opts.set),
|
|
106
124
|
});
|
|
107
125
|
render(created, (a) => success(`Created agent ${a.name} (${a.id})`));
|
|
108
126
|
});
|
|
109
127
|
agent
|
|
110
128
|
.command('update <id>')
|
|
111
|
-
.description('Update an agent')
|
|
129
|
+
.description('Update an agent (creator only)')
|
|
112
130
|
.option('-n, --name <name>', 'new name')
|
|
113
131
|
.option('-d, --description <text>', 'new description')
|
|
114
132
|
.option('-i, --instructions <text>', 'new system prompt (@file / - supported)')
|
|
@@ -117,7 +135,8 @@ export function agentCommand(globals) {
|
|
|
117
135
|
.option('-c, --category <name>', 'category')
|
|
118
136
|
.option('-t, --tag <tag...>', 'replace tags')
|
|
119
137
|
.option('--greeting <text>', 'opening message')
|
|
120
|
-
.option('--
|
|
138
|
+
.option('--max-steps <n>', `model calls allowed per chat turn, 1-${MAX_STEPS_LIMIT}; "default" clears it`)
|
|
139
|
+
.option('--set <key=value...>', 'arbitrary field (admin-only fields are dropped by the server)')
|
|
121
140
|
.action(async (id, opts) => {
|
|
122
141
|
const client = new WjiClient(globals());
|
|
123
142
|
const updated = await client.put(`/ai/agent/list/${id}`, {
|
|
@@ -129,6 +148,7 @@ export function agentCommand(globals) {
|
|
|
129
148
|
category: opts.category,
|
|
130
149
|
tags: opts.tag,
|
|
131
150
|
greeting: opts.greeting,
|
|
151
|
+
maxSteps: parseMaxSteps(opts.maxSteps),
|
|
132
152
|
...parseKeyValues(opts.set),
|
|
133
153
|
});
|
|
134
154
|
render(updated, () => success(`Updated ${id}`));
|
|
@@ -147,7 +167,7 @@ export function agentCommand(globals) {
|
|
|
147
167
|
});
|
|
148
168
|
agent
|
|
149
169
|
.command('files <id>')
|
|
150
|
-
.description('List files attached to an agent')
|
|
170
|
+
.description('List files attached to an agent (creator only)')
|
|
151
171
|
.action(async (id) => {
|
|
152
172
|
const client = new WjiClient(globals());
|
|
153
173
|
const files = await client.get(`/ai/agent/list/${id}/files`);
|
|
@@ -236,7 +256,7 @@ export function agentCommand(globals) {
|
|
|
236
256
|
});
|
|
237
257
|
agent
|
|
238
258
|
.command('versions <id>')
|
|
239
|
-
.description('List an agent\'s version history')
|
|
259
|
+
.description('List an agent\'s version history (creator only — snapshots hold instructions)')
|
|
240
260
|
.action(async (id) => {
|
|
241
261
|
const client = new WjiClient(globals());
|
|
242
262
|
const versions = await client.get(`/ai/agent/list/${id}/versions`);
|
|
@@ -251,7 +271,7 @@ export function agentCommand(globals) {
|
|
|
251
271
|
});
|
|
252
272
|
agent
|
|
253
273
|
.command('restore <id> <versionId>')
|
|
254
|
-
.description('Restore an agent to a previous version')
|
|
274
|
+
.description('Restore an agent to a previous version (creator only)')
|
|
255
275
|
.action(async (id, versionId) => {
|
|
256
276
|
const client = new WjiClient(globals());
|
|
257
277
|
const result = await client.post(`/ai/agent/list/${id}/versions/${versionId}/restore`);
|
|
@@ -7,6 +7,10 @@ const POSTS = '/backreel/post';
|
|
|
7
7
|
const KINDS = ['showcase', 'crowdfunding'];
|
|
8
8
|
const PROJECT_STATUSES = ['planning', 'pre_production', 'in_production', 'post_production', 'completed'];
|
|
9
9
|
const CREDIT_KINDS = ['creative', 'crew', 'cast'];
|
|
10
|
+
/** Backend LOGLINE_MAX (src/backreel/post/descriptionHtml.ts). */
|
|
11
|
+
const LOGLINE_MAX = 200;
|
|
12
|
+
/** BackreelVerificationKind — what `creators --role` filters on. */
|
|
13
|
+
const VERIFICATION_KINDS = ['investor', 'production_company', 'brand', 'distributor', 'sales_agent'];
|
|
10
14
|
/** Credit fields the create / update DTO accepts; the rest of a read-back credit is dropped. */
|
|
11
15
|
const CREDIT_FIELDS = ['kind', 'name', 'role', 'user', 'photo', 'avatarUrl', 'link', 'source', 'npcId', 'order'];
|
|
12
16
|
export function backreelCommand(globals) {
|
|
@@ -87,6 +91,50 @@ export function backreelCommand(globals) {
|
|
|
87
91
|
const result = await client.delete(`${POSTS}/list/${id}`);
|
|
88
92
|
render(result, () => success(`Deleted "${post.title}"`));
|
|
89
93
|
});
|
|
94
|
+
br.command('creators')
|
|
95
|
+
.description('Browse Backreel creators: editor picks, then ranked by recent likes / favorites')
|
|
96
|
+
.option('-k, --keyword <text>', 'match name or @handle')
|
|
97
|
+
.option('--role <kind>', `only creators verified as: ${VERIFICATION_KINDS.join(' | ')}`)
|
|
98
|
+
.option('--verified', 'only verified creators')
|
|
99
|
+
.option('--no-featured', 'skip the editor-picked creators')
|
|
100
|
+
.option('--page <n>', 'page number', '1')
|
|
101
|
+
.option('--limit <n>', 'page size (max 48)', '20')
|
|
102
|
+
.action(async (opts) => {
|
|
103
|
+
const client = new WjiClient(globals());
|
|
104
|
+
if (opts.role)
|
|
105
|
+
oneOf(opts.role, VERIFICATION_KINDS, '--role');
|
|
106
|
+
const result = await client.get('/backreel/creator/list', {
|
|
107
|
+
keyword: opts.keyword,
|
|
108
|
+
role: opts.role,
|
|
109
|
+
verifiedOnly: opts.verified ? 'true' : undefined,
|
|
110
|
+
withFeatured: opts.featured ? undefined : 'false',
|
|
111
|
+
page: Number(opts.page),
|
|
112
|
+
limit: Number(opts.limit),
|
|
113
|
+
});
|
|
114
|
+
render(result, (r) => {
|
|
115
|
+
const columns = [
|
|
116
|
+
{ header: 'id', value: (c) => c.id },
|
|
117
|
+
{ header: 'name', value: (c) => truncate(c.name, 24) },
|
|
118
|
+
{ header: 'handle', value: (c) => (c.handle ? `@${c.handle}` : '') },
|
|
119
|
+
{ header: 'reels', value: (c) => c.reelCount },
|
|
120
|
+
{ header: 'followers', value: (c) => c.followerCount },
|
|
121
|
+
{ header: 'likes', value: (c) => c.likeCount },
|
|
122
|
+
{ header: 'verified', value: (c) => (c.verifiedKinds || []).join(', ') },
|
|
123
|
+
];
|
|
124
|
+
if (r?.featured?.length) {
|
|
125
|
+
info(color.bold('Featured'));
|
|
126
|
+
table(r.featured, [...columns, { header: 'note', value: (c) => truncate(c.featuredNote, 30) }]);
|
|
127
|
+
process.stdout.write('\n');
|
|
128
|
+
info(color.bold('Hot'));
|
|
129
|
+
}
|
|
130
|
+
table(r?.data || [], columns);
|
|
131
|
+
const p = r?.pagination;
|
|
132
|
+
if (p) {
|
|
133
|
+
const more = p.page * p.limit < p.total ? ` · more: --page ${p.page + 1}` : '';
|
|
134
|
+
info(color.dim(`${p.total} ranked · page ${p.page}${more}`));
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
90
138
|
// ── credits ────────────────────────────────────────────────────────────
|
|
91
139
|
const credit = br.command('credit').aliases(['credits']).description('Cast and crew of a post (max 30)');
|
|
92
140
|
credit
|
|
@@ -176,6 +224,7 @@ export function backreelCommand(globals) {
|
|
|
176
224
|
function postOptions(cmd) {
|
|
177
225
|
return cmd
|
|
178
226
|
.option('--kind <kind>', KINDS.join(' | '))
|
|
227
|
+
.option('--logline <text>', `one-line hook, max ${LOGLINE_MAX} chars; public even when the description is locked ("" clears it)`)
|
|
179
228
|
.option('--category <category>', 'category')
|
|
180
229
|
.option('--project-status <status>', PROJECT_STATUSES.join(' | '))
|
|
181
230
|
.option('--tags <tags>', 'comma-separated tags (replaces the list)')
|
|
@@ -189,6 +238,13 @@ async function postBody(opts) {
|
|
|
189
238
|
const body = { ...((await readJson(opts.body)) || {}) };
|
|
190
239
|
if (opts.kind)
|
|
191
240
|
body.kind = oneOf(opts.kind, KINDS, '--kind');
|
|
241
|
+
if (opts.logline !== undefined) {
|
|
242
|
+
// Same normalisation the server applies: plain text, one line.
|
|
243
|
+
const logline = String(await readValue(opts.logline)).replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim();
|
|
244
|
+
if (logline.length > LOGLINE_MAX)
|
|
245
|
+
throw new Error(`--logline is ${logline.length} chars; the limit is ${LOGLINE_MAX}`);
|
|
246
|
+
body.logline = logline;
|
|
247
|
+
}
|
|
192
248
|
if (opts.category)
|
|
193
249
|
body.category = opts.category;
|
|
194
250
|
if (opts.projectStatus)
|
|
@@ -225,6 +281,7 @@ async function updateCredits(client, id, fn) {
|
|
|
225
281
|
throw new Error('A post can have at most 30 credits');
|
|
226
282
|
return client.put(`${POSTS}/list/${id}`, { credits: next });
|
|
227
283
|
}
|
|
284
|
+
const assetLabel = (a) => (a ? a.url || a.id || a : undefined);
|
|
228
285
|
function oneOf(value, allowed, flag) {
|
|
229
286
|
if (!allowed.includes(value))
|
|
230
287
|
throw new Error(`${flag} must be one of ${allowed.join(', ')}`);
|
|
@@ -239,8 +296,11 @@ function printPost(p) {
|
|
|
239
296
|
['project', p.projectStatus],
|
|
240
297
|
['category', p.category],
|
|
241
298
|
['tags', (p.tags || []).join(', ')],
|
|
299
|
+
['logline', p.logline],
|
|
242
300
|
['description', truncate(p.descriptionText || p.description, 120)],
|
|
243
|
-
['cover', p.cover
|
|
301
|
+
['cover', assetLabel(p.cover)],
|
|
302
|
+
['coverPortrait', assetLabel(p.coverPortrait)],
|
|
303
|
+
['trailer', p.trailer ? `${assetLabel(p.trailer)}${p.trailerDurationSec ? ` (${p.trailerDurationSec}s)` : ''}` : undefined],
|
|
244
304
|
['creator', p.creator?.name],
|
|
245
305
|
['likes', p.likeCount],
|
|
246
306
|
['updated', relativeTime(p.updatedAt)],
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { WjiClient } from '../core/client.js';
|
|
3
|
-
import { updateProfile } from '../core/config.js';
|
|
3
|
+
import { getProfile, updateProfile } from '../core/config.js';
|
|
4
4
|
import { confirm, parseKeyValues } from '../core/prompt.js';
|
|
5
5
|
import { color, detail, detailLevel, info, relativeTime, render, success, table, truncate } from '../core/output.js';
|
|
6
6
|
import { loadMembers, memberLabel, resolveMember } from '../core/members.js';
|
|
7
|
+
import { fetchModels } from './model.js';
|
|
7
8
|
/** App tokens accepted by `--app`; mirrors WorkspaceApplication on the backend. */
|
|
8
9
|
const APPS = {
|
|
9
10
|
dataset: 'Dataset',
|
|
@@ -342,6 +343,56 @@ export function workspaceCommand(globals) {
|
|
|
342
343
|
await client.delete(`/workspace/list/${wsId}/member/${m.memberId}`);
|
|
343
344
|
render({ removed: targets.map((m) => m.userId) }, () => success(`Removed ${names}`));
|
|
344
345
|
});
|
|
346
|
+
ws.command('leave <id>')
|
|
347
|
+
.description('Leave a workspace you were invited to (owners cannot leave)')
|
|
348
|
+
.option('-y, --yes', 'skip confirmation')
|
|
349
|
+
.action(async (id, opts) => {
|
|
350
|
+
const g = globals();
|
|
351
|
+
const client = new WjiClient(g);
|
|
352
|
+
const w = await client.get(`/workspace/list/${id}/basic`).catch(() => ({ name: id }));
|
|
353
|
+
if (!(await confirm(`Leave workspace "${w.name}" (${id})? You need a new invite to come back.`, opts.yes))) {
|
|
354
|
+
return info('Aborted');
|
|
355
|
+
}
|
|
356
|
+
const result = await client.post(`/workspace/list/${id}/leave`);
|
|
357
|
+
// A left workspace 403s from now on, so stop pointing the profile at it.
|
|
358
|
+
if (getProfile(g.profile).profile.workspace === id)
|
|
359
|
+
updateProfile(g.profile, { workspace: undefined });
|
|
360
|
+
render(result, () => success(`Left ${w.name} (${id})`));
|
|
361
|
+
});
|
|
362
|
+
// ── default models ─────────────────────────────────────────────────────────
|
|
363
|
+
ws.command('defaults [id]')
|
|
364
|
+
.description('Show or set the workspace default models (pass "none" to clear one)')
|
|
365
|
+
.option('--chat <model>', 'default chat model for new conversations')
|
|
366
|
+
.option('--image <model>', 'default image model')
|
|
367
|
+
.option('--video <model>', 'default video model')
|
|
368
|
+
.option('--storyboard <model>', 'default storyboard model')
|
|
369
|
+
.option('--audio <model>', 'default audio model')
|
|
370
|
+
.option('--image-resolution <value>', 'default image resolution, e.g. 2K')
|
|
371
|
+
.option('--video-resolution <value>', 'default video resolution, e.g. 720p')
|
|
372
|
+
.action(async (id, opts) => {
|
|
373
|
+
const client = new WjiClient(globals());
|
|
374
|
+
const wsId = client.requireWorkspace(id);
|
|
375
|
+
// settings only comes back at full detail, and PUT replaces settings whole —
|
|
376
|
+
// read it fresh so prompts / defaultApp / improvePromptDefault survive.
|
|
377
|
+
const w = await client.getFresh(`/workspace/list/${wsId}`, { detail: 'full' });
|
|
378
|
+
const current = { ...(w.settings?.defaultModels || {}) };
|
|
379
|
+
const changes = DEFAULT_MODEL_KEYS.filter((key) => opts[key] !== undefined);
|
|
380
|
+
if (!changes.length) {
|
|
381
|
+
return render(current, () => detail(DEFAULT_MODEL_KEYS.map((key) => [key, current[key] ?? color.dim('—')])));
|
|
382
|
+
}
|
|
383
|
+
const next = { ...current };
|
|
384
|
+
const needsModels = changes.some((key) => !key.endsWith('Resolution') && !isNone(opts[key]));
|
|
385
|
+
const models = needsModels ? await fetchModels(client, { workspace: wsId }) : [];
|
|
386
|
+
for (const key of changes) {
|
|
387
|
+
const raw = String(opts[key]).trim();
|
|
388
|
+
next[key] = isNone(raw) ? null : key.endsWith('Resolution') ? raw : resolveDefaultModel(models, key, raw);
|
|
389
|
+
}
|
|
390
|
+
await client.put(`/workspace/list/${wsId}`, { settings: { ...(w.settings || {}), defaultModels: next } });
|
|
391
|
+
render(next, () => {
|
|
392
|
+
success('Default models updated');
|
|
393
|
+
detail(DEFAULT_MODEL_KEYS.map((key) => [key, next[key] ?? color.dim('—')]));
|
|
394
|
+
});
|
|
395
|
+
});
|
|
345
396
|
// ── quota / stats ──────────────────────────────────────────────────────────
|
|
346
397
|
ws.command('quota [id]')
|
|
347
398
|
.description('Show credit quota usage')
|
|
@@ -384,6 +435,28 @@ export function workspaceCommand(globals) {
|
|
|
384
435
|
});
|
|
385
436
|
return ws;
|
|
386
437
|
}
|
|
438
|
+
const DEFAULT_MODEL_KEYS = [
|
|
439
|
+
'chat',
|
|
440
|
+
'image',
|
|
441
|
+
'video',
|
|
442
|
+
'storyboard',
|
|
443
|
+
'audio',
|
|
444
|
+
'imageResolution',
|
|
445
|
+
'videoResolution',
|
|
446
|
+
];
|
|
447
|
+
const isNone = (value) => ['none', 'null', ''].includes(String(value ?? '').trim().toLowerCase());
|
|
448
|
+
/**
|
|
449
|
+
* The web stores the chat default as the model `name` (what conversations carry)
|
|
450
|
+
* and the media defaults as the `nickname` its pickers emit — the value `-m` takes.
|
|
451
|
+
* Accept either spelling and store what the web would.
|
|
452
|
+
*/
|
|
453
|
+
function resolveDefaultModel(models, key, value) {
|
|
454
|
+
const model = models.find((m) => m.nickname === value || m.name === value);
|
|
455
|
+
if (!model) {
|
|
456
|
+
throw new Error(`Unknown model "${value}" for --${key}. See \`wji models list\`.`);
|
|
457
|
+
}
|
|
458
|
+
return key === 'chat' ? model.name : model.nickname || model.name;
|
|
459
|
+
}
|
|
387
460
|
export function printTree(node, prefix = '', connector = '') {
|
|
388
461
|
if (!node)
|
|
389
462
|
return;
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,12 @@ import { backreelCommand } from './commands/backreel.js';
|
|
|
23
23
|
// Read from package.json so `wji --version` cannot drift from the published
|
|
24
24
|
// version — the skill compares the two to detect a stale install.
|
|
25
25
|
const VERSION = createRequire(import.meta.url)('../package.json').version;
|
|
26
|
+
// `wji … | head` closes the pipe early; that is the reader being done, not a crash.
|
|
27
|
+
process.stdout.on('error', (err) => {
|
|
28
|
+
if (err.code === 'EPIPE')
|
|
29
|
+
process.exit(0);
|
|
30
|
+
throw err;
|
|
31
|
+
});
|
|
26
32
|
const program = new Command();
|
|
27
33
|
program
|
|
28
34
|
.name('wji')
|
package/package.json
CHANGED
package/skill/wji/SKILL.md
CHANGED
|
@@ -84,6 +84,9 @@ Most commands take `--workspace`, but setting a default is less error-prone:
|
|
|
84
84
|
```bash
|
|
85
85
|
wji ws list
|
|
86
86
|
wji ws use <workspaceId>
|
|
87
|
+
wji ws defaults # default chat / image / video / audio models
|
|
88
|
+
wji ws defaults --chat <model> --video <nickname> # "none" clears one
|
|
89
|
+
wji ws leave <workspaceId> # leave a workspace you were invited to
|
|
87
90
|
```
|
|
88
91
|
|
|
89
92
|
After that, `wji ws get`, `wji fs`, `wji gen` and `wji preset list` all default
|
|
@@ -319,8 +322,12 @@ wji agent skill-add <agentId> system:image user:<skillId>
|
|
|
319
322
|
wji agent skills <agentId>
|
|
320
323
|
wji agent versions <agentId> # every edit auto-snapshots a version
|
|
321
324
|
wji agent restore <agentId> <versionId>
|
|
325
|
+
wji agent update <agentId> --max-steps 80 # model calls per chat turn (default 40, max 200)
|
|
322
326
|
```
|
|
323
327
|
|
|
328
|
+
Versions, files, update and restore are creator-only — a 403 `無權操作此 Agent`
|
|
329
|
+
on someone else's agent is expected.
|
|
330
|
+
|
|
324
331
|
Skill refs are `system:<key>` or `user:<skillId>` (a bare id means `user:`).
|
|
325
332
|
System keys currently include `image`, `document`, `workspace-dataset`,
|
|
326
333
|
`canvas` and `seedance-25` — confirm with `wji skill system`.
|
|
@@ -493,6 +500,8 @@ wji backreel set <postId> --project-status in_production
|
|
|
493
500
|
wji backreel credit add <postId> --kind creative --name "Wayne" --role 導演
|
|
494
501
|
wji backreel credit add <postId> --npc @mika --role "飾 阿明" --job appearance
|
|
495
502
|
wji backreel publish <postId> # unpublish takes it offline
|
|
503
|
+
wji backreel set <postId> --logline "一句話賣點" # always public, ≤200 chars
|
|
504
|
+
wji backreel creators --role investor # browse creators
|
|
496
505
|
```
|
|
497
506
|
|
|
498
507
|
- Credits (max 30) are rewritten whole in order; `credit rm` goes by number.
|
|
@@ -72,6 +72,8 @@ switch endpoint.
|
|
|
72
72
|
| `ws update [id] [-n] [-d] [-r] [-l] [--set]` | `PUT /workspace/list/:id` |
|
|
73
73
|
| `ws rm <id> [-y]` | `DELETE /workspace/list/:id` (owner only) |
|
|
74
74
|
| `ws favorite <id> [--off]` | `PUT /workspace/list/:id/favorite` |
|
|
75
|
+
| `ws leave <id> [-y]` | `POST /workspace/list/:id/leave` — any member except the owner; coming back needs a new invite. Clears the profile default if it pointed there |
|
|
76
|
+
| `ws defaults [id] [--chat] [--image] [--video] [--storyboard] [--audio] [--image-resolution] [--video-resolution]` | no flags: shows `settings.defaultModels`. With flags: reads the workspace at `detail=full`, merges, `PUT /workspace/list/:id {settings}` (settings is replaced whole, so never send a partial `settings` via `ws update --set`). `none` clears one. Chat is stored as the model **name** (what conversations carry), media as the **nickname**; either spelling is accepted. The chat default is used for new conversations in the workspace |
|
|
75
77
|
| `ws fs [id] [-a appId]` | `GET /workspace/list/:id/fs[/:appid]` |
|
|
76
78
|
| `ws app list\|add <app> [-n]\|rm <appId> [-y]` | `POST/DELETE /workspace/list/:id/apps` |
|
|
77
79
|
| `ws member list [id] [-r role]` | members from `GET /workspace/list/:id` (there is no member-list endpoint): name, email, role, user id, membership id |
|
|
@@ -275,16 +277,20 @@ the CLI rejects both up front.
|
|
|
275
277
|
| --- | --- |
|
|
276
278
|
| `backreel list [--all] [-k] [--page] [--limit]` | `GET /backreel/post/search/my` (`--all`: `GET /backreel/post/search`) |
|
|
277
279
|
| `backreel get <postId>` | `GET /backreel/post/list/:id` |
|
|
278
|
-
| `backreel create <title> [--kind showcase\|crowdfunding] [--category] [--project-status] [--tags a,b] [-d text\|@file] [--cover assetId] [--cover-portrait] [--trailer] [--body json]` | `POST /backreel/post/create` (always a draft) |
|
|
280
|
+
| `backreel create <title> [--kind showcase\|crowdfunding] [--logline] [--category] [--project-status] [--tags a,b] [-d text\|@file] [--cover assetId] [--cover-portrait] [--trailer] [--body json]` | `POST /backreel/post/create` (always a draft) |
|
|
279
281
|
| `backreel set <postId> [--title] [same flags]` | `PUT /backreel/post/list/:id` with only the given fields |
|
|
280
282
|
| `backreel publish\|unpublish <postId>` | `POST /backreel/post/list/:id/publish\|unpublish` (publish needs a cover, media or an episode) |
|
|
281
283
|
| `backreel rm <postId> [-y]` | `DELETE /backreel/post/list/:id` |
|
|
284
|
+
| `backreel creators [-k] [--role kind] [--verified] [--no-featured] [--page] [--limit ≤48]` | `GET /backreel/creator/list` — editor-picked `featured` plus a heat-ranked page (recent likes, favorites ×2); creators with no recent activity are not listed. `--role`: investor, production_company, brand, distributor, sales_agent |
|
|
282
285
|
| `backreel credit list <postId>` | the post's `credits[]`, numbered |
|
|
283
286
|
| `backreel credit add <postId> --role [--name] [--kind cast\|crew\|creative] [--npc] [--user] [--link] [--job <type>]` | read, append, `PUT {credits}`; `--job` then appends to the NPC's `jobs` (own NPCs only, checked first) |
|
|
284
287
|
| `backreel credit rm <postId> <n...> [-y]` | read, drop, `PUT {credits}` |
|
|
285
288
|
|
|
286
289
|
Project status: planning, pre_production, in_production, post_production,
|
|
287
|
-
completed.
|
|
290
|
+
completed. `--logline` is a one-line hook (≤200 chars, HTML stripped, `""`
|
|
291
|
+
clears it) shown large on the post page and **always public**, even when the
|
|
292
|
+
description is gated. The post detail no longer carries playable URLs for VOD
|
|
293
|
+
episodes — playback is gated per episode on the web. `-d` plain text becomes `<p>` paragraphs; HTML passes through and
|
|
288
294
|
is sanitized server-side. Admin routes (`/api/backreel/*`) reject `sk_` keys.
|
|
289
295
|
|
|
290
296
|
## gen
|
|
@@ -361,7 +367,7 @@ Features: `text`, `image`, `video`, `audio`, `tts`, `web`, `thinking`,
|
|
|
361
367
|
## agent
|
|
362
368
|
|
|
363
369
|
`agent list` (public marketplace) · `agent mine` · `agent get <id>` ·
|
|
364
|
-
`agent create <name> -d [-i instructions] [-m model] [--visibility] [-c] [-t] [--greeting]` ·
|
|
370
|
+
`agent create <name> -d [-i instructions] [-m model] [--visibility] [-c] [-t] [--greeting] [--max-steps n]` ·
|
|
365
371
|
`agent update <id> …` · `agent rm <id> [-y]` · `agent files <id>` ·
|
|
366
372
|
`agent categories [--mine]` · `agent tags [--mine]` · `agent recommend`
|
|
367
373
|
|
|
@@ -380,6 +386,17 @@ takes `--skill <ref...>`.
|
|
|
380
386
|
Visibility: `private`, `unlist`, `public`. Instructions are only returned to
|
|
381
387
|
the agent's creator.
|
|
382
388
|
|
|
389
|
+
Ownership (backend since Oct 2026): a private agent is readable only by its
|
|
390
|
+
creator; `update`, `rm`, `files`, `versions` and `restore` are creator-only on
|
|
391
|
+
every agent (403 `無權操作此 Agent` otherwise — not a bug). `agent create`
|
|
392
|
+
needs the account's agent-create permission (without it: 400 `您沒有此功能的訪問權限`). `--set` cannot change `creator` or
|
|
393
|
+
`organization`, and non-admins cannot set `key`, `isSystem`, `isHighligted`,
|
|
394
|
+
`recommendTitle`, `weight` or `store` — the server drops them silently.
|
|
395
|
+
|
|
396
|
+
`--max-steps n` caps model calls per chat turn (1–200; parallel tool calls in
|
|
397
|
+
one step count once). Unset means the site default, 40. `update --max-steps
|
|
398
|
+
default` clears it.
|
|
399
|
+
|
|
383
400
|
Field caps: name ≤200, model ≤100, description and greeting ≤5,000,
|
|
384
401
|
instructions ≤200,000 characters.
|
|
385
402
|
|