syntaur 0.1.0 → 0.1.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/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # Syntaur
2
+
3
+ Syntaur is a local mission and assignment workflow for coding agents. It ships a CLI, a dashboard, a Claude Code plugin, and a Codex plugin.
4
+
5
+ ## Install and Run
6
+
7
+ Requirements:
8
+
9
+ - Node.js 20+
10
+ - `npx` from npm
11
+
12
+ Run Syntaur directly with `npx`:
13
+
14
+ ```bash
15
+ npx syntaur@latest
16
+ ```
17
+
18
+ This downloads the published `syntaur` package into npm's cache and runs the CLI. It does not do a global install unless you choose to install it globally yourself.
19
+
20
+ On first run, Syntaur will:
21
+
22
+ 1. Initialize `~/.syntaur/`
23
+ 2. Offer to install the Claude Code plugin
24
+ 3. Offer to install the Codex plugin
25
+ 4. Ask where those plugins should be installed, with recommended defaults based on your current machine
26
+ 5. Offer to launch the dashboard
27
+
28
+ You can also run setup explicitly:
29
+
30
+ ```bash
31
+ npx syntaur@latest setup
32
+ ```
33
+
34
+ Non-interactive setup:
35
+
36
+ ```bash
37
+ npx syntaur@latest setup --yes
38
+ npx syntaur@latest setup --yes --claude
39
+ npx syntaur@latest setup --yes --codex
40
+ npx syntaur@latest setup --yes --dashboard
41
+ ```
42
+
43
+ ## Plugin Install Paths
44
+
45
+ Syntaur remembers the plugin install locations you choose in `~/.syntaur/config.md`.
46
+
47
+ Interactive commands will prompt for install locations:
48
+
49
+ ```bash
50
+ npx syntaur@latest install-plugin
51
+ npx syntaur@latest install-codex-plugin
52
+ ```
53
+
54
+ You can also set paths explicitly:
55
+
56
+ ```bash
57
+ npx syntaur@latest install-plugin --target-dir ~/.claude/plugins/syntaur
58
+ npx syntaur@latest install-codex-plugin \
59
+ --target-dir ~/plugins/syntaur \
60
+ --marketplace-path ~/.agents/plugins/marketplace.json
61
+ ```
62
+
63
+ Setup supports the same path overrides:
64
+
65
+ ```bash
66
+ npx syntaur@latest setup \
67
+ --claude \
68
+ --claude-dir ~/.claude/plugins/syntaur \
69
+ --codex \
70
+ --codex-dir ~/plugins/syntaur \
71
+ --codex-marketplace-path ~/.agents/plugins/marketplace.json
72
+ ```
73
+
74
+ ## Common Commands
75
+
76
+ ```bash
77
+ npx syntaur@latest dashboard
78
+ npx syntaur@latest create-mission "My First Mission"
79
+ npx syntaur@latest create-assignment "Implement feature" --mission my-first-mission
80
+ npx syntaur@latest uninstall
81
+ npx syntaur@latest uninstall --all
82
+ ```
83
+
84
+ ## Uninstall
85
+
86
+ Remove Syntaur-managed Claude and Codex integrations:
87
+
88
+ ```bash
89
+ npx syntaur@latest uninstall
90
+ ```
91
+
92
+ Remove plugins and `~/.syntaur` data:
93
+
94
+ ```bash
95
+ npx syntaur@latest uninstall --all
96
+ ```
97
+
98
+ If your config points missions somewhere outside `~/.syntaur`, Syntaur will warn and leave that external directory alone.
99
+
100
+ ## Development
101
+
102
+ ```bash
103
+ npm install
104
+ npm run typecheck
105
+ npm test
106
+ npx vitest run src/__tests__/adapter-templates.test.ts
107
+ ```
108
+
109
+ Repo-local plugin linking for development:
110
+
111
+ ```bash
112
+ npx syntaur@latest install-plugin --link
113
+ npx syntaur@latest install-codex-plugin --link
114
+ ```
@@ -381,6 +381,13 @@ var init_paths = __esm({
381
381
  }
382
382
  });
