@ajvikram/relay 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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +538 -0
  3. package/dist/cli/commands/branch.d.ts +9 -0
  4. package/dist/cli/commands/branch.d.ts.map +1 -0
  5. package/dist/cli/commands/branch.js +69 -0
  6. package/dist/cli/commands/branch.js.map +1 -0
  7. package/dist/cli/commands/diff.d.ts +8 -0
  8. package/dist/cli/commands/diff.d.ts.map +1 -0
  9. package/dist/cli/commands/diff.js +61 -0
  10. package/dist/cli/commands/diff.js.map +1 -0
  11. package/dist/cli/commands/history.d.ts +8 -0
  12. package/dist/cli/commands/history.d.ts.map +1 -0
  13. package/dist/cli/commands/history.js +32 -0
  14. package/dist/cli/commands/history.js.map +1 -0
  15. package/dist/cli/commands/hook.d.ts +6 -0
  16. package/dist/cli/commands/hook.d.ts.map +1 -0
  17. package/dist/cli/commands/hook.js +118 -0
  18. package/dist/cli/commands/hook.js.map +1 -0
  19. package/dist/cli/commands/init.d.ts +4 -0
  20. package/dist/cli/commands/init.d.ts.map +1 -0
  21. package/dist/cli/commands/init.js +41 -0
  22. package/dist/cli/commands/init.js.map +1 -0
  23. package/dist/cli/commands/install.d.ts +18 -0
  24. package/dist/cli/commands/install.d.ts.map +1 -0
  25. package/dist/cli/commands/install.js +203 -0
  26. package/dist/cli/commands/install.js.map +1 -0
  27. package/dist/cli/commands/load.d.ts +9 -0
  28. package/dist/cli/commands/load.d.ts.map +1 -0
  29. package/dist/cli/commands/load.js +69 -0
  30. package/dist/cli/commands/load.js.map +1 -0
  31. package/dist/cli/commands/repos.d.ts +7 -0
  32. package/dist/cli/commands/repos.d.ts.map +1 -0
  33. package/dist/cli/commands/repos.js +53 -0
  34. package/dist/cli/commands/repos.js.map +1 -0
  35. package/dist/cli/commands/save.d.ts +9 -0
  36. package/dist/cli/commands/save.d.ts.map +1 -0
  37. package/dist/cli/commands/save.js +267 -0
  38. package/dist/cli/commands/save.js.map +1 -0
  39. package/dist/cli/commands/status.d.ts +23 -0
  40. package/dist/cli/commands/status.d.ts.map +1 -0
  41. package/dist/cli/commands/status.js +134 -0
  42. package/dist/cli/commands/status.js.map +1 -0
  43. package/dist/cli/commands/ui.d.ts +9 -0
  44. package/dist/cli/commands/ui.d.ts.map +1 -0
  45. package/dist/cli/commands/ui.js +54 -0
  46. package/dist/cli/commands/ui.js.map +1 -0
  47. package/dist/cli/commands/vscode.d.ts +6 -0
  48. package/dist/cli/commands/vscode.d.ts.map +1 -0
  49. package/dist/cli/commands/vscode.js +86 -0
  50. package/dist/cli/commands/vscode.js.map +1 -0
  51. package/dist/cli/index.d.ts +3 -0
  52. package/dist/cli/index.d.ts.map +1 -0
  53. package/dist/cli/index.js +143 -0
  54. package/dist/cli/index.js.map +1 -0
  55. package/dist/format/renderer.d.ts +5 -0
  56. package/dist/format/renderer.d.ts.map +1 -0
  57. package/dist/format/renderer.js +207 -0
  58. package/dist/format/renderer.js.map +1 -0
  59. package/dist/format/schema.d.ts +516 -0
  60. package/dist/format/schema.d.ts.map +1 -0
  61. package/dist/format/schema.js +90 -0
  62. package/dist/format/schema.js.map +1 -0
  63. package/dist/format/template.d.ts +44 -0
  64. package/dist/format/template.d.ts.map +1 -0
  65. package/dist/format/template.js +131 -0
  66. package/dist/format/template.js.map +1 -0
  67. package/dist/git/context.d.ts +23 -0
  68. package/dist/git/context.d.ts.map +1 -0
  69. package/dist/git/context.js +121 -0
  70. package/dist/git/context.js.map +1 -0
  71. package/dist/index.d.ts +8 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +8 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/mcp/server.d.ts +2 -0
  76. package/dist/mcp/server.d.ts.map +1 -0
  77. package/dist/mcp/server.js +164 -0
  78. package/dist/mcp/server.js.map +1 -0
  79. package/dist/server/index.d.ts +12 -0
  80. package/dist/server/index.d.ts.map +1 -0
  81. package/dist/server/index.js +143 -0
  82. package/dist/server/index.js.map +1 -0
  83. package/dist/server/ui.d.ts +2 -0
  84. package/dist/server/ui.d.ts.map +1 -0
  85. package/dist/server/ui.js +797 -0
  86. package/dist/server/ui.js.map +1 -0
  87. package/dist/storage/global.d.ts +40 -0
  88. package/dist/storage/global.d.ts.map +1 -0
  89. package/dist/storage/global.js +126 -0
  90. package/dist/storage/global.js.map +1 -0
  91. package/dist/storage/index.d.ts +59 -0
  92. package/dist/storage/index.d.ts.map +1 -0
  93. package/dist/storage/index.js +253 -0
  94. package/dist/storage/index.js.map +1 -0
  95. package/package.json +54 -0
