syntaur 0.1.0 → 0.1.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/README.md +116 -0
- package/dist/dashboard/server.js +74 -24
- package/dist/dashboard/server.js.map +1 -1
- package/dist/index.js +858 -160
- package/dist/index.js.map +1 -1
- package/package.json +18 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/agents/syntaur-expert.md +2 -2
- package/plugins/syntaur/.codex-plugin/plugin.json +1 -1
- package/plugins/syntaur/agents/syntaur-operator.md +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
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
|
+
For Claude Code, Syntaur will detect the machine's local plugin marketplace when one exists and recommend installing into that marketplace's `plugins/` directory.
|
|
48
|
+
|
|
49
|
+
Interactive commands will prompt for install locations:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx syntaur@latest install-plugin
|
|
53
|
+
npx syntaur@latest install-codex-plugin
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
You can also set paths explicitly:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx syntaur@latest install-plugin --target-dir ~/.claude/plugins/marketplaces/user-plugins/plugins/syntaur
|
|
60
|
+
npx syntaur@latest install-codex-plugin \
|
|
61
|
+
--target-dir ~/plugins/syntaur \
|
|
62
|
+
--marketplace-path ~/.agents/plugins/marketplace.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Setup supports the same path overrides:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx syntaur@latest setup \
|
|
69
|
+
--claude \
|
|
70
|
+
--claude-dir ~/.claude/plugins/marketplaces/user-plugins/plugins/syntaur \
|
|
71
|
+
--codex \
|
|
72
|
+
--codex-dir ~/plugins/syntaur \
|
|
73
|
+
--codex-marketplace-path ~/.agents/plugins/marketplace.json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Common Commands
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx syntaur@latest dashboard
|
|
80
|
+
npx syntaur@latest create-mission "My First Mission"
|
|
81
|
+
npx syntaur@latest create-assignment "Implement feature" --mission my-first-mission
|
|
82
|
+
npx syntaur@latest uninstall
|
|
83
|
+
npx syntaur@latest uninstall --all
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Uninstall
|
|
87
|
+
|
|
88
|
+
Remove Syntaur-managed Claude and Codex integrations:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npx syntaur@latest uninstall
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Remove plugins and `~/.syntaur` data:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx syntaur@latest uninstall --all
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If your config points missions somewhere outside `~/.syntaur`, Syntaur will warn and leave that external directory alone.
|
|
101
|
+
|
|
102
|
+
## Development
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm install
|
|
106
|
+
npm run typecheck
|
|
107
|
+
npm test
|
|
108
|
+
npx vitest run src/__tests__/adapter-templates.test.ts
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Repo-local plugin linking for development:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
npx syntaur@latest install-plugin --link
|
|
115
|
+
npx syntaur@latest install-codex-plugin --link
|
|
116
|
+
```
|
package/dist/dashboard/server.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
1202
|
-
example: "syntaur install-plugin"
|
|
1248
|
+
description: "Install the Syntaur Claude Code plugin, detecting the local Claude marketplace when available and prompting for the target directory when interactive.",
|
|
1249
|
+
example: "syntaur install-plugin --target-dir ~/.claude/plugins/marketplaces/user-plugins/plugins/syntaur"
|
|
1203
1250
|
},
|
|
1204
1251
|
{
|
|
1205
1252
|
command: "syntaur install-codex-plugin",
|
|
1206
|
-
description: "Install the Syntaur Codex plugin and register its
|
|
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
|
-
|
|
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
|
-
|
|
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 `---
|