@joshski/dust 0.1.51 → 0.1.53
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/dust.js +10 -1
- package/dist/logging/index.d.ts +44 -0
- package/dist/logging/match.d.ts +19 -0
- package/dist/logging/sink.d.ts +24 -0
- package/dist/logging.js +86 -0
- package/package.json +6 -2
package/dist/dust.js
CHANGED
|
@@ -3386,6 +3386,9 @@ function runBufferedProcess(spawnFn, command, commandArguments, cwd, shell, time
|
|
|
3386
3386
|
timer = setTimeout(() => {
|
|
3387
3387
|
resolved = true;
|
|
3388
3388
|
proc.kill();
|
|
3389
|
+
proc.stdout?.destroy();
|
|
3390
|
+
proc.stderr?.destroy();
|
|
3391
|
+
proc.unref();
|
|
3389
3392
|
resolve({
|
|
3390
3393
|
exitCode: 1,
|
|
3391
3394
|
output: chunks.join(""),
|
|
@@ -5131,4 +5134,10 @@ async function wireEntry(fsPrimitives, processPrimitives, consolePrimitives) {
|
|
|
5131
5134
|
}
|
|
5132
5135
|
|
|
5133
5136
|
// lib/cli/run.ts
|
|
5134
|
-
await wireEntry({ existsSync, statSync: statSync2, readFile: readFile2, writeFile: writeFile2, mkdir: mkdir2, readdir: readdir2, chmod: chmod2 }, {
|
|
5137
|
+
await wireEntry({ existsSync, statSync: statSync2, readFile: readFile2, writeFile: writeFile2, mkdir: mkdir2, readdir: readdir2, chmod: chmod2 }, {
|
|
5138
|
+
argv: process.argv,
|
|
5139
|
+
cwd: () => process.cwd(),
|
|
5140
|
+
exit: (code) => {
|
|
5141
|
+
process.exitCode = code;
|
|
5142
|
+
}
|
|
5143
|
+
}, { log: console.log, error: console.error });
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal debug logging framework.
|
|
3
|
+
*
|
|
4
|
+
* When the DEBUG environment variable is set, matching loggers write
|
|
5
|
+
* timestamped lines to `<cwd>/log/dust/<scope>.log`.
|
|
6
|
+
*
|
|
7
|
+
* The scope defaults to "debug" but can be changed via setLogScope()
|
|
8
|
+
* so that different commands (e.g. `loop`, `check`, `bucket`) write
|
|
9
|
+
* to separate log files.
|
|
10
|
+
*
|
|
11
|
+
* DEBUG is a comma-separated list of match expressions. Each expression
|
|
12
|
+
* can contain `*` as a wildcard (matches any sequence of characters).
|
|
13
|
+
*
|
|
14
|
+
* Examples:
|
|
15
|
+
* DEBUG=* → matches all loggers
|
|
16
|
+
* DEBUG=dust.bucket,dust.loop → exact matches
|
|
17
|
+
* DEBUG=dust.bucket.* → matches dust.bucket.loop, dust.bucket.ws, etc.
|
|
18
|
+
* DEBUG=*loop → matches dust.cli.commands.loop, dust.bucket.loop, etc.
|
|
19
|
+
*
|
|
20
|
+
* Logger names follow the convention `dust.<path>` mirroring the directory
|
|
21
|
+
* structure under `lib/`. For example, `lib/bucket/repository-loop.ts` uses
|
|
22
|
+
* the logger name `dust.bucket.repository-loop`.
|
|
23
|
+
*
|
|
24
|
+
* No external dependencies.
|
|
25
|
+
*/
|
|
26
|
+
import { type WriteFn } from './sink';
|
|
27
|
+
export { setLogScope } from './sink';
|
|
28
|
+
export type LogFn = (...messages: unknown[]) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Create a named logger function. The returned function writes to
|
|
31
|
+
* `log/dust/<scope>.log` when the logger name matches the DEBUG patterns.
|
|
32
|
+
*
|
|
33
|
+
* @param name - Logger name, e.g. `dust.bucket.loop`
|
|
34
|
+
* @param write - Override the default file writer (for testing)
|
|
35
|
+
*/
|
|
36
|
+
export declare function createLogger(name: string, write?: WriteFn): LogFn;
|
|
37
|
+
/**
|
|
38
|
+
* Check whether a logger name would be enabled under the current DEBUG value.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isEnabled(name: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Reset internal state (for testing only).
|
|
43
|
+
*/
|
|
44
|
+
export declare function _reset(): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure pattern-matching logic for debug logger names.
|
|
3
|
+
*
|
|
4
|
+
* Parses a DEBUG-style string (comma-separated, `*` wildcards)
|
|
5
|
+
* and tests logger names against it. No side effects.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Parse a DEBUG expression string into an array of RegExp matchers.
|
|
9
|
+
* Returns an empty array when the input is empty or undefined.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parsePatterns(debug: string | undefined): RegExp[];
|
|
12
|
+
/**
|
|
13
|
+
* Test whether a logger name matches any of the compiled patterns.
|
|
14
|
+
*/
|
|
15
|
+
export declare function matchesAny(name: string, patterns: RegExp[]): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Format a log line with ISO timestamp and logger name.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatLine(name: string, messages: unknown[]): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based log sink — the imperative shell for debug logging.
|
|
3
|
+
*
|
|
4
|
+
* Lazily creates `<cwd>/log/dust/<scope>.log` and appends lines to it.
|
|
5
|
+
* The scope defaults to "debug" but can be changed via setLogScope()
|
|
6
|
+
* so that different commands write to separate log files.
|
|
7
|
+
*/
|
|
8
|
+
export type WriteFn = (line: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Set the log scope, which determines the output filename.
|
|
11
|
+
* Must be called before any logger writes (i.e. at command startup).
|
|
12
|
+
*
|
|
13
|
+
* For example, `setLogScope('loop')` writes to `log/dust/loop.log`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function setLogScope(name: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Write a line to the debug log file.
|
|
18
|
+
* Silently no-ops if the file cannot be opened.
|
|
19
|
+
*/
|
|
20
|
+
export declare const writeToFile: WriteFn;
|
|
21
|
+
/**
|
|
22
|
+
* Reset sink state (for testing only).
|
|
23
|
+
*/
|
|
24
|
+
export declare function _resetSink(): void;
|
package/dist/logging.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// lib/logging/match.ts
|
|
2
|
+
function parsePatterns(debug) {
|
|
3
|
+
if (!debug)
|
|
4
|
+
return [];
|
|
5
|
+
const expressions = debug.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
6
|
+
return expressions.map((expr) => {
|
|
7
|
+
const escaped = expr.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
8
|
+
const pattern = escaped.replace(/\*/g, ".*");
|
|
9
|
+
return new RegExp(`^${pattern}$`);
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function matchesAny(name, patterns) {
|
|
13
|
+
return patterns.some((re) => re.test(name));
|
|
14
|
+
}
|
|
15
|
+
function formatLine(name, messages) {
|
|
16
|
+
const text = messages.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
17
|
+
return `${new Date().toISOString()} [${name}] ${text}
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// lib/logging/sink.ts
|
|
22
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
var logPath;
|
|
25
|
+
var ready = false;
|
|
26
|
+
var scope = process.env.DEBUG_LOG_SCOPE || "debug";
|
|
27
|
+
function ensureLogFile() {
|
|
28
|
+
if (ready)
|
|
29
|
+
return logPath;
|
|
30
|
+
ready = true;
|
|
31
|
+
const dir = join(process.cwd(), "log", "dust");
|
|
32
|
+
logPath = join(dir, `${scope}.log`);
|
|
33
|
+
try {
|
|
34
|
+
mkdirSync(dir, { recursive: true });
|
|
35
|
+
} catch {
|
|
36
|
+
logPath = undefined;
|
|
37
|
+
}
|
|
38
|
+
return logPath;
|
|
39
|
+
}
|
|
40
|
+
function setLogScope(name) {
|
|
41
|
+
scope = name;
|
|
42
|
+
process.env.DEBUG_LOG_SCOPE = name;
|
|
43
|
+
logPath = undefined;
|
|
44
|
+
ready = false;
|
|
45
|
+
}
|
|
46
|
+
var writeToFile = (line) => {
|
|
47
|
+
const path = ensureLogFile();
|
|
48
|
+
if (!path)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
appendFileSync(path, line);
|
|
52
|
+
} catch {}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// lib/logging/index.ts
|
|
56
|
+
var patterns = null;
|
|
57
|
+
var initialized = false;
|
|
58
|
+
function init() {
|
|
59
|
+
if (initialized)
|
|
60
|
+
return;
|
|
61
|
+
initialized = true;
|
|
62
|
+
const parsed = parsePatterns(process.env.DEBUG);
|
|
63
|
+
patterns = parsed.length > 0 ? parsed : null;
|
|
64
|
+
}
|
|
65
|
+
function createLogger(name, write = writeToFile) {
|
|
66
|
+
return (...messages) => {
|
|
67
|
+
init();
|
|
68
|
+
if (!patterns || !matchesAny(name, patterns))
|
|
69
|
+
return;
|
|
70
|
+
write(formatLine(name, messages));
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function isEnabled(name) {
|
|
74
|
+
init();
|
|
75
|
+
return patterns !== null && matchesAny(name, patterns);
|
|
76
|
+
}
|
|
77
|
+
function _reset() {
|
|
78
|
+
initialized = false;
|
|
79
|
+
patterns = null;
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
setLogScope,
|
|
83
|
+
isEnabled,
|
|
84
|
+
createLogger,
|
|
85
|
+
_reset
|
|
86
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joshski/dust",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"description": "Flow state for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
"import": "./dist/workflow-tasks.js",
|
|
15
15
|
"types": "./dist/workflow-tasks.d.ts"
|
|
16
16
|
},
|
|
17
|
+
"./logging": {
|
|
18
|
+
"import": "./dist/logging.js",
|
|
19
|
+
"types": "./dist/logging/index.d.ts"
|
|
20
|
+
},
|
|
17
21
|
"./istanbul/minimal-reporter": "./lib/istanbul/minimal-reporter.cjs"
|
|
18
22
|
},
|
|
19
23
|
"files": [
|
|
@@ -34,7 +38,7 @@
|
|
|
34
38
|
"author": "joshski",
|
|
35
39
|
"license": "MIT",
|
|
36
40
|
"scripts": {
|
|
37
|
-
"build": "bun build lib/cli/run.ts --target node --outfile dist/dust.js && printf '%s\\n%s' '#!/usr/bin/env node' \"$(cat dist/dust.js)\" > dist/dust.js && bun build lib/workflow-tasks.ts --target node --outfile dist/workflow-tasks.js && bunx tsc --project tsconfig.build.json",
|
|
41
|
+
"build": "bun build lib/cli/run.ts --target node --outfile dist/dust.js && printf '%s\\n%s' '#!/usr/bin/env node' \"$(cat dist/dust.js)\" > dist/dust.js && bun build lib/workflow-tasks.ts --target node --outfile dist/workflow-tasks.js && bun build lib/logging/index.ts --target node --outfile dist/logging.js && bunx tsc --project tsconfig.build.json",
|
|
38
42
|
"test": "vitest run",
|
|
39
43
|
"test:coverage": "vitest run --coverage",
|
|
40
44
|
"eval": "bun run ./evals/run.ts"
|