misterpropre 0.0.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/dist/cli.js ADDED
@@ -0,0 +1,256 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ KNOWN_SECRET_KEYS,
4
+ deleteSecret,
5
+ getSecret,
6
+ installSignalHandlers,
7
+ listSecretKeys,
8
+ runCommand,
9
+ runScheduleClear,
10
+ runScheduleSet,
11
+ runScheduleStatus,
12
+ setSecret
13
+ } from "./chunk-JCB4UDCP.js";
14
+ import {
15
+ checkSystem,
16
+ configPath,
17
+ defaultConfig,
18
+ installAllSkills,
19
+ isConfigured,
20
+ linkProvider,
21
+ readConfig,
22
+ realLinkDeps,
23
+ skillStatuses,
24
+ skillsRootFor,
25
+ writeConfig
26
+ } from "./chunk-HMGF6JWH.js";
27
+
28
+ // src/cli.ts
29
+ import { readFileSync } from "fs";
30
+ import { Command } from "commander";
31
+
32
+ // src/lib/check.ts
33
+ var green = (s) => `\x1B[32m${s}\x1B[0m`;
34
+ var red = (s) => `\x1B[31m${s}\x1B[0m`;
35
+ var dim = (s) => `\x1B[2m${s}\x1B[0m`;
36
+ function renderChecks(title, checks) {
37
+ const lines = checks.map((c) => {
38
+ const mark = c.ok ? green("\u2713") : red("\u2717");
39
+ const detail = c.ok ? dim(c.detail) : red(c.detail);
40
+ return ` ${mark} ${c.label.padEnd(10)} ${detail}`;
41
+ });
42
+ return [title, ...lines].join("\n");
43
+ }
44
+
45
+ // src/lib/auth.ts
46
+ import { execFileSync } from "child_process";
47
+ function exec(cmd, args) {
48
+ try {
49
+ const out = execFileSync(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
50
+ return { ok: true, out: out.trim() };
51
+ } catch {
52
+ return { ok: false, out: "" };
53
+ }
54
+ }
55
+ function ghAuthStatus() {
56
+ if (!exec("gh", ["auth", "status"]).ok) {
57
+ return { label: "gh auth", ok: false, detail: "not logged in (run `gh auth login`)" };
58
+ }
59
+ const who = exec("gh", ["api", "user", "--jq", ".login"]);
60
+ return { label: "gh auth", ok: true, detail: who.ok && who.out ? `as ${who.out}` : "logged in" };
61
+ }
62
+ function npmAuthStatus() {
63
+ const who = exec("npm", ["whoami"]);
64
+ return who.ok && who.out ? { label: "npm auth", ok: true, detail: `as ${who.out}` } : { label: "npm auth", ok: false, detail: "not authenticated (private @scope installs 401)" };
65
+ }
66
+ function checkAuth() {
67
+ return [ghAuthStatus(), npmAuthStatus()];
68
+ }
69
+
70
+ // src/commands/doctor.ts
71
+ function configCheck() {
72
+ return isConfigured() ? { label: "config", ok: true, detail: configPath() } : { label: "config", ok: false, detail: "not configured \u2014 run `misterpropre setup`" };
73
+ }
74
+ async function runDoctor() {
75
+ const tools = checkSystem();
76
+ const auth = checkAuth();
77
+ console.log(renderChecks("Toolchain", tools));
78
+ console.log();
79
+ console.log(renderChecks("Auth", auth));
80
+ console.log();
81
+ console.log(renderChecks("Config", [configCheck()]));
82
+ const allOk = [...tools, ...auth].every((c) => c.ok);
83
+ if (!allOk) {
84
+ console.log(`
85
+ \x1B[31mSome checks failed.\x1B[0m Resolve them, then re-run \`misterpropre doctor\`.`);
86
+ }
87
+ return allOk;
88
+ }
89
+
90
+ // src/commands/config.ts
91
+ import { createInterface } from "readline";
92
+ function runConfigPath() {
93
+ console.log(configPath());
94
+ }
95
+ function runConfigShow() {
96
+ const cfg = readConfig();
97
+ if (!cfg) {
98
+ console.log("(not configured) \u2014 run `misterpropre setup` to create a config.");
99
+ return;
100
+ }
101
+ console.log(JSON.stringify(cfg, null, 2));
102
+ }
103
+ function runConfigInit(opts) {
104
+ if (isConfigured() && !opts.force) {
105
+ console.log(`Already configured at ${configPath()} (use --force to overwrite).`);
106
+ return;
107
+ }
108
+ writeConfig(defaultConfig());
109
+ console.log(`Wrote default config \u2192 ${configPath()}`);
110
+ console.log("Edit it directly, or run `misterpropre setup` (coming soon) to customize.");
111
+ }
112
+ var mask = (v) => v ? `${v.slice(0, 3)}\u2026(${v.length})` : "\u2014";
113
+ function runSecretsList() {
114
+ const set = new Set(listSecretKeys());
115
+ console.log("Secrets (chmod 600, separate from config):");
116
+ for (const k of KNOWN_SECRET_KEYS) {
117
+ console.log(` ${k.padEnd(24)} ${set.has(k) ? mask(getSecret(k)) : "(not set)"}`);
118
+ }
119
+ for (const k of listSecretKeys().filter((k2) => !KNOWN_SECRET_KEYS.includes(k2))) {
120
+ console.log(` ${k.padEnd(24)} ${mask(getSecret(k))}`);
121
+ }
122
+ }
123
+ async function runSecretsSet(key) {
124
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
125
+ const value = await new Promise((resolve) => rl.question(`Value for ${key}: `, resolve));
126
+ rl.close();
127
+ if (!value.trim()) {
128
+ console.error("No value entered; aborted.");
129
+ return;
130
+ }
131
+ setSecret(key, value.trim());
132
+ console.log(`Set ${key}.`);
133
+ }
134
+ function runSecretsDelete(key) {
135
+ deleteSecret(key);
136
+ console.log(`Removed ${key}.`);
137
+ }
138
+
139
+ // src/commands/login.ts
140
+ async function runLogin(provider) {
141
+ if (provider !== "claude" && provider !== "kiro" && provider !== "q") {
142
+ console.error(`Unknown provider "${provider}" (expected claude | kiro | q).`);
143
+ return 1;
144
+ }
145
+ const result = await linkProvider(provider, realLinkDeps());
146
+ return result.loggedIn ? 0 : 1;
147
+ }
148
+
149
+ // src/commands/skills.ts
150
+ function varsFromConfig() {
151
+ const cfg = readConfig() ?? defaultConfig();
152
+ return {
153
+ ORG: cfg.org,
154
+ REPO_BASE: cfg.repoBaseDir,
155
+ PKG_SCOPE: cfg.packageScope,
156
+ BASE_BRANCH: cfg.baseBranch
157
+ };
158
+ }
159
+ function targetProviders(arg) {
160
+ if (arg === "both") return ["claude", "kiro"];
161
+ if (arg === "claude" || arg === "kiro" || arg === "q") return [arg];
162
+ const cfg = readConfig() ?? defaultConfig();
163
+ return [cfg.provider.default];
164
+ }
165
+ function runSkillsStatus(opts = {}) {
166
+ for (const provider of targetProviders(opts.provider)) {
167
+ if (provider === "q") {
168
+ console.log("Amazon Q \xB7 inlines skills at run time (nothing to install)");
169
+ continue;
170
+ }
171
+ const root = skillsRootFor(provider);
172
+ console.log(`Bundled skills \xB7 ${provider} \u2192 ${root}`);
173
+ for (const r of skillStatuses(root)) {
174
+ const state = !r.bundled ? "not bundled yet" : r.installed ? r.managed ? "installed (managed)" : "present (unmanaged \u2014 use --force to replace)" : "not installed";
175
+ console.log(` ${r.installName.padEnd(22)} ${state}`);
176
+ }
177
+ }
178
+ }
179
+ function runSkillsInstall(opts) {
180
+ const vars = varsFromConfig();
181
+ for (const provider of targetProviders(opts.provider)) {
182
+ if (provider === "q") {
183
+ console.log("Amazon Q inlines skills at run time \u2014 nothing to install.");
184
+ continue;
185
+ }
186
+ const root = skillsRootFor(provider);
187
+ console.log(`Installing skills \xB7 ${provider} \u2192 ${root}`);
188
+ for (const r of installAllSkills({ vars, targetRoot: root, force: opts.force })) {
189
+ console.log(` ${r.installName.padEnd(22)} ${r.action}${r.path ? ` \u2192 ${r.path}` : ""}`);
190
+ }
191
+ }
192
+ }
193
+
194
+ // src/cli.ts
195
+ var pkg = JSON.parse(
196
+ readFileSync(new URL("../package.json", import.meta.url), "utf8")
197
+ );
198
+ installSignalHandlers();
199
+ var program = new Command();
200
+ program.name("misterpropre").description("Mr. Clean for dependencies \u2014 automate Dependabot/Renovate fixes across your repos.").version(pkg.version, "-v, --version", "output the version number");
201
+ program.command("doctor").description("Check that the local toolchain is ready").action(async () => {
202
+ const ok = await runDoctor();
203
+ process.exit(ok ? 0 : 1);
204
+ });
205
+ var configCmd = program.command("config").description("View configuration");
206
+ configCmd.command("path").description("Print the config file path").action(runConfigPath);
207
+ configCmd.command("show").description("Print the current configuration").action(runConfigShow);
208
+ configCmd.command("init").description("Write a default config file").option("--force", "overwrite an existing config").action((opts) => runConfigInit({ force: Boolean(opts.force) }));
209
+ var secretsCmd = configCmd.command("secrets").description("Manage stored secrets (notify creds, optional tokens)");
210
+ secretsCmd.command("list").description("List secret keys (values masked)").action(runSecretsList);
211
+ secretsCmd.command("set <key>").description("Set a secret (value read from stdin)").action((key) => runSecretsSet(key));
212
+ secretsCmd.command("rm <key>").description("Remove a secret").action((key) => runSecretsDelete(key));
213
+ program.command("run [repos...]").description("Run the automation on one or more repos").option("--phase <phase>", "purge | fix | both", "fix").option("--provider <provider>", "claude | kiro | q").option("--all", "run every configured repo").option("--scheduled", "mark this run as scheduled (used by the launchd job)").action(
214
+ async (repos, opts) => {
215
+ const code = await runCommand(repos ?? [], {
216
+ phase: opts.phase,
217
+ provider: opts.provider,
218
+ all: Boolean(opts.all),
219
+ scheduled: Boolean(opts.scheduled)
220
+ });
221
+ process.exit(code);
222
+ }
223
+ );
224
+ program.command("login <provider>").description("Install (if needed) + log in to a provider: claude | kiro").action(async (provider) => {
225
+ process.exit(await runLogin(provider));
226
+ });
227
+ var scheduleCmd = program.command("schedule").description("Native daily schedule (launchd on macOS)");
228
+ scheduleCmd.command("set").description("Install/refresh the daily schedule").option("--time <HH:MM>", "time of day, 24h (default: config schedule.time)").option("--phase <phase>", "purge | fix | both", "both").action((opts) => process.exit(runScheduleSet(opts)));
229
+ scheduleCmd.command("status").description("Show the configured + installed schedule").action(() => process.exit(runScheduleStatus()));
230
+ scheduleCmd.command("clear").description("Remove the daily schedule").action(() => process.exit(runScheduleClear()));
231
+ program.command("setup").description("First-run onboarding, or edit the current configuration inline").action(async () => {
232
+ const { runSetup } = await import("./setup-R2IL4RHH.js");
233
+ const { runDashboard } = await import("./dashboard-W6QCV3NV.js");
234
+ const code = await runSetup();
235
+ if (code !== 0) process.exit(code);
236
+ process.exit(await runDashboard());
237
+ });
238
+ var skillsCmd = program.command("skills").description("Manage bundled agent skills");
239
+ skillsCmd.command("status").description("Show bundled vs installed skills").option("--provider <provider>", "claude | kiro | both (default: configured provider)").action((opts) => runSkillsStatus({ provider: opts.provider }));
240
+ skillsCmd.command("install").description("Render + install bundled skills (claude \u2192 ~/.claude/skills, kiro \u2192 ~/.kiro/skills)").option("--force", "overwrite a same-named skill not managed by misterpropre").option("--provider <provider>", "claude | kiro | both (default: configured provider)").action(
241
+ (opts) => runSkillsInstall({ force: Boolean(opts.force), provider: opts.provider })
242
+ );
243
+ program.action(async () => {
244
+ if (!process.stdout.isTTY) {
245
+ console.log(`misterpropre v${pkg.version} (non-interactive)`);
246
+ console.log("Run `misterpropre --help` for commands, or `misterpropre doctor` to check your setup.");
247
+ return;
248
+ }
249
+ const { runDashboard } = await import("./dashboard-W6QCV3NV.js");
250
+ process.exit(await runDashboard());
251
+ });
252
+ program.parseAsync(process.argv).catch((err) => {
253
+ console.error(err);
254
+ process.exit(1);
255
+ });
256
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,335 @@
1
+ import {
2
+ applySchedule,
3
+ applyUnschedule,
4
+ runCommand
5
+ } from "./chunk-JCB4UDCP.js";
6
+ import {
7
+ clearScreen,
8
+ runSetup
9
+ } from "./chunk-FDTKUXXE.js";
10
+ import {
11
+ Banner,
12
+ MultiSelect,
13
+ Panel,
14
+ Select,
15
+ appT,
16
+ readConfig,
17
+ theme
18
+ } from "./chunk-HMGF6JWH.js";
19
+
20
+ // src/commands/dashboard.ts
21
+ import { createElement } from "react";
22
+ import { render } from "ink";
23
+
24
+ // src/ui/dashboard.tsx
25
+ import { useState } from "react";
26
+ import { Box, Text, useApp, useInput } from "ink";
27
+ import { jsx, jsxs } from "react/jsx-runtime";
28
+ var PHASE_OF = { "run-fix": "fix", "run-purge": "purge", "run-both": "both" };
29
+ function Dashboard({
30
+ lang = "en",
31
+ repos = [],
32
+ schedule,
33
+ initialMode = "all",
34
+ onModeChange = () => {
35
+ },
36
+ onAction = () => {
37
+ }
38
+ }) {
39
+ const { exit } = useApp();
40
+ const t = appT(lang);
41
+ const [mode, setMode] = useState(initialMode);
42
+ const [pendingPhase, setPendingPhase] = useState(null);
43
+ useInput((_input, key) => {
44
+ if (key.tab && pendingPhase === null) {
45
+ const next = mode === "all" ? "single" : "all";
46
+ setMode(next);
47
+ onModeChange(next);
48
+ }
49
+ if (key.escape && pendingPhase !== null) setPendingPhase(null);
50
+ });
51
+ const emit = (action) => {
52
+ onAction(action);
53
+ exit();
54
+ };
55
+ const onMenu = (v) => {
56
+ if (v === "schedule") return emit({ kind: "schedule" });
57
+ if (v === "setup") return emit({ kind: "setup" });
58
+ if (v === "quit") return emit({ kind: "quit" });
59
+ const phase = PHASE_OF[v];
60
+ if (mode === "all") emit({ kind: "run", phase, repos: "all" });
61
+ else setPendingPhase(phase);
62
+ };
63
+ if (pendingPhase !== null) {
64
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
65
+ /* @__PURE__ */ jsx(Banner, { lang }),
66
+ /* @__PURE__ */ jsxs(Panel, { title: `\u276F ${t.chooseRepo}`, color: theme.primary, children: [
67
+ repos.length === 0 ? /* @__PURE__ */ jsx(Text, { color: theme.warn, children: t.noReposConfigured }) : /* @__PURE__ */ jsx(
68
+ Select,
69
+ {
70
+ items: repos.map((r) => ({ label: r, value: r })),
71
+ onSelect: (r) => emit({ kind: "run", phase: pendingPhase, repos: [r] })
72
+ }
73
+ ),
74
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: theme.dim, children: t.escBack }) })
75
+ ] })
76
+ ] });
77
+ }
78
+ const modeLabel = mode === "all" ? t.modeAll : t.modeSingle;
79
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
80
+ /* @__PURE__ */ jsx(Banner, { lang }),
81
+ /* @__PURE__ */ jsx(Panel, { title: `\u276F ${t.actions}`, color: theme.accent, children: /* @__PURE__ */ jsx(
82
+ Select,
83
+ {
84
+ items: [
85
+ { label: t.actionRunSecurity, value: "run-fix" },
86
+ { label: t.actionRunDependabot, value: "run-purge" },
87
+ { label: t.actionRunBoth, value: "run-both" },
88
+ { label: schedule?.enabled ? t.actionScheduleEdit : t.actionSchedule, value: "schedule" },
89
+ { label: t.actionSetup, value: "setup" },
90
+ { label: t.actionQuit, value: "quit" }
91
+ ],
92
+ onSelect: onMenu
93
+ }
94
+ ) }),
95
+ /* @__PURE__ */ jsxs(
96
+ Box,
97
+ {
98
+ justifyContent: "space-between",
99
+ alignItems: schedule?.enabled ? "flex-start" : "center",
100
+ width: "100%",
101
+ marginTop: -1,
102
+ children: [
103
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
104
+ schedule?.enabled && /* @__PURE__ */ jsxs(Text, { color: theme.success, children: [
105
+ "\u25F7 ",
106
+ t.schedule.active(schedule.time)
107
+ ] }),
108
+ /* @__PURE__ */ jsx(Text, { color: theme.dim, children: t.modeSwitchHint })
109
+ ] }),
110
+ /* @__PURE__ */ jsx(Box, { borderStyle: "round", borderColor: theme.primary, paddingX: 1, children: /* @__PURE__ */ jsxs(Text, { color: theme.primary, bold: true, children: [
111
+ "\u25CF ",
112
+ modeLabel
113
+ ] }) })
114
+ ]
115
+ }
116
+ )
117
+ ] });
118
+ }
119
+ function ReturnPrompt({
120
+ lang = "en",
121
+ onSelect = () => {
122
+ }
123
+ }) {
124
+ const { exit } = useApp();
125
+ const t = appT(lang);
126
+ return /* @__PURE__ */ jsx(Panel, { title: `\u25F7 ${t.runDone}`, color: theme.primary, children: /* @__PURE__ */ jsx(
127
+ Select,
128
+ {
129
+ items: [
130
+ { label: `\u21A9 ${t.returnToMain}`, value: "return" },
131
+ { label: t.actionQuit, value: "quit" }
132
+ ],
133
+ onSelect: (v) => {
134
+ onSelect(v);
135
+ exit();
136
+ }
137
+ }
138
+ ) });
139
+ }
140
+
141
+ // src/ui/schedule-editor.tsx
142
+ import { useState as useState2 } from "react";
143
+ import { Box as Box2, Text as Text2, useApp as useApp2, useInput as useInput2 } from "ink";
144
+ import TextInput from "ink-text-input";
145
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
146
+ var TIME_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
147
+ function ScheduleEditor({
148
+ lang = "en",
149
+ configuredRepos = [],
150
+ current = { enabled: false, time: "10:00", repos: [] },
151
+ apply,
152
+ disable,
153
+ onClose = () => {
154
+ }
155
+ }) {
156
+ const { exit } = useApp2();
157
+ const t = appT(lang);
158
+ const s = t.schedule;
159
+ const [step, setStep] = useState2(current.enabled ? "choice" : "repos");
160
+ const [repos, setRepos] = useState2(current.repos.length ? current.repos : configuredRepos);
161
+ const [time, setTime] = useState2(current.time);
162
+ const [error, setError] = useState2(null);
163
+ const [result, setResult] = useState2(null);
164
+ const close = () => {
165
+ onClose();
166
+ exit();
167
+ };
168
+ useInput2((_input, key) => {
169
+ if (key.escape && step !== "result") close();
170
+ });
171
+ const finishSet = (chosenTime) => {
172
+ const r = apply({ time: chosenTime, repos });
173
+ const runAll = repos.length === 0 || repos.length === configuredRepos.length;
174
+ const n = runAll ? configuredRepos.length : repos.length;
175
+ setResult({ ok: r.ok, text: r.ok ? s.setOk(chosenTime, n) : r.message });
176
+ setStep("result");
177
+ };
178
+ const finishDisable = () => {
179
+ const r = disable();
180
+ setResult({ ok: r.ok, text: r.ok ? s.cleared : r.message });
181
+ setStep("result");
182
+ };
183
+ if (configuredRepos.length === 0) {
184
+ return /* @__PURE__ */ jsxs2(Frame, { lang, children: [
185
+ /* @__PURE__ */ jsx2(Text2, { color: theme.warn, children: s.noRepos }),
186
+ /* @__PURE__ */ jsx2(Select, { items: [{ label: `\u21A9 ${t.returnToMain}`, value: "back" }], onSelect: close })
187
+ ] });
188
+ }
189
+ return /* @__PURE__ */ jsxs2(Frame, { lang, children: [
190
+ step === "choice" && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
191
+ /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: s.active(current.time) }),
192
+ /* @__PURE__ */ jsx2(
193
+ Select,
194
+ {
195
+ items: [
196
+ { label: s.modify, value: "modify" },
197
+ { label: s.disable, value: "disable" },
198
+ { label: s.cancel, value: "cancel" }
199
+ ],
200
+ onSelect: (v) => {
201
+ if (v === "modify") setStep("repos");
202
+ else if (v === "disable") finishDisable();
203
+ else close();
204
+ }
205
+ }
206
+ )
207
+ ] }),
208
+ step === "repos" && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
209
+ /* @__PURE__ */ jsx2(Text2, { color: theme.text, children: s.reposPrompt }),
210
+ /* @__PURE__ */ jsx2(
211
+ MultiSelect,
212
+ {
213
+ items: configuredRepos,
214
+ initial: repos,
215
+ hint: s.reposHint,
216
+ onConfirm: (sel) => {
217
+ setRepos(sel);
218
+ setStep("time");
219
+ }
220
+ }
221
+ ),
222
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: t.escBack }) })
223
+ ] }),
224
+ step === "time" && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
225
+ /* @__PURE__ */ jsx2(Text2, { color: theme.text, children: s.timePrompt }),
226
+ /* @__PURE__ */ jsxs2(Box2, { children: [
227
+ /* @__PURE__ */ jsxs2(Text2, { color: theme.dim, children: [
228
+ s.timeLabel,
229
+ ": "
230
+ ] }),
231
+ /* @__PURE__ */ jsx2(
232
+ TextInput,
233
+ {
234
+ value: time,
235
+ onChange: (v) => {
236
+ setTime(v);
237
+ setError(null);
238
+ },
239
+ onSubmit: (v) => {
240
+ const tt = v.trim();
241
+ if (!TIME_RE.test(tt)) {
242
+ setError(s.timeInvalid);
243
+ return;
244
+ }
245
+ setTime(tt);
246
+ finishSet(tt);
247
+ }
248
+ }
249
+ )
250
+ ] }),
251
+ error && /* @__PURE__ */ jsx2(Text2, { color: theme.error, children: error }),
252
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { color: theme.dim, children: t.escBack }) })
253
+ ] }),
254
+ step === "result" && result && /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
255
+ /* @__PURE__ */ jsxs2(Text2, { color: result.ok ? theme.success : theme.error, children: [
256
+ result.ok ? "\u2713" : "\u2717",
257
+ " ",
258
+ result.text
259
+ ] }),
260
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Select, { items: [{ label: `\u21A9 ${t.returnToMain}`, value: "back" }], onSelect: close }) })
261
+ ] })
262
+ ] });
263
+ }
264
+ function Frame({ lang, children }) {
265
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
266
+ /* @__PURE__ */ jsx2(Banner, { lang }),
267
+ /* @__PURE__ */ jsx2(Panel, { title: `\u25F7 ${appT(lang).schedule.title}`, color: theme.accent, children })
268
+ ] });
269
+ }
270
+
271
+ // src/commands/dashboard.ts
272
+ async function runDashboard() {
273
+ if (!readConfig()) {
274
+ const code = await runSetup();
275
+ if (code !== 0) return code;
276
+ if (!readConfig()) return 0;
277
+ }
278
+ let mode = "all";
279
+ for (; ; ) {
280
+ const cfg = readConfig();
281
+ if (!cfg) return 0;
282
+ clearScreen();
283
+ const action = await renderDashboard(cfg.lang, cfg.repos, cfg.schedule, mode, (m) => mode = m);
284
+ if (action.kind === "quit") return 0;
285
+ if (action.kind === "setup") {
286
+ clearScreen();
287
+ await runSetup();
288
+ continue;
289
+ }
290
+ if (action.kind === "schedule") {
291
+ clearScreen();
292
+ await renderScheduleEditor(cfg);
293
+ continue;
294
+ }
295
+ clearScreen();
296
+ if (action.repos === "all") await runCommand([], { phase: action.phase, all: true });
297
+ else await runCommand(action.repos, { phase: action.phase });
298
+ console.log("");
299
+ if (await renderReturnPrompt(cfg.lang) === "quit") return 0;
300
+ }
301
+ }
302
+ function renderDashboard(lang, repos, schedule, initialMode, onModeChange) {
303
+ return new Promise((resolve) => {
304
+ let action = { kind: "quit" };
305
+ const app = render(
306
+ createElement(Dashboard, { lang, repos, schedule, initialMode, onModeChange, onAction: (a) => action = a })
307
+ );
308
+ void app.waitUntilExit().then(() => resolve(action));
309
+ });
310
+ }
311
+ function renderScheduleEditor(cfg) {
312
+ return new Promise((resolve) => {
313
+ const app = render(
314
+ createElement(ScheduleEditor, {
315
+ lang: cfg.lang,
316
+ configuredRepos: cfg.repos,
317
+ current: { enabled: cfg.schedule.enabled, time: cfg.schedule.time, repos: cfg.schedule.repos },
318
+ apply: (input) => applySchedule(cfg, input),
319
+ disable: () => applyUnschedule()
320
+ })
321
+ );
322
+ void app.waitUntilExit().then(() => resolve());
323
+ });
324
+ }
325
+ function renderReturnPrompt(lang) {
326
+ return new Promise((resolve) => {
327
+ let choice = "return";
328
+ const app = render(createElement(ReturnPrompt, { lang, onSelect: (v) => choice = v }));
329
+ void app.waitUntilExit().then(() => resolve(choice));
330
+ });
331
+ }
332
+ export {
333
+ runDashboard
334
+ };
335
+ //# sourceMappingURL=dashboard-W6QCV3NV.js.map
@@ -0,0 +1,8 @@
1
+ import {
2
+ runSetup
3
+ } from "./chunk-FDTKUXXE.js";
4
+ import "./chunk-HMGF6JWH.js";
5
+ export {
6
+ runSetup
7
+ };
8
+ //# sourceMappingURL=setup-R2IL4RHH.js.map
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "misterpropre",
3
+ "version": "0.0.1",
4
+ "description": "Mr. Clean for dependencies — a bilingual CLI that automates Dependabot/Renovate security fixes and bot-PR triage across your repos, via Claude Code or Kiro.",
5
+ "type": "module",
6
+ "bin": {
7
+ "misterpropre": "dist/cli.js",
8
+ "mrp": "dist/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "skills",
13
+ "!dist/**/*.map"
14
+ ],
15
+ "engines": {
16
+ "node": ">=20"
17
+ },
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsx src/cli.ts",
21
+ "typecheck": "tsc --noEmit",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "prepublishOnly": "npm run typecheck && npm test && npm run build"
25
+ },
26
+ "keywords": [
27
+ "dependabot",
28
+ "renovate",
29
+ "security",
30
+ "automation",
31
+ "cli"
32
+ ],
33
+ "license": "MIT",
34
+ "author": "Ayman Kahya <kahya.ayman@gmail.com>",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/aymankahya/misterpropre.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/aymankahya/misterpropre/issues"
41
+ },
42
+ "homepage": "https://github.com/aymankahya/misterpropre#readme",
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "dependencies": {
47
+ "commander": "^12.1.0",
48
+ "ink": "^5.2.1",
49
+ "ink-big-text": "^2.0.0",
50
+ "ink-gradient": "^3.0.0",
51
+ "ink-text-input": "^6.0.0",
52
+ "react": "^18.3.1",
53
+ "zod": "^3.25.76"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^22.10.0",
57
+ "@types/react": "^18.3.31",
58
+ "ink-testing-library": "^4.0.0",
59
+ "tsup": "^8.3.5",
60
+ "tsx": "^4.19.2",
61
+ "typescript": "^5.7.2",
62
+ "vitest": "^2.1.8"
63
+ }
64
+ }