@garygentry/system1 0.3.2 → 0.4.0

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.
@@ -71,7 +71,11 @@ var EXIT = {
71
71
  budgetGuard: 4,
72
72
  providerError: 5,
73
73
  replayMiss: 6,
74
- /** `spec check --strict` only: the check ran, and an example did not pass. */
74
+ /**
75
+ * The check ran and did not pass: `spec check --strict` (an example missed),
76
+ * or `spec lint` (an error-level finding or invalid spec; with `--strict`, any
77
+ * warning).
78
+ */
75
79
  checkFailed: 7
76
80
  };
77
81
  var BY_CODE = {
@@ -147,7 +151,7 @@ function extractFormat(argv, fallback) {
147
151
  }
148
152
 
149
153
  // ../core/dist/version.js
150
- var VERSION = "0.3.2";
154
+ var VERSION = "0.4.0";
151
155
  var CLI_PACKAGE = "@garygentry/system1";
152
156
 
153
157
  export {
@@ -2,10 +2,10 @@ import { createRequire as __decideRequire } from "node:module"; const require =
2
2
  import {
3
3
  parseFileRef,
4
4
  parseQuestionSet
5
- } from "./chunk-5TUBFH7M.mjs";
5
+ } from "./chunk-QYUSJUFX.mjs";
6
6
  import {
7
7
  DecisionsError
8
- } from "./chunk-4ZZ3ZSJN.mjs";
8
+ } from "./chunk-WZIVOY5Q.mjs";
9
9
 
10
10
  // src/args.ts
11
11
  import { readFileSync } from "node:fs";
@@ -23,9 +23,11 @@ var DECIDE_OPTIONS = {
23
23
  staged: { type: "boolean" },
24
24
  text: { type: "string" },
25
25
  stdin: { type: "boolean" },
26
+ exclude: { type: "string", multiple: true },
26
27
  "allow-outside": { type: "boolean" },
27
28
  split: { type: "string" },
28
29
  keep: { type: "string", multiple: true },
30
+ "keep-any": { type: "string", multiple: true },
29
31
  sort: { type: "string" },
30
32
  limit: { type: "string" },
31
33
  fields: { type: "string" },
@@ -104,8 +106,10 @@ function buildInput(values, readStdin, cwd = process.cwd()) {
104
106
  );
105
107
  }
106
108
  if (sources.length) input.sources = sources;
109
+ set("exclude", values.exclude?.length ? values.exclude : void 0);
107
110
  set("split", values.split);
108
111
  set("keep", values.keep?.length ? values.keep : void 0);
112
+ set("keepAny", values["keep-any"]?.length ? values["keep-any"] : void 0);
109
113
  set("sort", values.sort);
110
114
  set("limit", int(values.limit, "--limit"));
111
115
  set(
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
2
2
  import {
3
3
  typedParse
4
- } from "./chunk-BGL272OK.mjs";
4
+ } from "./chunk-XNRV73UE.mjs";
5
5
  import {
6
6
  DEFAULT_EXCLUDES,
7
7
  activeTriggers,
@@ -10,11 +10,11 @@ import {
10
10
  loadConfig,
11
11
  repoConfigPath,
12
12
  setConsent
13
- } from "./chunk-5TUBFH7M.mjs";
13
+ } from "./chunk-QYUSJUFX.mjs";
14
14
  import {
15
15
  DecisionsError,
16
16
  emit
17
- } from "./chunk-4ZZ3ZSJN.mjs";
17
+ } from "./chunk-WZIVOY5Q.mjs";
18
18
 
19
19
  // src/commands/config.ts
20
20
  function runConfigCommand(argv, io, format) {
@@ -2,21 +2,21 @@ import { createRequire as __decideRequire } from "node:module"; const require =
2
2
  import {
3
3
  briefAsk,
4
4
  briefMany
5
- } from "./chunk-5LVOFZF3.mjs";
5
+ } from "./chunk-FU3D2MBS.mjs";
6
6
  import {
7
7
  buildInput,
8
8
  parseDecideFlags
9
- } from "./chunk-BGL272OK.mjs";
9
+ } from "./chunk-XNRV73UE.mjs";
10
10
  import {
11
11
  createContext,
12
12
  runAsk,
13
13
  runMany
14
- } from "./chunk-5TUBFH7M.mjs";
14
+ } from "./chunk-QYUSJUFX.mjs";
15
15
  import {
16
16
  DecisionsError,
17
17
  ENVELOPE_VERSION,
18
18
  emit
19
- } from "./chunk-4ZZ3ZSJN.mjs";
19
+ } from "./chunk-WZIVOY5Q.mjs";
20
20
 
