@liustack/modlens 2.7.1 → 2.7.2
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/main.js +49 -16
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -724,6 +724,7 @@ function listProviders() {
|
|
|
724
724
|
}
|
|
725
725
|
const DEFAULT_TIMEOUT_MS = 18e4;
|
|
726
726
|
const KILL_GRACE_MS = 3e4;
|
|
727
|
+
const DRAIN_GRACE_MS = 500;
|
|
727
728
|
async function analyzeImage(options) {
|
|
728
729
|
const resolvedInput = resolveInput(options.input);
|
|
729
730
|
if (resolvedInput.kind === "local") {
|
|
@@ -806,18 +807,60 @@ function runCommand(providerName, invocation, timeoutMs) {
|
|
|
806
807
|
let stdout = "";
|
|
807
808
|
let stderr = "";
|
|
808
809
|
let timedOut = false;
|
|
810
|
+
let settled = false;
|
|
811
|
+
let drainTimer;
|
|
809
812
|
const timer = setTimeout(() => {
|
|
810
813
|
timedOut = true;
|
|
811
814
|
child.kill("SIGTERM");
|
|
812
815
|
}, timeoutMs);
|
|
816
|
+
const settle = (code) => {
|
|
817
|
+
if (settled) {
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
settled = true;
|
|
821
|
+
clearTimeout(timer);
|
|
822
|
+
clearTimeout(drainTimer);
|
|
823
|
+
child.stdout?.destroy();
|
|
824
|
+
child.stderr?.destroy();
|
|
825
|
+
child.unref();
|
|
826
|
+
if (timedOut) {
|
|
827
|
+
reject(new Error(`${providerName} provider timed out after ${timeoutMs} ms.`));
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
if (code !== 0) {
|
|
831
|
+
reject(
|
|
832
|
+
new Error(
|
|
833
|
+
`${providerName} provider failed with code ${code}.${stderr ? ` stderr: ${stderr.trim()}` : ""}`
|
|
834
|
+
)
|
|
835
|
+
);
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
resolve({ stdout, stderr });
|
|
839
|
+
};
|
|
840
|
+
let exitCode = null;
|
|
841
|
+
let exited = false;
|
|
842
|
+
const restartDrain = () => {
|
|
843
|
+
if (!exited || settled) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
clearTimeout(drainTimer);
|
|
847
|
+
drainTimer = setTimeout(() => settle(exitCode), DRAIN_GRACE_MS);
|
|
848
|
+
};
|
|
813
849
|
child.stdout.on("data", (chunk) => {
|
|
814
850
|
stdout += chunk.toString();
|
|
851
|
+
restartDrain();
|
|
815
852
|
});
|
|
816
853
|
child.stderr.on("data", (chunk) => {
|
|
817
854
|
stderr += chunk.toString();
|
|
855
|
+
restartDrain();
|
|
818
856
|
});
|
|
819
857
|
child.on("error", (error) => {
|
|
858
|
+
if (settled) {
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
settled = true;
|
|
820
862
|
clearTimeout(timer);
|
|
863
|
+
clearTimeout(drainTimer);
|
|
821
864
|
if (error.code === "ENOENT") {
|
|
822
865
|
reject(
|
|
823
866
|
new Error(
|
|
@@ -828,22 +871,12 @@ function runCommand(providerName, invocation, timeoutMs) {
|
|
|
828
871
|
}
|
|
829
872
|
reject(error);
|
|
830
873
|
});
|
|
831
|
-
child.on("
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
return;
|
|
836
|
-
}
|
|
837
|
-
if (code !== 0) {
|
|
838
|
-
reject(
|
|
839
|
-
new Error(
|
|
840
|
-
`${providerName} provider failed with code ${code}.${stderr ? ` stderr: ${stderr.trim()}` : ""}`
|
|
841
|
-
)
|
|
842
|
-
);
|
|
843
|
-
return;
|
|
844
|
-
}
|
|
845
|
-
resolve({ stdout, stderr });
|
|
874
|
+
child.on("exit", (code) => {
|
|
875
|
+
exitCode = code;
|
|
876
|
+
exited = true;
|
|
877
|
+
restartDrain();
|
|
846
878
|
});
|
|
879
|
+
child.on("close", (code) => settle(code));
|
|
847
880
|
});
|
|
848
881
|
}
|
|
849
882
|
const EXT_BY_MIME = {
|
|
@@ -1236,7 +1269,7 @@ function recoverPastedImages(options = {}) {
|
|
|
1236
1269
|
return result;
|
|
1237
1270
|
}
|
|
1238
1271
|
const program = new Command();
|
|
1239
|
-
program.name("modlens").description("Plug-in vision for text-only LLMs: image in, structured JSON evidence out").version("2.7.
|
|
1272
|
+
program.name("modlens").description("Plug-in vision for text-only LLMs: image in, structured JSON evidence out").version("2.7.2");
|
|
1240
1273
|
program.command("analyze", { isDefault: true }).description("Analyze an image into structured JSON evidence (default command)").requiredOption("-i, --input <path|url>", "Input image path or https URL").option("-o, --output <path>", "Write result JSON to a file").option("-m, --model <name>", "Provider model name").option("-p, --provider <name>", `Vision provider (${listProviders().join(", ")})`).option("--prompt <text>", "Extra focus for this image").option("--timeout <ms>", "Provider timeout in milliseconds", "180000").option("--provider-bin <path>", "Provider binary path (default: agy)").option("--workdir <path>", "Working directory for the provider").action(async (options) => {
|
|
1241
1274
|
try {
|
|
1242
1275
|
const timeoutMs = Number.parseInt(options.timeout, 10);
|