ushman-ledger 1.3.0 → 1.3.1

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/README.md CHANGED
@@ -145,14 +145,18 @@ ushman-ledger record --workspace=<ws> --kind=change-log --subkind=semantic-clean
145
145
  ushman-ledger note regression --workspace=<ws> --phase=cleanup --summary="runtime drift" --body=/tmp/note.md
146
146
  ushman-ledger note cleanup-wave --workspace=<ws> --phase=cleanup --summary="wave 1" --body=/tmp/narrative.md
147
147
  ushman-ledger list --workspace=<ws> --json
148
+ ushman-ledger list --workspace=<ws> --json --progress
148
149
  ushman-ledger render --workspace=<ws> --to=retro
149
150
  ushman-ledger render --workspace=<ws> --to=migration-log-md
150
151
  ushman-ledger render --workspace=<ws> --to=workspace-narrative-md
152
+ ushman-ledger render --workspace=<ws> --to=retro --out=/tmp/retro.md --quiet
151
153
  ushman-ledger render --workspace=<ws> --to=jsonl --out=/tmp/ledger.jsonl
152
154
  ushman-ledger render --workspace=<ws> --to=dependency-graph --out=/tmp/ledger.mmd
153
155
  ushman-ledger archive --workspace=<ws> --out=/tmp/ledger.tgz
156
+ ushman-ledger archive --workspace=<ws> --out=/tmp/ledger.tgz --progress
154
157
  ushman-ledger doctor --workspace=<ws>
155
158
  ushman-ledger doctor --workspace=<ws> --json
159
+ ushman-ledger doctor --workspace=<ws> --quiet
156
160
  ```
157
161
 
158
162
  Valid record kinds: `tool-invocation`, `stage-write`, `agent-patch`, `operator-patch`, `operator-decision`, `validator-result`, `runtime-event`, `note`, `correction`, `strip-decision-reverted`, `change-log`
@@ -184,6 +188,12 @@ Valid render targets: `retro`, `jsonl`, `timeline-html`, `dependency-graph`, `mi
184
188
  `render()` still returns a string for in-memory callers. `renderTo()` is the bounded-output alternative for large ledgers and can write to a callback or the canonical render file on disk.
185
189
  `renderTo()` writers receive sequential chunks, can return synchronously or asynchronously, and should throw only when the render should abort.
186
190
 
191
+ ## CLI quiet and progress modes
192
+
193
+ - `--progress` writes concise progress lines to stderr for long-running `list`, `render`, `archive`, and `doctor` CLI operations. Stdout remains reserved for the command result, so `list --json --progress` still emits parseable JSON.
194
+ - `--quiet` suppresses verbose human output on those commands. `doctor --quiet` prints `ok` or one finding code per line; `archive --quiet` and `render --quiet` print `ok` on success; `list --quiet` prints one entry id per line for non-JSON output.
195
+ - `--quiet` takes precedence over `--progress`. For render targets without a canonical ledger render file, such as `jsonl` and `dependency-graph`, `render --quiet` requires `--out`.
196
+
187
197
  ## Workspace prerequisite
188
198
 
189
199
  `openLedger()` and the CLI expect a valid ushman v4 workspace with `.lab/lab.json` already present.
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA6DA,KAAK,UAAU,GAAG;IACd,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE;QACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC1C,CAAC;AAsjCF,eAAO,MAAM,YAAY,GAAU,MAAM,SAAS,MAAM,EAAE,EAAE,UAAS,OAAO,CAAC,UAAU,CAAM,KAAG,OAAO,CAAC,MAAM,CAqC7G,CAAC;AAEF,eAAO,MAAM,IAAI,GAAU,OAAM,SAAS,MAAM,EAA0B,KAAG,OAAO,CAAC,MAAM,CAE1F,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAmEA,KAAK,UAAU,GAAG;IACd,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE;QACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC5B,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC1C,CAAC;AAomCF,eAAO,MAAM,YAAY,GAAU,MAAM,SAAS,MAAM,EAAE,EAAE,UAAS,OAAO,CAAC,UAAU,CAAM,KAAG,OAAO,CAAC,MAAM,CAqC7G,CAAC;AAEF,eAAO,MAAM,IAAI,GAAU,OAAM,SAAS,MAAM,EAA0B,KAAG,OAAO,CAAC,MAAM,CAE1F,CAAC"}
package/dist/cli.js CHANGED
@@ -15,7 +15,7 @@ import { LEDGER_LIBRARY_VERSION } from "./version.js";
15
15
  const execFileAsync = promisify(execFile);