21
21
  // src/commands/decide.ts
22
22
  import { readFileSync } from "node:fs";
@@ -1,10 +1,10 @@
1
1
  import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
2
2
  import {
3
3
  runDoctor
4
- } from "./chunk-5TUBFH7M.mjs";
4
+ } from "./chunk-QYUSJUFX.mjs";
5
5
  import {
6
6
  emit
7
- } from "./chunk-4ZZ3ZSJN.mjs";
7
+ } from "./chunk-WZIVOY5Q.mjs";
8
8
 
9
9
  // src/commands/doctor.ts
10
10
  import { execFile } from "node:child_process";
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
2
2
  import {
3
3
  typedParse
4
- } from "./chunk-BGL272OK.mjs";
4
+ } from "./chunk-XNRV73UE.mjs";
5
5
  import {
6
6
  TOOL_SCHEMAS,
7
7
  createContext,
@@ -10,13 +10,13 @@ import {
10
10
  probeUrl,
11
11
  resolveConnection,
12
12
  runUsage
13
- } from "./chunk-5TUBFH7M.mjs";
13
+ } from "./chunk-QYUSJUFX.mjs";
14
14
  import {
15
15
  DecisionsError,
16
16
  EXIT,
17
17
  emit,
18
18
  isDecisionsError
19
- } from "./chunk-4ZZ3ZSJN.mjs";
19
+ } from "./chunk-WZIVOY5Q.mjs";
20
20
 
21
21
  // src/commands/misc.ts
