@cordfuse/crosstalk 5.0.0-alpha.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/bin/crosstalk.js +111 -0
- package/package.json +46 -0
- package/src/actor.ts +106 -0
- package/src/attach.ts +118 -0
- package/src/channel.ts +62 -0
- package/src/chat.ts +203 -0
- package/src/cursor.ts +48 -0
- package/src/dispatch.ts +519 -0
- package/src/dlq.ts +263 -0
- package/src/filenames.ts +28 -0
- package/src/frontmatter.ts +26 -0
- package/src/init.ts +157 -0
- package/src/open.ts +183 -0
- package/src/send.ts +80 -0
- package/src/status.ts +114 -0
- package/src/transport.ts +303 -0
- package/src/turnq.ts +59 -0
- package/src/upgrade.ts +213 -0
- package/src/wake.ts +8 -0
- package/template/.amazonq/rules/crosstalk.md +2 -0
- package/template/.continue/rules/crosstalk.md +7 -0
- package/template/.cursor/rules/crosstalk.mdc +7 -0
- package/template/.github/copilot-instructions.md +2 -0
- package/template/.windsurfrules +2 -0
- package/template/AGENTS.md +2 -0
- package/template/ANTIGRAVITY.md +2 -0
- package/template/CLAUDE.md +2 -0
- package/template/GEMINI.md +2 -0
- package/template/OPENCODE.md +2 -0
- package/template/QWEN.md +2 -0
- package/template/README.md +22 -0
- package/template/local/CROSSTALK.md +4 -0
- package/template/upstream/CROSSTALK-VERSION +1 -0
- package/template/upstream/CROSSTALK.md +589 -0
- package/template/upstream/JITTER.md +24 -0
- package/template/upstream/OPERATOR.md +60 -0
- package/template/upstream/PROTOCOL.md +180 -0
- package/template/upstream/actors/cloud-architect.md +83 -0
- package/template/upstream/actors/concierge.md +105 -0
- package/template/upstream/actors/devops-engineer.md +83 -0
- package/template/upstream/actors/documentation-engineer.md +107 -0
- package/template/upstream/actors/infrastructure-engineer.md +83 -0
- package/template/upstream/actors/junior-developer.md +83 -0
- package/template/upstream/actors/precise-generalist.md +48 -0
- package/template/upstream/actors/product-manager.md +83 -0
- package/template/upstream/actors/qa-engineer.md +83 -0
- package/template/upstream/actors/security-engineer.md +92 -0
- package/template/upstream/actors/senior-generalist-engineer.md +111 -0
- package/template/upstream/actors/senior-software-engineer.md +94 -0
- package/template/upstream/actors/skeptic.md +89 -0
- package/template/upstream/actors/technical-writer.md +89 -0
- package/template/upstream/actors/ux-designer.md +83 -0
package/src/upgrade.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// crosstalk upgrade — sync the transport's upstream/ against the runtime's
|
|
2
|
+
// bundled template.
|
|
3
|
+
//
|
|
4
|
+
// The transport's upstream/ contains runtime-managed files: spec, agent
|
|
5
|
+
// orientation prompts, protocol version pin, default actor profiles. When
|
|
6
|
+
// the operator updates their runtime (via `npm update -g @cordfuse/crosstalk`),
|
|
7
|
+
// the bundled template ships with a newer spec; this command copies those
|
|
8
|
+
// files into the operator's transport so they catch up.
|
|
9
|
+
//
|
|
10
|
+
// What this command DOES touch:
|
|
11
|
+
// - upstream/CROSSTALK.md, PROTOCOL.md, OPERATOR.md, JITTER.md
|
|
12
|
+
// - upstream/CROSSTALK-VERSION
|
|
13
|
+
// - upstream/actors/ (default actor profile starter set)
|
|
14
|
+
//
|
|
15
|
+
// What this command NEVER touches:
|
|
16
|
+
// - local/ — operator-owned actor profiles and identity
|
|
17
|
+
// - hosts/ — operator-owned host file
|
|
18
|
+
// - data/ — channels and memories
|
|
19
|
+
// - cursors/, dlq/, errors/ — dispatcher-owned runtime state
|
|
20
|
+
// - root pointer files (CLAUDE.md etc.) — only updated if a --pointers flag
|
|
21
|
+
// is passed, since they rarely change and overwriting them surprises
|
|
22
|
+
// operators who've customized them
|
|
23
|
+
//
|
|
24
|
+
// Usage:
|
|
25
|
+
// crosstalk upgrade — sync upstream/ from runtime template
|
|
26
|
+
// crosstalk upgrade --dry-run — show what would change, no writes
|
|
27
|
+
// crosstalk upgrade --pointers — also overwrite the 11 entry pointer files
|
|
28
|
+
|
|
29
|
+
import { existsSync, readFileSync, writeFileSync, cpSync, statSync, readdirSync } from 'fs';
|
|
30
|
+
import { resolve, join, dirname, relative } from 'path';
|
|
31
|
+
import { fileURLToPath } from 'url';
|
|
32
|
+
|
|
33
|
+
const transportRoot = resolve(process.cwd());
|
|
34
|
+
const argv = process.argv.slice(2);
|
|
35
|
+
const dryRun = argv.includes('--dry-run');
|
|
36
|
+
const updatePointers = argv.includes('--pointers');
|
|
37
|
+
|
|
38
|
+
const POINTER_FILES = [
|
|
39
|
+
'CLAUDE.md', 'AGENTS.md', 'GEMINI.md', 'QWEN.md', 'ANTIGRAVITY.md', 'OPENCODE.md',
|
|
40
|
+
'.windsurfrules',
|
|
41
|
+
'.amazonq/rules/crosstalk.md',
|
|
42
|
+
'.continue/rules/crosstalk.md',
|
|
43
|
+
'.cursor/rules/crosstalk.mdc',
|
|
44
|
+
'.github/copilot-instructions.md',
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
function locateTemplate(): string {
|
|
48
|
+
const thisFileDir = dirname(fileURLToPath(import.meta.url));
|
|
49
|
+
const runtimeRoot = resolve(thisFileDir, '..');
|
|
50
|
+
const candidates = [
|
|
51
|
+
join(runtimeRoot, 'template'),
|
|
52
|
+
join(runtimeRoot, '..', 'transport'),
|
|
53
|
+
];
|
|
54
|
+
const found = candidates.find((c) => existsSync(join(c, 'upstream', 'CROSSTALK-VERSION')));
|
|
55
|
+
if (!found) {
|
|
56
|
+
console.error('crosstalk upgrade: cannot find the bundled transport template.');
|
|
57
|
+
console.error('Looked in:');
|
|
58
|
+
for (const c of candidates) console.error(` ${c}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
return found;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function readVersion(p: string): string | null {
|
|
65
|
+
try { return readFileSync(p, 'utf-8').trim(); } catch { return null; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function listFilesRelative(dir: string): string[] {
|
|
69
|
+
const out: string[] = [];
|
|
70
|
+
const walk = (d: string, prefix: string): void => {
|
|
71
|
+
if (!existsSync(d)) return;
|
|
72
|
+
for (const entry of readdirSync(d)) {
|
|
73
|
+
const full = join(d, entry);
|
|
74
|
+
const rel = prefix ? `${prefix}/${entry}` : entry;
|
|
75
|
+
const st = statSync(full);
|
|
76
|
+
if (st.isDirectory()) walk(full, rel);
|
|
77
|
+
else out.push(rel);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
walk(dir, '');
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function classifyChange(templatePath: string, transportPath: string): 'add' | 'modify' | 'unchanged' {
|
|
85
|
+
if (!existsSync(transportPath)) return 'add';
|
|
86
|
+
const a = readFileSync(templatePath, 'utf-8');
|
|
87
|
+
const b = readFileSync(transportPath, 'utf-8');
|
|
88
|
+
return a === b ? 'unchanged' : 'modify';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Sanity checks ─────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
const transportVersionPath = join(transportRoot, 'upstream', 'CROSSTALK-VERSION');
|
|
94
|
+
if (!existsSync(transportVersionPath)) {
|
|
95
|
+
console.error(`crosstalk upgrade: not a transport (no upstream/CROSSTALK-VERSION).`);
|
|
96
|
+
console.error(`Run from inside a transport directory, or use 'crosstalk init' to scaffold one.`);
|
|
97
|
+
process.exit(2);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const templateDir = locateTemplate();
|
|
101
|
+
const templateUpstream = join(templateDir, 'upstream');
|
|
102
|
+
const transportUpstream = join(transportRoot, 'upstream');
|
|
103
|
+
|
|
104
|
+
const fromVersion = readVersion(transportVersionPath) ?? '?';
|
|
105
|
+
const toVersion = readVersion(join(templateUpstream, 'CROSSTALK-VERSION')) ?? '?';
|
|
106
|
+
|
|
107
|
+
// Detect downgrade.
|
|
108
|
+
const parseMM = (v: string): [number, number] => {
|
|
109
|
+
const m = v.match(/^(\d+)\.(\d+)/);
|
|
110
|
+
return m ? [Number(m[1]), Number(m[2])] : [0, 0];
|
|
111
|
+
};
|
|
112
|
+
const [fromMaj, fromMin] = parseMM(fromVersion);
|
|
113
|
+
const [toMaj, toMin] = parseMM(toVersion);
|
|
114
|
+
const isDowngrade = toMaj < fromMaj || (toMaj === fromMaj && toMin < fromMin);
|
|
115
|
+
if (isDowngrade) {
|
|
116
|
+
console.error(`crosstalk upgrade: bundled template is OLDER than your transport.`);
|
|
117
|
+
console.error(` transport: ${fromVersion}`);
|
|
118
|
+
console.error(` template: ${toVersion}`);
|
|
119
|
+
console.error(`Your runtime is older than the runtime that scaffolded this transport.`);
|
|
120
|
+
console.error(`To upgrade your runtime: npm update -g @cordfuse/crosstalk`);
|
|
121
|
+
process.exit(3);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log(`crosstalk upgrade${dryRun ? ' (dry-run)' : ''}`);
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log(` transport CROSSTALK-VERSION: ${fromVersion}`);
|
|
127
|
+
console.log(` template CROSSTALK-VERSION: ${toVersion}`);
|
|
128
|
+
console.log('');
|
|
129
|
+
|
|
130
|
+
// ── Plan the changes ──────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
const upstreamFiles = listFilesRelative(templateUpstream);
|
|
133
|
+
const changes: { rel: string; kind: 'add' | 'modify' | 'unchanged' }[] = [];
|
|
134
|
+
|
|
135
|
+
for (const rel of upstreamFiles) {
|
|
136
|
+
const fromPath = join(templateUpstream, rel);
|
|
137
|
+
const toPath = join(transportUpstream, rel);
|
|
138
|
+
changes.push({ rel, kind: classifyChange(fromPath, toPath) });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const adds = changes.filter((c) => c.kind === 'add');
|
|
142
|
+
const mods = changes.filter((c) => c.kind === 'modify');
|
|
143
|
+
const same = changes.filter((c) => c.kind === 'unchanged');
|
|
144
|
+
|
|
145
|
+
console.log(`upstream/ changes:`);
|
|
146
|
+
console.log(` ${adds.length} new file${adds.length === 1 ? '' : 's'}`);
|
|
147
|
+
console.log(` ${mods.length} modified`);
|
|
148
|
+
console.log(` ${same.length} unchanged`);
|
|
149
|
+
|
|
150
|
+
if (adds.length > 0 || mods.length > 0) {
|
|
151
|
+
console.log('');
|
|
152
|
+
for (const c of [...adds, ...mods].slice(0, 20)) {
|
|
153
|
+
console.log(` [${c.kind === 'add' ? '+' : '~'}] upstream/${c.rel}`);
|
|
154
|
+
}
|
|
155
|
+
if (adds.length + mods.length > 20) {
|
|
156
|
+
console.log(` … and ${adds.length + mods.length - 20} more`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (updatePointers) {
|
|
161
|
+
console.log('');
|
|
162
|
+
console.log(`pointer files (with --pointers):`);
|
|
163
|
+
for (const pf of POINTER_FILES) {
|
|
164
|
+
const fromPath = join(templateDir, pf);
|
|
165
|
+
const toPath = join(transportRoot, pf);
|
|
166
|
+
if (!existsSync(fromPath)) continue;
|
|
167
|
+
const kind = classifyChange(fromPath, toPath);
|
|
168
|
+
if (kind !== 'unchanged') console.log(` [${kind === 'add' ? '+' : '~'}] ${pf}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ── Apply or stop ─────────────────────────────────────────────────────
|
|
173
|
+
|
|
174
|
+
if (dryRun) {
|
|
175
|
+
console.log('');
|
|
176
|
+
console.log('Dry run — no changes written. Re-run without --dry-run to apply.');
|
|
177
|
+
process.exit(0);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (adds.length === 0 && mods.length === 0 && !updatePointers) {
|
|
181
|
+
console.log('');
|
|
182
|
+
console.log('Already in sync. Nothing to do.');
|
|
183
|
+
process.exit(0);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log('Applying...');
|
|
188
|
+
|
|
189
|
+
// Copy upstream/ recursively. cpSync with force=true handles both add and modify.
|
|
190
|
+
cpSync(templateUpstream, transportUpstream, { recursive: true, force: true });
|
|
191
|
+
console.log(` ✓ upstream/ synced`);
|
|
192
|
+
|
|
193
|
+
if (updatePointers) {
|
|
194
|
+
for (const pf of POINTER_FILES) {
|
|
195
|
+
const fromPath = join(templateDir, pf);
|
|
196
|
+
const toPath = join(transportRoot, pf);
|
|
197
|
+
if (!existsSync(fromPath)) continue;
|
|
198
|
+
const targetDir = dirname(toPath);
|
|
199
|
+
if (!existsSync(targetDir)) {
|
|
200
|
+
cpSync(targetDir, targetDir, { recursive: true });
|
|
201
|
+
}
|
|
202
|
+
cpSync(fromPath, toPath, { force: true });
|
|
203
|
+
}
|
|
204
|
+
console.log(` ✓ pointer files synced`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
console.log('');
|
|
208
|
+
console.log(`Spec ${fromVersion} → ${toVersion}.`);
|
|
209
|
+
console.log(`Commit the upstream/ changes when ready:`);
|
|
210
|
+
console.log(` git add upstream/${updatePointers ? ' ' + POINTER_FILES.slice(0, 3).join(' ') + ' ...' : ''}`);
|
|
211
|
+
console.log(` git commit -m "spec: upgrade to ${toVersion}"`);
|
|
212
|
+
console.log('');
|
|
213
|
+
console.log('Your local/, hosts/, data/, cursors/, dlq/, errors/ were not touched.');
|
package/src/wake.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { resolve, join } from 'path';
|
|
3
|
+
|
|
4
|
+
const transportRoot = resolve(process.cwd());
|
|
5
|
+
const wakeDir = join(transportRoot, '.turnq');
|
|
6
|
+
mkdirSync(wakeDir, { recursive: true });
|
|
7
|
+
writeFileSync(join(wakeDir, 'wake.signal'), `${Date.now()}\n`);
|
|
8
|
+
console.log('wake signal sent');
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Crosstalk transport agent instructions
|
|
3
|
+
applyTo: "**"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Read [local/CROSSTALK.md](local/CROSSTALK.md) for your identity configuration (if you are a dispatched actor).
|
|
7
|
+
Read [upstream/CROSSTALK.md](upstream/CROSSTALK.md) for the protocol specification.
|
package/template/QWEN.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Transport template
|
|
2
|
+
|
|
3
|
+
This directory is the scaffold for a Crosstalk transport — the markdown + folder structure that becomes an operator's transport when they run:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
crosstalk init my-transport
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## What's here
|
|
10
|
+
|
|
11
|
+
- `upstream/` — runtime-managed. Protocol spec (`CROSSTALK.md`, `PROTOCOL.md`, `OPERATOR.md`, `JITTER.md`), version pin (`CROSSTALK-VERSION`), default actor profiles (`actors/`). **Operators don't edit these.** The runtime can re-sync them when a new spec version ships.
|
|
12
|
+
- `local/` — operator-owned. Custom actor profiles (`actors/`), local identity config (`CROSSTALK.md`). Operators edit these freely.
|
|
13
|
+
- `hosts/` — host files declaring which actors run where, per-actor tier configurations.
|
|
14
|
+
- Agent entry pointer files at root (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, etc.) — these direct agents to the right files when their CLI starts up in the transport directory.
|
|
15
|
+
|
|
16
|
+
## How a transport is born
|
|
17
|
+
|
|
18
|
+
`crosstalk init` copies this entire `transport/` tree to the operator's chosen directory, then initializes it as a git repo. From that moment on, the operator's transport is independent — they own it, customize `local/`, declare hosts in `hosts/`, and dispatch runs against it.
|
|
19
|
+
|
|
20
|
+
## Spec reference
|
|
21
|
+
|
|
22
|
+
The canonical protocol specification lives in `upstream/CROSSTALK.md`. The version pin lives in `upstream/CROSSTALK-VERSION`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
5.0
|