383
383
 
384
+ // src/templates/config.ts
385
+ var init_config = __esm({
386
+ "src/templates/config.ts"() {
387
+ "use strict";
388
+ }
389
+ });
390
+
384
391
  // src/utils/config.ts
385
392
  import { readFile as readFile2 } from "fs/promises";
386
393
  import { resolve as resolve3, isAbsolute } from "path";
@@ -528,6 +535,42 @@ function serializeStatusConfig(statuses) {
528
535
  }
529
536
  return lines.join("\n");
530
537
  }
538
+ function stripTopLevelBlock(fmBlock, key) {
539
+ const blockStart = fmBlock.match(new RegExp(`^${key}:\\s*$`, "m"));
540
+ if (!blockStart) {
541
+ return fmBlock.replace(/\n+$/, "");
542
+ }
543
+ const startIdx = fmBlock.indexOf(blockStart[0]);
544
+ const before = fmBlock.slice(0, startIdx);
545
+ const after = fmBlock.slice(startIdx + blockStart[0].length);
546
+ const remaining = after.split("\n");
547
+ let endIdx = 0;
548
+ for (let i = 0; i < remaining.length; i++) {
549
+ const line = remaining[i];
550
+ if (line.trim() === "") {
551
+ endIdx = i + 1;
552
+ continue;
553
+ }
554
+ if (line.length > 0 && line[0] !== " ") {
555
+ break;
556
+ }
557
+ endIdx = i + 1;
558
+ }
559
+ return (before + remaining.slice(endIdx).join("\n")).replace(/\n+$/, "");
560
+ }
561
+ function parseOptionalAbsolutePath(value, fieldName) {
562
+ if (!value) {
563
+ return null;
564
+ }
565
+ const expanded = expandHome(String(value));
566
+ if (!isAbsolute(expanded)) {
567
+ console.warn(
568
+ `Warning: config.md ${fieldName} is not an absolute path ("${value}"), ignoring it`
569
+ );
570
+ return null;
571
+ }
572
+ return resolve3(expanded);
573
+ }
531
574
  async function writeStatusConfig(statuses) {
532
575
  const configPath = resolve3(syntaurRoot(), "config.md");
533
576
  const statusBlock = serializeStatusConfig(statuses);
@@ -590,23 +633,7 @@ async function deleteStatusConfig() {
590
633
  if (!fmMatch) return;
591
634
  const fmBlock = fmMatch[2];
592
635
  const afterFrontmatter = existing.slice(fmMatch[0].length);
593
- const statusesStart = fmBlock.match(/^statuses:\s*$/m);
594
- if (!statusesStart) return;
595
- const startIdx = fmBlock.indexOf(statusesStart[0]);
596
- const before = fmBlock.slice(0, startIdx);
597
- const after = fmBlock.slice(startIdx + statusesStart[0].length);
598
- const remaining = after.split("\n");
599
- let endIdx = 0;
600
- for (let i = 0; i < remaining.length; i++) {
601
- const line = remaining[i];
602
- if (line.trim() === "") {
603
- endIdx = i + 1;
604
- continue;
605
- }
606
- if (line.length > 0 && line[0] !== " ") break;
607
- endIdx = i + 1;
608
- }
609
- const cleanedFm = (before + remaining.slice(endIdx).join("\n")).replace(/\n+$/, "");
636
+ const cleanedFm = stripTopLevelBlock(fmBlock, "statuses");
610
637
  const newContent = `---
611
638
  ${cleanedFm}
612
639
  ---${afterFrontmatter}`;
@@ -637,15 +664,30 @@ async function readConfig() {
637
664
  trustLevel: fm["agentDefaults.trustLevel"] || DEFAULT_CONFIG.agentDefaults.trustLevel,
638
665
  autoApprove: fm["agentDefaults.autoApprove"] === "true" || DEFAULT_CONFIG.agentDefaults.autoApprove
639
666
  },
667
+ integrations: {
668
+ claudePluginDir: parseOptionalAbsolutePath(
669
+ fm["integrations.claudePluginDir"],
670
+ "integrations.claudePluginDir"
671
+ ),
672
+ codexPluginDir: parseOptionalAbsolutePath(
673
+ fm["integrations.codexPluginDir"],
674
+ "integrations.codexPluginDir"
675
+ ),
676
+ codexMarketplacePath: parseOptionalAbsolutePath(
677
+ fm["integrations.codexMarketplacePath"],
678
+ "integrations.codexMarketplacePath"
679
+ )
680
+ },
640
681
  statuses: parseStatusConfig(content)
641
682
  };
642
683
  }