22
22
  function runSchemaCommand(argv, io, format) {
@@ -0,0 +1,144 @@
1
+ import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
2
+ import {
3
+ typedParse
4
+ } from "./chunk-XNRV73UE.mjs";
5
+ import {
6
+ createContext,
7
+ runOpportunitiesAdd,
8
+ runOpportunitiesCheck,
9
+ runOpportunitiesList
10
+ } from "./chunk-QYUSJUFX.mjs";
11
+ import {
12
+ DecisionsError,
13
+ emit
14
+ } from "./chunk-WZIVOY5Q.mjs";
15
+
16
+ // src/commands/opportunities.ts
17
+ import { readFileSync } from "node:fs";
18
+ import { resolve } from "node:path";
19
+ var OPPORTUNITIES_OPTIONS = {
20
+ file: { type: "string" },
21
+ keep: { type: "string", multiple: true },
22
+ sort: { type: "string" },
23
+ limit: { type: "string" },
24
+ fields: { type: "string" }
25
+ };
26
+ var USAGE = "Usage: decide opportunities add --file <candidates.json> | list [--keep \u2026] [--sort \u2026] [--limit N] [--fields a,b] | check";
27
+ function runOpportunitiesCommand(argv, io, format) {
28
+ const [action, ...rest] = argv;
29
+ const ctx = () => createContext({ ...io, cwd: io.cwd ?? process.cwd(), env: io.env });
30
+ const cwd = io.cwd ?? process.cwd();
31
+ switch (action) {
32
+ case "add":
33
+ return emit(
34
+ io,
35
+ "opportunities",
36
+ format,
37
+ () => {
38
+ const { values } = parse(rest, ["file"]);
39
+ if (!values.file) throw new DecisionsError("invalid-request", USAGE);
40
+ return runOpportunitiesAdd(ctx(), {
41
+ candidates: readCandidates(resolve(cwd, values.file), values.file)
42
+ });
43
+ },
44
+ (r, f) => f === "brief" ? `decide opportunities add: ${r.added.length} added \xB7 ${r.updated.length} updated \xB7 ${r.staled.length} marked stale \xB7 ${r.total} in ${r.file}` : void 0
45
+ );
46
+ case "list":
47
+ return emit(
48
+ io,
49
+ "opportunities",
50
+ format,
51
+ () => {
52
+ const { values } = parse(rest, ["keep", "sort", "limit", "fields"]);
53
+ if (values.limit !== void 0 && !/^\d+$/.test(values.limit)) {
54
+ throw new DecisionsError("invalid-request", "--limit must be a whole number");
55
+ }
56
+ return runOpportunitiesList(ctx(), {
57
+ ...values.keep?.length ? { keep: values.keep } : {},
58
+ ...values.sort ? { sort: values.sort } : {},
59
+ ...values.limit !== void 0 ? { limit: Number(values.limit) } : {},
60
+ ...values.fields ? {
61
+ fields: values.fields.split(",").map((s) => s.trim()).filter(Boolean)
62
+ } : {}
63
+ });
64
+ },
65
+ (r, f) => f === "brief" ? briefList(r) : void 0
66
+ );
67
+ case "check":
68
+ return emit(
69
+ io,
70
+ "opportunities",
71
+ format,
72
+ () => {
73
+ parse(rest, []);
74
+ return runOpportunitiesCheck(ctx());
75
+ },
76
+ (r, f) => f === "brief" ? r.exists ? `decide opportunities check: valid \xB7 ${r.entries} entr${r.entries === 1 ? "y" : "ies"}${Object.keys(r.byStatus).length ? ` (${Object.entries(r.byStatus).map(([s, n]) => `${n} ${s}`).join(", ")})` : ""} \xB7 ${r.file}` : `decide opportunities check: no backlog yet (${r.file})` : void 0
77
+ );
78
+ default:
79
+ return emit(io, "opportunities", format, () => {
80
+ throw new DecisionsError("invalid-request", USAGE);
81
+ });
82
+ }
83
+ }
84
+ function parse(argv, allowed) {
85
+ const options = Object.fromEntries(allowed.map((k) => [k, OPPORTUNITIES_OPTIONS[k]]));
86
+ return typedParse({ args: argv, options, strict: true });
87
+ }
88
+ function readCandidates(path, ref) {
89
+ let text;
90
+ try {
91
+ text = readFileSync(path, "utf8");
92
+ } catch {
93
+ throw new DecisionsError("invalid-request", `--file: cannot read ${ref}`);
94
+ }
95
+ let value;
96
+ try {
97
+ value = JSON.parse(text);
98
+ } catch (error) {
99
+ throw new DecisionsError(
100
+ "invalid-request",
101
+ `--file ${ref}: not JSON (${error.message})`
102
+ );
103
+ }
104
+ if (Array.isArray(value)) return value;
105
+ if (value && typeof value === "object" && "candidates" in value) {
106
+ const extra = Object.keys(value).filter((k) => k !== "candidates");
107
+ if (extra.length) {
108
+ throw new DecisionsError(
109
+ "invalid-request",
110
+ `--file ${ref}: unknown key(s) ${extra.join(", ")}; only "candidates" is read`
111
+ );
112
+ }
113
+ return value.candidates;
114
+ }
115
+ throw new DecisionsError(
116
+ "invalid-request",
117
+ `--file ${ref}: expected a JSON array of candidates, or {"candidates": [...]}`
118
+ );
119
+ }
120
+ function briefList(r) {
121
+ const lines = [
122
+ `decide opportunities list: ${r.opportunities.length} shown \xB7 ${r.matched} matched \xB7 ${r.total} total \xB7 savings projected`
123
+ ];
124
+ for (const o of r.opportunities) {
125
+ const where = o.location ? `${o.location.path}${o.location.lines ? `:${o.location.lines.start}-${o.location.lines.end}` : ""}` : "";
126
+ const saving = o.projected ? ` \xB7 $${o.projected.savingUsd} per ${o.projected.per} (projected)` : "";
127
+ const head = [
128
+ o.id,
129
+ o.status,
130
+ o.mode,
131
+ o.shape,
132
+ o.benefit,
133
+ o.risk ? `risk ${o.risk.level}` : void 0
134
+ ].filter(Boolean).join(" \xB7 ");
135
+ lines.push(` ${head}${saving}${where ? ` ${where}` : ""}`);
136
+ if (o.mechanism) lines.push(` ${o.mechanism}`);
137
+ if (o.statusReason) lines.push(` ${o.status}: ${o.statusReason}`);
138
+ }
139
+ return lines.join("\n");
140
+ }
141
+ export {
142
+ OPPORTUNITIES_OPTIONS,
143
+ runOpportunitiesCommand
144
+ };
@@ -1,14 +1,14 @@
1
1
  import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
2
2
  import {
3
3
  typedParse
4
- } from "./chunk-BGL272OK.mjs";
4
+ } from "./chunk-XNRV73UE.mjs";
5
5
  import {
6
6
  runRoute
7
- } from "./chunk-5TUBFH7M.mjs";
7
+ } from "./chunk-QYUSJUFX.mjs";
8
8
  import {
9
9
  DecisionsError,
10
10
  emit
11
- } from "./chunk-4ZZ3ZSJN.mjs";
11
+ } from "./chunk-WZIVOY5Q.mjs";
12
12
 
