@projectctx/agent 0.1.0-alpha.4 → 0.1.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/assets/instructions/README.md +35 -0
- package/assets/instructions/chatgpt-claudeai.v1.md +6 -0
- package/assets/instructions/chatgpt-claudeai.v2.md +6 -0
- package/assets/instructions/claude-code.v1.md +15 -0
- package/assets/instructions/claude-code.v2.md +15 -0
- package/assets/instructions/codex.v1.md +10 -0
- package/assets/instructions/codex.v2.md +10 -0
- package/assets/instructions/cursor.v1.md +10 -0
- package/assets/instructions/cursor.v2.md +10 -0
- package/dist/cli.d.ts +27 -0
- package/dist/cli.js +117 -0
- package/dist/connect.d.ts +101 -0
- package/dist/connect.js +544 -0
- package/dist/doctor.js +19 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mcp.js +2 -2
- package/dist/token-commands.d.ts +40 -0
- package/dist/token-commands.js +127 -0
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -13,11 +13,38 @@ security expectations.
|
|
|
13
13
|
```bash
|
|
14
14
|
npm install -g @projectctx/agent@alpha
|
|
15
15
|
projectctx login --token <agent-token>
|
|
16
|
+
projectctx connect --dry-run # preview client wiring; drop --dry-run to apply
|
|
16
17
|
projectctx doctor
|
|
17
18
|
projectctx scan .
|
|
18
19
|
projectctx mcp
|
|
19
20
|
```
|
|
20
21
|
|
|
22
|
+
## `projectctx connect`
|
|
23
|
+
|
|
24
|
+
One command wires the `project-memory` MCP into every locally installed AI
|
|
25
|
+
client and installs the memory instruction blocks:
|
|
26
|
+
|
|
27
|
+
- **Detects** Claude Code (`~/.claude.json`), Cursor (`~/.cursor/mcp.json`), and
|
|
28
|
+
Codex (`~/.codex/config.toml`) by config presence.
|
|
29
|
+
- **Wires the MCP** per client — `claude mcp add …` when the `claude` CLI is on
|
|
30
|
+
PATH, otherwise a direct JSON merge for Claude Code; JSON merge for Cursor;
|
|
31
|
+
TOML block append for Codex.
|
|
32
|
+
- **Installs instruction blocks** (from `assets/instructions/`) into
|
|
33
|
+
`~/.claude/CLAUDE.md`, `~/.cursor/rules/projectctx.mdc`, and
|
|
34
|
+
`~/.codex/AGENTS.md`, wrapped in `<!-- projectctx:begin/end -->` markers so
|
|
35
|
+
re-runs replace the block instead of appending.
|
|
36
|
+
- **Prints the manual remainder** for ChatGPT / claude.ai / Claude Desktop
|
|
37
|
+
(account-side connectors — no local config file).
|
|
38
|
+
|
|
39
|
+
Safety: every config file is parsed → merged → written atomically (temp +
|
|
40
|
+
rename) with a timestamped `.bak-<ts>` backup, and connect warns if the target
|
|
41
|
+
client appears to be running. `--dry-run` prints the full plan without touching
|
|
42
|
+
disk. Re-runs are idempotent (empty diff on already-wired files).
|
|
43
|
+
|
|
44
|
+
Instruction texts ship in two versions; `v1` (goal-mode) is installed today.
|
|
45
|
+
Swap to `v2` (checkin-mode) by re-running `connect` after roadmap T-301 — see
|
|
46
|
+
[assets/instructions/README.md](assets/instructions/README.md).
|
|
47
|
+
|
|
21
48
|
PR 20 publishes public alpha packages only after local pack verification passes.
|
|
22
49
|
Use the `alpha` dist-tag, never `latest`.
|
|
23
50
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# ProjectCtx instruction texts (T-002)
|
|
2
|
+
|
|
3
|
+
These are the bootstrap instruction blocks that `projectctx connect` (T-001)
|
|
4
|
+
installs into each client's rules file. They are the entire trigger mechanism on
|
|
5
|
+
clients without hooks, and the discretionary half (what to search, what to save)
|
|
6
|
+
even where hooks exist. See `roadmap/tasks/T-002-bootstrap-instructions.md`.
|
|
7
|
+
|
|
8
|
+
## Versioning (load-bearing)
|
|
9
|
+
|
|
10
|
+
- **v1** is the installed default today. It uses **goal-mode** wording
|
|
11
|
+
(`get_context` with the session's goal) because `get_context {mode:"checkin"}`
|
|
12
|
+
FAILS Zod validation until T-301 deploys (`goal` is currently required).
|
|
13
|
+
- **v2** uses **checkin-mode** wording. Swap it in by re-running
|
|
14
|
+
`projectctx connect` *after T-301 ships*. The `<!-- projectctx:begin/end -->`
|
|
15
|
+
markers make the swap a clean replace, not an append.
|
|
16
|
+
|
|
17
|
+
Never ship both versions into one file — the two first sentences contradict.
|
|
18
|
+
|
|
19
|
+
To move the default from v1 to v2, change `INSTRUCTION_VERSION` in
|
|
20
|
+
`src/connect.ts` (currently `"v1"`).
|
|
21
|
+
|
|
22
|
+
## Files
|
|
23
|
+
|
|
24
|
+
| Client | File(s) | Installed into |
|
|
25
|
+
|--------|---------|----------------|
|
|
26
|
+
| Claude Code | `claude-code.v1.md` / `.v2.md` | `~/.claude/CLAUDE.md` |
|
|
27
|
+
| Cursor | `cursor.v1.md` / `.v2.md` | `~/.cursor/rules/projectctx.mdc` (with frontmatter) |
|
|
28
|
+
| Codex | `codex.v1.md` / `.v2.md` | `~/.codex/AGENTS.md` |
|
|
29
|
+
| ChatGPT / claude.ai | `chatgpt-claudeai.v1.md` / `.v2.md` | pasted manually (custom instructions) |
|
|
30
|
+
|
|
31
|
+
The Cursor `.mdc` frontmatter (`description` + `alwaysApply: true`) is written by
|
|
32
|
+
`connect` outside the marker block, since frontmatter must sit at the file top.
|
|
33
|
+
|
|
34
|
+
The ChatGPT / claude.ai text is printed as part of the manual remainder — those
|
|
35
|
+
connectors are account-side (settings UIs), not local config files.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
I use a personal memory service (project-memory connector). At the start of
|
|
2
|
+
a conversation, call get_context with this conversation's goal and use it as
|
|
3
|
+
background about me. Search it whenever a topic from its memory map comes up or I
|
|
4
|
+
reference past work. Save important decisions and learnings before we finish;
|
|
5
|
+
update existing records rather than duplicating. Don't save trivia. If asked
|
|
6
|
+
what you remember about me, answer from get_context and searches — don't guess.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
I use a personal memory service (project-memory connector). At the start of
|
|
2
|
+
a conversation, call get_context with mode "checkin" and use it as background
|
|
3
|
+
about me. Search it whenever a topic from its memory map comes up or I
|
|
4
|
+
reference past work. Save important decisions and learnings before we finish;
|
|
5
|
+
update existing records rather than duplicating. Don't save trivia. If asked
|
|
6
|
+
what you remember about me, answer from checkin and searches — don't guess.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## Memory (project-memory MCP)
|
|
2
|
+
|
|
3
|
+
At session start, call get_context on project-memory with this session's goal
|
|
4
|
+
and treat the result as background truth about me and my work.
|
|
5
|
+
|
|
6
|
+
During the session, search memory before assuming or asking when a topic
|
|
7
|
+
matching any collection in the returned memory map comes up, or when I
|
|
8
|
+
reference past work, a decision, or "what we discussed" — and before saying
|
|
9
|
+
something doesn't exist.
|
|
10
|
+
|
|
11
|
+
Before the session ends — or right after any significant decision — save
|
|
12
|
+
durable outcomes: decisions and why, learnings that outlive this session,
|
|
13
|
+
corrections I gave you. Prefer updating existing records (via
|
|
14
|
+
preview_memory_changes upserts) over creating new ones (save_memory).
|
|
15
|
+
Never save session-local trivia.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## Memory (project-memory MCP)
|
|
2
|
+
|
|
3
|
+
At session start, call get_context with {mode: "checkin"} once and treat
|
|
4
|
+
the result as background truth about me and my work.
|
|
5
|
+
|
|
6
|
+
During the session, search memory before assuming or asking when a topic
|
|
7
|
+
matching any collection in the checkin map comes up, or when I reference
|
|
8
|
+
past work, a decision, or "what we discussed" — and before saying
|
|
9
|
+
something doesn't exist.
|
|
10
|
+
|
|
11
|
+
Before the session ends — or right after any significant decision — save
|
|
12
|
+
durable outcomes: decisions and why, learnings that outlive this session,
|
|
13
|
+
corrections I gave you. Prefer updating existing records (via
|
|
14
|
+
preview_memory_changes upserts) over creating new ones (save_memory).
|
|
15
|
+
Never save session-local trivia.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Memory (project-memory MCP)
|
|
2
|
+
|
|
3
|
+
At session start, call get_context on project-memory with this session's goal;
|
|
4
|
+
treat the result as background truth about me and my work. Search memory before
|
|
5
|
+
assuming or asking when a topic from the returned memory map comes up, when I
|
|
6
|
+
reference past work or a decision, or before saying something doesn't exist.
|
|
7
|
+
Before finishing — or right after a significant decision — save durable outcomes
|
|
8
|
+
(decisions and why, lasting learnings, corrections I gave). Prefer updating
|
|
9
|
+
existing records (preview_memory_changes upserts) over new ones (save_memory).
|
|
10
|
+
Never save session-local trivia.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Memory (project-memory MCP)
|
|
2
|
+
|
|
3
|
+
At session start, call get_context with {mode: "checkin"} once; treat the result
|
|
4
|
+
as background truth about me and my work. Search memory before assuming or asking
|
|
5
|
+
when a topic from the checkin map comes up, when I reference past work or a
|
|
6
|
+
decision, or before saying something doesn't exist. Before finishing — or right
|
|
7
|
+
after a significant decision — save durable outcomes (decisions and why, lasting
|
|
8
|
+
learnings, corrections I gave). Prefer updating existing records
|
|
9
|
+
(preview_memory_changes upserts) over new ones (save_memory). Never save
|
|
10
|
+
session-local trivia.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Memory (project-memory MCP)
|
|
2
|
+
|
|
3
|
+
At session start, call get_context on project-memory with this session's goal;
|
|
4
|
+
treat the result as background truth about me and my work. Search memory before
|
|
5
|
+
assuming or asking when a topic from the returned memory map comes up, when I
|
|
6
|
+
reference past work or a decision, or before saying something doesn't exist.
|
|
7
|
+
Before finishing — or right after a significant decision — save durable outcomes
|
|
8
|
+
(decisions and why, lasting learnings, corrections I gave). Prefer updating
|
|
9
|
+
existing records (preview_memory_changes upserts) over new ones (save_memory).
|
|
10
|
+
Never save session-local trivia.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Memory (project-memory MCP)
|
|
2
|
+
|
|
3
|
+
At session start, call get_context with {mode: "checkin"} once; treat the result
|
|
4
|
+
as background truth about me and my work. Search memory before assuming or asking
|
|
5
|
+
when a topic from the checkin map comes up, when I reference past work or a
|
|
6
|
+
decision, or before saying something doesn't exist. Before finishing — or right
|
|
7
|
+
after a significant decision — save durable outcomes (decisions and why, lasting
|
|
8
|
+
learnings, corrections I gave). Prefer updating existing records
|
|
9
|
+
(preview_memory_changes upserts) over new ones (save_memory). Never save
|
|
10
|
+
session-local trivia.
|
package/dist/cli.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ export type CliCommand = {
|
|
|
6
6
|
} | {
|
|
7
7
|
command: "doctor";
|
|
8
8
|
debug: boolean;
|
|
9
|
+
} | {
|
|
10
|
+
command: "connect";
|
|
11
|
+
debug: boolean;
|
|
12
|
+
dryRun: boolean;
|
|
9
13
|
} | {
|
|
10
14
|
command: "scan";
|
|
11
15
|
debug: boolean;
|
|
@@ -30,6 +34,29 @@ export type CliCommand = {
|
|
|
30
34
|
command: "workspace-use";
|
|
31
35
|
debug: boolean;
|
|
32
36
|
workspaceId: string;
|
|
37
|
+
} | {
|
|
38
|
+
command: "token-create";
|
|
39
|
+
debug: boolean;
|
|
40
|
+
scopes: string[];
|
|
41
|
+
name?: string;
|
|
42
|
+
authToken?: string;
|
|
43
|
+
expiresInSeconds?: number;
|
|
44
|
+
workspaceId?: string;
|
|
45
|
+
apiUrl?: string;
|
|
46
|
+
noStore: boolean;
|
|
47
|
+
} | {
|
|
48
|
+
command: "token-list";
|
|
49
|
+
debug: boolean;
|
|
50
|
+
authToken?: string;
|
|
51
|
+
workspaceId?: string;
|
|
52
|
+
apiUrl?: string;
|
|
53
|
+
} | {
|
|
54
|
+
command: "token-revoke";
|
|
55
|
+
debug: boolean;
|
|
56
|
+
credentialId: string;
|
|
57
|
+
authToken?: string;
|
|
58
|
+
workspaceId?: string;
|
|
59
|
+
apiUrl?: string;
|
|
33
60
|
};
|
|
34
61
|
export declare function parseCliArgs(argv: string[]): CliCommand;
|
|
35
62
|
export declare function runCli(argv?: string[]): Promise<void>;
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,8 @@ import { runDoctor } from "./doctor.js";
|
|
|
6
6
|
import { runScanWorkspace } from "./scan-workspace.js";
|
|
7
7
|
import { startMcpServer } from "./mcp.js";
|
|
8
8
|
import { runLogin, runLogout, runWhoami, runWorkspaceUse, runWorkspaces } from "./auth-commands.js";
|
|
9
|
+
import { runConnect, formatConnectOutput } from "./connect.js";
|
|
10
|
+
import { runTokenCreate, runTokenList, runTokenRevoke } from "./token-commands.js";
|
|
9
11
|
import { AgentError, toErrorShape } from "./errors.js";
|
|
10
12
|
function usage(exitCode = 1) {
|
|
11
13
|
process.stderr.write([
|
|
@@ -14,12 +16,16 @@ function usage(exitCode = 1) {
|
|
|
14
16
|
"Commands:",
|
|
15
17
|
" projectctx mcp [--debug]",
|
|
16
18
|
" projectctx doctor [--debug]",
|
|
19
|
+
" projectctx connect [--dry-run] [--debug]",
|
|
17
20
|
" projectctx scan [rootPath] [options]",
|
|
18
21
|
" projectctx login [--token <token>] [--api-url <url>] [--allow-file-token-fallback] [--debug]",
|
|
19
22
|
" projectctx logout [--debug]",
|
|
20
23
|
" projectctx whoami [--debug]",
|
|
21
24
|
" projectctx workspaces [--debug]",
|
|
22
25
|
" projectctx workspace use <workspaceId> [--debug]",
|
|
26
|
+
" projectctx token create --scopes <a,b> [--name <n>] [--auth-token <t>] [--expires-in-days <n>] [--workspace <id>] [--no-store] [--debug]",
|
|
27
|
+
" projectctx token list [--auth-token <t>] [--workspace <id>] [--debug]",
|
|
28
|
+
" projectctx token revoke <credentialId> [--auth-token <t>] [--workspace <id>] [--debug]",
|
|
23
29
|
"",
|
|
24
30
|
"Scan options:",
|
|
25
31
|
" --max-repos <n>",
|
|
@@ -56,6 +62,19 @@ export function parseCliArgs(argv) {
|
|
|
56
62
|
}
|
|
57
63
|
return { command, debug };
|
|
58
64
|
}
|
|
65
|
+
if (command === "connect") {
|
|
66
|
+
let debug = false;
|
|
67
|
+
let dryRun = false;
|
|
68
|
+
for (const arg of rest) {
|
|
69
|
+
if (arg === "--debug")
|
|
70
|
+
debug = true;
|
|
71
|
+
else if (arg === "--dry-run")
|
|
72
|
+
dryRun = true;
|
|
73
|
+
else
|
|
74
|
+
usage();
|
|
75
|
+
}
|
|
76
|
+
return { command: "connect", debug, dryRun };
|
|
77
|
+
}
|
|
59
78
|
if (command === "login") {
|
|
60
79
|
let debug = false;
|
|
61
80
|
let token;
|
|
@@ -82,6 +101,74 @@ export function parseCliArgs(argv) {
|
|
|
82
101
|
}
|
|
83
102
|
return { command: "login", debug, token, apiUrl, allowFileTokenFallback };
|
|
84
103
|
}
|
|
104
|
+
if (command === "token") {
|
|
105
|
+
const [sub, ...flags] = rest;
|
|
106
|
+
if (sub !== "create" && sub !== "list" && sub !== "revoke")
|
|
107
|
+
usage();
|
|
108
|
+
let debug = false;
|
|
109
|
+
let authToken;
|
|
110
|
+
let workspaceId;
|
|
111
|
+
let apiUrl;
|
|
112
|
+
let name;
|
|
113
|
+
let scopes = [];
|
|
114
|
+
let expiresInSeconds;
|
|
115
|
+
let noStore = false;
|
|
116
|
+
let credentialId;
|
|
117
|
+
for (let i = 0; i < flags.length; i++) {
|
|
118
|
+
const arg = flags[i];
|
|
119
|
+
if (arg === "--debug")
|
|
120
|
+
debug = true;
|
|
121
|
+
else if (arg === "--no-store")
|
|
122
|
+
noStore = true;
|
|
123
|
+
else if (arg === "--auth-token") {
|
|
124
|
+
if (!flags[i + 1])
|
|
125
|
+
usage();
|
|
126
|
+
authToken = flags[++i];
|
|
127
|
+
}
|
|
128
|
+
else if (arg === "--workspace") {
|
|
129
|
+
if (!flags[i + 1])
|
|
130
|
+
usage();
|
|
131
|
+
workspaceId = flags[++i];
|
|
132
|
+
}
|
|
133
|
+
else if (arg === "--api-url") {
|
|
134
|
+
if (!flags[i + 1])
|
|
135
|
+
usage();
|
|
136
|
+
apiUrl = flags[++i];
|
|
137
|
+
}
|
|
138
|
+
else if (arg === "--name") {
|
|
139
|
+
if (!flags[i + 1])
|
|
140
|
+
usage();
|
|
141
|
+
name = flags[++i];
|
|
142
|
+
}
|
|
143
|
+
else if (arg === "--scopes" || arg === "--scope") {
|
|
144
|
+
if (!flags[i + 1])
|
|
145
|
+
usage();
|
|
146
|
+
// Accept comma-separated or repeated flags.
|
|
147
|
+
for (const value of flags[++i].split(",")) {
|
|
148
|
+
const trimmed = value.trim();
|
|
149
|
+
if (trimmed)
|
|
150
|
+
scopes.push(trimmed);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (arg === "--expires-in-days") {
|
|
154
|
+
if (!flags[i + 1])
|
|
155
|
+
usage();
|
|
156
|
+
expiresInSeconds = readPositiveInt(flags[++i], arg) * 24 * 60 * 60;
|
|
157
|
+
}
|
|
158
|
+
else if (!arg.startsWith("-") && sub === "revoke" && !credentialId) {
|
|
159
|
+
credentialId = arg;
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
usage();
|
|
163
|
+
}
|
|
164
|
+
if (sub === "create")
|
|
165
|
+
return { command: "token-create", debug, scopes, name, authToken, expiresInSeconds, workspaceId, apiUrl, noStore };
|
|
166
|
+
if (sub === "list")
|
|
167
|
+
return { command: "token-list", debug, authToken, workspaceId, apiUrl };
|
|
168
|
+
if (!credentialId)
|
|
169
|
+
usage();
|
|
170
|
+
return { command: "token-revoke", debug, credentialId, authToken, workspaceId, apiUrl };
|
|
171
|
+
}
|
|
85
172
|
if (command === "workspace") {
|
|
86
173
|
const [sub, workspaceId, ...flags] = rest;
|
|
87
174
|
if (sub !== "use" || !workspaceId || workspaceId.startsWith("-"))
|
|
@@ -153,6 +240,14 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
153
240
|
case "doctor":
|
|
154
241
|
printJson(await runDoctor(logger));
|
|
155
242
|
return;
|
|
243
|
+
case "connect": {
|
|
244
|
+
// Onboarding copy is human-readable, not JSON. The real run shells out
|
|
245
|
+
// to `claude mcp add` when available (runCliCommands: true); --dry-run
|
|
246
|
+
// never writes or shells out.
|
|
247
|
+
const result = runConnect({ dryRun: parsed.dryRun, runCliCommands: !parsed.dryRun, logger });
|
|
248
|
+
process.stdout.write(formatConnectOutput(result));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
156
251
|
case "login":
|
|
157
252
|
printJson(await runLogin({ token: parsed.token, apiUrl: parsed.apiUrl, allowFileTokenFallback: parsed.allowFileTokenFallback }, logger));
|
|
158
253
|
return;
|
|
@@ -168,6 +263,28 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
168
263
|
case "workspace-use":
|
|
169
264
|
printJson(await runWorkspaceUse(parsed.workspaceId, logger));
|
|
170
265
|
return;
|
|
266
|
+
case "token-create":
|
|
267
|
+
printJson(await runTokenCreate({
|
|
268
|
+
scopes: parsed.scopes,
|
|
269
|
+
name: parsed.name,
|
|
270
|
+
authToken: parsed.authToken,
|
|
271
|
+
expiresInSeconds: parsed.expiresInSeconds,
|
|
272
|
+
workspaceId: parsed.workspaceId,
|
|
273
|
+
apiUrl: parsed.apiUrl,
|
|
274
|
+
store: !parsed.noStore
|
|
275
|
+
}, logger));
|
|
276
|
+
return;
|
|
277
|
+
case "token-list":
|
|
278
|
+
printJson(await runTokenList({ authToken: parsed.authToken, workspaceId: parsed.workspaceId, apiUrl: parsed.apiUrl }, logger));
|
|
279
|
+
return;
|
|
280
|
+
case "token-revoke":
|
|
281
|
+
printJson(await runTokenRevoke({
|
|
282
|
+
credentialId: parsed.credentialId,
|
|
283
|
+
authToken: parsed.authToken,
|
|
284
|
+
workspaceId: parsed.workspaceId,
|
|
285
|
+
apiUrl: parsed.apiUrl
|
|
286
|
+
}, logger));
|
|
287
|
+
return;
|
|
171
288
|
case "scan":
|
|
172
289
|
printJson(runScanWorkspace({ rootPath: parsed.rootPath, ...parsed.options }, logger));
|
|
173
290
|
return;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { DebugLogger } from "./log.js";
|
|
2
|
+
export declare const MCP_SERVER_NAME = "project-memory";
|
|
3
|
+
export declare const MCP_URL = "https://projectctx.com/mcp";
|
|
4
|
+
export declare const INSTRUCTION_VERSION: "v1" | "v2";
|
|
5
|
+
export type ClientId = "claude-code" | "cursor" | "codex";
|
|
6
|
+
export interface FileChange {
|
|
7
|
+
path: string;
|
|
8
|
+
kind: "mcp-config" | "instructions";
|
|
9
|
+
before: string | null;
|
|
10
|
+
after: string;
|
|
11
|
+
changed: boolean;
|
|
12
|
+
note?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ClientPlan {
|
|
15
|
+
client: ClientId;
|
|
16
|
+
label: string;
|
|
17
|
+
detected: boolean;
|
|
18
|
+
cliCommand?: {
|
|
19
|
+
argv: string[];
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
changes: FileChange[];
|
|
23
|
+
warnings: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface ConnectPlan {
|
|
26
|
+
dryRun: boolean;
|
|
27
|
+
home: string;
|
|
28
|
+
instructionVersion: "v1" | "v2";
|
|
29
|
+
clients: ClientPlan[];
|
|
30
|
+
manualRemainder: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ConnectResult extends ConnectPlan {
|
|
33
|
+
applied: boolean;
|
|
34
|
+
}
|
|
35
|
+
interface ConnectPaths {
|
|
36
|
+
home: string;
|
|
37
|
+
claudeJson: string;
|
|
38
|
+
claudeMd: string;
|
|
39
|
+
cursorMcp: string;
|
|
40
|
+
cursorRules: string;
|
|
41
|
+
codexToml: string;
|
|
42
|
+
codexAgents: string;
|
|
43
|
+
}
|
|
44
|
+
export declare function connectPaths(home?: string): ConnectPaths;
|
|
45
|
+
export declare function readManualRemainderText(version: "v1" | "v2"): string;
|
|
46
|
+
/**
|
|
47
|
+
* Insert or replace the projectctx marker block in a markdown-ish file. Content
|
|
48
|
+
* outside the markers is preserved verbatim. Re-running with the same body is a
|
|
49
|
+
* no-op (byte-identical output), which is what makes connect idempotent.
|
|
50
|
+
*/
|
|
51
|
+
export declare function upsertMarkerBlock(existing: string | null, body: string): string;
|
|
52
|
+
export declare function buildCursorMdc(existing: string | null, body: string): string;
|
|
53
|
+
interface JsonMergeResult {
|
|
54
|
+
after: string;
|
|
55
|
+
changed: boolean;
|
|
56
|
+
}
|
|
57
|
+
export declare function mergeMcpServersJson(existing: string | null, entry: Record<string, unknown>): JsonMergeResult;
|
|
58
|
+
export declare function upsertCodexToml(existing: string | null): JsonMergeResult;
|
|
59
|
+
/**
|
|
60
|
+
* Write `content` to `path` atomically: back up any existing file to
|
|
61
|
+
* `<target>.bak-<timestamp>`, write to a temp file in the same directory, then
|
|
62
|
+
* rename over the target (atomic on POSIX). The temp+rename means a crash
|
|
63
|
+
* mid-write never leaves a truncated config.
|
|
64
|
+
*
|
|
65
|
+
* Symlinked configs (dotfiles setups) are followed: the write and backup act on
|
|
66
|
+
* the resolved real path, so the link stays intact and the linked target gets
|
|
67
|
+
* the new content. Renaming over the link path itself would silently replace
|
|
68
|
+
* the symlink with a regular file and leave the real target stale (review
|
|
69
|
+
* finding S1).
|
|
70
|
+
*/
|
|
71
|
+
export declare function atomicWriteWithBackup(path: string, content: string): {
|
|
72
|
+
backupPath?: string;
|
|
73
|
+
};
|
|
74
|
+
export declare function buildConnectPlan(opts?: {
|
|
75
|
+
home?: string;
|
|
76
|
+
version?: "v1" | "v2";
|
|
77
|
+
logger?: DebugLogger;
|
|
78
|
+
}): ConnectPlan;
|
|
79
|
+
export interface RunConnectOptions {
|
|
80
|
+
dryRun?: boolean;
|
|
81
|
+
home?: string;
|
|
82
|
+
version?: "v1" | "v2";
|
|
83
|
+
runCliCommands?: boolean;
|
|
84
|
+
logger?: DebugLogger;
|
|
85
|
+
}
|
|
86
|
+
export declare function runConnect(opts?: RunConnectOptions): ConnectResult;
|
|
87
|
+
export interface ClientConfigStatus {
|
|
88
|
+
client: ClientId;
|
|
89
|
+
label: string;
|
|
90
|
+
configPath: string;
|
|
91
|
+
configExists: boolean;
|
|
92
|
+
mcpConfigured: boolean;
|
|
93
|
+
}
|
|
94
|
+
export declare function inspectClientConfigs(home?: string): ClientConfigStatus[];
|
|
95
|
+
/**
|
|
96
|
+
* Render the plan as product-grade terminal copy. Doubles as onboarding, so it
|
|
97
|
+
* names every file it would touch, flags detected-vs-not, and prints the manual
|
|
98
|
+
* remainder. In dry-run it says nothing was written.
|
|
99
|
+
*/
|
|
100
|
+
export declare function formatConnectOutput(result: ConnectResult): string;
|
|
101
|
+
export {};
|