agens-studio 0.1.4 → 0.1.6

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/cli.js CHANGED
@@ -861,59 +861,88 @@ async function menuAssets() {
861
861
  else if (c === '4') search = await ask('搜索关键词');
862
862
  else if (c !== '1') { console.log(`${C.red}无效选择${C.reset}`); continue; }
863
863
 
864
- const { items, total } = await assetStore.listAssets({ type, search, pageSize: 20 });
864
+ const pageSize = 20;
865
+ let page = 1;
865
866
 
866
- if (items.length === 0) {
867
- console.log(`\n${C.gray}暂无素材${total > 0 ? `(共 ${total} 条,当前页为空)` : ''}${C.reset}`);
868
- continue;
869
- }
867
+ while (true) {
868
+ const { items, total } = await assetStore.listAssets({ type, search, page, pageSize });
869
+ const totalPages = Math.max(1, Math.ceil(total / pageSize));
870
+ const startIdx = (page - 1) * pageSize;
870
871
 
871
- console.log(`\n${C.bold}共 ${total} 条素材:${C.reset}\n`);
872
- items.forEach((a, i) => {
873
- const icon = a.type === 'video' ? '🎬' : '🖼';
874
- const prompt = (a.prompt || '').slice(0, 50);
875
- const note = a.note ? ` | ${a.note}` : '';
876
- console.log(` ${C.cyan}${String(i + 1).padStart(2)}.${C.reset} ${icon} ${a.filename}`);
877
- console.log(` ${C.gray}${prompt}${note}${C.reset}`);
878
- console.log(` ${formatSize(a.size)} | ${fmtDate(a.createdAt)} | ${a.kept ? C.green + '保留' + C.reset : C.gray + '未保留' + C.reset}`);
879
- });
872
+ if (items.length === 0) {
873
+ console.log(`\n${C.gray}暂无素材${total > 0 ? `(共 ${total} 条,当前页为空)` : ''}${C.reset}`);
874
+ break;
875
+ }
880
876
 
881
- // 操作
882
- console.log('');
883
- const op = await ask('输入序号查看详情/操作,或回车返回');
884
- if (!op) continue;
885
- const idx = parseInt(op, 10) - 1;
886
- if (isNaN(idx) || idx < 0 || idx >= items.length) { console.log(`${C.red}无效序号${C.reset}`); continue; }
877
+ console.log(`\n${C.bold}共 ${total} 条素材(第 ${page}/${totalPages} 页):${C.reset}\n`);
878
+ items.forEach((a, i) => {
879
+ const globalIdx = startIdx + i + 1;
880
+ const icon = a.type === 'video' ? '🎬' : '🖼';
881
+ const prompt = (a.prompt || '').slice(0, 50);
882
+ const note = a.note ? ` | ${a.note}` : '';
883
+ console.log(` ${C.cyan}${String(globalIdx).padStart(3)}.${C.reset} ${icon} ${a.filename}`);
884
+ console.log(` ${C.gray}${prompt}${note}${C.reset}`);
885
+ console.log(` ${formatSize(a.size)} | ${fmtDate(a.createdAt)} | ${a.kept ? C.green + '保留' + C.reset : C.gray + '未保留' + C.reset}`);
886
+ });
887
887
 
888
- const asset = items[idx];
889
- const absPath = path.join(config.dirs.root, asset.path);
890
- console.log(`\n${C.bold}素材详情:${C.reset}`);
891
- console.log(` ID:${asset.id}`);
892
- console.log(` 文件:${absPath}`);
893
- console.log(` 提示词:${asset.prompt || '(无)'}`);
894
- console.log(` 模式:${asset.mode || '(无)'}`);
895
- console.log(` 大小:${formatSize(asset.size)}`);
896
- console.log(` 创建:${fmtDate(asset.createdAt)}`);
897
- console.log(` 保留:${asset.kept ? '' : '否'}`);
898
- if (asset.note) console.log(` 备注:${asset.note}`);
899
-
900
- const action = await choose('操作', ['打开文件', '切换保留状态', '添加备注', '删除']);
901
- if (action === 0) {
902
- openFile(absPath);
903
- } else if (action === 1) {
904
- await assetStore.updateAsset(asset.id, { kept: !asset.kept });
905
- console.log(`${C.green}已${asset.kept ? '取消保留' : '标记保留'}${C.reset}`);
906
- } else if (action === 2) {
907
- const note = await ask('输入备注');
908
- if (note) {
909
- await assetStore.updateAsset(asset.id, { note });
910
- console.log(`${C.green}备注已保存${C.reset}`);
911
- }
912
- } else if (action === 3) {
913
- if (await confirm(`确认删除 ${asset.filename}`)) {
914
- await assetStore.deleteAsset(asset.id);
915
- console.log(`${C.green}已删除${C.reset}`);
888
+ const navHints = [];
889
+ if (page < totalPages) navHints.push('n=下一页');
890
+ if (page > 1) navHints.push('p=上一页');
891
+ const navStr = navHints.length ? `(${navHints.join(',')})` : '';
892
+
893
+ console.log('');
894
+ const op = await ask(`输入序号查看详情${navStr},或回车返回`);
895
+ if (!op) break;
896
+
897
+ if (op.toLowerCase() === 'n' && page < totalPages) { page++; continue; }
898
+ if (op.toLowerCase() === 'p' && page > 1) { page--; continue; }
899
+
900
+ const num = parseInt(op, 10);
901
+ if (isNaN(num) || num < 1 || num > total) { console.log(`${C.red}无效序号(范围 1-${total})${C.reset}`); continue; }
902
+
903
+ const targetPage = Math.ceil(num / pageSize);
904
+ const localIdx = num - (targetPage - 1) * pageSize - 1;
905
+ let asset;
906
+ if (targetPage === page) {
907
+ asset = items[localIdx];
908
+ } else {
909
+ const nextPageData = await assetStore.listAssets({ type, search, page: targetPage, pageSize });
910
+ asset = nextPageData.items[localIdx];
911
+ page = targetPage;
916
912
  }
913
+ if (asset) await showAssetDetail(asset);
914
+ }
915
+ }
916
+ }
917
+
918
+ async function showAssetDetail(asset) {
919
+ const absPath = path.join(config.dirs.root, asset.path);
920
+ console.log(`\n${C.bold}素材详情:${C.reset}`);
921
+ console.log(` ID:${asset.id}`);
922
+ console.log(` 文件:${absPath}`);
923
+ console.log(` 提示词:${asset.prompt || '(无)'}`);
924
+ console.log(` 模式:${asset.mode || '(无)'}`);
925
+ console.log(` 大小:${formatSize(asset.size)}`);
926
+ console.log(` 创建:${fmtDate(asset.createdAt)}`);
927
+ console.log(` 保留:${asset.kept ? '是' : '否'}`);
928
+ if (asset.note) console.log(` 备注:${asset.note}`);
929
+
930
+ const action = await choose('操作', ['打开文件', '切换保留状态', '添加备注', '删除']);
931
+ if (action === 0) {
932
+ openFile(absPath);
933
+ } else if (action === 1) {
934
+ await assetStore.updateAsset(asset.id, { kept: !asset.kept });
935
+ console.log(`${C.green}已${asset.kept ? '取消保留' : '标记保留'}${C.reset}`);
936
+ } else if (action === 2) {
937
+ const note = await ask('输入备注');
938
+ if (note) {
939
+ await assetStore.updateAsset(asset.id, { note });
940
+ console.log(`${C.green}备注已保存${C.reset}`);
941
+ }
942
+ } else if (action === 3) {
943
+ if (await confirm(`确认删除 ${asset.filename}`)) {
944
+ await assetStore.deleteAsset(asset.id);
945
+ console.log(`${C.green}已删除${C.reset}`);
917
946
  }
918
947
  }
919
948
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agens-studio",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Agens 创作工作台 —— AI 图片/视频生成 CLI + Web 工作台",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -76,7 +76,7 @@ async function localImageToString(localPath, asDataUri) {
76
76
 
77
77
  async function agnesFetch(url, opts, options) {
78
78
  const opts2 = options || {};
79
- const retries = opts2.retries != null ? opts2.retries : 3;
79
+ const retries = opts2.retries != null ? opts2.retries : 5;
80
80
  const timeoutMs = opts2.timeoutMs != null ? opts2.timeoutMs : 120000;
81
81
  let lastErr;
82
82
  for (let attempt = 0; attempt <= retries; attempt++) {
@@ -87,8 +87,20 @@ async function agnesFetch(url, opts, options) {
87
87
  clearTimeout(timer);
88
88
  if ((res.status === 429 || res.status === 503) && attempt < retries) {
89
89
  const t = await res.text().catch(function () { return ''; });
90
- console.log('[agnes] ' + res.status + ' busy, retry ' + (attempt + 1) + ' in 5s: ' + t.slice(0, 100));
91
- await new Promise(function (r) { setTimeout(r, 5000); });
90
+ // 429 = 限频(1次/分钟),等 65 秒;503 = 服务忙,等 15
91
+ const waitSec = res.status === 429 ? 65 : 15;
92
+ const reason = res.status === 429 ? '限频' : '服务忙';
93
+ console.log('[agnes] ' + res.status + ' ' + reason + ',' + waitSec + '秒后重试 (' + (attempt + 1) + '/' + retries + ')');
94
+ // 倒计时显示(仅 429 长等待时显示)
95
+ if (waitSec >= 30) {
96
+ for (let s = waitSec; s > 0; s--) {
97
+ process.stdout.write('\r 等待中... ' + s + '秒 ');
98
+ await new Promise(function (r) { setTimeout(r, 1000); });
99
+ }
100
+ process.stdout.write('\r' + ' '.repeat(40) + '\r');
101
+ } else {
102
+ await new Promise(function (r) { setTimeout(r, waitSec * 1000); });
103
+ }
92
104
  continue;
93
105
  }
94
106
  return res;