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.
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.js +55 -0
- package/dist/index.js +6 -1
- package/dist/lib/github-uri.d.ts +14 -0
- package/dist/lib/github-uri.js +22 -0
- package/dist/lib/spawn.d.ts +4 -0
- package/dist/lib/spawn.js +19 -0
- package/dist/steps/auto-init.d.ts +2 -0
- package/dist/steps/auto-init.js +43 -0
- package/package.json +1 -1
|
@@ -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.
|
|
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,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,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
|
+
}
|