@headways/cli 0.4.0 → 0.4.1
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 +43 -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,23 +2,25 @@
|
|
|
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";
|
|
23
|
+
import { createRequire } from "module";
|
|
22
24
|
import { program } from "commander";
|
|
23
25
|
|
|
24
26
|
// src/commands/auth.ts
|
|
@@ -382,34 +384,35 @@ function registerImportCommand(program2) {
|
|
|
382
384
|
import "commander";
|
|
383
385
|
import * as fs3 from "fs/promises";
|
|
384
386
|
import * as path3 from "path";
|
|
385
|
-
import { watch } from "fs";
|
|
387
|
+
import { watch, existsSync } from "fs";
|
|
388
|
+
var catchMissing = (e) => {
|
|
389
|
+
if (e.code === "ENOENT") return null;
|
|
390
|
+
throw e;
|
|
391
|
+
};
|
|
386
392
|
async function readSkillDir(dir) {
|
|
387
393
|
const skillMdPath = path3.join(dir, "SKILL.md");
|
|
388
|
-
|
|
389
|
-
let headline;
|
|
390
|
-
const headwaysYamlPath = path3.join(dir, "headways.yaml");
|
|
394
|
+
let body;
|
|
391
395
|
try {
|
|
392
|
-
|
|
393
|
-
const match = yaml.match(/headline:\s*['"]?(.+?)['"]?\s*$/m);
|
|
394
|
-
if (match) headline = match[1] ?? void 0;
|
|
396
|
+
body = await fs3.readFile(skillMdPath, "utf-8");
|
|
395
397
|
} catch {
|
|
398
|
+
throw new Error(`SKILL.md not found in ${dir}`);
|
|
396
399
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
400
|
+
const [headwaysYaml, capabilitiesYaml, connectionsYaml] = await Promise.all([
|
|
401
|
+
fs3.readFile(path3.join(dir, "headways.yaml"), "utf-8").catch(catchMissing),
|
|
402
|
+
fs3.readFile(path3.join(dir, "capabilities.yaml"), "utf-8").catch(catchMissing),
|
|
403
|
+
fs3.readFile(path3.join(dir, "connections.yaml"), "utf-8").catch(catchMissing)
|
|
404
|
+
]);
|
|
405
|
+
let headline;
|
|
406
|
+
if (headwaysYaml) {
|
|
407
|
+
const match = headwaysYaml.match(/headline:\s*['"]?(.+?)['"]?\s*$/m);
|
|
408
|
+
if (match) headline = match[1] ?? void 0;
|
|
403
409
|
}
|
|
404
410
|
let connections;
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const connYaml = await fs3.readFile(connYamlPath, "utf-8");
|
|
408
|
-
const items = parseConnectionsYaml(connYaml);
|
|
411
|
+
if (connectionsYaml) {
|
|
412
|
+
const items = parseConnectionsYaml(connectionsYaml);
|
|
409
413
|
if (items.length > 0) connections = items;
|
|
410
|
-
} catch {
|
|
411
414
|
}
|
|
412
|
-
return { body, headline, capabilities, connections };
|
|
415
|
+
return { body, headline, capabilities: capabilitiesYaml ?? void 0, connections };
|
|
413
416
|
}
|
|
414
417
|
function parseConnectionsYaml(yaml) {
|
|
415
418
|
const items = [];
|
|
@@ -446,11 +449,17 @@ async function pushSkill(slug, dir) {
|
|
|
446
449
|
});
|
|
447
450
|
console.log(`Pushed '${slug}' draft`);
|
|
448
451
|
}
|
|
452
|
+
function resolveSkillDir(slug) {
|
|
453
|
+
if (!slug) return process.cwd();
|
|
454
|
+
const installedPath = path3.join(CLAUDE_SKILLS_DIR, slug);
|
|
455
|
+
if (existsSync(installedPath)) return installedPath;
|
|
456
|
+
return path3.join(process.cwd(), slug);
|
|
457
|
+
}
|
|
449
458
|
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>
|
|
459
|
+
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
460
|
requireAuth();
|
|
452
461
|
const resolvedSlug = slug ?? path3.basename(process.cwd());
|
|
453
|
-
const dir = opts.dir ?? (slug
|
|
462
|
+
const dir = opts.dir ?? resolveSkillDir(slug);
|
|
454
463
|
await pushSkill(resolvedSlug, dir);
|
|
455
464
|
if (opts.watch) {
|
|
456
465
|
console.log(`Watching ${dir} for changes...`);
|
|
@@ -552,7 +561,7 @@ Declare every MCP connector the skill depends on. Users see this list on \`headw
|
|
|
552
561
|
and the Headways app gates installation on the connectors being configured.
|
|
553
562
|
|
|
554
563
|
\`\`\`yaml
|
|
555
|
-
- connector: slack # connector identifier (e.g. slack, github,
|
|
564
|
+
- connector: slack # connector identifier (e.g. slack, github, atlassian, linear, notion, google-drive, stripe, asana, hubspot, datadog)
|
|
556
565
|
purpose: Read channel messages and threads via Slack MCP tools
|
|
557
566
|
- connector: github
|
|
558
567
|
purpose: Read pull requests and issues
|
|
@@ -627,8 +636,8 @@ function registerSkillsCommands(program2) {
|
|
|
627
636
|
console.log(SKILLS_GUIDE);
|
|
628
637
|
});
|
|
629
638
|
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-
|
|
639
|
+
const { requireAuth: requireAuth2 } = await import("./config-XQHAXREA.js");
|
|
640
|
+
const { apiRequest: apiRequest2 } = await import("./api-5EKGGFQ6.js");
|
|
632
641
|
requireAuth2();
|
|
633
642
|
const result = await apiRequest2("/v1/skills");
|
|
634
643
|
if (result.data.length === 0) {
|
|
@@ -640,10 +649,10 @@ function registerSkillsCommands(program2) {
|
|
|
640
649
|
}
|
|
641
650
|
});
|
|
642
651
|
skills.command("accept <slug>").description("Accept a pending skill update and install it locally").action(async (slug) => {
|
|
643
|
-
const { acceptSkill } = await import("./sync-
|
|
652
|
+
const { acceptSkill } = await import("./sync-Q3OQUWOD.js");
|
|
644
653
|
await acceptSkill(slug);
|
|
645
654
|
try {
|
|
646
|
-
const { apiRequest: apiRequest2 } = await import("./api-
|
|
655
|
+
const { apiRequest: apiRequest2 } = await import("./api-5EKGGFQ6.js");
|
|
647
656
|
const metadata = await apiRequest2(`/v1/skills/${slug}/bundle/metadata`);
|
|
648
657
|
const reqs = metadata.connectionRequirements ?? [];
|
|
649
658
|
if (reqs.length > 0) {
|
|
@@ -747,7 +756,7 @@ function registerEmitCommand(program2) {
|
|
|
747
756
|
}
|
|
748
757
|
|
|
749
758
|
// src/commands/prime.ts
|
|
750
|
-
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
759
|
+
import { existsSync as existsSync2, readdirSync, readFileSync } from "fs";
|
|
751
760
|
import "commander";
|
|
752
761
|
function registerPrimeCommand(program2) {
|
|
753
762
|
program2.command("prime").description("Output Headways workflow context for AI coding assistants").action(() => {
|
|
@@ -823,7 +832,7 @@ function registerPrimeCommand(program2) {
|
|
|
823
832
|
});
|
|
824
833
|
}
|
|
825
834
|
function getInstalledSkills() {
|
|
826
|
-
if (!
|
|
835
|
+
if (!existsSync2(INSTALLED_DIR)) return [];
|
|
827
836
|
try {
|
|
828
837
|
return readdirSync(INSTALLED_DIR).filter((f) => f.endsWith(".json")).map((f) => {
|
|
829
838
|
const slug = f.replace(/\.json$/, "");
|
|
@@ -846,7 +855,9 @@ function getInstalledSkills() {
|
|
|
846
855
|
}
|
|
847
856
|
|
|
848
857
|
// src/index.ts
|
|
849
|
-
|
|
858
|
+
var require2 = createRequire(import.meta.url);
|
|
859
|
+
var { version } = require2("../package.json");
|
|
860
|
+
program.name("headways").description("Headways CLI \u2014 skill authoring, sync, and runtime SDK").version(version);
|
|
850
861
|
registerAuthCommands(program);
|
|
851
862
|
registerSkillsCommands(program);
|
|
852
863
|
registerConnectionsCommands(program);
|