modelos-secure 0.3.3 → 0.3.5

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
@@ -8,35 +8,36 @@ npx modelos-secure scan .
8
8
 
9
9
  It reads the code the way an engineer would, starting where the app starts, draws the system's map and asks only what it cannot work out. Everything it decides goes into `modelos-secure.yaml`.
10
10
 
11
- Before it sends anything it asks once whether a model may read the code it needs, or only an outline of it, or nothing. Every answer it sends passes a filter that takes secrets out, and settings files, keys and credentials are never read. `.modelos-secure/sent.jsonl` lists what was sent, `--explain` shows the outline and what may and may not be read without sending anything, and `--offline` keeps everything on your machine.
11
+ Before it sends anything it asks once whether a model may read the code it needs, or only an outline of it, or nothing. Every answer it sends passes a filter that takes secrets out, and settings files, keys and credentials are never sent. What leaves: the outline, the reader's answers, the map it registers, your answer key if you add one, and the last lines of the app's own output when a start fails. `.modelos-secure/sent.jsonl` lists every answer the reader sent, `--explain` shows the outline and what may and may not be read without sending anything, and `--offline` keeps everything on your machine.
12
12
 
13
13
  At a terminal, `modelos-secure` on its own starts a session about the app in the folder: ask about it in your own words, and each answer cites the files and lines it rests on, checked against the code.
14
14
 
15
- | Command | Does |
16
- | --------------------------------------------- | ------------------------------------------------------------------ |
17
- | `modelos-secure` | At a terminal, a session about the app in this folder. |
18
- | `modelos-secure login` | Saves a workspace token, and signs in with Google if needed. |
19
- | `modelos-secure scan .` | Connects this repository. `--offline`, `--explain`, `--yes`. |
20
- | `modelos-secure review` | Starts a review of this system. `--quick`, `--ci`, `--budget`. |
21
- | `modelos-secure replay F-031` | Replays one finding. |
22
- | `modelos-secure doctor` | Checks the setup and fixes what it can. |
23
- | `modelos-secure runner` | Serves a review's attempts from this machine, in the app's folder. |
24
- | `modelos-secure export R-1179 --format sarif` | Writes a review's findings as SARIF or JSON. |
25
- | `modelos-secure --version` | Prints this CLI's version. |
15
+ | Command | Does |
16
+ | --------------------------------------------- | --------------------------------------------------------------------------------------------- |
17
+ | `modelos-secure` | At a terminal, a session about the app in this folder. |
18
+ | `modelos-secure login` | Saves a workspace token, and signs in with Google if needed. |
19
+ | `modelos-secure scan .` | Connects this repository. `--offline`, `--explain`, `--yes`, `--ci`, `--no-review`. |
20
+ | `modelos-secure review` | Starts a review of this system. `--quick`, `--ci`, `--yes`, `--budget`, `--instances`. |
21
+ | `modelos-secure replay F-031` | Replays one finding of an app the scan connected. |
22
+ | `modelos-secure doctor` | Checks the setup and fixes what it can. |
23
+ | `modelos-secure runner` | Serves a review's attempts from this machine, in the app's folder. `--system`, `--instances`. |
24
+ | `modelos-secure export R-1179 --format sarif` | Prints a review's findings as SARIF or JSON; `--out` writes a file. |
25
+ | `modelos-secure --version` | Prints this CLI's version. |
26
26
 
27
27
  A review of an app connected by the scan reaches it through a runner on the machine that runs it. `modelos-secure review` starts one itself, and keeps it while the review is paused; a review started from the app needs `modelos-secure runner` running in the app's folder, and says so if none is. A start command is checked before it runs and saved only once the app has started with it.
28
28
 
29
- During a review, actions are held and never run. Outside a review the hooks do nothing. Requires Node 22 or newer. Python apps need Python 3.10 or newer.
29
+ During a review, the tools marked as held in `modelos-secure.yaml` are caught and never run; the scan marks every tool that can act, and a tool set to `run` runs for real. Outside a review the hooks do nothing. Requires Node 22 or newer. Python apps need Python 3.10 or newer.
30
30
 
31
31
  Every command says what it takes with `--help`, such as `modelos-secure scan --help`, and refuses a flag it does not take.
32
32
 
