@joshski/dust 0.1.50 → 0.1.52
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 +7 -0
- 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
|
@@ -4131,12 +4131,16 @@ async function lintMarkdown(dependencies) {
|
|
|
4131
4131
|
}
|
|
4132
4132
|
|
|
4133
4133
|
// lib/cli/commands/check.ts
|
|
4134
|
+
var log5 = createLogger("dust.cli.commands.check");
|
|
4134
4135
|
var DEFAULT_CHECK_TIMEOUT_MS = 13000;
|
|
4135
4136
|
async function runSingleCheck(check, cwd, runner) {
|
|
4136
4137
|
const timeoutMs = check.timeoutMilliseconds ?? DEFAULT_CHECK_TIMEOUT_MS;
|
|
4138
|
+
log5(`running check ${check.name}: ${check.command}`);
|
|
4137
4139
|
const startTime = Date.now();
|
|
4138
4140
|
const result = await runner.run(check.command, cwd, timeoutMs);
|
|
4139
4141
|
const durationMs = Date.now() - startTime;
|
|
4142
|
+
const status = result.timedOut ? "timed out" : result.exitCode === 0 ? "passed" : "failed";
|
|
4143
|
+
log5(`check ${check.name} ${status} (${durationMs}ms)`);
|
|
4140
4144
|
return {
|
|
4141
4145
|
name: check.name,
|
|
4142
4146
|
command: check.command,
|
|
@@ -4166,6 +4170,7 @@ async function runValidationCheck(dependencies) {
|
|
|
4166
4170
|
stdout: (msg) => outputLines.push(msg),
|
|
4167
4171
|
stderr: (msg) => outputLines.push(msg)
|
|
4168
4172
|
};
|
|
4173
|
+
log5("running built-in check: dust lint");
|
|
4169
4174
|
const startTime = Date.now();
|
|
4170
4175
|
const result = await lintMarkdown({
|
|
4171
4176
|
...dependencies,
|
|
@@ -4173,6 +4178,8 @@ async function runValidationCheck(dependencies) {
|
|
|
4173
4178
|
arguments: []
|
|
4174
4179
|
});
|
|
4175
4180
|
const durationMs = Date.now() - startTime;
|
|
4181
|
+
const lintStatus = result.exitCode === 0 ? "passed" : "failed";
|
|
4182
|
+
log5(`built-in check dust lint ${lintStatus} (${durationMs}ms)`);
|
|
4176
4183
|
return {
|
|
4177
4184
|
name: "lint",
|
|
4178
4185
|
command: "dust lint",
|
|
@@ -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.52",
|
|
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"
|