@huicai/cli 2026.711.0 → 2026.711.24617
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/LICENSE +43 -21
- package/package.json +4 -3
- package/src/advisor.js +1 -46
- package/src/agent.js +1 -518
- package/src/api.js +1 -359
- package/src/autofix.js +1 -90
- package/src/banner.js +1 -83
- package/src/checkpoints.js +1 -99
- package/src/clipboard.js +1 -34
- package/src/codeindex.js +1 -229
- package/src/colors.js +1 -47
- package/src/commands.js +1 -1294
- package/src/compaction.js +1 -144
- package/src/config.js +1 -86
- package/src/consult.js +1 -65
- package/src/context-report.js +1 -119
- package/src/context.js +1 -152
- package/src/cron.js +1 -64
- package/src/daemon.js +1 -62
- package/src/device.js +1 -88
- package/src/diffview.js +1 -115
- package/src/doctor.js +1 -72
- package/src/executors.js +1 -391
- package/src/forks.js +1 -59
- package/src/gitflow.js +1 -140
- package/src/hooks.js +1 -207
- package/src/ide.js +1 -53
- package/src/input.js +1 -182
- package/src/insights.js +1 -102
- package/src/kbsync.js +1 -141
- package/src/markdown.js +0 -0
- package/src/markup-filter.js +1 -85
- package/src/mcp.js +1 -207
- package/src/memory.js +1 -161
- package/src/permissions.js +1 -120
- package/src/render.js +1 -138
- package/src/repl.js +1 -271
- package/src/scan.js +1 -84
- package/src/schedule.js +1 -48
- package/src/session.js +1 -140
- package/src/settings.js +0 -0
- package/src/skills.js +1 -248
- package/src/subagent.js +1 -183
- package/src/todo.js +1 -75
- package/src/tools.js +1 -147
- package/src/transcript.js +1 -94
- package/src/tui/app.js +1 -666
- package/src/usage.js +1 -43
- package/src/watch.js +1 -74
package/src/usage.js
CHANGED
|
@@ -1,43 +1 @@
|
|
|
1
|
-
|
|
2
|
-
// limit 约定:>0 上限;-1 无限;0 该档未开放。两窗(5小时/7天)取占比最高者。
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {{allowed?:boolean, used5h?:number, limit5h?:number, used7d?:number, limit7d?:number, resetAtEpochMs?:number|null}|null} win
|
|
6
|
-
* @returns {{level:'warn'|'exhausted', label:string, used:number, limit:number, pct:number, resetAtEpochMs?:number|null}|null}
|
|
7
|
-
* null = 正常(<80% 或无可判定窗口)。warn ≥80%;exhausted ≥100% 或平台判定 allowed=false。
|
|
8
|
-
*/
|
|
9
|
-
export function usageStatus(win) {
|
|
10
|
-
if (!win) return null;
|
|
11
|
-
let worst = null;
|
|
12
|
-
for (const w of [
|
|
13
|
-
{ label: '5小时', used: win.used5h, limit: win.limit5h },
|
|
14
|
-
{ label: '7天', used: win.used7d, limit: win.limit7d },
|
|
15
|
-
]) {
|
|
16
|
-
if (typeof w.limit !== 'number' || w.limit <= 0 || typeof w.used !== 'number') continue; // -1 无限 / 0 未开放
|
|
17
|
-
const pct = w.used / w.limit;
|
|
18
|
-
if (!worst || pct > worst.pct) worst = { ...w, pct };
|
|
19
|
-
}
|
|
20
|
-
if (win.allowed === false) {
|
|
21
|
-
return {
|
|
22
|
-
level: 'exhausted',
|
|
23
|
-
label: worst?.label || '窗口',
|
|
24
|
-
used: worst?.used,
|
|
25
|
-
limit: worst?.limit,
|
|
26
|
-
pct: worst ? worst.pct : 1,
|
|
27
|
-
resetAtEpochMs: win.resetAtEpochMs,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
if (!worst) return null;
|
|
31
|
-
if (worst.pct >= 1) return { level: 'exhausted', ...worst, resetAtEpochMs: win.resetAtEpochMs };
|
|
32
|
-
if (worst.pct >= 0.8) return { level: 'warn', ...worst, resetAtEpochMs: win.resetAtEpochMs };
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** 剩余时长(到 resetAtEpochMs)转「N小时M分后重置」;已过或缺省返回空串。 */
|
|
37
|
-
export function fmtReset(ms) {
|
|
38
|
-
const d = (ms || 0) - Date.now();
|
|
39
|
-
if (d <= 0) return '';
|
|
40
|
-
const h = Math.floor(d / 3600000);
|
|
41
|
-
const m = Math.round((d % 3600000) / 60000);
|
|
42
|
-
return h > 0 ? `${h}小时${m}分后重置` : `${m}分后重置`;
|
|
43
|
-
}
|
|
1
|
+
export function usageStatus(e){if(!e)return null;let t=null;for(const l of[{label:"5小时",used:e.used5h,limit:e.limit5h},{label:"7天",used:e.used7d,limit:e.limit7d}]){if("number"!=typeof l.limit||l.limit<=0||"number"!=typeof l.used)continue;const e=l.used/l.limit;(!t||e>t.pct)&&(t={...l,pct:e})}return!1===e.allowed?{level:"exhausted",label:t?.label||"窗口",used:t?.used,limit:t?.limit,pct:t?t.pct:1,resetAtEpochMs:e.resetAtEpochMs}:t?t.pct>=1?{level:"exhausted",...t,resetAtEpochMs:e.resetAtEpochMs}:t.pct>=.8?{level:"warn",...t,resetAtEpochMs:e.resetAtEpochMs}:null:null}export function fmtReset(e){const t=(e||0)-Date.now();if(t<=0)return"";const l=Math.floor(t/36e5),s=Math.round(t%36e5/6e4);return l>0?`${l}小时${s}分后重置`:`${s}分后重置`}
|
package/src/watch.js
CHANGED
|
@@ -1,74 +1 @@
|
|
|
1
|
-
|
|
2
|
-
// 例:保存代码即自动跑测试/审查。默认任务可自定义(-p),文件名可用 glob 过滤(--glob "*.js")。
|
|
3
|
-
|
|
4
|
-
import { spawn } from 'node:child_process';
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import { huicaiBin } from './forks.js';
|
|
8
|
-
|
|
9
|
-
const IGNORE = new Set([
|
|
10
|
-
'.git', 'node_modules', 'dist', 'build', 'target', 'out', '.next', '.nuxt',
|
|
11
|
-
'.venv', 'venv', '__pycache__', '.idea', '.gradle', 'coverage', '.cache',
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
function patToRegex(pattern) {
|
|
15
|
-
return new RegExp('^' + String(pattern).replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') + '$');
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 启动文件监听。
|
|
20
|
-
* @param {{cwd:string, prompt:string, pattern?:string, debounceMs?:number, log?:(s:string)=>void, spawnImpl?:Function}} p
|
|
21
|
-
*/
|
|
22
|
-
export async function runWatch({ cwd, prompt, pattern = null, debounceMs = 1500, log = (s) => process.stdout.write(s + '\n'), spawnImpl }) {
|
|
23
|
-
const bin = huicaiBin();
|
|
24
|
-
if (!bin && !spawnImpl) throw new Error('无法定位 huicai 可执行文件(watch 需在 CLI 环境运行)');
|
|
25
|
-
const re = pattern ? patToRegex(pattern) : null;
|
|
26
|
-
let timer = null;
|
|
27
|
-
let running = false;
|
|
28
|
-
const changed = new Set();
|
|
29
|
-
|
|
30
|
-
const doSpawn = spawnImpl || ((fullPrompt) => {
|
|
31
|
-
const child = spawn(process.execPath, [bin, '-p', fullPrompt, '--yolo', '--plain'], { cwd, stdio: 'inherit', env: process.env });
|
|
32
|
-
return child;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const trigger = () => {
|
|
36
|
-
if (running) return;
|
|
37
|
-
running = true;
|
|
38
|
-
const files = [...changed];
|
|
39
|
-
changed.clear();
|
|
40
|
-
log(`\n▶ 变更 ${files.length} 文件 → 触发智能体:${prompt}`);
|
|
41
|
-
const fullPrompt = prompt + (files.length ? `\n(刚变更的文件:${files.slice(0, 20).join(', ')})` : '');
|
|
42
|
-
const child = doSpawn(fullPrompt);
|
|
43
|
-
const done = () => {
|
|
44
|
-
running = false;
|
|
45
|
-
if (changed.size) schedule();
|
|
46
|
-
};
|
|
47
|
-
if (child && child.on) child.on('close', done);
|
|
48
|
-
else done();
|
|
49
|
-
};
|
|
50
|
-
const schedule = () => {
|
|
51
|
-
if (timer) clearTimeout(timer);
|
|
52
|
-
timer = setTimeout(trigger, debounceMs);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const watcher = fs.watch(cwd, { recursive: true }, (event, filename) => {
|
|
56
|
-
if (!filename) return;
|
|
57
|
-
const rel = String(filename);
|
|
58
|
-
const top = rel.split(path.sep)[0];
|
|
59
|
-
if (IGNORE.has(top)) return;
|
|
60
|
-
if (re && !re.test(path.basename(rel))) return;
|
|
61
|
-
changed.add(rel);
|
|
62
|
-
schedule();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
log(`huicai 监听已启动:${cwd}${pattern ? ` (${pattern})` : ''} → 变更即跑「${prompt}」· Ctrl-C 退出`);
|
|
66
|
-
await new Promise((resolve) => {
|
|
67
|
-
process.on('SIGINT', () => {
|
|
68
|
-
watcher.close();
|
|
69
|
-
if (timer) clearTimeout(timer);
|
|
70
|
-
log('\n监听已停止。');
|
|
71
|
-
resolve();
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
}
|
|
1
|
+
import{spawn as e}from"node:child_process";import t from"node:fs";import n from"node:path";import{huicaiBin as o}from"./forks.js";const r=new Set([".git","node_modules","dist","build","target","out",".next",".nuxt",".venv","venv","__pycache__",".idea",".gradle","coverage",".cache"]);export async function runWatch({cwd:c,prompt:s,pattern:i=null,debounceMs:a=1500,log:l=e=>process.stdout.write(e+"\n"),spawnImpl:p}){const u=o();if(!u&&!p)throw new Error("无法定位 huicai 可执行文件(watch 需在 CLI 环境运行)");const d=i?function(e){return new RegExp("^"+String(e).replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*")+"$")}(i):null;let m=null,h=!1;const w=new Set,g=p||(t=>e(process.execPath,[u,"-p",t,"--yolo","--plain"],{cwd:c,stdio:"inherit",env:process.env})),f=()=>{if(h)return;h=!0;const e=[...w];w.clear(),l(`\n▶ 变更 ${e.length} 文件 → 触发智能体:${s}`);const t=s+(e.length?`\n(刚变更的文件:${e.slice(0,20).join(", ")})`:""),n=g(t),o=()=>{h=!1,w.size&&$()};n&&n.on?n.on("close",o):o()},$=()=>{m&&clearTimeout(m),m=setTimeout(f,a)},v=t.watch(c,{recursive:!0},(e,t)=>{if(!t)return;const o=String(t),c=o.split(n.sep)[0];r.has(c)||d&&!d.test(n.basename(o))||(w.add(o),$())});l(`huicai 监听已启动:${c}${i?` (${i})`:""} → 变更即跑「${s}」· Ctrl-C 退出`),await new Promise(e=>{process.on("SIGINT",()=>{v.close(),m&&clearTimeout(m),l("\n监听已停止。"),e()})})}
|