sfora-cli 0.3.0 → 0.5.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/README.md +1 -0
- package/dist/api-client.d.ts +5 -0
- package/dist/api-client.js +5 -0
- package/dist/cli.js +25 -5
- package/dist/config.d.ts +1 -1
- package/dist/config.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ or `echo >` straight into it. Ships first-class verbs, an interactive shell, and
|
|
|
7
7
|
an **MCP server** (`--mcp`) so agents in Claude / Cursor operate sfora natively.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
+
sfora new "Acme" # create a project
|
|
10
11
|
sfora post plan.md --project acme # push a markdown plan as a post
|
|
11
12
|
sfora task spec.md --project acme # …or a task on the board
|
|
12
13
|
sfora cat /projects/acme/board/01-todo/0042-fix-login.md
|
package/dist/api-client.d.ts
CHANGED
|
@@ -70,6 +70,11 @@ export declare class SforaApiClient {
|
|
|
70
70
|
constructor(config: SforaApiConfig);
|
|
71
71
|
/** `GET /v1/fs/projects` */
|
|
72
72
|
listProjects(): Promise<Project[]>;
|
|
73
|
+
/** `POST /v1/fs/projects` — create a project; the caller becomes its lead. */
|
|
74
|
+
createProject(name: string): Promise<{
|
|
75
|
+
slug: string;
|
|
76
|
+
name: string;
|
|
77
|
+
}>;
|
|
73
78
|
/**
|
|
74
79
|
* `GET …/posts` or `…/drafts`. `scheduled` lists drafts that have a
|
|
75
80
|
* (future) `scheduledFor` set.
|
package/dist/api-client.js
CHANGED
|
@@ -85,6 +85,11 @@ export class SforaApiClient {
|
|
|
85
85
|
const data = await this.#json("/v1/fs/projects");
|
|
86
86
|
return data.projects;
|
|
87
87
|
}
|
|
88
|
+
/** `POST /v1/fs/projects` — create a project; the caller becomes its lead. */
|
|
89
|
+
async createProject(name) {
|
|
90
|
+
const res = await this.#request("POST", "/v1/fs/projects", JSON.stringify({ name }));
|
|
91
|
+
return (await res.json());
|
|
92
|
+
}
|
|
88
93
|
/**
|
|
89
94
|
* `GET …/posts` or `…/drafts`. `scheduled` lists drafts that have a
|
|
90
95
|
* (future) `scheduledFor` set.
|
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import * as readline from "node:readline";
|
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
11
11
|
import { readFile as readLocalFile } from "node:fs/promises";
|
|
12
12
|
import { basename } from "node:path";
|
|
13
|
-
import { createSforaShell } from "./index.js";
|
|
13
|
+
import { createSforaShell, SforaApiClient } from "./index.js";
|
|
14
14
|
import { runMcpServer } from "./mcp-server.js";
|
|
15
15
|
import { readConfig, writeConfig, resolveSettings, DEFAULT_URL, } from "./config.js";
|
|
16
16
|
const colors = {
|
|
@@ -89,8 +89,11 @@ Push markdown straight to sfora:
|
|
|
89
89
|
sfora task <file.md> [--project <slug>] [--column <name>] Create a task
|
|
90
90
|
sfora doc <file.md> [--project <slug>] Create a doc
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
Projects:
|
|
93
|
+
sfora new "<name>" Create a project
|
|
93
94
|
sfora projects List your projects
|
|
95
|
+
|
|
96
|
+
Browse:
|
|
94
97
|
sfora ls [path] List a path (default /projects)
|
|
95
98
|
sfora cat <path> Print a file's markdown
|
|
96
99
|
sfora Open the interactive shell
|
|
@@ -260,14 +263,30 @@ async function resolveProject(fs, flag, md) {
|
|
|
260
263
|
return slugs[0];
|
|
261
264
|
throw new Error(`specify --project <slug>${slugs.length ? ` (yours: ${slugs.join(", ")})` : ""}`);
|
|
262
265
|
}
|
|
263
|
-
const VERBS = new Set([
|
|
264
|
-
|
|
266
|
+
const VERBS = new Set([
|
|
267
|
+
"projects",
|
|
268
|
+
"new",
|
|
269
|
+
"ls",
|
|
270
|
+
"cat",
|
|
271
|
+
"post",
|
|
272
|
+
"task",
|
|
273
|
+
"doc",
|
|
274
|
+
]);
|
|
275
|
+
async function runVerb(args, fs, client) {
|
|
265
276
|
const ok = (msg) => console.log(`${colors.green}✓${colors.reset} ${msg}`);
|
|
266
277
|
if (args.command === "projects") {
|
|
267
278
|
const slugs = await fs.readdir("/projects");
|
|
268
279
|
console.log(slugs.length ? slugs.join("\n") : "(no projects)");
|
|
269
280
|
return;
|
|
270
281
|
}
|
|
282
|
+
if (args.command === "new") {
|
|
283
|
+
const name = args.rest.join(" ").trim();
|
|
284
|
+
if (!name)
|
|
285
|
+
throw new Error('usage: sfora new "<project name>"');
|
|
286
|
+
const res = await client.createProject(name);
|
|
287
|
+
ok(`Created project ${res.name} · /projects/${res.slug}`);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
271
290
|
if (args.command === "ls") {
|
|
272
291
|
const entries = await fs.readdir(args.rest[0] ?? "/projects");
|
|
273
292
|
console.log(entries.join("\n"));
|
|
@@ -354,8 +373,9 @@ async function main() {
|
|
|
354
373
|
apiKey,
|
|
355
374
|
org: settings.org ?? "",
|
|
356
375
|
});
|
|
376
|
+
const client = new SforaApiClient({ baseUrl, apiKey });
|
|
357
377
|
try {
|
|
358
|
-
await runVerb(args, fs);
|
|
378
|
+
await runVerb(args, fs, client);
|
|
359
379
|
}
|
|
360
380
|
catch (e) {
|
|
361
381
|
process.stderr.write(`${colors.red}error:${colors.reset} ${e instanceof Error ? e.message : String(e)}\n`);
|
package/dist/config.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface SforaConfig {
|
|
|
8
8
|
}>;
|
|
9
9
|
}
|
|
10
10
|
export declare const CONFIG_PATH: string;
|
|
11
|
-
export declare const DEFAULT_URL = "
|
|
11
|
+
export declare const DEFAULT_URL = "https://www.sfora.ai";
|
|
12
12
|
export declare function readConfig(): Promise<SforaConfig>;
|
|
13
13
|
export declare function writeConfig(cfg: SforaConfig): Promise<string>;
|
|
14
14
|
export interface ResolvedSettings {
|
package/dist/config.js
CHANGED
|
@@ -8,7 +8,9 @@ import { join } from "node:path";
|
|
|
8
8
|
import { readFile, writeFile, mkdir, chmod } from "node:fs/promises";
|
|
9
9
|
const CONFIG_DIR = join(homedir(), ".sfora");
|
|
10
10
|
export const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
11
|
-
|
|
11
|
+
// Production sfora. Local development of sfora itself overrides via --url or
|
|
12
|
+
// SFORA_URL (e.g. the dev Convex .site host).
|
|
13
|
+
export const DEFAULT_URL = "https://www.sfora.ai";
|
|
12
14
|
export async function readConfig() {
|
|
13
15
|
try {
|
|
14
16
|
const raw = await readFile(CONFIG_PATH, "utf8");
|
package/package.json
CHANGED