13
13
  // src/commands/route.ts
14
14
  import { readFileSync } from "node:fs";
@@ -1,23 +1,25 @@
1
1
  import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
2
2
  import {
3
- briefSpecCheck
4
- } from "./chunk-5LVOFZF3.mjs";
3
+ briefSpecCheck,
4
+ briefSpecLint
5
+ } from "./chunk-FU3D2MBS.mjs";
5
6
  import {
6
7
  typedParse
7
- } from "./chunk-BGL272OK.mjs";
8
+ } from "./chunk-XNRV73UE.mjs";
8
9
  import {
9
10
  assertExamples,
10
11
  createContext,
11
12
  exampleProblems,
12
13
  listSpecs,
13
14
  loadSpec,
14
- runSpecCheck
15
- } from "./chunk-5TUBFH7M.mjs";
15
+ runSpecCheck,
16
+ runSpecLint
17
+ } from "./chunk-QYUSJUFX.mjs";
16
18
  import {
17
19
  DecisionsError,
18
20
  EXIT,
19
21
  emit
20
- } from "./chunk-4ZZ3ZSJN.mjs";
22
+ } from "./chunk-WZIVOY5Q.mjs";
21
23
 
22
24
  // src/commands/spec.ts
23
25
  function runSpecCommand(argv, io, format) {
@@ -72,11 +74,13 @@ function runSpecCommand(argv, io, format) {
72
74
  );
73
75
  case "check":
74
76
  return check(argv.slice(1), io, format, ctx);
77
+ case "lint":
78
+ return lint(argv.slice(1), io, format, ctx);
75
79
  default:
76
80
  return emit(io, "spec", format, () => {
77
81
  throw new DecisionsError(
78
82
  "invalid-request",
79
- `Unknown spec action "${action}". Use: list, show, validate, check`
83
+ `Unknown spec action "${action}". Use: list, show, validate, lint, check`
80
84
  );
81
85
  });
82
86
  }
@@ -96,6 +100,37 @@ async function check(argv, io, format, ctx) {
96
100
  );
97
101
  return code === EXIT.ok && failed && parse(argv).values.strict ? EXIT.checkFailed : code;
98
102
  }
103
+ async function lint(argv, io, format, ctx) {
104
+ let failed = false;
105
+ let strict = false;
106
+ const code = await emit(
107
+ io,
108
+ "spec",
109
+ format,
110
+ () => {
111
+ const { values, positionals } = typedParse({
112
+ args: argv,
113
+ allowPositionals: true,
114
+ strict: true,
115
+ options: LINT_OPTIONS
116
+ });
117
+ const [spec, extra] = positionals;
118
+ if (extra !== void 0) {
119
+ throw new DecisionsError(
120
+ "invalid-request",
121
+ "Usage: decide spec lint [name|path] [--strict]"
122
+ );
123
+ }
124
+ strict = values.strict ?? false;
125
+ const result = runSpecLint(ctx(), spec ? { spec } : {});
126
+ failed = !result.passed || strict && result.counts.warnings > 0;
127
+ return result;
128
+ },
129
+ (r, f) => f === "brief" ? briefSpecLint(r) : void 0
130
+ );
131
+ return code === EXIT.ok && failed ? EXIT.checkFailed : code;
132
+ }
133
+ var LINT_OPTIONS = { strict: { type: "boolean" } };
99
134
  function checkInput(argv) {
100
135
  const { values, positionals } = parse(argv);
101
136
  const [spec, extra] = positionals;
@@ -4,4 +4,4 @@ import { createRequire as __decideRequire } from "node:module"; const require =
4
4
  // src/entry.ts
5
5
  import module from "node:module";
6
6
  module.enableCompileCache?.();
7
- await import("./chunks/bin-3EWFISFQ.mjs");
7
+ await import("./chunks/bin-TIEUYIP3.mjs");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@garygentry/system1",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "The `decide` CLI: typed, calibrated decisions for coding agents, hooks and CI.",
5
5
  "type": "module",
6
6
  "license": "MIT",