@@ -0,0 +1,61 @@
1
+ import chalk from 'chalk';
2
+ import { getRepoRoot } from '../../git/context.js';
3
+ import { readHandoff, readHistory, readHistoryEntry, resolveCwd } from '../../storage/index.js';
4
+ export async function diffCommand(options) {
5
+ const cwd = resolveCwd(options.dir);
6
+ const repoRoot = await getRepoRoot(cwd);
7
+ if (!repoRoot) {
8
+ console.error(chalk.red('✗ Not a git repository.'));
9
+ process.exit(1);
10
+ }
11
+ const currentHandoff = readHandoff(repoRoot);
12
+ const history = readHistory(repoRoot);
13
+ if (!currentHandoff && history.length === 0) {
14
+ console.error(chalk.red('✗ No handoff records found to compare.'));
15
+ process.exit(1);
16
+ }
17
+ let fromContent = null;
18
+ let toContent = null;
19
+ let fromLabel = '';
20
+ let toLabel = '';
21
+ if (options.from && options.to) {
22
+ fromContent = readHistoryEntry(repoRoot, options.from);
23
+ toContent = readHistoryEntry(repoRoot, options.to);
24
+ fromLabel = `History #${options.from}`;
25
+ toLabel = `History #${options.to}`;
26
+ }
27
+ else if (options.from) {
28
+ fromContent = readHistoryEntry(repoRoot, options.from);
29
+ toContent = currentHandoff ? JSON.stringify(currentHandoff, null, 2) : null;
30
+ fromLabel = `History #${options.from}`;
31
+ toLabel = 'Current Handoff';
32
+ }
33
+ else {
34
+ // Compare current with the latest history archive
35
+ if (history.length > 0) {
36
+ fromContent = readHistoryEntry(repoRoot, history[0].id);
37
+ fromLabel = `Previous Handoff (${history[0].id})`;
38
+ }
39
+ toContent = currentHandoff ? JSON.stringify(currentHandoff, null, 2) : null;
40
+ toLabel = 'Current Active Handoff';
41
+ }
42
+ if (!fromContent && !toContent) {
43
+ console.error(chalk.red('✗ Insufficient handoff history to produce a diff.'));
44
+ process.exit(1);
45
+ }
46
+ console.log(chalk.bold('\n🔄 Relay Handoff Comparison'));
47
+ console.log(chalk.dim(`Comparing: ${fromLabel || 'Start'} ➔ ${toLabel}`));
48
+ console.log(chalk.dim('─'.repeat(60)));
49
+ if (currentHandoff) {
50
+ console.log(chalk.bold('Active Goal:'), currentHandoff.session.goal);
51
+ console.log(chalk.bold('Active Status:'), currentHandoff.session.status);
52
+ console.log(chalk.bold('Decisions count:'), currentHandoff.decisions.length);
53
+ console.log(chalk.bold('Constraints count:'), currentHandoff.constraints.length);
54
+ console.log(chalk.bold('Failed approaches recorded:'), currentHandoff.failed_approaches.length);
55
+ console.log(chalk.bold('Pending next steps:'), currentHandoff.next_steps.length);
56
+ }
57
+ console.log(chalk.dim('─'.repeat(60)));
58
+ console.log(chalk.dim(`Tip: Run ${chalk.cyan('relay history')} to list all available handoff IDs.`));
59
+ console.log('');
60
+ }
61
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/cli/commands/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface HistoryOptions {
2
+ dir?: string;
3
+ show?: string;
4
+ limit?: number;
5
+ }
6
+ export declare function historyCommand(options: HistoryOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/history.ts"],"names":[],"mappings":"AAKA,UAAU,cAAc;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA+B3E"}
@@ -0,0 +1,32 @@
1
+ import chalk from 'chalk';
2
+ import { getRepoRoot } from '../../git/context.js';
3
+ import { readHistory, readHistoryEntry, resolveCwd } from '../../storage/index.js';
4
+ import { renderHistoryList } from '../../format/renderer.js';
5
+ export async function historyCommand(options) {
6
+ const cwd = resolveCwd(options.dir);
7
+ const repoRoot = await getRepoRoot(cwd);
8
+ if (!repoRoot) {
9
+ console.error(chalk.red('✗ Not a git repository.'));
10
+ process.exit(1);
11
+ }
12
+ // ── Show a specific entry ──────────────────────────────────────────────────
13
+ if (options.show) {
14
+ const content = readHistoryEntry(repoRoot, options.show);
15
+ if (!content) {
16
+ console.error(chalk.red(`✗ No history entry found with ID: ${options.show}`));
17
+ console.error(chalk.dim(` Run ${chalk.white('relay history')} to see available IDs.`));
18
+ process.exit(1);
19
+ }
20
+ console.log(content);
21
+ return;
22
+ }
23
+ // ── List history ───────────────────────────────────────────────────────────
24
+ const entries = readHistory(repoRoot);
25
+ const limited = options.limit ? entries.slice(0, options.limit) : entries;
26
+ console.log('');
27
+ console.log(renderHistoryList(limited));
28
+ if (entries.length > 0) {
29
+ console.log(chalk.dim(`To view a specific handoff: relay history --show <id>`));
30
+ }
31
+ }
32
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../../src/cli/commands/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAQ7D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC1D,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;IAExC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,8EAA8E;IAC9E,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,qCAAqC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAC9E,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE1E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;IAExC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC,CAAC;IAClF,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ interface HookOptions {
2
+ dir?: string;
3
+ }
4
+ export declare function hookCommand(action: string, options: HookOptions): Promise<void>;
5
+ export {};
6
+ //# sourceMappingURL=hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/hook.ts"],"names":[],"mappings":"AAQA,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAYD,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8GrF"}
@@ -0,0 +1,118 @@
1
+ import chalk from 'chalk';
2
+ import { existsSync, readFileSync, writeFileSync, chmodSync, unlinkSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { getRepoRoot, captureGitContext } from '../../git/context.js';
5
+ import { resolveCwd, readHandoff, saveHandoff, initRelayDir, isRelayInitialized } from '../../storage/index.js';
6
+ import { HandoffSchema } from '../../format/schema.js';
7
+ import { randomUUID } from 'crypto';
8
+ const HOOK_MARKER = '# Relay Git Auto-Draft Hook';
9
+ const POST_COMMIT_SCRIPT = `#!/bin/sh
10
+ ${HOOK_MARKER}
11
+ if command -v relay >/dev/null 2>&1; then
12
+ relay hook run post-commit >/dev/null 2>&1 &
13
+ elif [ -f "./dist/cli/index.js" ]; then
14
+ node "./dist/cli/index.js" hook run post-commit >/dev/null 2>&1 &
15
+ fi
16
+ `;
17
+ export async function hookCommand(action, options) {
18
+ const cwd = resolveCwd(options.dir);
19
+ const repoRoot = await getRepoRoot(cwd);
20
+ if (!repoRoot) {
21
+ console.error(chalk.red('✗ Not a git repository.'));
22
+ process.exit(1);
23
+ }
24
+ const hooksDir = join(repoRoot, '.git', 'hooks');
25
+ const postCommitPath = join(hooksDir, 'post-commit');
26
+ if (action === 'install') {
27
+ if (!isRelayInitialized(repoRoot)) {
28
+ initRelayDir(repoRoot);
29
+ }
30
+ if (existsSync(postCommitPath)) {
31
+ const existing = readFileSync(postCommitPath, 'utf-8');
32
+ if (existing.includes(HOOK_MARKER)) {
33
+ console.log(chalk.yellow('⚠️ Relay post-commit hook is already installed.'));
34
+ return;
35
+ }
36
+ writeFileSync(postCommitPath, existing.trimEnd() + '\n\n' + POST_COMMIT_SCRIPT);
37
+ }
38
+ else {
39
+ writeFileSync(postCommitPath, POST_COMMIT_SCRIPT);
40
+ }
41
+ try {
42
+ chmodSync(postCommitPath, '755');
43
+ }
44
+ catch {
45
+ // Best effort on Unix
46
+ }
47
+ console.log(chalk.green('✓ Installed Relay post-commit auto-draft hook'));
48
+ console.log(chalk.dim(' New commits will now automatically stage context into .relay/handoff.md\n'));
49
+ return;
50
+ }
51
+ if (action === 'uninstall') {
52
+ if (existsSync(postCommitPath)) {
53
+ const content = readFileSync(postCommitPath, 'utf-8');
54
+ if (content.includes(HOOK_MARKER)) {
55
+ if (content.trim() === POST_COMMIT_SCRIPT.trim()) {
56
+ unlinkSync(postCommitPath);
57
+ }
58
+ else {
59
+ const cleaned = content.replace(new RegExp(`${HOOK_MARKER}[\\s\\S]*?&`, 'g'), '').trim();
60
+ writeFileSync(postCommitPath, cleaned ? cleaned + '\n' : '');
61
+ }
62
+ console.log(chalk.green('✓ Uninstalled Relay post-commit hook'));
63
+ return;
64
+ }
65
+ }
66
+ console.log(chalk.yellow('Relay hook was not installed.'));
67
+ return;
68
+ }
69
+ if (action === 'run') {
70
+ // Execute hook logic
71
+ const gitContext = await captureGitContext(repoRoot);
72
+ let handoff = readHandoff(repoRoot, gitContext.repository.branch);
73
+ if (handoff) {
74
+ // Enrich existing handoff with latest commit info
75
+ const headMsg = gitContext.repository.head_message;
76
+ const alreadyHasDecision = headMsg && handoff.decisions.some((d) => d.what.includes(headMsg));
77
+ if (headMsg && !alreadyHasDecision && headMsg !== 'initial commit') {
78
+ handoff.decisions.push({
79
+ what: `Commit: ${headMsg}`,
80
+ why: 'Auto-recorded from commit message',
81
+ evidence: gitContext.repository.head_commit,
82
+ });
83
+ }
84
+ handoff.repository = gitContext.repository;
85
+ handoff.raw_diff = gitContext.raw_diff || handoff.raw_diff;
86
+ handoff.files_modified = gitContext.files_modified.length > 0 ? gitContext.files_modified : handoff.files_modified;
87
+ saveHandoff(repoRoot, handoff);
88
+ }
89
+ else {
90
+ // Create initial draft
91
+ const newDraft = HandoffSchema.parse({
92
+ version: '1',
93
+ id: randomUUID().slice(0, 8),
94
+ timestamp: new Date().toISOString(),
95
+ source_platform: 'other',
96
+ repository: gitContext.repository,
97
+ raw_diff: gitContext.raw_diff || undefined,
98
+ files_modified: gitContext.files_modified,
99
+ session: {
100
+ goal: gitContext.repository.head_message || 'Work in progress',
101
+ status: 'in_progress',
102
+ token_exhausted: false,
103
+ },
104
+ decisions: gitContext.repository.head_message
105
+ ? [{ what: `Commit: ${gitContext.repository.head_message}`, why: 'Initial commit in session', evidence: gitContext.repository.head_commit }]
106
+ : [],
107
+ constraints: [],
108
+ failed_approaches: [],
109
+ next_steps: [],
110
+ });
111
+ saveHandoff(repoRoot, newDraft);
112
+ }
113
+ return;
114
+ }
115
+ console.log(chalk.yellow(`Unknown hook action: ${action}`));
116
+ console.log(chalk.dim('Available: relay hook install, relay hook uninstall'));
117
+ }
118
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook.js","sourceRoot":"","sources":["../../../src/cli/commands/hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function initCommand(options: {
2
+ dir?: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C1E"}
@@ -0,0 +1,41 @@
1
+ import chalk from 'chalk';
2
+ import { existsSync } from 'fs';
3
+ import { getRepoRoot } from '../../git/context.js';
4
+ import { initRelayDir, isRelayInitialized, resolveCwd, RELAY_DIR } from '../../storage/index.js';
5
+ export async function initCommand(options) {
6
+ const cwd = resolveCwd(options.dir);
7
+ const repoRoot = await getRepoRoot(cwd);
8
+ if (!repoRoot) {
9
+ console.error(chalk.red('✗ Not a git repository. Relay works best inside a git repo.'));
10
+ console.error(chalk.dim(' Run `git init` first, or navigate to a git repository.'));
11
+ process.exit(1);
12
+ }
13
+ if (isRelayInitialized(repoRoot)) {
14
+ console.log(chalk.yellow(`⚠ Relay is already initialized in this repository.`));
15
+ console.log(chalk.dim(` Directory: ${repoRoot}/${RELAY_DIR}/`));
16
+ console.log(``);
17
+ console.log(`Run ${chalk.cyan('relay save')} to create your first handoff.`);
18
+ return;
19
+ }
20
+ console.log(chalk.bold('Initializing Relay...'));
21
+ console.log(chalk.dim(`Repository: ${repoRoot}`));
22
+ console.log(``);
23
+ initRelayDir(repoRoot);
24
+ console.log(chalk.green('✓ Created .relay/ directory'));
25
+ console.log(chalk.green('✓ Created .relay/history/ directory'));
26
+ console.log(chalk.green('✓ Created .relay/config.yaml'));
27
+ const gitignorePath = `${repoRoot}/.gitignore`;
28
+ if (existsSync(gitignorePath)) {
29
+ console.log(chalk.green('✓ Updated .gitignore'));
30
+ }
31
+ console.log(``);
32
+ console.log(chalk.bold.green('✓ Relay initialized!'));
33
+ console.log(``);
34
+ console.log(`Next steps:`);
35
+ console.log(` ${chalk.cyan('relay save')} — save context when you hit a token limit`);
36
+ console.log(` ${chalk.cyan('relay load')} — load context when starting on a new platform`);
37
+ console.log(` ${chalk.cyan('relay install')} — add bootstrap rules to each AI platform`);
38
+ console.log(``);
39
+ console.log(chalk.dim(`Tip: Commit ${chalk.white('.relay/handoff.md')} so your team can also pick up context.`));
40
+ }
41
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export type SupportedPlatform = 'claude' | 'cursor' | 'antigravity' | 'copilot' | 'all';
2
+ export interface InstallOptions {
3
+ dir?: string;
4
+ dryRun?: boolean;
5
+ global?: boolean;
6
+ }
7
+ export interface InstallTarget {
8
+ name: string;
9
+ rule: string;
10
+ globalRule?: string;
11
+ getPath: (repoRoot: string) => string;
12
+ getGlobalPath?: () => string;
13
+ appendMode: 'append' | 'prepend' | 'create';
14
+ marker: string;
15
+ }
16
+ export declare const PLATFORMS: Record<Exclude<SupportedPlatform, 'all'>, InstallTarget>;
17
+ export declare function installCommand(platform: SupportedPlatform, options: InstallOptions): Promise<void>;
18
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,GAAG,SAAS,GAAG,KAAK,CAAC;AAExF,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA8FD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,UAAU,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,KAAK,CAAC,EAAE,aAAa,CAqC9E,CAAC;AAEF,wBAAsB,cAAc,CAClC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAuFf"}
@@ -0,0 +1,203 @@
1
+ import chalk from 'chalk';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ import { getRepoRoot } from '../../git/context.js';
6
+ import { resolveCwd } from '../../storage/index.js';
7
+ import { registerRepo } from '../../storage/global.js';
8
+ // ─── Bootstrap rules ──────────────────────────────────────────────────────────
9
+ // These are injected into platform-specific config files so agents
10
+ // automatically read the handoff on session start.
11
+ const RELAY_RULE_CLAUDE = `
12
+ ## Relay Context Handoff
13
+
14
+ Before starting ANY task in this repository, check if \`.relay/handoff.md\` exists.
15
+ If it does:
16
+ 1. Read it completely before doing anything else
17
+ 2. Acknowledge the handoff context: state the goal, current status, and what you will do first
18
+ 3. Respect all listed constraints — do not violate them without flagging it explicitly
19
+ 4. Do not repeat any of the listed failed approaches
20
+
21
+ If \`.relay/handoff.md\` does not exist, proceed normally.
22
+
23
+ When asked to "save a handoff" or "write a relay handoff", run: \`relay save\`
24
+ Or if the relay CLI is not available, write a structured summary to \`.relay/handoff.md\` following the format in that file.
25
+ `.trim();
26
+ const RELAY_RULE_CURSOR = `
27
+ # Relay Context Handoff
28
+
29
+ When starting work in this repository:
30
+ 1. Check if \`.relay/handoff.md\` exists
31
+ 2. If it exists, read it FIRST before taking any action
32
+ 3. Acknowledge the handoff: state the goal and your first action
33
+ 4. Respect all constraints listed — flag any violations explicitly
34
+ 5. Never repeat approaches marked as failed
35
+
36
+ To save context before switching platforms: run \`relay save\` in the terminal.
37
+ `.trim();
38
+ const RELAY_RULE_ANTIGRAVITY = `
39
+ ## Relay Context Handoff
40
+
41
+ When working in this repository, always check for \`.relay/handoff.md\` before starting.
42
+ If it exists, read it and orient yourself before taking any actions.
43
+ Acknowledge the handoff context and state what you will do first.
44
+ `.trim();
45
+ const RELAY_RULE_COPILOT = `
46
+ # Relay Context Handoff
47
+
48
+ This repository uses [Relay](https://github.com/relay-ai/relay) for cross-platform AI context handoff.
49
+
50
+ When starting a session:
51
+ - Check if \`.relay/handoff.md\` exists
52
+ - If yes, read it before making any suggestions or changes
53
+ - Acknowledge the handoff context before proceeding
54
+ - Respect all constraints listed in the file
55
+ `.trim();
56
+ // Global rule variant (applies to any workspace/repo)
57
+ const RELAY_GLOBAL_RULE_CLAUDE = `
58
+ ## Relay Global Context Handoff
59
+
60
+ Whenever working in a project workspace:
61
+ 1. Check if \`.relay/handoff.md\` exists in the current project or workspace root.
62
+ 2. If present, read it FIRST before taking any action.
63
+ 3. Acknowledge active context: state the current goal, constraints, and your initial step.
64
+ 4. When switching tasks or platforms, encourage running \`relay save\`.
65
+ `.trim();
66
+ const RELAY_GLOBAL_RULE_CURSOR = `
67
+ # Relay Global Context Handoff
68
+
69
+ Whenever working in any workspace:
70
+ 1. Check if \`.relay/handoff.md\` exists at the root.
71
+ 2. If it exists, read it FIRST before making changes.
72
+ 3. Respect all stated constraints and avoid listed failed approaches.
73
+ 4. Run \`relay save\` when completing or pausing a session.
74
+ `.trim();
75
+ const RELAY_GLOBAL_RULE_ANTIGRAVITY = `
76
+ ## Relay Global Context Handoff
77
+
78
+ When working in any project, check if \`.relay/handoff.md\` exists in the workspace.
79
+ If it exists, read it to restore context before taking actions.
80
+ `.trim();
81
+ const RELAY_GLOBAL_RULE_COPILOT = `
82
+ # Relay Global Context Handoff
83
+
84
+ When working in any project:
85
+ - Check if \`.relay/handoff.md\` exists in the repository.
86
+ - If present, read it before answering or suggesting code changes.
87
+ - Respect constraints and pending tasks defined in the handoff.
88
+ `.trim();
89
+ export const PLATFORMS = {
90
+ claude: {
91
+ name: 'Claude / Claude Code',
92
+ rule: RELAY_RULE_CLAUDE,
93
+ globalRule: RELAY_GLOBAL_RULE_CLAUDE,
94
+ getPath: (root) => join(root, 'CLAUDE.md'),
95
+ getGlobalPath: () => join(homedir(), '.claude', 'CLAUDE.md'),
96
+ appendMode: 'append',
97
+ marker: 'Relay Context Handoff',
98
+ },
99
+ cursor: {
100
+ name: 'Cursor',
101
+ rule: RELAY_RULE_CURSOR,
102
+ globalRule: RELAY_GLOBAL_RULE_CURSOR,
103
+ getPath: (root) => join(root, '.cursor', 'rules', 'relay.mdc'),
104
+ getGlobalPath: () => join(homedir(), '.cursor', 'rules', 'relay.mdc'),
105
+ appendMode: 'create',
106
+ marker: 'Relay Context Handoff',
107
+ },
108
+ antigravity: {
109
+ name: 'Antigravity',
110
+ rule: RELAY_RULE_ANTIGRAVITY,
111
+ globalRule: RELAY_GLOBAL_RULE_ANTIGRAVITY,
112
+ getPath: (root) => join(root, 'AGENTS.md'),
113
+ getGlobalPath: () => join(homedir(), '.antigravity', 'AGENTS.md'),
114
+ appendMode: 'append',
115
+ marker: 'Relay Context Handoff',
116
+ },
117
+ copilot: {
118
+ name: 'GitHub Copilot',
119
+ rule: RELAY_RULE_COPILOT,
120
+ globalRule: RELAY_GLOBAL_RULE_COPILOT,
121
+ getPath: (root) => join(root, '.github', 'copilot-instructions.md'),
122
+ getGlobalPath: () => join(homedir(), '.config', 'github-copilot', 'instructions.md'),
123
+ appendMode: 'append',
124
+ marker: 'Relay Context Handoff',
125
+ },
126
+ };
127
+ export async function installCommand(platform, options) {
128
+ const isGlobal = Boolean(options.global);
129
+ const cwd = resolveCwd(options.dir);
130
+ const repoRoot = await getRepoRoot(cwd);
131
+ if (!isGlobal && !repoRoot) {
132
+ console.error(chalk.red('✗ Not a git repository. Use --global (-g) to install system-wide rules.'));
133
+ process.exit(1);
134
+ }
135
+ const targets = platform === 'all'
136
+ ? Object.entries(PLATFORMS)
137
+ : [[platform, PLATFORMS[platform]]];
138
+ if (options.dryRun) {
139
+ console.log(chalk.yellow(`DRY RUN — no files will be modified (${isGlobal ? 'Global' : 'Repository'} mode)`));
140
+ console.log('');
141
+ }
142
+ for (const [key, target] of targets) {
143
+ if (!target) {
144
+ console.error(chalk.red(`✗ Unknown platform: ${key}`));
145
+ continue;
146
+ }
147
+ const filePath = isGlobal
148
+ ? (target.getGlobalPath ? target.getGlobalPath() : target.getPath(homedir()))
149
+ : target.getPath(repoRoot);
150
+ const displayPath = isGlobal
151
+ ? filePath.replace(homedir(), '~')
152
+ : filePath.replace(repoRoot, '');
153
+ console.log(chalk.bold(`Installing ${isGlobal ? 'global ' : ''}Relay rule for ${target.name}...`));
154
+ console.log(chalk.dim(` File: ${displayPath}`));
155
+ const ruleContent = isGlobal && target.globalRule ? target.globalRule : target.rule;
156
+ // Check if already installed
157
+ if (existsSync(filePath)) {
158
+ const existing = readFileSync(filePath, 'utf-8');
159
+ if (existing.includes(target.marker)) {
160
+ console.log(chalk.yellow(` ⚠ Already installed — skipping`));
161
+ console.log('');
162
+ continue;
163
+ }
164
+ }
165
+ if (!options.dryRun) {
166
+ // Create parent directories if needed
167
+ const lastSlash = filePath.lastIndexOf('/');
168
+ if (lastSlash > 0) {
169
+ const dir = filePath.substring(0, lastSlash);
170
+ mkdirSync(dir, { recursive: true });
171
+ }
172
+ if (target.appendMode === 'create') {
173
+ writeFileSync(filePath, ruleContent + '\n');
174
+ }
175
+ else {
176
+ const existing = existsSync(filePath) ? readFileSync(filePath, 'utf-8') : '';
177
+ const separator = existing.length > 0 ? '\n\n---\n\n' : '';
178
+ if (target.appendMode === 'prepend') {
179
+ writeFileSync(filePath, ruleContent + separator + existing);
180
+ }
181
+ else {
182
+ writeFileSync(filePath, existing.trimEnd() + separator + ruleContent + '\n');
183
+ }
184
+ }
185
+ }
186
+ console.log(chalk.green(` ✓ Installed`));
187
+ console.log('');
188
+ }
189
+ // If in a repo, register it globally as well
190
+ if (repoRoot && !options.dryRun) {
191
+ registerRepo(repoRoot);
192
+ }
193
+ console.log(chalk.bold.green(`✓ ${isGlobal ? 'Global bootstrap' : 'Bootstrap'} rules installed!`));
194
+ console.log('');
195
+ if (isGlobal) {
196
+ console.log(chalk.dim('All AI sessions across your computer will now check for .relay/handoff.md in workspace roots.'));
197
+ }
198
+ else {
199
+ console.log(chalk.dim('The next AI session in this repo will automatically read .relay/handoff.md'));
200
+ }
201
+ console.log(chalk.dim('Remember to run `relay save` before switching platforms.'));
202
+ }
203
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/cli/commands/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ interface LoadOptions {
2
+ dir?: string;
3
+ prompt?: boolean;
4
+ clipboard?: boolean;
5
+ json?: boolean;
6
+ }
7
+ export declare function loadCommand(options: LoadOptions): Promise<void>;
8
+ export {};
9
+ //# sourceMappingURL=load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/load.ts"],"names":[],"mappings":"AAMA,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuErE"}
@@ -0,0 +1,69 @@
1
+ import chalk from 'chalk';
2
+ import clipboard from 'clipboardy';
3
+ import { getRepoRoot } from '../../git/context.js';
4
+ import { readHandoff, resolveCwd } from '../../storage/index.js';
5
+ import { renderMarkdown, renderAgentPrompt } from '../../format/renderer.js';
6
+ export async function loadCommand(options) {
7
+ const cwd = resolveCwd(options.dir);
8
+ const repoRoot = await getRepoRoot(cwd);
9
+ if (!repoRoot) {
10
+ console.error(chalk.red('✗ Not a git repository.'));
11
+ process.exit(1);
12
+ }
13
+ const handoff = readHandoff(repoRoot);
14
+ if (!handoff) {
15
+ console.error(chalk.red('✗ No handoff found.'));
16
+ console.error(chalk.dim(` Expected: ${repoRoot}/.relay/handoff.json`));
17
+ console.error('');
18
+ console.error(`Run ${chalk.cyan('relay save')} first to create a handoff.`);
19
+ process.exit(1);
20
+ }
21
+ // ── Output modes ───────────────────────────────────────────────────────────
22
+ if (options.json) {
23
+ console.log(JSON.stringify(handoff, null, 2));
24
+ return;
25
+ }
26
+ let output;
27
+ if (options.prompt) {
28
+ // Compact agent prompt — optimised for pasting into a new session
29
+ output = renderAgentPrompt(handoff);
30
+ }
31
+ else {
32
+ // Full Markdown — same as the file
33
+ output = renderMarkdown(handoff);
34
+ }
35
+ // ── Copy to clipboard if requested ────────────────────────────────────────
36
+ if (options.clipboard) {
37
+ try {
38
+ await clipboard.write(output);
39
+ console.log(chalk.green('✓ Handoff copied to clipboard!'));
40
+ console.log(chalk.dim('Paste it at the start of your new AI agent session.'));
41
+ return;
42
+ }
43
+ catch {
44
+ console.error(chalk.yellow('⚠ Could not access clipboard. Printing to stdout instead.'));
45
+ console.log('');
46
+ }
47
+ }
48
+ // ── Print to stdout ────────────────────────────────────────────────────────
49
+ if (!options.prompt && !options.clipboard) {
50
+ // Show a header when printing the full markdown
51
+ const ts = new Date(handoff.timestamp).toLocaleString();
52
+ const statusIcon = handoff.session.status === 'completed' ? '✅' : handoff.session.status === 'blocked' ? '🔴' : '🟡';
53
+ console.log(chalk.bold(`\n${statusIcon} Relay Handoff`));
54
+ console.log(chalk.dim(`Source: ${handoff.source_platform} | Saved: ${ts} | Branch: ${handoff.repository.branch}`));
55
+ console.log('');
56
+ console.log(chalk.dim('─'.repeat(60)));
57
+ console.log('');
58
+ }
59
+ console.log(output);
60
+ if (!options.prompt) {
61
+ console.log('');
62
+ console.log(chalk.dim('─'.repeat(60)));
63
+ console.log('');
64
+ console.log(chalk.dim('Tips:'));
65
+ console.log(chalk.dim(` relay load --prompt — compact agent-ready prompt`));
66
+ console.log(chalk.dim(` relay load --clipboard — copy to clipboard`));
67
+ }
68
+ }
69
+ //# sourceMappingURL=load.js.map