@headways/cli 0.4.0 → 0.4.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/dist/{api-2BK6MGZB.js → api-5EKGGFQ6.js} +2 -2
- package/dist/{chunk-HYEL7L5Z.js → chunk-2INXZHRG.js} +1 -1
- package/dist/{chunk-T2H7EXOV.js → chunk-UUFIIGTZ.js} +2 -0
- package/dist/{chunk-OZULVVQC.js → chunk-XTEQBKIN.js} +6 -8
- package/dist/{config-SHMIVRAP.js → config-XQHAXREA.js} +3 -1
- package/dist/index.js +86 -32
- package/dist/{sync-6PKI35ZY.js → sync-Q3OQUWOD.js} +2 -2
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@ var HEADWAYS_DIR = join(homedir(), ".headways");
|
|
|
8
8
|
var CONFIG_FILE = join(HEADWAYS_DIR, "config.json");
|
|
9
9
|
var CATALOG_FILE = join(HEADWAYS_DIR, "catalog.json");
|
|
10
10
|
var INSTALLED_DIR = join(HEADWAYS_DIR, "installed");
|
|
11
|
+
var CLAUDE_SKILLS_DIR = join(homedir(), ".claude", "skills");
|
|
11
12
|
function readConfig() {
|
|
12
13
|
if (!existsSync(CONFIG_FILE)) return {};
|
|
13
14
|
try {
|
|
@@ -42,6 +43,7 @@ export {
|
|
|
42
43
|
CONFIG_FILE,
|
|
43
44
|
CATALOG_FILE,
|
|
44
45
|
INSTALLED_DIR,
|
|
46
|
+
CLAUDE_SKILLS_DIR,
|
|
45
47
|
readConfig,
|
|
46
48
|
writeConfig,
|
|
47
49
|
getApiUrl,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
CLAUDE_SKILLS_DIR,
|
|
3
4
|
HEADWAYS_DIR,
|
|
4
5
|
getApiUrl,
|
|
5
6
|
readConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-UUFIIGTZ.js";
|
|
7
8
|
|
|
8
9
|
// src/commands/sync/index.ts
|
|
9
10
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync, rmSync as rmSync2 } from "fs";
|
|
10
|
-
import { homedir as homedir2 } from "os";
|
|
11
11
|
import { join as join2 } from "path";
|
|
12
12
|
import { createGunzip } from "zlib";
|
|
13
13
|
import { Readable } from "stream";
|
|
@@ -53,9 +53,8 @@ function registerUninstallCommand(program) {
|
|
|
53
53
|
removeHooks(CLAUDE_SETTINGS_GLOBAL);
|
|
54
54
|
removeHooks(CLAUDE_SETTINGS_LOCAL);
|
|
55
55
|
console.log("\u2713 Removed Claude Code hooks");
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
rmSync(skillsDir, { recursive: true, force: true });
|
|
56
|
+
if (existsSync(CLAUDE_SKILLS_DIR)) {
|
|
57
|
+
rmSync(CLAUDE_SKILLS_DIR, { recursive: true, force: true });
|
|
59
58
|
console.log("\u2713 Removed ~/.claude/skills/");
|
|
60
59
|
}
|
|
61
60
|
const headwaysDir = join(homedir(), ".headways");
|
|
@@ -232,9 +231,8 @@ async function downloadAndMaterialize(slug, version, state, apiUrl) {
|
|
|
232
231
|
});
|
|
233
232
|
if (!res.ok) throw new Error(`Bundle fetch failed: ${res.status}`);
|
|
234
233
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
235
|
-
const
|
|
236
|
-
const
|
|
237
|
-
const staging = join2(skillsDir, `.${slug}-staging`);
|
|
234
|
+
const dest = join2(CLAUDE_SKILLS_DIR, slug);
|
|
235
|
+
const staging = join2(CLAUDE_SKILLS_DIR, `.${slug}-staging`);
|
|
238
236
|
mkdirSync2(staging, { recursive: true });
|
|
239
237
|
await extractTarGz(buf, staging);
|
|
240
238
|
if (existsSync2(dest)) rmSync2(dest, { recursive: true });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CATALOG_FILE,
|
|
4
|
+
CLAUDE_SKILLS_DIR,
|
|
4
5
|
CONFIG_FILE,
|
|
5
6
|
HEADWAYS_DIR,
|
|
6
7
|
INSTALLED_DIR,
|
|
@@ -9,9 +10,10 @@ import {
|
|
|
9
10
|
readConfig,
|
|
10
11
|
requireAuth,
|
|
11
12
|
writeConfig
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UUFIIGTZ.js";
|
|
13
14
|
export {
|
|
14
15
|
CATALOG_FILE,
|
|
16
|
+
CLAUDE_SKILLS_DIR,
|
|
15
17
|
CONFIG_FILE,
|
|
16
18
|
HEADWAYS_DIR,
|
|
17
19
|
INSTALLED_DIR,
|
package/dist/index.js
CHANGED
|
@@ -2,25 +2,72 @@
|
|
|
2
2
|
import {
|
|
3
3
|
apiRequest,
|
|
4
4
|
rawRequest
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2INXZHRG.js";
|
|
6
6
|
import {
|
|
7
7
|
registerSetupCommand,
|
|
8
8
|
registerSyncCommands,
|
|
9
9
|
registerUninstallCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-XTEQBKIN.js";
|
|
11
11
|
import {
|
|
12
|
+
CLAUDE_SKILLS_DIR,
|
|
12
13
|
INSTALLED_DIR,
|
|
13
14
|
getApiUrl,
|
|
14
15
|
getAppUrl,
|
|
15
16
|
readConfig,
|
|
16
17
|
requireAuth,
|
|
17
18
|
writeConfig
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-UUFIIGTZ.js";
|
|
19
20
|
|
|
20
21
|
// src/index.ts
|
|
21
22
|
import "dotenv/config";
|
|
22
23
|
import { program } from "commander";
|
|
23
24
|
|
|
25
|
+
// package.json
|
|
26
|
+
var package_default = {
|
|
27
|
+
name: "@headways/cli",
|
|
28
|
+
version: "0.4.2",
|
|
29
|
+
type: "module",
|
|
30
|
+
description: "Headways CLI \u2014 authoring, sync, and runtime SDK",
|
|
31
|
+
license: "MIT",
|
|
32
|
+
files: [
|
|
33
|
+
"dist",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
37
|
+
bin: {
|
|
38
|
+
headways: "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
publishConfig: {
|
|
41
|
+
access: "public"
|
|
42
|
+
},
|
|
43
|
+
scripts: {
|
|
44
|
+
build: "tsup",
|
|
45
|
+
dev: "tsx src/index.ts",
|
|
46
|
+
test: "vitest run",
|
|
47
|
+
"test:unit": "vitest run",
|
|
48
|
+
"type-check": "tsc -p tsconfig.json --noEmit",
|
|
49
|
+
prepublishOnly: "pnpm build"
|
|
50
|
+
},
|
|
51
|
+
dependencies: {
|
|
52
|
+
"@headways/db": "workspace:*",
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
54
|
+
chalk: "^5.3.0",
|
|
55
|
+
commander: "^12.1.0",
|
|
56
|
+
dotenv: "^16.4.7",
|
|
57
|
+
"node-fetch": "^3.3.2",
|
|
58
|
+
yaml: "^2.5.1",
|
|
59
|
+
zod: "^3.25.28"
|
|
60
|
+
},
|
|
61
|
+
devDependencies: {
|
|
62
|
+
"@headways/config": "workspace:*",
|
|
63
|
+
"@types/node": "^22.16.5",
|
|
64
|
+
tsup: "^8.5.1",
|
|
65
|
+
tsx: "^4.21.0",
|
|
66
|
+
typescript: "^5.8.3",
|
|
67
|
+
vitest: "^3.2.4"
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
24
71
|
// src/commands/auth.ts
|
|
25
72
|
import "commander";
|
|
26
73
|
import * as http from "http";
|
|
@@ -382,34 +429,35 @@ function registerImportCommand(program2) {
|
|
|
382
429
|
import "commander";
|
|
383
430
|
import * as fs3 from "fs/promises";
|
|
384
431
|
import * as path3 from "path";
|
|
385
|
-
import { watch } from "fs";
|
|
432
|
+
import { watch, existsSync } from "fs";
|
|
433
|
+
var catchMissing = (e) => {
|
|
434
|
+
if (e.code === "ENOENT") return null;
|
|
435
|
+
throw e;
|
|
436
|
+
};
|
|
386
437
|
async function readSkillDir(dir) {
|
|
387
438
|
const skillMdPath = path3.join(dir, "SKILL.md");
|
|
388
|
-
|
|
389
|
-
let headline;
|
|
390
|
-
const headwaysYamlPath = path3.join(dir, "headways.yaml");
|
|
439
|
+
let body;
|
|
391
440
|
try {
|
|
392
|
-
|
|
393
|
-
const match = yaml.match(/headline:\s*['"]?(.+?)['"]?\s*$/m);
|
|
394
|
-
if (match) headline = match[1] ?? void 0;
|
|
441
|
+
body = await fs3.readFile(skillMdPath, "utf-8");
|
|
395
442
|
} catch {
|
|
443
|
+
throw new Error(`SKILL.md not found in ${dir}`);
|
|
396
444
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
445
|
+
const [headwaysYaml, capabilitiesYaml, connectionsYaml] = await Promise.all([
|
|
446
|
+
fs3.readFile(path3.join(dir, "headways.yaml"), "utf-8").catch(catchMissing),
|
|
447
|
+
fs3.readFile(path3.join(dir, "capabilities.yaml"), "utf-8").catch(catchMissing),
|
|
448
|
+
fs3.readFile(path3.join(dir, "connections.yaml"), "utf-8").catch(catchMissing)
|
|
449
|
+
]);
|
|
450
|
+
let headline;
|
|
451
|
+
if (headwaysYaml) {
|
|
452
|
+
const match = headwaysYaml.match(/headline:\s*['"]?(.+?)['"]?\s*$/m);
|
|
453
|
+
if (match) headline = match[1] ?? void 0;
|
|
403
454
|
}
|
|
404
455
|
let connections;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const connYaml = await fs3.readFile(connYamlPath, "utf-8");
|
|
408
|
-
const items = parseConnectionsYaml(connYaml);
|
|
456
|
+
if (connectionsYaml) {
|
|
457
|
+
const items = parseConnectionsYaml(connectionsYaml);
|
|
409
458
|
if (items.length > 0) connections = items;
|
|
410
|
-
} catch {
|
|
411
459
|
}
|
|
412
|
-
return { body, headline, capabilities, connections };
|
|
460
|
+
return { body, headline, capabilities: capabilitiesYaml ?? void 0, connections };
|
|
413
461
|
}
|
|
414
462
|
function parseConnectionsYaml(yaml) {
|
|
415
463
|
const items = [];
|
|
@@ -446,11 +494,17 @@ async function pushSkill(slug, dir) {
|
|
|
446
494
|
});
|
|
447
495
|
console.log(`Pushed '${slug}' draft`);
|
|
448
496
|
}
|
|
497
|
+
function resolveSkillDir(slug) {
|
|
498
|
+
if (!slug) return process.cwd();
|
|
499
|
+
const installedPath = path3.join(CLAUDE_SKILLS_DIR, slug);
|
|
500
|
+
if (existsSync(installedPath)) return installedPath;
|
|
501
|
+
return path3.join(process.cwd(), slug);
|
|
502
|
+
}
|
|
449
503
|
function registerPushCommand(program2) {
|
|
450
|
-
program2.command("push [slug]").description("Push local skill files as a draft to Headways").option("--watch", "Watch for file changes and auto-push").option("--dir <dir>", "Skill directory (default: ./<slug>
|
|
504
|
+
program2.command("push [slug]").description("Push local skill files as a draft to Headways").option("--watch", "Watch for file changes and auto-push").option("--dir <dir>", "Skill directory (default: installed location, then ./<slug>)").action(async (slug, opts) => {
|
|
451
505
|
requireAuth();
|
|
452
506
|
const resolvedSlug = slug ?? path3.basename(process.cwd());
|
|
453
|
-
const dir = opts.dir ?? (slug
|
|
507
|
+
const dir = opts.dir ?? resolveSkillDir(slug);
|
|
454
508
|
await pushSkill(resolvedSlug, dir);
|
|
455
509
|
if (opts.watch) {
|
|
456
510
|
console.log(`Watching ${dir} for changes...`);
|
|
@@ -552,7 +606,7 @@ Declare every MCP connector the skill depends on. Users see this list on \`headw
|
|
|
552
606
|
and the Headways app gates installation on the connectors being configured.
|
|
553
607
|
|
|
554
608
|
\`\`\`yaml
|
|
555
|
-
- connector: slack # connector identifier (e.g. slack, github,
|
|
609
|
+
- connector: slack # connector identifier (e.g. slack, github, atlassian, linear, notion, google-drive, stripe, asana, hubspot, datadog)
|
|
556
610
|
purpose: Read channel messages and threads via Slack MCP tools
|
|
557
611
|
- connector: github
|
|
558
612
|
purpose: Read pull requests and issues
|
|
@@ -627,8 +681,8 @@ function registerSkillsCommands(program2) {
|
|
|
627
681
|
console.log(SKILLS_GUIDE);
|
|
628
682
|
});
|
|
629
683
|
skills.command("list").description("List skills in the active org").action(async () => {
|
|
630
|
-
const { requireAuth: requireAuth2 } = await import("./config-
|
|
631
|
-
const { apiRequest: apiRequest2 } = await import("./api-
|
|
684
|
+
const { requireAuth: requireAuth2 } = await import("./config-XQHAXREA.js");
|
|
685
|
+
const { apiRequest: apiRequest2 } = await import("./api-5EKGGFQ6.js");
|
|
632
686
|
requireAuth2();
|
|
633
687
|
const result = await apiRequest2("/v1/skills");
|
|
634
688
|
if (result.data.length === 0) {
|
|
@@ -640,10 +694,10 @@ function registerSkillsCommands(program2) {
|
|
|
640
694
|
}
|
|
641
695
|
});
|
|
642
696
|
skills.command("accept <slug>").description("Accept a pending skill update and install it locally").action(async (slug) => {
|
|
643
|
-
const { acceptSkill } = await import("./sync-
|
|
697
|
+
const { acceptSkill } = await import("./sync-Q3OQUWOD.js");
|
|
644
698
|
await acceptSkill(slug);
|
|
645
699
|
try {
|
|
646
|
-
const { apiRequest: apiRequest2 } = await import("./api-
|
|
700
|
+
const { apiRequest: apiRequest2 } = await import("./api-5EKGGFQ6.js");
|
|
647
701
|
const metadata = await apiRequest2(`/v1/skills/${slug}/bundle/metadata`);
|
|
648
702
|
const reqs = metadata.connectionRequirements ?? [];
|
|
649
703
|
if (reqs.length > 0) {
|
|
@@ -747,7 +801,7 @@ function registerEmitCommand(program2) {
|
|
|
747
801
|
}
|
|
748
802
|
|
|
749
803
|
// src/commands/prime.ts
|
|
750
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
804
|
+
import { existsSync as existsSync2, readdirSync, readFileSync } from "fs";
|
|
751
805
|
import "commander";
|
|
752
806
|
function registerPrimeCommand(program2) {
|
|
753
807
|
program2.command("prime").description("Output Headways workflow context for AI coding assistants").action(() => {
|
|
@@ -823,7 +877,7 @@ function registerPrimeCommand(program2) {
|
|
|
823
877
|
});
|
|
824
878
|
}
|
|
825
879
|
function getInstalledSkills() {
|
|
826
|
-
if (!
|
|
880
|
+
if (!existsSync2(INSTALLED_DIR)) return [];
|
|
827
881
|
try {
|
|
828
882
|
return readdirSync(INSTALLED_DIR).filter((f) => f.endsWith(".json")).map((f) => {
|
|
829
883
|
const slug = f.replace(/\.json$/, "");
|
|
@@ -846,7 +900,7 @@ function getInstalledSkills() {
|
|
|
846
900
|
}
|
|
847
901
|
|
|
848
902
|
// src/index.ts
|
|
849
|
-
program.name("headways").description("Headways CLI \u2014 skill authoring, sync, and runtime SDK").version(
|
|
903
|
+
program.name("headways").description("Headways CLI \u2014 skill authoring, sync, and runtime SDK").version(package_default.version);
|
|
850
904
|
registerAuthCommands(program);
|
|
851
905
|
registerSkillsCommands(program);
|
|
852
906
|
registerConnectionsCommands(program);
|