16
16
  const DEFAULT_GIT_DIFF_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
17
17
  const DEFAULT_GIT_DIFF_TIMEOUT_MS = 30_000;
18
- const BOOLEAN_FLAG_NAMES = new Set(['from-stdin', 'help', 'json']);
18
+ const BOOLEAN_FLAG_NAMES = new Set(['from-stdin', 'help', 'json', 'progress', 'quiet']);
19
19
  const GIT_DIFF_FORMAT_ARGS = ['--no-color', '--no-ext-diff', '--src-prefix=a/', '--dst-prefix=b/'];
20
20
  const RENDER_TARGETS = [
21
21
  'retro',
@@ -25,6 +25,12 @@ const RENDER_TARGETS = [
25
25
  'migration-log-md',
26
26
  'workspace-narrative-md',
27
27
  ];
28
+ const CANONICAL_RENDER_TARGETS = new Set([
29
+ 'migration-log-md',
30
+ 'retro',
31
+ 'timeline-html',
32
+ 'workspace-narrative-md',
33
+ ]);
28
34
  const GIT_DIFF_FLAG_NAMES = ['git-diff-max-buffer-bytes', 'git-diff-timeout-ms', 'git-paths'];
29
35
  const CHANGE_LOG_RECORD_ONLY_FLAGS = [
30
36
  'commands',
@@ -75,12 +81,12 @@ const renderHelp = (commandName) => `${commandName}
75
81
  Commands:
76
82
  ${renderRecordUsage(commandName)}
77
83
  ${commandName} note <subkind> [--workspace=<ws>] --phase=<phase> --summary="..." [--body=<markdown-file>] [--from-stdin]
78
- ${commandName} list [--workspace=<ws>] [--phase=<phase>] [--kind=<kind>] [--since=<iso>] [--limit=<n>] [--json]
84
+ ${commandName} list [--workspace=<ws>] [--phase=<phase>] [--kind=<kind>] [--since=<iso>] [--limit=<n>] [--json] [--quiet] [--progress]
79
85
  ${commandName} show [--workspace=<ws>] <entry-id>
80
86
  ${commandName} tail [--workspace=<ws>] [--phase=<phase>] [--limit=<n>]
81
- ${commandName} render [--workspace=<ws>] [--to=retro|jsonl|timeline-html|dependency-graph|migration-log-md|workspace-narrative-md] [--phase=<phase>] [--since=<iso>] [--limit=<n>] [--out=<file>]
82
- ${commandName} archive [--workspace=<ws>] --out=<file.tgz>
83
- ${commandName} doctor [--workspace=<ws>] [--json]
87
+ ${commandName} render [--workspace=<ws>] [--to=retro|jsonl|timeline-html|dependency-graph|migration-log-md|workspace-narrative-md] [--phase=<phase>] [--since=<iso>] [--limit=<n>] [--out=<file>] [--quiet] [--progress]
88
+ ${commandName} archive [--workspace=<ws>] --out=<file.tgz> [--quiet] [--progress]
89
+ ${commandName} doctor [--workspace=<ws>] [--json] [--quiet] [--progress]
84
90
  ${commandName} --version
85
91
 
86
92
  ${renderValidValues()}
@@ -98,17 +104,17 @@ ${renderRuntimeTuningHelp()}`;
98
104
  ${renderValidValues()}
99
105
  ${renderRuntimeTuningHelp()}`;
100
106
  case 'list':
101
- return `${commandName} list [--workspace=<ws>] [--phase=<phase>] [--kind=<kind>] [--since=<iso>] [--limit=<n>] [--json]
107
+ return `${commandName} list [--workspace=<ws>] [--phase=<phase>] [--kind=<kind>] [--since=<iso>] [--limit=<n>] [--json] [--quiet] [--progress]
102
108
 
103
109
  ${renderValidValues()}
104
110
  ${renderRuntimeTuningHelp()}`;
105
111
  case 'render':
106
- return `${commandName} render [--workspace=<ws>] [--to=<target>] [--phase=<phase>] [--since=<iso>] [--limit=<n>] [--out=<file>]
112
+ return `${commandName} render [--workspace=<ws>] [--to=<target>] [--phase=<phase>] [--since=<iso>] [--limit=<n>] [--out=<file>] [--quiet] [--progress]
107
113
 
108
114
  ${renderValidValues()}
109
115
  ${renderRuntimeTuningHelp()}`;
110
116
  case 'doctor':
111
- return `${commandName} doctor [--workspace=<ws>] [--json]
117
+ return `${commandName} doctor [--workspace=<ws>] [--json] [--quiet] [--progress]
112
118
 
113
119
  ${renderRuntimeTuningHelp()}`;
114
120
  default:
@@ -307,6 +313,14 @@ const print = (context, text) => {
307
313
  const printJson = (context, value) => {
308
314
  print(context, JSON.stringify(value, null, 2));
309
315
  };
316
+ const isQuiet = (flags) => hasFlag(flags, 'quiet');
317
+ const isProgressEnabled = (flags) => hasFlag(flags, 'progress') && !isQuiet(flags);
318
+ const printProgress = (context, flags, message) => {
319
+ if (!isProgressEnabled(flags)) {
320
+ return;
321
+ }
322
+ context.stderr.write(`progress ${message}\n`);
323
+ };
310
324
  const parseLimit = (flags) => getFlag(flags, 'limit')
311
325
  ? parsePositiveIntegerFlag({
312
326
  defaultValue: 0,
@@ -791,7 +805,9 @@ const runNoteCli = async (parsed, context) => {
791
805
  return 0;
792
806
  };
793
807
  const runListCli = async (parsed, context) => {
808
+ printProgress(context, parsed.flags, 'list start');
794
809
  const ledger = await openLedger(getWorkspaceRoot(parsed.flags));
810
+ let entryCount = 0;
795
811
  if (hasFlag(parsed.flags, 'json')) {
796
812
  let wroteEntry = false;
797
813
  context.stdout.write('[\n');
@@ -807,8 +823,10 @@ const runListCli = async (parsed, context) => {
807
823
  const renderedEntry = JSON.stringify(entry, null, 2).replaceAll('\n', '\n ');
808
824
  context.stdout.write(` ${renderedEntry}`);
809
825
  wroteEntry = true;
826
+ entryCount += 1;
810
827
  }
811
828
  context.stdout.write(wroteEntry ? '\n]\n' : ']\n');
829
+ printProgress(context, parsed.flags, `list done entries=${entryCount}`);
812
830
  return 0;
813
831
  }
814
832
  for await (const entry of ledger.list({
@@ -817,8 +835,15 @@ const runListCli = async (parsed, context) => {
817
835
  phase: parseOptionalPhase(parsed.flags),
818
836
  since: parseSince(parsed.flags),
819
837
  })) {
820
- print(context, `${entry.id} ${entry.phase} ${entry.kind} ${entry.summary}`);
838
+ entryCount += 1;
839
+ if (isQuiet(parsed.flags)) {
840
+ print(context, entry.id);
841
+ }
842
+ else {
843
+ print(context, `${entry.id} ${entry.phase} ${entry.kind} ${entry.summary}`);
844
+ }
821
845
  }
846
+ printProgress(context, parsed.flags, `list done entries=${entryCount}`);
822
847
  return 0;
823
848
  };
824
849
  const runShowCli = async (parsed, context) => {
@@ -843,6 +868,7 @@ const runTailCli = async (parsed, context) => runListCli({
843
868
  }, context);
844
869
  const runRenderCli = async (parsed, context) => {
845
870
  const target = parseRenderTarget(parsed.flags);
871
+ printProgress(context, parsed.flags, `render start target=${target}`);
846
872
  const ledger = await openLedger(getWorkspaceRoot(parsed.flags));
847
873
  const renderOptions = {
848
874
  limit: parseLimit(parsed.flags),
@@ -851,19 +877,29 @@ const runRenderCli = async (parsed, context) => {
851
877
  since: parseSince(parsed.flags),
852
878
  to: target,
853
879
  };
854
- if (renderOptions.out) {
880
+ if (isQuiet(parsed.flags) && !renderOptions.out && !CANONICAL_RENDER_TARGETS.has(target)) {
881
+ throw new CliUsageError(`render --quiet requires --out for ${target} output.`);
882
+ }
883
+ if (renderOptions.out || isQuiet(parsed.flags)) {
855
884
  await ledger.renderTo(renderOptions);
885
+ if (isQuiet(parsed.flags)) {
886
+ print(context, 'ok');
887
+ }
888
+ printProgress(context, parsed.flags, `render done target=${target}`);
856
889
  return 0;
857
890
  }
858
891
  const content = await ledger.render(renderOptions);
859
892
  print(context, content);
893
+ printProgress(context, parsed.flags, `render done target=${target}`);
860
894
  return 0;
861
895
  };
862
896
  const runArchiveCli = async (parsed, context) => {
863
897
  const outPath = getRequiredString(parsed.flags, 'out');
898
+ printProgress(context, parsed.flags, 'archive start');
864
899
  const ledger = await openLedger(getWorkspaceRoot(parsed.flags));
865
900
  const result = await ledger.archive(outPath);
866
- print(context, result.integrityHash);
901
+ print(context, isQuiet(parsed.flags) ? 'ok' : result.integrityHash);
902
+ printProgress(context, parsed.flags, 'archive done');
867
903
  return 0;
868
904
  };
869
905
  const formatDoctorFinding = (finding) => [`[${finding.code}] ${finding.message}`, `Next step: ${finding.remediation}`].join('\n');
@@ -878,17 +914,32 @@ const printDoctorFindings = (context, report) => {
878
914
  context.stderr.write('\n');
879
915
  };
880
916
  const runDoctorCli = async (parsed, context) => {
917
+ printProgress(context, parsed.flags, 'doctor start');
881
918
  const ledger = await openLedger(getWorkspaceRoot(parsed.flags));
882
919
  const result = await ledger.doctor();
883
920
  if (hasFlag(parsed.flags, 'json')) {
884
921
  printJson(context, result);
922
+ printProgress(context, parsed.flags, `doctor done issues=${result.issueCount}`);
923
+ return result.ok ? 0 : 1;
924
+ }
925
+ if (isQuiet(parsed.flags)) {
926
+ if (result.ok) {
927
+ print(context, 'ok');
928
+ }
929
+ else {
930
+ for (const finding of result.findings) {
931
+ print(context, finding.code);
932
+ }
933
+ }
885
934
  return result.ok ? 0 : 1;
886
935
  }
887
936
  if (result.ok) {
888
937
  print(context, 'ok');
938
+ printProgress(context, parsed.flags, 'doctor done issues=0');
889
939
  return 0;
890
940
  }
891
941
  printDoctorFindings(context, result);
942
+ printProgress(context, parsed.flags, `doctor done issues=${result.issueCount}`);
892
943
  return 1;
893
944
  };
894
945
  const formatCliError = (error) => {
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,sBAAsB;;;EAuBlC,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,UAAU,MAAM,EAAE,cAAc,kBAG7D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,EAAE,kBAAiB,kBAcpE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,KAAK,EACxC,WAAW,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC7C,QAAQ,MAAM,OAAO,CAAC,KAAK,CAAC,mBAuB/B,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,sBAAsB;;;EAuBlC,CAAC;AAEF,eAAO,MAAM,OAAO,GAAU,UAAU,MAAM,EAAE,cAAc,kBAG7D,CAAC;AAEF,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,EAAE,kBAAiB,kBAcpE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,KAAK,EACxC,WAAW,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC7C,QAAQ,MAAM,OAAO,CAAC,KAAK,CAAC,mBAuB/B,CAAC"}
package/dist/helpers.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { mkdir, mkdtemp, rm, stat, utimes, writeFile } from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
+ import { V4_SCHEMA_VERSION } from 'ushman-lab-types';
4
5
  export const createWorkspaceFixture = async () => {
5
6
  const workspaceRoot = await mkdtemp(path.join(os.tmpdir(), 'ushman-ledger-'));
6
7
  await mkdir(path.join(workspaceRoot, '.lab'), { recursive: true });
7
8
  await mkdir(path.join(workspaceRoot, 'src'), { recursive: true });
8
9
  await writeFile(path.join(workspaceRoot, '.lab', 'lab.json'), `${JSON.stringify({
9
- schemaVersion: 'ushman-lab/v4.0',
10
+ schemaVersion: V4_SCHEMA_VERSION,
10
11
  workspaceId: '3d71d4fb-dca0-4d63-9ad6-69d59a2395f4',
11
12
  }, null, 2)}\n`, 'utf8');
12
13
  return {
package/dist/lab-min.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as v from 'valibot';
2
2
  export declare const LabManifestMin: v.LooseObjectSchema<{
3
3
  readonly createdAt: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
4
- readonly schemaVersion: v.LiteralSchema<"ushman-lab/v4.0", undefined>;
4
+ readonly schemaVersion: v.LiteralSchema<"shibuk-lab/v4.0", undefined>;
5
5
  readonly workspaceId: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.UuidAction<string, undefined>]>;
6
6
  }, undefined>;
7
7
  export type LabManifestMin = v.InferOutput<typeof LabManifestMin>;
@@ -1 +1 @@
1
- {"version":3,"file":"lab-min.d.ts","sourceRoot":"","sources":["../src/lab-min.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,cAAc;;;;aAIzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,cAAc,CAAC,CAAC;AAElE,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,cAAc,CAWtF,CAAC"}
1
+ {"version":3,"file":"lab-min.d.ts","sourceRoot":"","sources":["../src/lab-min.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,cAAc;;;;aAIzB,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC,OAAO,cAAc,CAAC,CAAC;AAElE,eAAO,MAAM,kBAAkB,GAAU,eAAe,MAAM,KAAG,OAAO,CAAC,cAAc,CAWtF,CAAC"}
package/dist/lab-min.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
+ import { V4_SCHEMA_VERSION } from 'ushman-lab-types';
3
4
  import * as v from 'valibot';
4
5
  export const LabManifestMin = v.looseObject({
5
6
  createdAt: v.optional(v.string()),
6
- schemaVersion: v.literal('ushman-lab/v4.0'),
7
+ schemaVersion: v.literal(V4_SCHEMA_VERSION),
7
8
  workspaceId: v.pipe(v.string(), v.uuid()),
8
9
  });
9
10
  export const readLabManifestMin = async (workspaceRoot) => {
package/package.json CHANGED
@@ -12,6 +12,7 @@
12
12
  "dependencies": {
13
13
  "safe-stable-stringify": "^2.5.0",
14
14
  "tar": "^7.5.15",
15
+ "ushman-lab-types": "^0.2.0",
15
16
  "valibot": "^1.4.1"
16
17
  },
17
18
  "description": "Append-only workspace ledger library and CLI for Ushman v4.",
@@ -70,5 +71,5 @@
70
71
  },
71
72
  "type": "module",
72
73
  "types": "dist/index.d.ts",
73
- "version": "1.3.0"
74
+ "version": "1.3.1"
74
75
  }