agentboot 0.1.0

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.
Files changed (78) hide show
  1. package/.github/ISSUE_TEMPLATE/persona-request.md +62 -0
  2. package/.github/ISSUE_TEMPLATE/quality-feedback.md +67 -0
  3. package/.github/workflows/cla.yml +25 -0
  4. package/.github/workflows/validate.yml +49 -0
  5. package/.idea/agentboot.iml +9 -0
  6. package/.idea/misc.xml +6 -0
  7. package/.idea/modules.xml +8 -0
  8. package/.idea/vcs.xml +6 -0
  9. package/CLA.md +98 -0
  10. package/CLAUDE.md +230 -0
  11. package/CONTRIBUTING.md +168 -0
  12. package/LICENSE +191 -0
  13. package/NOTICE +4 -0
  14. package/PERSONAS.md +156 -0
  15. package/README.md +172 -0
  16. package/agentboot.config.json +207 -0
  17. package/bin/agentboot.js +17 -0
  18. package/core/gotchas/README.md +35 -0
  19. package/core/instructions/baseline.instructions.md +133 -0
  20. package/core/instructions/security.instructions.md +186 -0
  21. package/core/personas/code-reviewer/SKILL.md +175 -0
  22. package/core/personas/code-reviewer/persona.config.json +11 -0
  23. package/core/personas/security-reviewer/SKILL.md +233 -0
  24. package/core/personas/security-reviewer/persona.config.json +11 -0
  25. package/core/personas/test-data-expert/SKILL.md +234 -0
  26. package/core/personas/test-data-expert/persona.config.json +10 -0
  27. package/core/personas/test-generator/SKILL.md +262 -0
  28. package/core/personas/test-generator/persona.config.json +10 -0
  29. package/core/traits/audit-trail.md +182 -0
  30. package/core/traits/confidence-signaling.md +172 -0
  31. package/core/traits/critical-thinking.md +129 -0
  32. package/core/traits/schema-awareness.md +132 -0
  33. package/core/traits/source-citation.md +174 -0
  34. package/core/traits/structured-output.md +199 -0
  35. package/docs/ci-cd-automation.md +548 -0
  36. package/docs/claude-code-reference/README.md +21 -0
  37. package/docs/claude-code-reference/agentboot-coverage.md +484 -0
  38. package/docs/claude-code-reference/feature-inventory.md +906 -0
  39. package/docs/cli-commands-audit.md +112 -0
  40. package/docs/cli-design.md +924 -0
  41. package/docs/concepts.md +1117 -0
  42. package/docs/config-schema-audit.md +121 -0
  43. package/docs/configuration.md +645 -0
  44. package/docs/delivery-methods.md +758 -0
  45. package/docs/developer-onboarding.md +342 -0
  46. package/docs/extending.md +448 -0
  47. package/docs/getting-started.md +298 -0
  48. package/docs/knowledge-layer.md +464 -0
  49. package/docs/marketplace.md +822 -0
  50. package/docs/org-connection.md +570 -0
  51. package/docs/plans/architecture.md +2429 -0
  52. package/docs/plans/design.md +2018 -0
  53. package/docs/plans/prd.md +1862 -0
  54. package/docs/plans/stack-rank.md +261 -0
  55. package/docs/plans/technical-spec.md +2755 -0
  56. package/docs/privacy-and-safety.md +807 -0
  57. package/docs/prompt-optimization.md +1071 -0
  58. package/docs/test-plan.md +972 -0
  59. package/docs/third-party-ecosystem.md +496 -0
  60. package/domains/compliance-template/README.md +173 -0
  61. package/domains/compliance-template/traits/compliance-aware.md +228 -0
  62. package/examples/enterprise/agentboot.config.json +184 -0
  63. package/examples/minimal/agentboot.config.json +46 -0
  64. package/package.json +63 -0
  65. package/repos.json +1 -0
  66. package/scripts/cli.ts +1069 -0
  67. package/scripts/compile.ts +1000 -0
  68. package/scripts/dev-sync.ts +149 -0
  69. package/scripts/lib/config.ts +137 -0
  70. package/scripts/lib/frontmatter.ts +61 -0
  71. package/scripts/sync.ts +687 -0
  72. package/scripts/validate.ts +421 -0
  73. package/tests/REGRESSION-PLAN.md +705 -0
  74. package/tests/TEST-PLAN.md +111 -0
  75. package/tests/cli.test.ts +705 -0
  76. package/tests/pipeline.test.ts +608 -0
  77. package/tests/validate.test.ts +278 -0
  78. package/tsconfig.json +62 -0
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Dev-only: syncs all platform distributions to their native locations
3
+ * in the current repo for local dogfooding. Gitignored output only.
4
+ *
5
+ * This is NOT the production sync script (sync.ts). This is a convenience
6
+ * for developing AgentBoot itself with its own personas loaded.
7
+ *
8
+ * Usage:
9
+ * npm run dev-sync (after npm run build)
10
+ * npm run full-build && npm run dev-sync
11
+ */
12
+
13
+ import fs from "node:fs";
14
+ import path from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+ import chalk from "chalk";
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+ const ROOT = path.resolve(__dirname, "..");
20
+ const DIST = path.join(ROOT, "dist");
21
+
22
+ function copyRecursive(src: string, dest: string): number {
23
+ let count = 0;
24
+ if (!fs.existsSync(src)) return count;
25
+
26
+ const entries = fs.readdirSync(src, { withFileTypes: true });
27
+ for (const entry of entries) {
28
+ const srcPath = path.join(src, entry.name);
29
+ const destPath = path.join(dest, entry.name);
30
+
31
+ if (entry.isDirectory()) {
32
+ count += copyRecursive(srcPath, destPath);
33
+ } else {
34
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
35
+ fs.copyFileSync(srcPath, destPath);
36
+ count++;
37
+ }
38
+ }
39
+ return count;
40
+ }
41
+
42
+ /**
43
+ * Remove only files that exist in the source tree from the destination.
44
+ * This avoids destroying manually-created files (e.g., .claude/rules/ or
45
+ * .claude/settings.json that are checked into the repo).
46
+ */
47
+ function cleanMatchingFiles(src: string, dest: string): void {
48
+ if (!fs.existsSync(src) || !fs.existsSync(dest)) return;
49
+
50
+ const entries = fs.readdirSync(src, { withFileTypes: true });
51
+ for (const entry of entries) {
52
+ const destPath = path.join(dest, entry.name);
53
+ if (!fs.existsSync(destPath)) continue;
54
+
55
+ if (entry.isDirectory()) {
56
+ cleanMatchingFiles(path.join(src, entry.name), destPath);
57
+ // Remove directory only if now empty
58
+ try {
59
+ const remaining = fs.readdirSync(destPath);
60
+ if (remaining.length === 0) fs.rmdirSync(destPath);
61
+ } catch { /* ignore */ }
62
+ } else {
63
+ fs.unlinkSync(destPath);
64
+ }
65
+ }
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Platform sync definitions
70
+ // ---------------------------------------------------------------------------
71
+
72
+ const platforms: Array<{
73
+ name: string;
74
+ distSubdir: string;
75
+ repoTarget: string;
76
+ available: boolean;
77
+ }> = [
78
+ {
79
+ name: "claude",
80
+ distSubdir: "claude/core",
81
+ repoTarget: ".claude",
82
+ available: false,
83
+ },
84
+ {
85
+ name: "copilot",
86
+ distSubdir: "copilot/core",
87
+ repoTarget: ".github/copilot",
88
+ available: false,
89
+ },
90
+ {
91
+ name: "cursor",
92
+ distSubdir: "cursor/core",
93
+ repoTarget: ".cursor/agentboot",
94
+ available: false,
95
+ },
96
+ {
97
+ name: "skill",
98
+ distSubdir: "skill/core",
99
+ repoTarget: ".agentboot/skill",
100
+ available: false,
101
+ },
102
+ {
103
+ name: "gemini",
104
+ distSubdir: "gemini/core",
105
+ repoTarget: ".gemini/agentboot",
106
+ available: false,
107
+ },
108
+ ];
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // Main
112
+ // ---------------------------------------------------------------------------
113
+
114
+ console.log(chalk.bold("\nAgentBoot — dev-sync"));
115
+
116
+ if (!fs.existsSync(DIST)) {
117
+ console.error(chalk.red("✗ dist/ not found. Run `npm run build` first."));
118
+ process.exit(1);
119
+ }
120
+
121
+ let totalFiles = 0;
122
+
123
+ for (const platform of platforms) {
124
+ const src = path.join(DIST, platform.distSubdir);
125
+ if (!fs.existsSync(src)) {
126
+ continue;
127
+ }
128
+
129
+ platform.available = true;
130
+ const dest = path.join(ROOT, platform.repoTarget);
131
+ cleanMatchingFiles(src, dest);
132
+ const count = copyRecursive(src, dest);
133
+ totalFiles += count;
134
+
135
+ console.log(` ${chalk.green("✓")} ${platform.name} → ${platform.repoTarget}/ (${count} files)`);
136
+ }
137
+
138
+ const skipped = platforms.filter((p) => !p.available);
139
+ if (skipped.length > 0) {
140
+ console.log(chalk.gray(` (not built: ${skipped.map((p) => p.name).join(", ")})`));
141
+ }
142
+
143
+ console.log(
144
+ chalk.bold(`\n${chalk.green("✓")} Dev-synced ${totalFiles} files across ${platforms.filter((p) => p.available).length} platforms (gitignored)`)
145
+ );
146
+
147
+ if (totalFiles > 0) {
148
+ console.log(chalk.yellow("\n ⚠ Restart Claude Code to pick up persona changes\n"));
149
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Shared configuration types and utilities used by validate, compile, and sync scripts.
3
+ */
4
+
5
+ import fs from "node:fs";
6
+ import path from "node:path";
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Types
10
+ // ---------------------------------------------------------------------------
11
+
12
+ export interface AgentBootConfig {
13
+ org: string;
14
+ orgDisplayName?: string;
15
+ groups?: Record<string, GroupConfig>;
16
+ personas?: {
17
+ enabled?: string[];
18
+ customDir?: string;
19
+ outputFormats?: string[];
20
+ };
21
+ traits?: {
22
+ enabled?: string[];
23
+ };
24
+ instructions?: {
25
+ enabled?: string[];
26
+ };
27
+ output?: {
28
+ distPath?: string;
29
+ provenanceHeaders?: boolean;
30
+ failOnDirtyDist?: boolean;
31
+ tokenBudget?: { warnAt?: number };
32
+ };
33
+ sync?: {
34
+ repos?: string;
35
+ targetDir?: string;
36
+ writePersonasIndex?: boolean;
37
+ dryRun?: boolean;
38
+ pr?: {
39
+ enabled?: boolean;
40
+ branchPrefix?: string;
41
+ titleTemplate?: string;
42
+ };
43
+ };
44
+ claude?: {
45
+ hooks?: Record<string, unknown>;
46
+ permissions?: { allow?: string[]; deny?: string[] };
47
+ mcpServers?: Record<string, unknown>;
48
+ };
49
+ validation?: {
50
+ secretPatterns?: string[];
51
+ strictMode?: boolean;
52
+ };
53
+ }
54
+
55
+ export interface GroupConfig {
56
+ teams?: string[];
57
+ }
58
+
59
+ export interface PersonaConfig {
60
+ name: string;
61
+ description: string;
62
+ invocation?: string;
63
+ model?: string;
64
+ permissionMode?: string;
65
+ traits?: string[];
66
+ groups?: Record<string, { traits?: string[] }>;
67
+ teams?: Record<string, { traits?: string[] }>;
68
+ }
69
+
70
+ // ---------------------------------------------------------------------------
71
+ // JSONC stripping
72
+ // ---------------------------------------------------------------------------
73
+
74
+ /**
75
+ * Strip single-line // comments from a JSONC string, respecting string literals.
76
+ * Tracks whether we are inside a quoted string (handling escaped quotes) before
77
+ * deciding to truncate a line at a // comment.
78
+ */
79
+ export function stripJsoncComments(raw: string): string {
80
+ const lines = raw.split("\n");
81
+ const result: string[] = [];
82
+
83
+ for (const line of lines) {
84
+ let inString = false;
85
+ let i = 0;
86
+ let out = "";
87
+
88
+ while (i < line.length) {
89
+ const ch = line[i]!;
90
+
91
+ if (inString) {
92
+ out += ch;
93
+ if (ch === "\\" && i + 1 < line.length) {
94
+ i++;
95
+ out += line[i]!;
96
+ } else if (ch === '"') {
97
+ inString = false;
98
+ }
99
+ } else {
100
+ if (ch === '"') {
101
+ inString = true;
102
+ out += ch;
103
+ } else if (ch === "/" && line[i + 1] === "/") {
104
+ break;
105
+ } else {
106
+ out += ch;
107
+ }
108
+ }
109
+ i++;
110
+ }
111
+
112
+ result.push(out.trimEnd());
113
+ }
114
+
115
+ return result.join("\n");
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Config loading
120
+ // ---------------------------------------------------------------------------
121
+
122
+ export function resolveConfigPath(argv: string[], root: string): string {
123
+ const idx = argv.indexOf("--config");
124
+ if (idx !== -1 && argv[idx + 1]) {
125
+ return path.resolve(argv[idx + 1]!);
126
+ }
127
+ return path.join(root, "agentboot.config.json");
128
+ }
129
+
130
+ export function loadConfig(configPath: string): AgentBootConfig {
131
+ if (!fs.existsSync(configPath)) {
132
+ throw new Error(`Config file not found: ${configPath}`);
133
+ }
134
+ const raw = fs.readFileSync(configPath, "utf-8");
135
+ const stripped = stripJsoncComments(raw);
136
+ return JSON.parse(stripped) as AgentBootConfig;
137
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Shared frontmatter and secret-scanning utilities.
3
+ *
4
+ * Used by both the validate script and the test suite.
5
+ */
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Frontmatter parsing
9
+ // ---------------------------------------------------------------------------
10
+
11
+ const FRONTMATTER_RE = /^---\n([\s\S]+?)\n---/;
12
+
13
+ export function parseFrontmatter(content: string): Map<string, string> | null {
14
+ const match = FRONTMATTER_RE.exec(content);
15
+ if (!match) return null;
16
+
17
+ const lines = (match[1] ?? "").split("\n");
18
+ const fields = new Map<string, string>();
19
+
20
+ for (const line of lines) {
21
+ const colonIdx = line.indexOf(":");
22
+ if (colonIdx === -1) continue;
23
+ const key = line.slice(0, colonIdx).trim();
24
+ const value = line.slice(colonIdx + 1).trim();
25
+ fields.set(key, value);
26
+ }
27
+
28
+ return fields;
29
+ }
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Secret scanning
33
+ // ---------------------------------------------------------------------------
34
+
35
+ export const DEFAULT_SECRET_PATTERNS: RegExp[] = [
36
+ /(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]+['"]/i,
37
+ /(?:api[_-]?key|apikey)\s*[:=]\s*['"][^'"]+['"]/i,
38
+ /(?:secret|token)\s*[:=]\s*['"][^'"]+['"]/i,
39
+ /aws[_-]?(?:access[_-]?key|secret[_-]?key)/i,
40
+ /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/,
41
+ /(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36}/, // GitHub tokens
42
+ /xox[baprs]-[0-9A-Za-z-]+/, // Slack tokens
43
+ ];
44
+
45
+ export function scanForSecrets(
46
+ content: string,
47
+ patterns: RegExp[] = DEFAULT_SECRET_PATTERNS
48
+ ): Array<{ line: number; pattern: string }> {
49
+ const hits: Array<{ line: number; pattern: string }> = [];
50
+ const lines = content.split("\n");
51
+
52
+ for (let i = 0; i < lines.length; i++) {
53
+ for (const pattern of patterns) {
54
+ if (pattern.test(lines[i]!)) {
55
+ hits.push({ line: i + 1, pattern: pattern.source });
56
+ }
57
+ }
58
+ }
59
+
60
+ return hits;
61
+ }