@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.
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  apiRequest,
4
4
  rawRequest
5
- } from "./chunk-HYEL7L5Z.js";
6
- import "./chunk-T2H7EXOV.js";
5
+ } from "./chunk-2INXZHRG.js";
6
+ import "./chunk-UUFIIGTZ.js";
7
7
  export {
8
8
  apiRequest,
9
9
  rawRequest
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getApiUrl,
4
4
  requireAuth
5
- } from "./chunk-T2H7EXOV.js";
5
+ } from "./chunk-UUFIIGTZ.js";
6
6
 
7
7
  // src/lib/api.ts
8
8
  async function rawRequest(path, token, options = {}, apiUrl) {
@@ -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-T2H7EXOV.js";
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
- const skillsDir = join(homedir(), ".claude", "skills");
57
- if (existsSync(skillsDir)) {
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 skillsDir = join2(homedir2(), ".claude", "skills");
236
- const dest = join2(skillsDir, slug);
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-T2H7EXOV.js";
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-HYEL7L5Z.js";
5
+ } from "./chunk-2INXZHRG.js";
6
6
  import {
7
7
  registerSetupCommand,
8
8
  registerSyncCommands,
9
9
  registerUninstallCommand
10
- } from "./chunk-OZULVVQC.js";
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-T2H7EXOV.js";
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
- const body = await fs3.readFile(skillMdPath, "utf-8").catch(() => "");
389
- let headline;
390
- const headwaysYamlPath = path3.join(dir, "headways.yaml");
394
+ let body;
391
395
  try {
392
- const yaml = await fs3.readFile(headwaysYamlPath, "utf-8");
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
- let capabilities;
398
- const capYamlPath = path3.join(dir, "capabilities.yaml");
399
- try {
400
- const capYaml = await fs3.readFile(capYamlPath, "utf-8");
401
- capabilities = { raw: capYaml };
402
- } catch {
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
- const connYamlPath = path3.join(dir, "connections.yaml");
406
- try {
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> or cwd)").action(async (slug, opts) => {
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 ? path3.join(process.cwd(), slug) : process.cwd());
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, jira, linear, notion, google-drive)
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-SHMIVRAP.js");
631
- const { apiRequest: apiRequest2 } = await import("./api-2BK6MGZB.js");
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-6PKI35ZY.js");
652
+ const { acceptSkill } = await import("./sync-Q3OQUWOD.js");
644
653
  await acceptSkill(slug);
645
654
  try {
646
- const { apiRequest: apiRequest2 } = await import("./api-2BK6MGZB.js");
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 (!existsSync(INSTALLED_DIR)) return [];
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
- program.name("headways").description("Headways CLI \u2014 skill authoring, sync, and runtime SDK").version("0.2.1");
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);
@@ -5,8 +5,8 @@ import {
5
5
  registerDevice,
6
6
  registerSyncCommands,
7
7
  writeSyncState
8
- } from "./chunk-OZULVVQC.js";
9
- import "./chunk-T2H7EXOV.js";
8
+ } from "./chunk-XTEQBKIN.js";
9
+ import "./chunk-UUFIIGTZ.js";
10
10
  export {
11
11
  acceptSkill,
12
12
  readSyncState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@headways/cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Headways CLI — authoring, sync, and runtime SDK",
6
6
  "license": "MIT",