@kodr/aiwrangler 0.0.0-stage → 0.1.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.
- package/CHANGELOG.md +38 -0
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +434 -2
- package/aiwrangler.config.example.json +62 -0
- package/dist/chunk-2CIV4KGU.js +1276 -0
- package/dist/chunk-2CIV4KGU.js.map +1 -0
- package/dist/chunk-EAQASAXL.js +1252 -0
- package/dist/chunk-EAQASAXL.js.map +1 -0
- package/dist/chunk-EDVWHCQV.js +145 -0
- package/dist/chunk-EDVWHCQV.js.map +1 -0
- package/dist/chunk-NQFO47CV.js +522 -0
- package/dist/chunk-NQFO47CV.js.map +1 -0
- package/dist/cli.js +262 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +697 -0
- package/dist/index.js +77 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.js +214 -0
- package/dist/mcp.js.map +1 -0
- package/dist/plugin.js +112 -0
- package/dist/plugin.js.map +1 -0
- package/dist/tools.js +127 -0
- package/dist/tools.js.map +1 -0
- package/package.json +87 -3
package/dist/cli.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
acknowledgeFindings,
|
|
4
|
+
listPendingAck,
|
|
5
|
+
planAck,
|
|
6
|
+
planOverride,
|
|
7
|
+
reportOverrides,
|
|
8
|
+
resolveGateDir,
|
|
9
|
+
writeOverrides
|
|
10
|
+
} from "./chunk-NQFO47CV.js";
|
|
11
|
+
import "./chunk-2CIV4KGU.js";
|
|
12
|
+
import "./chunk-EDVWHCQV.js";
|
|
13
|
+
import {
|
|
14
|
+
RuntimeOverridesSchema
|
|
15
|
+
} from "./chunk-EAQASAXL.js";
|
|
16
|
+
|
|
17
|
+
// src/cli.ts
|
|
18
|
+
import { realpathSync } from "fs";
|
|
19
|
+
import { resolve } from "path";
|
|
20
|
+
import { pathToFileURL } from "url";
|
|
21
|
+
import { parseArgs } from "util";
|
|
22
|
+
|
|
23
|
+
// src/confirm.ts
|
|
24
|
+
import { createInterface } from "readline/promises";
|
|
25
|
+
var NON_TTY_REFUSAL = "aiwrangler: refusing to write without a human at the terminal. Re-run in a TTY and type yes. --yes does not authorize a write. Nothing was recorded.";
|
|
26
|
+
var YES_FLAG_REFUSAL = "aiwrangler: --yes does not authorize a write. Type yes at the TTY prompt, or approve the in-editor elicitation or desktop dialog. Nothing was recorded.";
|
|
27
|
+
async function confirmHuman(opts) {
|
|
28
|
+
const input = opts.input ?? process.stdin;
|
|
29
|
+
const output = opts.output ?? process.stdout;
|
|
30
|
+
if (input.isTTY !== true) return { ok: false, message: NON_TTY_REFUSAL };
|
|
31
|
+
const rl = createInterface({ input, output });
|
|
32
|
+
try {
|
|
33
|
+
const answer = (await rl.question(opts.prompt)).trim().toLowerCase();
|
|
34
|
+
if (answer === "yes") return { ok: true, confirmation: "tty" };
|
|
35
|
+
return { ok: false, message: "aiwrangler: not confirmed; nothing was recorded" };
|
|
36
|
+
} finally {
|
|
37
|
+
rl.close();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/cli.ts
|
|
42
|
+
var HELP = `aiwrangler: owner commands for HUMAN REVIEW acks and runtime overrides.
|
|
43
|
+
|
|
44
|
+
Inside Cursor or opencode, prefer the MCP tools: a write asks you in the
|
|
45
|
+
editor (elicitation) or a desktop dialog. This CLI is the terminal path.
|
|
46
|
+
It asks you to type yes on a TTY. --yes does not authorize a write.
|
|
47
|
+
|
|
48
|
+
Usage:
|
|
49
|
+
aiwrangler ack [--dir DIR] [--rules RULE[,RULE...]] [--note TEXT] [--diff-hash HEX]
|
|
50
|
+
aiwrangler override [--dir DIR] [--set JSON] [--clear] [--note TEXT]
|
|
51
|
+
|
|
52
|
+
ack with no --rules lists pending human findings and the diff hash.
|
|
53
|
+
override with no --set or --clear reports active overrides.
|
|
54
|
+
Acks bind to that diff hash and void when the diff changes.
|
|
55
|
+
Overrides expire on the next PASS verdict.
|
|
56
|
+
`;
|
|
57
|
+
function isGateError(text) {
|
|
58
|
+
return /^aiwrangler\b/.test(text);
|
|
59
|
+
}
|
|
60
|
+
function emit(stream, text) {
|
|
61
|
+
stream.write(text.endsWith("\n") ? text : text + "\n");
|
|
62
|
+
}
|
|
63
|
+
function parseRules(values) {
|
|
64
|
+
if (!values) return [];
|
|
65
|
+
return values.flatMap((value) => value.split(",")).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
66
|
+
}
|
|
67
|
+
function readFlags(argv, options) {
|
|
68
|
+
return parseArgs({ args: argv, options, strict: true, allowPositionals: false });
|
|
69
|
+
}
|
|
70
|
+
async function runAck(argv, io) {
|
|
71
|
+
let flags;
|
|
72
|
+
try {
|
|
73
|
+
flags = readFlags(argv, {
|
|
74
|
+
dir: { type: "string" },
|
|
75
|
+
rules: { type: "string", multiple: true },
|
|
76
|
+
note: { type: "string" },
|
|
77
|
+
"diff-hash": { type: "string" },
|
|
78
|
+
yes: { type: "boolean", default: false },
|
|
79
|
+
help: { type: "boolean", default: false }
|
|
80
|
+
});
|
|
81
|
+
} catch (err) {
|
|
82
|
+
emit(io.error, `aiwrangler: ${err instanceof Error ? err.message : String(err)}`);
|
|
83
|
+
emit(io.error, HELP);
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
if (flags.values.help === true) {
|
|
87
|
+
emit(io.output, HELP);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if (flags.values.yes === true) {
|
|
91
|
+
emit(io.error, YES_FLAG_REFUSAL);
|
|
92
|
+
return 1;
|
|
93
|
+
}
|
|
94
|
+
const dir = resolveGateDir(typeof flags.values.dir === "string" ? flags.values.dir : void 0);
|
|
95
|
+
const ruleArgs = Array.isArray(flags.values.rules) ? flags.values.rules.filter((r) => typeof r === "string") : void 0;
|
|
96
|
+
const rules = parseRules(ruleArgs);
|
|
97
|
+
const note = typeof flags.values.note === "string" ? flags.values.note : void 0;
|
|
98
|
+
const diffHash = typeof flags.values["diff-hash"] === "string" ? flags.values["diff-hash"] : void 0;
|
|
99
|
+
if (ruleArgs === void 0) {
|
|
100
|
+
if (note !== void 0 || diffHash !== void 0) {
|
|
101
|
+
emit(io.error, "aiwrangler: --note and --diff-hash require --rules; nothing was recorded");
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
const text2 = listPendingAck(dir);
|
|
105
|
+
emit(isGateError(text2) ? io.error : io.output, text2);
|
|
106
|
+
return isGateError(text2) ? 1 : 0;
|
|
107
|
+
}
|
|
108
|
+
if (rules.length === 0) {
|
|
109
|
+
emit(io.error, 'aiwrangler: --rules must name at least one rule id (or "*"); nothing was recorded');
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
const planned = planAck(dir, { rules, ...note !== void 0 ? { note } : {}, ...diffHash !== void 0 ? { diffHash } : {} });
|
|
113
|
+
if (!planned.ok) {
|
|
114
|
+
emit(io.error, planned.message);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
const confirmed = await confirmHuman({
|
|
118
|
+
prompt: planned.summary + "\nType yes to confirm: ",
|
|
119
|
+
input: io.input,
|
|
120
|
+
output: io.output
|
|
121
|
+
});
|
|
122
|
+
if (!confirmed.ok) {
|
|
123
|
+
emit(io.error, confirmed.message);
|
|
124
|
+
return 1;
|
|
125
|
+
}
|
|
126
|
+
const text = acknowledgeFindings(dir, {
|
|
127
|
+
rules: planned.rules,
|
|
128
|
+
diffHash: planned.diffHash,
|
|
129
|
+
confirmation: confirmed.confirmation,
|
|
130
|
+
by: "cli",
|
|
131
|
+
...planned.note !== void 0 ? { note: planned.note } : {}
|
|
132
|
+
});
|
|
133
|
+
emit(isGateError(text) ? io.error : io.output, text);
|
|
134
|
+
return isGateError(text) ? 1 : 0;
|
|
135
|
+
}
|
|
136
|
+
async function runOverride(argv, io) {
|
|
137
|
+
let flags;
|
|
138
|
+
try {
|
|
139
|
+
flags = readFlags(argv, {
|
|
140
|
+
dir: { type: "string" },
|
|
141
|
+
set: { type: "string" },
|
|
142
|
+
clear: { type: "boolean", default: false },
|
|
143
|
+
note: { type: "string" },
|
|
144
|
+
yes: { type: "boolean", default: false },
|
|
145
|
+
help: { type: "boolean", default: false }
|
|
146
|
+
});
|
|
147
|
+
} catch (err) {
|
|
148
|
+
emit(io.error, `aiwrangler: ${err instanceof Error ? err.message : String(err)}`);
|
|
149
|
+
emit(io.error, HELP);
|
|
150
|
+
return 1;
|
|
151
|
+
}
|
|
152
|
+
if (flags.values.help === true) {
|
|
153
|
+
emit(io.output, HELP);
|
|
154
|
+
return 0;
|
|
155
|
+
}
|
|
156
|
+
if (flags.values.yes === true) {
|
|
157
|
+
emit(io.error, YES_FLAG_REFUSAL);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
const dir = resolveGateDir(typeof flags.values.dir === "string" ? flags.values.dir : void 0);
|
|
161
|
+
const note = typeof flags.values.note === "string" ? flags.values.note : void 0;
|
|
162
|
+
const setRaw = typeof flags.values.set === "string" ? flags.values.set : void 0;
|
|
163
|
+
const clear = flags.values.clear === true;
|
|
164
|
+
if (clear && setRaw !== void 0) {
|
|
165
|
+
emit(io.error, "aiwrangler: pass only one of --set or --clear; nothing was changed");
|
|
166
|
+
return 1;
|
|
167
|
+
}
|
|
168
|
+
if (!clear && setRaw === void 0) {
|
|
169
|
+
if (note !== void 0) {
|
|
170
|
+
emit(io.error, "aiwrangler: --note applies to --set or --clear; nothing was changed");
|
|
171
|
+
return 1;
|
|
172
|
+
}
|
|
173
|
+
const text2 = reportOverrides(dir);
|
|
174
|
+
emit(isGateError(text2) ? io.error : io.output, text2);
|
|
175
|
+
return isGateError(text2) ? 1 : 0;
|
|
176
|
+
}
|
|
177
|
+
let set;
|
|
178
|
+
if (setRaw !== void 0) {
|
|
179
|
+
let raw;
|
|
180
|
+
try {
|
|
181
|
+
raw = JSON.parse(setRaw);
|
|
182
|
+
} catch (err) {
|
|
183
|
+
emit(io.error, `aiwrangler: --set must be JSON (${err instanceof Error ? err.message : String(err)})`);
|
|
184
|
+
return 1;
|
|
185
|
+
}
|
|
186
|
+
const parsed = RuntimeOverridesSchema.safeParse(raw);
|
|
187
|
+
if (!parsed.success) {
|
|
188
|
+
emit(io.error, `aiwrangler: invalid overrides: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
|
|
189
|
+
return 1;
|
|
190
|
+
}
|
|
191
|
+
set = parsed.data;
|
|
192
|
+
}
|
|
193
|
+
const planned = planOverride(dir, {
|
|
194
|
+
...clear ? { clear: true } : {},
|
|
195
|
+
...set !== void 0 ? { set } : {},
|
|
196
|
+
...note !== void 0 ? { note } : {}
|
|
197
|
+
});
|
|
198
|
+
if (!planned.ok) {
|
|
199
|
+
emit(io.error, planned.message);
|
|
200
|
+
return 1;
|
|
201
|
+
}
|
|
202
|
+
if (planned.kind === "noop") {
|
|
203
|
+
emit(io.output, planned.message);
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
const confirmed = await confirmHuman({
|
|
207
|
+
prompt: planned.summary + "\nType yes to confirm: ",
|
|
208
|
+
input: io.input,
|
|
209
|
+
output: io.output
|
|
210
|
+
});
|
|
211
|
+
if (!confirmed.ok) {
|
|
212
|
+
emit(io.error, confirmed.message);
|
|
213
|
+
return 1;
|
|
214
|
+
}
|
|
215
|
+
const text = writeOverrides(dir, {
|
|
216
|
+
confirmation: confirmed.confirmation,
|
|
217
|
+
by: "cli",
|
|
218
|
+
...planned.kind === "clear" ? { clear: true } : { set: planned.set },
|
|
219
|
+
...planned.note !== void 0 ? { note: planned.note } : {}
|
|
220
|
+
});
|
|
221
|
+
emit(isGateError(text) ? io.error : io.output, text);
|
|
222
|
+
return isGateError(text) ? 1 : 0;
|
|
223
|
+
}
|
|
224
|
+
async function runCli(argv, io) {
|
|
225
|
+
const full = {
|
|
226
|
+
input: io?.input ?? process.stdin,
|
|
227
|
+
output: io?.output ?? process.stdout,
|
|
228
|
+
error: io?.error ?? process.stderr
|
|
229
|
+
};
|
|
230
|
+
const [cmd, ...rest] = argv;
|
|
231
|
+
if (cmd === void 0 || cmd === "--help" || cmd === "-h" || cmd === "help") {
|
|
232
|
+
emit(full.output, HELP);
|
|
233
|
+
return cmd === void 0 ? 1 : 0;
|
|
234
|
+
}
|
|
235
|
+
if (cmd === "ack") return runAck(rest, full);
|
|
236
|
+
if (cmd === "override") return runOverride(rest, full);
|
|
237
|
+
emit(full.error, `aiwrangler: unknown command '${cmd}'`);
|
|
238
|
+
emit(full.error, HELP);
|
|
239
|
+
return 1;
|
|
240
|
+
}
|
|
241
|
+
function isDirectRun() {
|
|
242
|
+
const entry = process.argv[1];
|
|
243
|
+
if (!entry) return false;
|
|
244
|
+
try {
|
|
245
|
+
return import.meta.url === pathToFileURL(realpathSync(resolve(entry))).href;
|
|
246
|
+
} catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
if (isDirectRun()) {
|
|
251
|
+
runCli(process.argv.slice(2)).then((code) => {
|
|
252
|
+
process.exit(code);
|
|
253
|
+
}).catch((err) => {
|
|
254
|
+
process.stderr.write(`aiwrangler: fatal: ${err instanceof Error ? err.message : String(err)}
|
|
255
|
+
`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
export {
|
|
260
|
+
runCli
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/confirm.ts"],"sourcesContent":["#!/usr/bin/env node\n// Owner CLI for HUMAN REVIEW acks and runtime overrides.\n// In Cursor and opencode the MCP server asks in the editor instead.\n// --yes is rejected: a flag is not a human.\n//\n// aiwrangler ack [--dir DIR] [--rules RULE[,RULE...]] [--note TEXT] [--diff-hash HEX]\n// aiwrangler override [--dir DIR] [--set JSON] [--clear] [--note TEXT]\nimport { realpathSync } from \"node:fs\"\nimport { resolve } from \"node:path\"\nimport type { Readable, Writable } from \"node:stream\"\nimport { pathToFileURL } from \"node:url\"\nimport { parseArgs, type ParseArgsConfig } from \"node:util\"\nimport { confirmHuman, YES_FLAG_REFUSAL } from \"./confirm.js\"\nimport { acknowledgeFindings, listPendingAck, planAck, planOverride, reportOverrides, resolveGateDir, writeOverrides } from \"./core.js\"\nimport { RuntimeOverridesSchema, type RuntimeOverrides } from \"./overrides.js\"\n\nexport interface CliIO {\n input: Readable & { isTTY?: boolean }\n output: Writable\n error: Writable\n}\n\nconst HELP = `aiwrangler: owner commands for HUMAN REVIEW acks and runtime overrides.\n\nInside Cursor or opencode, prefer the MCP tools: a write asks you in the\neditor (elicitation) or a desktop dialog. This CLI is the terminal path.\nIt asks you to type yes on a TTY. --yes does not authorize a write.\n\nUsage:\n aiwrangler ack [--dir DIR] [--rules RULE[,RULE...]] [--note TEXT] [--diff-hash HEX]\n aiwrangler override [--dir DIR] [--set JSON] [--clear] [--note TEXT]\n\nack with no --rules lists pending human findings and the diff hash.\noverride with no --set or --clear reports active overrides.\nAcks bind to that diff hash and void when the diff changes.\nOverrides expire on the next PASS verdict.\n`\n\nfunction isGateError(text: string): boolean {\n return /^aiwrangler\\b/.test(text)\n}\n\nfunction emit(stream: Writable, text: string): void {\n stream.write(text.endsWith(\"\\n\") ? text : text + \"\\n\")\n}\n\nfunction parseRules(values: string[] | undefined): string[] {\n if (!values) return []\n return values\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n}\n\nfunction readFlags(argv: string[], options: ParseArgsConfig[\"options\"]): ReturnType<typeof parseArgs> {\n return parseArgs({ args: argv, options, strict: true, allowPositionals: false })\n}\n\nasync function runAck(argv: string[], io: CliIO): Promise<number> {\n let flags: ReturnType<typeof parseArgs>\n try {\n flags = readFlags(argv, {\n dir: { type: \"string\" },\n rules: { type: \"string\", multiple: true },\n note: { type: \"string\" },\n \"diff-hash\": { type: \"string\" },\n yes: { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n })\n } catch (err) {\n emit(io.error, `aiwrangler: ${err instanceof Error ? err.message : String(err)}`)\n emit(io.error, HELP)\n return 1\n }\n if (flags.values.help === true) {\n emit(io.output, HELP)\n return 0\n }\n if (flags.values.yes === true) {\n emit(io.error, YES_FLAG_REFUSAL)\n return 1\n }\n const dir = resolveGateDir(typeof flags.values.dir === \"string\" ? flags.values.dir : undefined)\n const ruleArgs = Array.isArray(flags.values.rules) ? flags.values.rules.filter((r): r is string => typeof r === \"string\") : undefined\n const rules = parseRules(ruleArgs)\n const note = typeof flags.values.note === \"string\" ? flags.values.note : undefined\n const diffHash = typeof flags.values[\"diff-hash\"] === \"string\" ? flags.values[\"diff-hash\"] : undefined\n if (ruleArgs === undefined) {\n if (note !== undefined || diffHash !== undefined) {\n emit(io.error, \"aiwrangler: --note and --diff-hash require --rules; nothing was recorded\")\n return 1\n }\n const text = listPendingAck(dir)\n emit(isGateError(text) ? io.error : io.output, text)\n return isGateError(text) ? 1 : 0\n }\n if (rules.length === 0) {\n emit(io.error, 'aiwrangler: --rules must name at least one rule id (or \"*\"); nothing was recorded')\n return 1\n }\n const planned = planAck(dir, { rules, ...(note !== undefined ? { note } : {}), ...(diffHash !== undefined ? { diffHash } : {}) })\n if (!planned.ok) {\n emit(io.error, planned.message)\n return 1\n }\n const confirmed = await confirmHuman({\n prompt: planned.summary + \"\\nType yes to confirm: \",\n input: io.input,\n output: io.output,\n })\n if (!confirmed.ok) {\n emit(io.error, confirmed.message)\n return 1\n }\n const text = acknowledgeFindings(dir, {\n rules: planned.rules,\n diffHash: planned.diffHash,\n confirmation: confirmed.confirmation,\n by: \"cli\",\n ...(planned.note !== undefined ? { note: planned.note } : {}),\n })\n emit(isGateError(text) ? io.error : io.output, text)\n return isGateError(text) ? 1 : 0\n}\n\nasync function runOverride(argv: string[], io: CliIO): Promise<number> {\n let flags: ReturnType<typeof parseArgs>\n try {\n flags = readFlags(argv, {\n dir: { type: \"string\" },\n set: { type: \"string\" },\n clear: { type: \"boolean\", default: false },\n note: { type: \"string\" },\n yes: { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n })\n } catch (err) {\n emit(io.error, `aiwrangler: ${err instanceof Error ? err.message : String(err)}`)\n emit(io.error, HELP)\n return 1\n }\n if (flags.values.help === true) {\n emit(io.output, HELP)\n return 0\n }\n if (flags.values.yes === true) {\n emit(io.error, YES_FLAG_REFUSAL)\n return 1\n }\n const dir = resolveGateDir(typeof flags.values.dir === \"string\" ? flags.values.dir : undefined)\n const note = typeof flags.values.note === \"string\" ? flags.values.note : undefined\n const setRaw = typeof flags.values.set === \"string\" ? flags.values.set : undefined\n const clear = flags.values.clear === true\n if (clear && setRaw !== undefined) {\n emit(io.error, \"aiwrangler: pass only one of --set or --clear; nothing was changed\")\n return 1\n }\n if (!clear && setRaw === undefined) {\n if (note !== undefined) {\n emit(io.error, \"aiwrangler: --note applies to --set or --clear; nothing was changed\")\n return 1\n }\n const text = reportOverrides(dir)\n emit(isGateError(text) ? io.error : io.output, text)\n return isGateError(text) ? 1 : 0\n }\n let set: RuntimeOverrides | undefined\n if (setRaw !== undefined) {\n let raw: unknown\n try {\n raw = JSON.parse(setRaw)\n } catch (err) {\n emit(io.error, `aiwrangler: --set must be JSON (${err instanceof Error ? err.message : String(err)})`)\n return 1\n }\n const parsed = RuntimeOverridesSchema.safeParse(raw)\n if (!parsed.success) {\n emit(io.error, `aiwrangler: invalid overrides: ${parsed.error.issues.map((issue) => issue.message).join(\"; \")}`)\n return 1\n }\n set = parsed.data\n }\n const planned = planOverride(dir, {\n ...(clear ? { clear: true } : {}),\n ...(set !== undefined ? { set } : {}),\n ...(note !== undefined ? { note } : {}),\n })\n if (!planned.ok) {\n emit(io.error, planned.message)\n return 1\n }\n if (planned.kind === \"noop\") {\n emit(io.output, planned.message)\n return 0\n }\n const confirmed = await confirmHuman({\n prompt: planned.summary + \"\\nType yes to confirm: \",\n input: io.input,\n output: io.output,\n })\n if (!confirmed.ok) {\n emit(io.error, confirmed.message)\n return 1\n }\n const text = writeOverrides(dir, {\n confirmation: confirmed.confirmation,\n by: \"cli\",\n ...(planned.kind === \"clear\" ? { clear: true } : { set: planned.set }),\n ...(planned.note !== undefined ? { note: planned.note } : {}),\n })\n emit(isGateError(text) ? io.error : io.output, text)\n return isGateError(text) ? 1 : 0\n}\n\nexport async function runCli(argv: string[], io?: Partial<CliIO>): Promise<number> {\n const full: CliIO = {\n input: io?.input ?? process.stdin,\n output: io?.output ?? process.stdout,\n error: io?.error ?? process.stderr,\n }\n const [cmd, ...rest] = argv\n if (cmd === undefined || cmd === \"--help\" || cmd === \"-h\" || cmd === \"help\") {\n emit(full.output, HELP)\n return cmd === undefined ? 1 : 0\n }\n if (cmd === \"ack\") return runAck(rest, full)\n if (cmd === \"override\") return runOverride(rest, full)\n emit(full.error, `aiwrangler: unknown command '${cmd}'`)\n emit(full.error, HELP)\n return 1\n}\n\nfunction isDirectRun(): boolean {\n const entry = process.argv[1]\n if (!entry) return false\n try {\n return import.meta.url === pathToFileURL(realpathSync(resolve(entry))).href\n } catch {\n return false\n }\n}\n\nif (isDirectRun()) {\n runCli(process.argv.slice(2))\n .then((code) => {\n process.exit(code)\n })\n .catch((err) => {\n process.stderr.write(`aiwrangler: fatal: ${err instanceof Error ? err.message : String(err)}\\n`)\n process.exit(1)\n })\n}\n","// TTY confirmation for the owner CLI. There is no flag that skips this.\nimport { createInterface } from \"node:readline/promises\"\nimport type { Readable, Writable } from \"node:stream\"\nimport type { HumanConfirmation } from \"./ledger.js\"\n\nexport interface ConfirmResult {\n ok: true\n confirmation: HumanConfirmation\n}\n\nexport interface ConfirmRefusal {\n ok: false\n message: string\n}\n\nexport const NON_TTY_REFUSAL =\n \"aiwrangler: refusing to write without a human at the terminal. Re-run in a TTY and type yes. --yes does not authorize a write. Nothing was recorded.\"\n\nexport const YES_FLAG_REFUSAL =\n \"aiwrangler: --yes does not authorize a write. Type yes at the TTY prompt, or approve the in-editor elicitation or desktop dialog. Nothing was recorded.\"\n\nexport async function confirmHuman(opts: {\n prompt: string\n input?: Readable & { isTTY?: boolean }\n output?: Writable\n}): Promise<ConfirmResult | ConfirmRefusal> {\n const input = opts.input ?? process.stdin\n const output = opts.output ?? process.stdout\n if (input.isTTY !== true) return { ok: false, message: NON_TTY_REFUSAL }\n const rl = createInterface({ input, output })\n try {\n const answer = (await rl.question(opts.prompt)).trim().toLowerCase()\n if (answer === \"yes\") return { ok: true, confirmation: \"tty\" }\n return { ok: false, message: \"aiwrangler: not confirmed; nothing was recorded\" }\n } finally {\n rl.close()\n }\n}\n"],"mappings":"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","names":["text"]}
|