33
- | Exit code | Means |
34
- | --------- | -------------------------------------------------------------- |
35
- | 0 | Done. |
36
- | 1 | Something failed, or a fix check found a break. |
37
- | 2 | The command was used wrongly. |
38
- | 3 | There are questions only a person can answer, as `--ci` lists. |
39
- | 130 | Stopped with Ctrl-C. What was done is kept. |
33
+ | Exit code | Means |
34
+ | --------- | ------------------------------------------------------------------------------- |
35
+ | 0 | Done. |
36
+ | 1 | Something failed, or a fix check found a break. |
37
+ | 2 | The command was used wrongly. |
38
+ | 3 | There are questions only a person can answer, as `--ci` lists. |
39
+ | 130 | Stopped with Ctrl-C. What was done is kept. |
40
+ | 143, 129 | Stopped by a signal, or the terminal closed. The app it started is stopped too. |
40
41
 
41
42
  ## Signing in
42
43
 
@@ -49,11 +49,26 @@ function step(name, detail, state = "done") {
49
49
  const right = state === "done" ? "done" : "";
50
50
  say(` ${bold(name.padEnd(STEP_WIDTH))}${detail}${right ? ` ${grey(right)}` : ""}`);
51
51
  }
52
+ var RECOMMENDED = " (recommended)";
53
+ /**
54
+ * The choices as the lines they take on screen, one each and none wider than the window. The
55
+ * picker redraws by moving up exactly this many lines, so a line that wrapped would leave the one
56
+ * above it standing: seen on an 80-column window, where "Yes" appeared twice.
57
+ */
58
+ function choiceLines(choices, index, columns) {
59
+ return choices.map((choice, i) => {
60
+ const tail = choice.recommended ? RECOMMENDED : "";
61
+ const room = Math.max(8, columns - 1 - 4 - tail.length);
62
+ const label = choice.label.length > room ? `${choice.label.slice(0, room - 1)}${unicode ? "…" : "~"}` : choice.label;
63
+ return ` ${i === index ? blue(pointer) : " "} ${label}${tail ? grey(tail) : ""}`;
64
+ });
65
+ }
52
66
  /** One question, one reason, a default. Arrows, Enter and the first letter of each choice. */
53
67
  async function ask(question, why, choices) {
54
68
  const start = Math.max(0, choices.findIndex((c) => c.recommended));
55
69
  say();
56
70
  say(` ${question}`);
71
+ if (why) say(` ${grey(`Why we ask: ${why}`)}`);
57
72
  say();
58
73
  if (!interactive()) {
59
74
  const chosen = choices[start];
@@ -63,14 +78,10 @@ async function ask(question, why, choices) {
63
78
  let index = start;
64
79
  const render = (first) => {
65
80
  if (!first) process.stdout.write(`\u001b[${choices.length.toString()}A`);
66
- for (const [i, choice] of choices.entries()) {
67
- const mark = i === index ? blue(pointer) : " ";
68
- process.stdout.write(`\u001b[2K ${mark} ${choice.label}${choice.recommended ? grey(" (recommended)") : ""}\n`);
69
- }
81
+ const columns = process.stdout.columns || 80;
82
+ for (const line of choiceLines(choices, index, columns)) process.stdout.write(`\u001b[2K${line}\n`);
70
83
  };
71
84
  render(true);
72
- if (why) say(`\n ${grey(`Why we ask: ${why}`)}`);
73
- if (why) process.stdout.write(`\u001b[2A`);
74
85
  return new Promise((resolve, reject) => {
75
86
  emitKeypressEvents(process.stdin);
76
87
  process.stdin.setRawMode(true);
@@ -79,7 +90,6 @@ async function ask(question, why, choices) {
79
90
  process.stdin.off("keypress", onKey);
80
91
  process.stdin.setRawMode(false);
81
92
  process.stdin.pause();
82
- if (why) process.stdout.write(`\u001b[2B\n`);
83
93
  };
84
94
  const onKey = (text, key) => {
85
95
  if (key.ctrl && key.name === "c") {
@@ -89,7 +99,7 @@ async function ask(question, why, choices) {
89
99
  }
90
100
  if (key.name === "up") index = (index - 1 + choices.length) % choices.length;
91
101
  else if (key.name === "down") index = (index + 1) % choices.length;
92
- else if (key.name === "return") {
102
+ else if (key.name === "return" || key.name === "enter") {
93
103
  done();
94
104
  resolve(choices[index].value);
95
105
  return;
@@ -120,7 +130,7 @@ async function askText(question, secret = false) {
120
130
  reject(new Interrupted());
121
131
  return;
122
132
  }
123
- if (key.name === "return") {
133
+ if (key.name === "return" || key.name === "enter") {
124
134
  process.stdin.off("keypress", onKey);
125
135
  process.stdin.setRawMode(false);
126
136
  process.stdin.pause();
@@ -0,0 +1 @@
1
+ export { t as loginCommand } from "./login-DeGa63BQ.js";