wordspace 0.0.6 → 0.0.8

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.
@@ -0,0 +1 @@
1
+ export declare function run(target: string | undefined, force: boolean): Promise<void>;
@@ -0,0 +1,55 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parseGitHubUri, toRawUrl, fileName } from "../lib/github-uri.js";
4
+ import { httpGet, getAuthHeaders } from "../lib/workflows.js";
5
+ import { isClaudeInstalled, spawnClaude } from "../lib/spawn.js";
6
+ import { ensureInit } from "../steps/auto-init.js";
7
+ import * as log from "../lib/log.js";
8
+ export async function run(target, force) {
9
+ if (!target) {
10
+ log.error("Usage: wordspace run <github:owner/repo/path.prose | local-path>");
11
+ process.exit(1);
12
+ }
13
+ if (!isClaudeInstalled()) {
14
+ log.error("claude CLI not found. Install Claude Code first: https://claude.ai/code");
15
+ process.exit(1);
16
+ }
17
+ const cwd = process.cwd();
18
+ // Auto-init if needed
19
+ ensureInit(cwd);
20
+ let prosePath;
21
+ if (target.startsWith("github:")) {
22
+ // Remote: download from GitHub
23
+ const ref = parseGitHubUri(target);
24
+ const name = fileName(ref);
25
+ const workflowsDir = join(cwd, "workflows");
26
+ const dest = join(workflowsDir, name);
27
+ if (existsSync(dest) && !force) {
28
+ log.skip(`${name} (cached)`);
29
+ }
30
+ else {
31
+ const url = toRawUrl(ref);
32
+ log.info(`Fetching ${name}...`);
33
+ const headers = getAuthHeaders();
34
+ const content = await httpGet(url, headers);
35
+ mkdirSync(workflowsDir, { recursive: true });
36
+ writeFileSync(dest, content, "utf-8");
37
+ log.success(`Downloaded ${name}`);
38
+ }
39
+ prosePath = `workflows/${name}`;
40
+ }
41
+ else {
42
+ // Local path
43
+ if (!existsSync(target)) {
44
+ log.error(`File not found: ${target}`);
45
+ process.exit(1);
46
+ }
47
+ prosePath = target;
48
+ }
49
+ const prompt = `/prose run ${prosePath}`;
50
+ console.log();
51
+ log.info(prompt);
52
+ console.log();
53
+ const exitCode = spawnClaude(prompt, cwd);
54
+ process.exit(exitCode);
55
+ }
package/dist/index.js CHANGED
@@ -2,8 +2,9 @@
2
2
  import { init } from "./commands/init.js";
3
3
  import { search } from "./commands/search.js";
4
4
  import { add } from "./commands/add.js";
5
+ import { run } from "./commands/run.js";
5
6
  import * as log from "./lib/log.js";
