pi-soly 2.5.3 → 2.5.5
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/package.json +1 -1
- package/quota/minimax.ts +47 -8
- package/visual/footer.ts +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-soly",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.5",
|
|
4
4
|
"description": "Workflow + project management for pi-coding-agent. Plans, state, MANDATORY rules, self-review, multi-question picker. One npm install, zero config. LLM drives the workflow inline via the soly_workflow tool — no external subagent plugin.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
package/quota/minimax.ts
CHANGED
|
@@ -26,8 +26,21 @@
|
|
|
26
26
|
// =============================================================================
|
|
27
27
|
|
|
28
28
|
import { execFile } from "node:child_process";
|
|
29
|
+
import * as fs from "node:fs";
|
|
30
|
+
import * as os from "node:os";
|
|
31
|
+
import * as path from "node:path";
|
|
29
32
|
import type { QuotaProvider, QuotaSnapshot } from "./types.ts";
|
|
30
33
|
|
|
34
|
+
/** TEMP DEBUG. */
|
|
35
|
+
const DEBUG_LOG = path.join(os.tmpdir(), "pi-soly-quota-debug.log");
|
|
36
|
+
function dbg(msg: string): void {
|
|
37
|
+
try { fs.appendFileSync(DEBUG_LOG, `[${new Date().toISOString()}] [minimax] ${msg}\n`); } catch { /* best effort */ }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Detect Windows (where npm-installed CLIs are `.cmd` shims that execFile
|
|
41
|
+
* can't spawn directly without a shell). */
|
|
42
|
+
const IS_WIN = process.platform === "win32";
|
|
43
|
+
|
|
31
44
|
/** Minimal shape we read from `mmx quota show --output json`. */
|
|
32
45
|
type MinimaxQuotaResponse = {
|
|
33
46
|
model_remains?: Array<{
|
|
@@ -39,12 +52,28 @@ type MinimaxQuotaResponse = {
|
|
|
39
52
|
};
|
|
40
53
|
|
|
41
54
|
/** Run mmx and capture stdout. Resolves to null on any failure
|
|
42
|
-
* (mmx missing, non-zero exit, timeout, bad JSON). Never throws.
|
|
55
|
+
* (mmx missing, non-zero exit, timeout, bad JSON). Never throws.
|
|
56
|
+
*
|
|
57
|
+
* On Windows, npm-global CLIs are `.cmd` shims (e.g. `mmx.cmd`). Node's
|
|
58
|
+
* `execFile` spawns the executable directly without a shell, so it can't
|
|
59
|
+
* resolve `mmx` → `mmx.cmd` and fails with ENOENT. `shell: true` lets the
|
|
60
|
+
* shell do that resolution. Safe here: args are fixed (no user input). */
|
|
43
61
|
function runMmx(args: string[], timeoutMs: number): Promise<string | null> {
|
|
44
62
|
return new Promise((resolve) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
63
|
+
const opts = {
|
|
64
|
+
encoding: "utf-8" as const,
|
|
65
|
+
timeout: timeoutMs,
|
|
66
|
+
maxBuffer: 1024 * 1024,
|
|
67
|
+
shell: IS_WIN, // resolve .cmd shims on Windows
|
|
68
|
+
};
|
|
69
|
+
execFile("mmx", args, opts, (err, stdout, stderr) => {
|
|
70
|
+
if (err) {
|
|
71
|
+
dbg(`runMmx error: ${err instanceof Error ? err.message : String(err)} (code=${(err as { code?: string }).code ?? "?"}) stderr=${(stderr ?? "").slice(0, 200)}`);
|
|
72
|
+
resolve(null);
|
|
73
|
+
} else {
|
|
74
|
+
dbg(`runMmx ok: ${String(stdout).length} bytes`);
|
|
75
|
+
resolve(stdout ?? "");
|
|
76
|
+
}
|
|
48
77
|
});
|
|
49
78
|
});
|
|
50
79
|
}
|
|
@@ -54,16 +83,26 @@ function parseGeneralQuota(raw: string): QuotaSnapshot | null {
|
|
|
54
83
|
let parsed: unknown;
|
|
55
84
|
try {
|
|
56
85
|
parsed = JSON.parse(raw);
|
|
57
|
-
} catch {
|
|
86
|
+
} catch (e) {
|
|
87
|
+
dbg(`parse: JSON.parse failed: ${e instanceof Error ? e.message : String(e)}; raw[0..100]=${raw.slice(0, 100)}`);
|
|
58
88
|
return null; // not valid JSON — mmx printed an error to stdout
|
|
59
89
|
}
|
|
60
90
|
// Cast at the boundary (single documented place, per code-style rules).
|
|
61
91
|
const data = parsed as MinimaxQuotaResponse;
|
|
62
|
-
if (data.base_resp?.status_code !== 0)
|
|
92
|
+
if (data.base_resp?.status_code !== 0) {
|
|
93
|
+
dbg(`parse: status_code=${data.base_resp?.status_code} (expected 0)`);
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
63
96
|
const general = data.model_remains?.find((m) => m.model_name === "general");
|
|
64
|
-
if (!general)
|
|
97
|
+
if (!general) {
|
|
98
|
+
dbg(`parse: no 'general' model entry; have: ${(data.model_remains ?? []).map((m) => m.model_name).join(",")}`);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
65
101
|
const pct = general.current_interval_remaining_percent;
|
|
66
|
-
if (typeof pct !== "number")
|
|
102
|
+
if (typeof pct !== "number") {
|
|
103
|
+
dbg(`parse: pct is ${typeof pct}`);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
67
106
|
return {
|
|
68
107
|
remainingPercent: pct,
|
|
69
108
|
resetsInMs: typeof general.remains_time === "number" ? general.remains_time : null,
|
package/visual/footer.ts
CHANGED
|
@@ -75,6 +75,21 @@ export function buildFooterLine(data: ChromeData, fd: FooterData, width: number,
|
|
|
75
75
|
const quotaText = ascii ? `${data.quotaPercent}%` : `⬢ ${data.quotaPercent}%`;
|
|
76
76
|
const label = data.quotaResetsLabel ? `${quotaText} · ${data.quotaResetsLabel}` : quotaText;
|
|
77
77
|
left.push({ id: "quota", text: styler.fg("muted", label), priority: 6 });
|
|
78
|
+
// TEMP DEBUG
|
|
79
|
+
try {
|
|
80
|
+
const fs = require("node:fs");
|
|
81
|
+
const os = require("node:os");
|
|
82
|
+
const p = require("node:path");
|
|
83
|
+
fs.appendFileSync(p.join(os.tmpdir(), "pi-soly-quota-debug.log"), `[${new Date().toISOString()}] [footer] render: pushed quota segment pct=${data.quotaPercent}\n`);
|
|
84
|
+
} catch {}
|
|
85
|
+
} else {
|
|
86
|
+
// TEMP DEBUG
|
|
87
|
+
try {
|
|
88
|
+
const fs = require("node:fs");
|
|
89
|
+
const os = require("node:os");
|
|
90
|
+
const p = require("node:path");
|
|
91
|
+
fs.appendFileSync(p.join(os.tmpdir(), "pi-soly-quota-debug.log"), `[${new Date().toISOString()}] [footer] render: quotaPercent=null (segment skipped)\n`);
|
|
92
|
+
} catch {}
|
|
78
93
|
}
|
|
79
94
|
|
|
80
95
|
if (data.rulesActive > 0) {
|