@montytools/cli 0.1.2 → 0.1.3
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 +49 -1
- package/bin/postinstall.mjs +24 -0
- package/package.json +5 -3
- package/skills/monty-build/SKILL.md +47 -0
package/bin/monty.mjs
CHANGED
|
@@ -63,6 +63,7 @@ async function login() {
|
|
|
63
63
|
mkdirSync(MONTY_HOME, { recursive: true });
|
|
64
64
|
console.log(`logged-in: ${host} (key saved to ~/.monty/config.json)`);
|
|
65
65
|
console.log(`apps home: ${MONTY_HOME}`);
|
|
66
|
+
installSkills({ silent: false });
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
// Loopback auth: serve one callback on 127.0.0.1, send the browser to
|
|
@@ -129,6 +130,44 @@ function openInBrowser(url) {
|
|
|
129
130
|
}
|
|
130
131
|
|
|
131
132
|
|
|
133
|
+
|
|
134
|
+
// ── agent skills ─────────────────────────────────────────────────────────────
|
|
135
|
+
// The build skill ships inside this package and is stamped wherever agents
|
|
136
|
+
// look for it: ~/.claude/skills (user) and <app>/.claude + <app>/.agents
|
|
137
|
+
// (project — self-propagating contract, refreshed whenever the CLI runs).
|
|
138
|
+
const CLI_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
139
|
+
const CLI_VERSION = JSON.parse(readFileSync(join(CLI_ROOT, "package.json"), "utf8")).version;
|
|
140
|
+
const SKILLS_SRC = join(CLI_ROOT, "skills");
|
|
141
|
+
|
|
142
|
+
function installSkillsInto(dir, { silent = true } = {}) {
|
|
143
|
+
if (!existsSync(SKILLS_SRC)) return false;
|
|
144
|
+
let changed = false;
|
|
145
|
+
for (const name of readdirSync(SKILLS_SRC)) {
|
|
146
|
+
const dest = join(dir, name);
|
|
147
|
+
const versionFile = join(dest, "VERSION");
|
|
148
|
+
const installed = existsSync(versionFile) ? readFileSync(versionFile, "utf8").trim() : null;
|
|
149
|
+
if (installed === CLI_VERSION) continue;
|
|
150
|
+
cpSync(join(SKILLS_SRC, name), dest, { recursive: true });
|
|
151
|
+
writeFileSync(versionFile, CLI_VERSION + "\n");
|
|
152
|
+
changed = true;
|
|
153
|
+
}
|
|
154
|
+
if (changed && !silent) console.log(`skills: installed -> ${dir} (v${CLI_VERSION})`);
|
|
155
|
+
return changed;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function installSkills({ appDir = null, silent = true } = {}) {
|
|
159
|
+
if (process.env.MONTY_NO_SKILLS) return;
|
|
160
|
+
try {
|
|
161
|
+
let changed = installSkillsInto(join(homedir(), ".claude", "skills"), { silent });
|
|
162
|
+
for (const base of appDir ? [join(appDir, ".claude", "skills"), join(appDir, ".agents", "skills")] : []) {
|
|
163
|
+
changed = installSkillsInto(base, { silent }) || changed;
|
|
164
|
+
}
|
|
165
|
+
if (changed && silent) console.log(`skills: refreshed (v${CLI_VERSION})`);
|
|
166
|
+
} catch {
|
|
167
|
+
/* skills are best-effort — never block a command */
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
132
171
|
// ── monty current / select / apps ───────────────────────────────────────────
|
|
133
172
|
// Folder management users never think about: every app lives in ~/Monty,
|
|
134
173
|
// `current` says where you are, `select` prints the folder for cd $(...).
|
|
@@ -265,6 +304,7 @@ async function create() {
|
|
|
265
304
|
console.log(`config: WARNING — could not reach ${host}/api/config; copy .env.example to .env.local manually`);
|
|
266
305
|
}
|
|
267
306
|
|
|
307
|
+
installSkills({ appDir: target });
|
|
268
308
|
console.log(`created: ${target}`);
|
|
269
309
|
console.log(`next: cd ${target} && pnpm install && monty dev`);
|
|
270
310
|
}
|
|
@@ -506,6 +546,9 @@ function walk(dir) {
|
|
|
506
546
|
}
|
|
507
547
|
|
|
508
548
|
// ── dispatch ───────────────────────────────────────────────────────────────
|
|
549
|
+
// Keep agent skills fresh on every invocation (user level + current app).
|
|
550
|
+
installSkills({ appDir: findAppRoot(process.cwd()) });
|
|
551
|
+
|
|
509
552
|
switch (command) {
|
|
510
553
|
case "login":
|
|
511
554
|
await login();
|
|
@@ -535,11 +578,15 @@ switch (command) {
|
|
|
535
578
|
case "apps":
|
|
536
579
|
apps();
|
|
537
580
|
break;
|
|
581
|
+
case "skills":
|
|
582
|
+
installSkills({ appDir: findAppRoot(process.cwd()), silent: false });
|
|
583
|
+
console.log("skills: up to date");
|
|
584
|
+
break;
|
|
538
585
|
case "deploy":
|
|
539
586
|
await deploy();
|
|
540
587
|
break;
|
|
541
588
|
default:
|
|
542
|
-
console.log("usage: monty <login|create|current|select|apps|dev|add|components|docs|deploy>");
|
|
589
|
+
console.log("usage: monty <login|create|current|select|apps|dev|add|components|docs|deploy|skills>");
|
|
543
590
|
console.log(" login [--host <url>] [--key <mk_...>] sign in (opens your browser to authorize)");
|
|
544
591
|
console.log(" create <slug> [--name N] [--icon I] stamp a new app into ~/Monty/<slug>");
|
|
545
592
|
console.log(" dev [--port 5173] run the app locally (sandboxed data)");
|
|
@@ -550,5 +597,6 @@ switch (command) {
|
|
|
550
597
|
console.log(" select <slug> print an app's folder — cd \"$(monty select x)\"");
|
|
551
598
|
console.log(" apps list local apps in ~/Monty");
|
|
552
599
|
console.log(" deploy build + upload this app");
|
|
600
|
+
console.log(" skills install/refresh the agent build skill");
|
|
553
601
|
process.exit(command ? 1 : 0);
|
|
554
602
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Best-effort: put the agent build skill where Claude Code looks for it
|
|
2
|
+
// (~/.claude/skills) as soon as the package lands. Never fails the install;
|
|
3
|
+
// set MONTY_NO_SKILLS=1 to opt out. `monty skills` re-runs this any time.
|
|
4
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
if (process.env.MONTY_NO_SKILLS || process.env.CI) process.exit(0);
|
|
11
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
|
+
const src = join(root, "skills");
|
|
13
|
+
if (!existsSync(src)) process.exit(0);
|
|
14
|
+
const version = JSON.parse(readFileSync(join(root, "package.json"), "utf8")).version;
|
|
15
|
+
const target = join(homedir(), ".claude", "skills");
|
|
16
|
+
mkdirSync(target, { recursive: true });
|
|
17
|
+
for (const name of readdirSync(src)) {
|
|
18
|
+
cpSync(join(src, name), join(target, name), { recursive: true });
|
|
19
|
+
writeFileSync(join(target, name, "VERSION"), version + "\n");
|
|
20
|
+
}
|
|
21
|
+
console.log(`monty: agent skill installed (~/.claude/skills, v${version})`);
|
|
22
|
+
} catch {
|
|
23
|
+
/* silent — skills are a convenience, not a dependency */
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@montytools/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"monty": "./bin/monty.mjs"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"bin",
|
|
10
|
-
"template"
|
|
10
|
+
"template",
|
|
11
|
+
"skills"
|
|
11
12
|
],
|
|
12
13
|
"engines": {
|
|
13
14
|
"node": ">=22"
|
|
14
15
|
},
|
|
15
16
|
"scripts": {
|
|
16
17
|
"prepack": "node scripts/bundle-template.mjs",
|
|
17
|
-
"typecheck": "node --check bin/monty.mjs"
|
|
18
|
+
"typecheck": "node --check bin/monty.mjs",
|
|
19
|
+
"postinstall": "node bin/postinstall.mjs"
|
|
18
20
|
},
|
|
19
21
|
"dependencies": {
|
|
20
22
|
"esbuild": "^0.28.1"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: monty-build
|
|
3
|
+
description: Build, run, and deploy Monty workspace apps. Use whenever the task involves a Monty app, monty.config.ts, the monty CLI (create/dev/deploy/add), the @montytools/sdk, or a prompt mentioning usemonty.dev. Covers folder discipline, the build loop, data/auth rules, and error handling.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Building Monty apps
|
|
7
|
+
|
|
8
|
+
Monty is a work OS: teams get internal apps built by coding agents. You write
|
|
9
|
+
product logic only — data, auth, tenancy, deployment, and embedding are the
|
|
10
|
+
platform's job. The complete contract lives in the app's own `AGENTS.md`
|
|
11
|
+
(nearest-file-wins — read it before writing code). This skill is the map, not
|
|
12
|
+
the territory.
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
1. **Folders are managed.** Apps live in `~/Monty/<slug>`. `monty current`
|
|
17
|
+
tells you where you are; `cd "$(monty select <slug>)"` jumps to an app;
|
|
18
|
+
`monty apps` lists local ones. Never mkdir app folders by hand.
|
|
19
|
+
2. **The loop:** `monty create <slug> --name "Name" --icon <lucide-icon>` →
|
|
20
|
+
edit `monty.config.ts` (zod tables) + `src/routes/` → verify with
|
|
21
|
+
`monty dev` (localhost:5173, already authenticated, sandboxed data) →
|
|
22
|
+
`monty deploy`. You are done when deploy prints the URL.
|
|
23
|
+
3. **One import surface:** `@montytools/sdk` (`defineApp`, zod) and
|
|
24
|
+
`@montytools/sdk/react` (hooks: `useList`, `useInsert`, …). Never import
|
|
25
|
+
Clerk or Convex directly; never fetch external APIs from app code — the
|
|
26
|
+
platform CSP blocks them.
|
|
27
|
+
4. **Schema is zod in `monty.config.ts`.** Field names `_*`, `updatedAt`,
|
|
28
|
+
`createdBy` are reserved. Push happens automatically on dev/deploy.
|
|
29
|
+
5. **UI is stock shadcn** (preset already wired). Add curated components with
|
|
30
|
+
`monty add <name>`; browse with `monty components` / `monty docs <name>`.
|
|
31
|
+
6. **Errors are instructions.** Every failure prints
|
|
32
|
+
`[MontyError CODE] Fix: …` — do exactly what the Fix says; don't guess.
|
|
33
|
+
Typecheck failures block deploy by design.
|
|
34
|
+
7. **Verify before deploy.** `monty dev` writes to a `#dev` sandbox — live
|
|
35
|
+
team records are never touched, so exercise the app for real.
|
|
36
|
+
|
|
37
|
+
## CLI reference
|
|
38
|
+
|
|
39
|
+
| command | purpose |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `monty login` | browser sign-in (loopback authorize), once per machine |
|
|
42
|
+
| `monty create <slug>` | stamp a new app into `~/Monty/<slug>` |
|
|
43
|
+
| `monty current` / `select` / `apps` | where am I / jump to app / list local |
|
|
44
|
+
| `monty dev` | run locally on :5173, sandboxed data, auto-auth |
|
|
45
|
+
| `monty add <name…>` | install curated shadcn components |
|
|
46
|
+
| `monty deploy` | build + typecheck + upload; app appears in the workspace |
|
|
47
|
+
| `monty skills` | (re)install this skill for your agent |
|