6
- const VERSION = "0.0.6";
7
+ const VERSION = "0.0.8";
7
8
  const HELP = `
8
9
  Usage: wordspace <command> [options]
9
10
 
@@ -11,6 +12,7 @@ Commands:
11
12
  init Bootstrap a new wordspace project
12
13
  search [q] List available workflows (optionally filter by query)
13
14
  add <name> Download specific workflow(s) by name
15
+ run <target> Run a .prose workflow via Claude Code
14
16
 
15
17
  Options:
16
18
  --force Re-run all steps / overwrite existing files
@@ -39,6 +41,9 @@ async function main() {
39
41
  else if (command === "add") {
40
42
  await add(positional.slice(1), force);
41
43
  }
44
+ else if (command === "run") {
45
+ await run(positional[1], force);
46
+ }
42
47
  else if (!command) {
43
48
  console.log(HELP);
44
49
  process.exit(0);
@@ -0,0 +1,14 @@
1
+ export interface GitHubRef {
2
+ owner: string;
3
+ repo: string;
4
+ path: string;
5
+ branch: string;
6
+ }
7
+ /**
8
+ * Parse a `github:owner/repo/path/file.prose[@branch]` URI.
9
+ */
10
+ export declare function parseGitHubUri(uri: string): GitHubRef;
11
+ /** Build the raw.githubusercontent.com URL for a ref. */
12
+ export declare function toRawUrl(ref: GitHubRef): string;
13
+ /** Extract the filename from the path (last segment). */
14
+ export declare function fileName(ref: GitHubRef): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Parse a `github:owner/repo/path/file.prose[@branch]` URI.
3
+ */
4
+ export function parseGitHubUri(uri) {
5
+ const body = uri.replace(/^github:/, "");
6
+ const [pathPart, branch = "main"] = body.split("@");
7
+ const segments = pathPart.split("/");
8
+ if (segments.length < 3) {
9
+ throw new Error(`Invalid GitHub URI: "${uri}". Expected github:owner/repo/path[...@branch]`);
10
+ }
11
+ const [owner, repo, ...rest] = segments;
12
+ return { owner, repo, path: rest.join("/"), branch };
13
+ }
14
+ /** Build the raw.githubusercontent.com URL for a ref. */
15
+ export function toRawUrl(ref) {
16
+ return `https://raw.githubusercontent.com/${ref.owner}/${ref.repo}/${ref.branch}/${ref.path}`;
17
+ }
18
+ /** Extract the filename from the path (last segment). */
19
+ export function fileName(ref) {
20
+ const parts = ref.path.split("/");
21
+ return parts[parts.length - 1];
22
+ }
@@ -0,0 +1,4 @@
1
+ /** Check if `claude` CLI is available on PATH. */
2
+ export declare function isClaudeInstalled(): boolean;
3
+ /** Spawn `claude` interactively, handing over the terminal. */
4
+ export declare function spawnClaude(prompt: string, cwd: string): number;
@@ -0,0 +1,19 @@
1
+ import { spawnSync, execSync } from "node:child_process";
2
+ /** Check if `claude` CLI is available on PATH. */
3
+ export function isClaudeInstalled() {
4
+ try {
5
+ execSync("which claude", { stdio: "pipe" });
6
+ return true;
7
+ }
8
+ catch {
9
+ return false;
10
+ }
11
+ }
12
+ /** Spawn `claude` interactively, handing over the terminal. */
13
+ export function spawnClaude(prompt, cwd) {
14
+ const result = spawnSync("claude", [prompt], {
15
+ cwd,
16
+ stdio: "inherit",
17
+ });
18
+ return result.status ?? 1;
19
+ }
@@ -0,0 +1,2 @@
1
+ /** Silently initialize the project if not already done. */
2
+ export declare function ensureInit(cwd: string): void;
@@ -0,0 +1,43 @@
1
+ import { existsSync } from "node:fs";
2
+ import { execSync } from "node:child_process";
3
+ import { join } from "node:path";
4
+ import { setupClaude } from "./setup-claude.js";
5
+ import { createDirs } from "./create-dirs.js";
6
+ import * as log from "../lib/log.js";
7
+ const SKILL_PACKAGES = [
8
+ "frames-engineering/skills",
9
+ "frames-engineering/wordspace",
10
+ ];
11
+ function installSkills(cwd) {
12
+ for (const pkg of SKILL_PACKAGES) {
13
+ try {
14
+ execSync(`npx -y skills add ${pkg} --all`, {
15
+ cwd,
16
+ stdio: "inherit",
17
+ });
18
+ }
19
+ catch {
20
+ log.warn(`Could not install skills from ${pkg}`);
21
+ }
22
+ }
23
+ }
24
+ /** Silently initialize the project if not already done. */
25
+ export function ensureInit(cwd) {
26
+ const hasSettings = existsSync(join(cwd, ".claude", "settings.local.json"));
27
+ const hasOutput = existsSync(join(cwd, "output"));
28
+ const skillsDir = join(cwd, ".agents", "skills");
29
+ const hasSkills = existsSync(join(skillsDir, "open-prose")) &&
30
+ existsSync(join(skillsDir, "agentwallet")) &&
31
+ existsSync(join(skillsDir, "registry")) &&
32
+ existsSync(join(skillsDir, "wordspace"));
33
+ if (hasSettings && hasOutput && hasSkills)
34
+ return;
35
+ log.info("Auto-initializing project...");
36
+ if (!hasSettings || !hasOutput) {
37
+ setupClaude(cwd);
38
+ createDirs(cwd);
39
+ }
40
+ if (!hasSkills) {
41
+ installSkills(cwd);
42
+ }
43
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wordspace",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"