smashspace 0.1.0 → 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/README.md +23 -0
- package/dist/smash.mjs +90 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -45,6 +45,7 @@ Drop this at your repo root so `smash` knows which board to operate on:
|
|
|
45
45
|
## Everyday commands
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
+
smash status # what context is this directory in? (see below)
|
|
48
49
|
smash read # show the board (lists + cards)
|
|
49
50
|
smash scan --list "やること" # actionable cards as JSON (for agents)
|
|
50
51
|
smash create "Fix signup bug" # add a card (to the first list, or --list)
|
|
@@ -56,6 +57,28 @@ smash --help # full command list (board/list/card/…)
|
|
|
56
57
|
Pick a board with `-b <label>` (defaults to `main`), or bypass config with
|
|
57
58
|
`--board-id <id>`.
|
|
58
59
|
|
|
60
|
+
## Multiple repos on one machine
|
|
61
|
+
|
|
62
|
+
`smash` is **directory-aware**: it walks up from your current directory to the
|
|
63
|
+
nearest `.smashspace.json`, so each repo operates on its own instance and board
|
|
64
|
+
automatically — no global switch to flip.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
smash status # config file, instance, board, and signed-in account for CWD
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
config .smashspace.json
|
|
72
|
+
base_url https://smashspace.app (.smashspace.json)
|
|
73
|
+
board main → b_xxxxxxxx
|
|
74
|
+
account <userId> ✓ token ok (23 boards) [file]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Run it whenever you're unsure which repo/board a command will hit. Add
|
|
78
|
+
`--no-check` to skip the network round-trip, or `--json` for scripts. The login
|
|
79
|
+
token itself is stored once per instance in `~/.config/smash/credentials.json`
|
|
80
|
+
and shared across repos that point at the same `base_url`.
|
|
81
|
+
|
|
59
82
|
> `smash space …` is an alias of `smash board …`, and the HTTP API mirrors
|
|
60
83
|
> `/api/boards` at `/api/spaces`. In `.smashspace.json`, `space_id` / `spaces`
|
|
61
84
|
> also work as aliases for `board_id` / `boards`.
|
package/dist/smash.mjs
CHANGED
|
@@ -3395,6 +3395,7 @@ import { randomBytes } from "node:crypto";
|
|
|
3395
3395
|
import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3396
3396
|
import { platform as platform2 } from "node:os";
|
|
3397
3397
|
import { createInterface } from "node:readline/promises";
|
|
3398
|
+
import { relative } from "node:path";
|
|
3398
3399
|
import { stdin, stdout } from "node:process";
|
|
3399
3400
|
|
|
3400
3401
|
// ../../shared/board-registry.ts
|
|
@@ -4389,6 +4390,95 @@ program2.command("whoami").description("Show the user identified by the saved/en
|
|
|
4389
4390
|
[`\u2713 ${me.userId} (${me.boardCount} boards) on ${baseUrl}`]
|
|
4390
4391
|
);
|
|
4391
4392
|
});
|
|
4393
|
+
program2.command("status").aliases(["context", "where"]).description(
|
|
4394
|
+
"Show the context resolved from the current directory: config file, instance, board, and signed-in account"
|
|
4395
|
+
).option("--no-check", "Skip the live token check (offline)").action(async (opts) => {
|
|
4396
|
+
const loaded = loadProjectConfig();
|
|
4397
|
+
const baseUrl = resolveBaseUrl(loaded);
|
|
4398
|
+
const baseSource = program2.getOptionValueSource("baseUrl") === "cli" ? "--base-url" : loaded?.config.base_url ? CONFIG_FILENAME : process.env.SMASH_BASE_URL ? "env:SMASH_BASE_URL" : "default";
|
|
4399
|
+
let board = null;
|
|
4400
|
+
let boardError = null;
|
|
4401
|
+
if (loaded) {
|
|
4402
|
+
try {
|
|
4403
|
+
const entry = resolveBoardEntry(loaded.config, void 0);
|
|
4404
|
+
board = { label: entry.label, boardId: entry.board_id };
|
|
4405
|
+
} catch (e) {
|
|
4406
|
+
boardError = e instanceof Error ? e.message : String(e);
|
|
4407
|
+
}
|
|
4408
|
+
}
|
|
4409
|
+
const cred = await findCredential(baseUrl);
|
|
4410
|
+
const token = await resolveToken(baseUrl);
|
|
4411
|
+
const tokenSource = process.env.SMASH_TOKEN ? "env:SMASH_TOKEN" : cred ? "file" : null;
|
|
4412
|
+
let live = null;
|
|
4413
|
+
if (token && opts.check) {
|
|
4414
|
+
try {
|
|
4415
|
+
const ctrl = new AbortController();
|
|
4416
|
+
const timer = setTimeout(() => ctrl.abort(), 5e3);
|
|
4417
|
+
const res = await fetch(new URL("/api/usage/me", baseUrl), {
|
|
4418
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
4419
|
+
signal: ctrl.signal
|
|
4420
|
+
}).finally(() => clearTimeout(timer));
|
|
4421
|
+
if (res.ok) {
|
|
4422
|
+
const me = await res.json();
|
|
4423
|
+
live = { ok: true, userId: me.userId, boardCount: me.boardCount };
|
|
4424
|
+
} else {
|
|
4425
|
+
live = { ok: false, error: `${res.status} ${res.statusText}` };
|
|
4426
|
+
}
|
|
4427
|
+
} catch (e) {
|
|
4428
|
+
live = { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
const account = (live?.ok ? live.userId : void 0) ?? cred?.userId ?? null;
|
|
4432
|
+
if (getOpts().json) {
|
|
4433
|
+
show({
|
|
4434
|
+
cwd: process.cwd(),
|
|
4435
|
+
config: loaded?.path ?? null,
|
|
4436
|
+
baseUrl,
|
|
4437
|
+
baseUrlSource: baseSource,
|
|
4438
|
+
board,
|
|
4439
|
+
boardError,
|
|
4440
|
+
account,
|
|
4441
|
+
tokenPresent: !!token,
|
|
4442
|
+
tokenSource,
|
|
4443
|
+
live,
|
|
4444
|
+
boards: loaded?.config.boards.map((b) => ({
|
|
4445
|
+
label: b.label,
|
|
4446
|
+
boardId: b.board_id
|
|
4447
|
+
})) ?? []
|
|
4448
|
+
});
|
|
4449
|
+
return;
|
|
4450
|
+
}
|
|
4451
|
+
const cfgDisplay = loaded ? relative(process.cwd(), loaded.path) || loaded.path : `(none \u2014 searched up from ${process.cwd()})`;
|
|
4452
|
+
const lines = [
|
|
4453
|
+
`config ${cfgDisplay}`,
|
|
4454
|
+
`base_url ${baseUrl} (${baseSource})`
|
|
4455
|
+
];
|
|
4456
|
+
if (board)
|
|
4457
|
+
lines.push(`board ${board.label} \u2192 ${board.boardId}`);
|
|
4458
|
+
else if (boardError)
|
|
4459
|
+
lines.push(`board (unresolved: ${boardError})`);
|
|
4460
|
+
else
|
|
4461
|
+
lines.push(`board (no ${CONFIG_FILENAME}; pass --board-id)`);
|
|
4462
|
+
if (!token) {
|
|
4463
|
+
lines.push(`account \u2717 not signed in \u2014 run 'smash login'`);
|
|
4464
|
+
} else if (live) {
|
|
4465
|
+
lines.push(
|
|
4466
|
+
live.ok ? `account ${live.userId} \u2713 token ok (${live.boardCount} boards) [${tokenSource}]` : `account ${account ?? "?"} \u2717 token check failed: ${live.error} [${tokenSource}]`
|
|
4467
|
+
);
|
|
4468
|
+
} else {
|
|
4469
|
+
lines.push(
|
|
4470
|
+
`account ${account ?? "(token set)"} [${tokenSource}] (not checked)`
|
|
4471
|
+
);
|
|
4472
|
+
}
|
|
4473
|
+
if (loaded && loaded.config.boards.length > 1) {
|
|
4474
|
+
const active = board?.label ?? loaded.config.default ?? "main";
|
|
4475
|
+
lines.push("", "boards:");
|
|
4476
|
+
for (const b of loaded.config.boards) {
|
|
4477
|
+
lines.push(` ${b.label === active ? "*" : " "} ${b.label} \u2192 ${b.board_id}`);
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
show(void 0, lines);
|
|
4481
|
+
});
|
|
4392
4482
|
program2.command("create <title>").description(`Create a card on the resolved board (${CONFIG_FILENAME}, default "main")`).option("-b, --board <label>", "board label from config").option("--board-id <id>", "explicit board id (bypass config)").option("-l, --list <name>", "target list name (default: first list)").option("-d, --desc <text>", "card description (Markdown)").action(async (title, opts) => {
|
|
4393
4483
|
const ctx = resolveContext(opts);
|
|
4394
4484
|
const detail = await fetchBoard(ctx.boardId, ctx.baseUrl);
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smashspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "SmashSpace CLI + MCP — operate SmashSpace boards from your terminal, Claude Code, Cursor, and Codex.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"smash": "dist/smash.mjs",
|
|
8
|
+
"smashspace": "dist/smash.mjs",
|
|
8
9
|
"smashspace-mcp": "dist/smashspace-mcp.mjs"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|