643
684
  var DEFAULT_CONFIG;
644
- var init_config = __esm({
685
+ var init_config2 = __esm({
645
686
  "src/utils/config.ts"() {
646
687
  "use strict";
647
688
  init_paths();
648
689
  init_fs();
690
+ init_config();
649
691
  DEFAULT_CONFIG = {
650
692
  version: "1.0",
651
693
  defaultMissionDir: defaultMissionDir(),
@@ -653,6 +695,11 @@ var init_config = __esm({
653
695
  trustLevel: "medium",
654
696
  autoApprove: false
655
697
  },
698
+ integrations: {
699
+ claudePluginDir: null,
700
+ codexPluginDir: null,
701
+ codexMarketplacePath: null
702
+ },
656
703
  statuses: null
657
704
  };
658
705
  }
@@ -1198,13 +1245,13 @@ var init_help = __esm({
1198
1245
  // --- Plugin & adapter setup (indices 13-16) ---
1199
1246
  {
1200
1247
  command: "syntaur install-plugin",
1201
- description: "Install the Syntaur Claude Code plugin into your home plugin directory.",
1202
- example: "syntaur install-plugin"
1248
+ description: "Install the Syntaur Claude Code plugin, prompting for the target directory when interactive.",
1249
+ example: "syntaur install-plugin --target-dir ~/.claude/plugins/syntaur"
1203
1250
  },
1204
1251
  {
1205
1252
  command: "syntaur install-codex-plugin",
1206
- description: "Install the Syntaur Codex plugin and register its local marketplace entry.",
1207
- example: "syntaur install-codex-plugin"
1253
+ description: "Install the Syntaur Codex plugin and register its marketplace entry, prompting for both paths when interactive.",
1254
+ example: "syntaur install-codex-plugin --target-dir ~/plugins/syntaur --marketplace-path ~/.agents/plugins/marketplace.json"
1208
1255
  },
1209
1256
  {
1210
1257
  command: "syntaur uninstall",
@@ -2660,7 +2707,7 @@ var init_api = __esm({
2660
2707
  "use strict";
2661
2708
  init_lifecycle();
2662
2709
  init_fs();
2663
- init_config();
2710
+ init_config2();
2664
2711
  init_parser();
2665
2712
  init_help();
2666
2713
  STALE_ASSIGNMENT_MS = 7 * 24 * 60 * 60 * 1e3;
@@ -3157,7 +3204,7 @@ function createWatcher(options) {
3157
3204
 
3158
3205
  // src/dashboard/server.ts
3159
3206
  init_fs();
3160
- init_config();
3207
+ init_config2();
3161
3208
 
3162
3209
  // src/dashboard/api-write.ts
3163
3210
  init_lifecycle();
@@ -3229,6 +3276,9 @@ function toggleAcceptanceCriterion(content, index, checked) {
3229
3276
  // src/dashboard/api-write.ts
3230
3277
  init_api();
3231
3278
 
3279
+ // src/templates/index.ts
3280
+ init_config();
3281
+
3232
3282
  // src/templates/manifest.ts
3233
3283
  function renderManifest(params) {
3234
3284
  return `---