@montytools/cli 0.1.1 → 0.1.2
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/bin/monty.mjs +79 -1
- package/package.json +1 -1
- package/template/AGENTS.md +2 -0
package/bin/monty.mjs
CHANGED
|
@@ -128,6 +128,72 @@ function openInBrowser(url) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
|
|
132
|
+
// ── monty current / select / apps ───────────────────────────────────────────
|
|
133
|
+
// Folder management users never think about: every app lives in ~/Monty,
|
|
134
|
+
// `current` says where you are, `select` prints the folder for cd $(...).
|
|
135
|
+
function findAppRoot(start) {
|
|
136
|
+
let d = start;
|
|
137
|
+
for (;;) {
|
|
138
|
+
if (existsSync(join(d, "monty.config.ts"))) return d;
|
|
139
|
+
const parent = dirname(d);
|
|
140
|
+
if (parent === d) return null;
|
|
141
|
+
d = parent;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function readSlugFromConfig(dir) {
|
|
146
|
+
try {
|
|
147
|
+
return /slug:\s*"([^"]+)"/.exec(readFileSync(join(dir, "monty.config.ts"), "utf8"))?.[1] ?? null;
|
|
148
|
+
} catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function listLocalApps() {
|
|
154
|
+
if (!existsSync(MONTY_HOME)) return [];
|
|
155
|
+
return readdirSync(MONTY_HOME)
|
|
156
|
+
.map((name) => join(MONTY_HOME, name))
|
|
157
|
+
.filter((p) => existsSync(join(p, "monty.config.ts")))
|
|
158
|
+
.map((p) => ({ path: p, slug: readSlugFromConfig(p) ?? basename(p) }));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function current() {
|
|
162
|
+
const root = findAppRoot(process.cwd());
|
|
163
|
+
if (!root) {
|
|
164
|
+
fail("NOT_IN_APP", `You are not inside a Monty app. \`monty apps\` lists local apps; cd "$(monty select <slug>)" jumps to one.`);
|
|
165
|
+
}
|
|
166
|
+
console.log(`app: ${readSlugFromConfig(root) ?? "?"}`);
|
|
167
|
+
console.log(`path: ${root}`);
|
|
168
|
+
if (!root.startsWith(MONTY_HOME)) {
|
|
169
|
+
console.log(`note: outside ${MONTY_HOME} (fine, but apps normally live there)`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function select() {
|
|
174
|
+
const slug = rest.find((a) => !a.startsWith("--"));
|
|
175
|
+
if (!slug) {
|
|
176
|
+
fail("MISSING_SLUG", `Usage: cd "$(monty select <slug>)" — prints the app's folder.`);
|
|
177
|
+
}
|
|
178
|
+
const apps = listLocalApps();
|
|
179
|
+
const hit = apps.find((a) => a.slug === slug || basename(a.path) === slug);
|
|
180
|
+
if (!hit) {
|
|
181
|
+
const known = apps.map((a) => a.slug).join(", ") || "(none)";
|
|
182
|
+
fail("APP_NOT_LOCAL", `No local source for "${slug}" in ${MONTY_HOME}. Local apps: ${known}. Create it with \`monty create ${slug}\`.`);
|
|
183
|
+
}
|
|
184
|
+
// Bare path on stdout so command substitution works: cd "$(monty select x)"
|
|
185
|
+
console.log(hit.path);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function apps() {
|
|
189
|
+
const local = listLocalApps();
|
|
190
|
+
if (!local.length) {
|
|
191
|
+
console.log(`no local apps in ${MONTY_HOME} — create one with \`monty create <slug>\``);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
for (const a of local) console.log(`${a.slug}\t${a.path}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
131
197
|
// ── monty create ───────────────────────────────────────────────────────────
|
|
132
198
|
async function create() {
|
|
133
199
|
const slug = rest.find((a) => !a.startsWith("--"));
|
|
@@ -460,17 +526,29 @@ switch (command) {
|
|
|
460
526
|
case "docs":
|
|
461
527
|
await docs();
|
|
462
528
|
break;
|
|
529
|
+
case "current":
|
|
530
|
+
current();
|
|
531
|
+
break;
|
|
532
|
+
case "select":
|
|
533
|
+
select();
|
|
534
|
+
break;
|
|
535
|
+
case "apps":
|
|
536
|
+
apps();
|
|
537
|
+
break;
|
|
463
538
|
case "deploy":
|
|
464
539
|
await deploy();
|
|
465
540
|
break;
|
|
466
541
|
default:
|
|
467
|
-
console.log("usage: monty <login|create|dev|add|components|docs|deploy>");
|
|
542
|
+
console.log("usage: monty <login|create|current|select|apps|dev|add|components|docs|deploy>");
|
|
468
543
|
console.log(" login [--host <url>] [--key <mk_...>] sign in (opens your browser to authorize)");
|
|
469
544
|
console.log(" create <slug> [--name N] [--icon I] stamp a new app into ~/Monty/<slug>");
|
|
470
545
|
console.log(" dev [--port 5173] run the app locally (sandboxed data)");
|
|
471
546
|
console.log(" add <name...> install curated UI components (see `monty components`)");
|
|
472
547
|
console.log(" components [query] list the curated component catalog");
|
|
473
548
|
console.log(" docs <name> view a component's source before installing");
|
|
549
|
+
console.log(" current which app folder am I in?");
|
|
550
|
+
console.log(" select <slug> print an app's folder — cd \"$(monty select x)\"");
|
|
551
|
+
console.log(" apps list local apps in ~/Monty");
|
|
474
552
|
console.log(" deploy build + upload this app");
|
|
475
553
|
process.exit(command ? 1 : 0);
|
|
476
554
|
}
|
package/package.json
CHANGED
package/template/AGENTS.md
CHANGED
|
@@ -4,6 +4,8 @@ Monty is a work OS: your app runs inside a team's workspace, on shared reactive
|
|
|
4
4
|
data, with auth and deployment handled by the platform. **You only write product
|
|
5
5
|
logic.** Everything below is the complete contract.
|
|
6
6
|
|
|
7
|
+
Folders are managed for you: this app lives in `~/Monty/<slug>`. `monty current` confirms where you are; `cd "$(monty select <slug>)"` jumps to any app; never create app folders by hand.
|
|
8
|
+
|
|
7
9
|
## The three files that matter
|
|
8
10
|
|
|
9
11
|
| File | What it is |
|