@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.
- package/LICENSE +21 -0
- package/README.md +538 -0
- package/dist/cli/commands/branch.d.ts +9 -0
- package/dist/cli/commands/branch.d.ts.map +1 -0
- package/dist/cli/commands/branch.js +69 -0
- package/dist/cli/commands/branch.js.map +1 -0
- package/dist/cli/commands/diff.d.ts +8 -0
- package/dist/cli/commands/diff.d.ts.map +1 -0
- package/dist/cli/commands/diff.js +61 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/history.d.ts +8 -0
- package/dist/cli/commands/history.d.ts.map +1 -0
- package/dist/cli/commands/history.js +32 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/hook.d.ts +6 -0
- package/dist/cli/commands/hook.d.ts.map +1 -0
- package/dist/cli/commands/hook.js +118 -0
- package/dist/cli/commands/hook.js.map +1 -0
- package/dist/cli/commands/init.d.ts +4 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +41 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/install.d.ts +18 -0
- package/dist/cli/commands/install.d.ts.map +1 -0
- package/dist/cli/commands/install.js +203 -0
- package/dist/cli/commands/install.js.map +1 -0
- package/dist/cli/commands/load.d.ts +9 -0
- package/dist/cli/commands/load.d.ts.map +1 -0
- package/dist/cli/commands/load.js +69 -0
- package/dist/cli/commands/load.js.map +1 -0
- package/dist/cli/commands/repos.d.ts +7 -0
- package/dist/cli/commands/repos.d.ts.map +1 -0
- package/dist/cli/commands/repos.js +53 -0
- package/dist/cli/commands/repos.js.map +1 -0
- package/dist/cli/commands/save.d.ts +9 -0
- package/dist/cli/commands/save.d.ts.map +1 -0
- package/dist/cli/commands/save.js +267 -0
- package/dist/cli/commands/save.js.map +1 -0
- package/dist/cli/commands/status.d.ts +23 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +134 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/ui.d.ts +9 -0
- package/dist/cli/commands/ui.d.ts.map +1 -0
- package/dist/cli/commands/ui.js +54 -0
- package/dist/cli/commands/ui.js.map +1 -0
- package/dist/cli/commands/vscode.d.ts +6 -0
- package/dist/cli/commands/vscode.d.ts.map +1 -0
- package/dist/cli/commands/vscode.js +86 -0
- package/dist/cli/commands/vscode.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +143 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/format/renderer.d.ts +5 -0
- package/dist/format/renderer.d.ts.map +1 -0
- package/dist/format/renderer.js +207 -0
- package/dist/format/renderer.js.map +1 -0
- package/dist/format/schema.d.ts +516 -0
- package/dist/format/schema.d.ts.map +1 -0
- package/dist/format/schema.js +90 -0
- package/dist/format/schema.js.map +1 -0
- package/dist/format/template.d.ts +44 -0
- package/dist/format/template.d.ts.map +1 -0
- package/dist/format/template.js +131 -0
- package/dist/format/template.js.map +1 -0
- package/dist/git/context.d.ts +23 -0
- package/dist/git/context.d.ts.map +1 -0
- package/dist/git/context.js +121 -0
- package/dist/git/context.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +164 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +143 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/ui.d.ts +2 -0
- package/dist/server/ui.d.ts.map +1 -0
- package/dist/server/ui.js +797 -0
- package/dist/server/ui.js.map +1 -0
- package/dist/storage/global.d.ts +40 -0
- package/dist/storage/global.d.ts.map +1 -0
- package/dist/storage/global.js +126 -0
- package/dist/storage/global.js.map +1 -0
- package/dist/storage/index.d.ts +59 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +253 -0
- package/dist/storage/index.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|