create-academic-research 0.1.13 → 0.1.15

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 CHANGED
@@ -114,6 +114,7 @@ Inside a generated project:
114
114
 
115
115
  ```bash
116
116
  npm run doctor
117
+ npm run update
117
118
  npm run setup
118
119
  npm run rename -- --title "New Title" --slug new-title --package new_title
119
120
  npm run agents:list
@@ -127,6 +128,7 @@ npm run skills:remove -- source-ingestion
127
128
  npm run skills:uninstall -- source-ingestion
128
129
  npm run skills:update
129
130
  npm run mcp:list
131
+ npm run mcp:modes
130
132
  npm run mcp:enabled
131
133
  npm run mcp:available
132
134
  npm run mcp:commands -- arxiv
@@ -147,8 +149,36 @@ For direct one-off invocation without the generated package scripts, use
147
149
 
148
150
  ## Command Model
149
151
 
152
+ `academic-research update` is a dry-run by default. It reports managed project
153
+ files that would change and writes them only with `--apply`.
154
+ Generated projects intentionally keep `npm run update` on
155
+ `create-academic-research@latest` so one command can preview migrations from an
156
+ older scaffold. Other lifecycle scripts use the package version recorded in the
157
+ project dev dependency for reproducibility.
158
+
159
+ ```bash
160
+ npm run update
161
+ npm run update -- --apply
162
+ ```
163
+
164
+ Very old projects may still have a pinned `update` script. Use the latest
165
+ generator directly in that case:
166
+
167
+ ```bash
168
+ npm exec --yes --package=create-academic-research@latest -- academic-research update --root .
169
+ npm exec --yes --package=create-academic-research@latest -- academic-research update --root . --apply
170
+ ```
171
+
172
+ Safe migrations are tracked in `.academic-research/managed-files.json`. The
173
+ manifest stores non-secret checksums for generator-owned files. If a file was
174
+ edited locally, update reports `skip` instead of overwriting it.
175
+
176
+ `academic-research init` initializes an existing repository without overwriting
177
+ existing files. It adds the research contract, merges lifecycle package scripts,
178
+ and preserves existing README, `.gitignore`, and custom package scripts.
179
+
150
180
  `academic-research setup` is a non-destructive onboarding status command. It
151
- prints the active preset, agent, skill counts, enabled MCP records, and next
181
+ prints the active preset, agent, skill counts, selected MCP records, and next
152
182
  commands without changing files.
153
183
 
154
184
  Skills are project-local by default.
@@ -167,17 +197,21 @@ MCP commands are split by side-effect:
167
197
  | Command | Meaning |
168
198
  |---|---|
169
199
  | `mcp list` | List known MCP servers with enabled/available status. |
200
+ | `mcp modes` | Show which servers can run locally, use a hosted endpoint, use a custom endpoint, require a local app, or need manual setup. |
201
+ | `mcp status` | Show friendly selected/setup/client/probe readiness and next action for each MCP server. Add `--verbose` for technical lifecycle fields. |
170
202
  | `mcp enabled` | List only enabled MCP server ids. |
171
203
  | `mcp available` | List the local MCP catalog. |
172
204
  | `mcp commands` | Print finite external install commands without running them. Runtime-only `uvx`/`npx` servers may have no install command. |
173
205
  | `mcp env` | Print required/recommended env vars, hosted endpoints, local prerequisites, and setup commands for selected servers. Use `--dotenv --all` to print dotenv content or `--write .env.example --all` to regenerate `.env.example`. |
174
- | `mcp enable` | Enable an MCP server in project records and generated snippets. |
206
+ | `mcp enable` | Select an MCP server in project records and generated snippets. Use `--mode local`, `--mode remote`, or `--mode remote-custom --url <url>` where supported. |
175
207
  | `mcp disable` | Remove an MCP server from project records and generated snippets. |
208
+ | `mcp setup` | Run or dry-run finite setup for manual-local integrations such as Overleaf. |
209
+ | `mcp client add` / `mcp client remove` | Register or remove supported MCP client entries, currently Codex, without writing secrets into client config. |
176
210
  | `mcp install` | Run finite external tool install commands for selected MCP servers. It must not launch stdio MCP servers. |
177
211
  | `mcp uninstall` | Run the external uninstall command when one exists. |
178
212
  | `mcp smoke` | Print non-launching readiness diagnostics for enabled or selected MCP servers. |
179
213
  | `mcp doctor` | Validate enabled MCP records, generated snippets, required env vars, and documented manual prerequisites. Pass `--env-file .env.local` to read explicit local secrets. |
180
- | `mcp probe` | Opt-in runtime check that starts selected MCP servers and performs a stdio JSON-RPC handshake. |
214
+ | `mcp probe` | Opt-in runtime check. Local stdio servers get a JSON-RPC handshake; remote endpoints are reported as configured without a network probe. |
181
215
 
182
216
  ## Companion Skills
183
217
 
@@ -213,19 +247,36 @@ Zotero, Overleaf, Crossref, and fallback aggregators are useful, but they need
213
247
  API keys, local apps, manual setup, or source-policy review. Enable them with
214
248
  `npm run mcp:enable -- <server>` after reading
215
249
  `docs/agent/mcp-setup.md`, use `npm run mcp:env -- <server>` to see runtime
216
- prerequisites, then run `npm run mcp:doctor`.
217
-
218
- The MCP catalog distinguishes local runtime adapters from hosted endpoints and
219
- manual integrations. arXiv and DBLP are low-friction local `uvx` runtimes.
250
+ prerequisites, then run `npm run mcp:modes`, `npm run mcp:status`, and
251
+ `npm run mcp:doctor`.
252
+
253
+ The MCP catalog uses plain modes by default:
254
+ local means your machine runs the MCP server, remote means your client connects
255
+ to an existing hosted endpoint, custom remote means you provide the endpoint,
256
+ requires local app means another desktop/service app must be running, and
257
+ manual setup means guided setup is required before client registration.
258
+ arXiv and DBLP are low-friction local `uvx` runtimes.
220
259
  Semantic Scholar is useful for citation graphs but works best with
221
260
  `SEMANTIC_SCHOLAR_API_KEY`. OpenAlex requires `OPENALEX_API_KEY` for the
222
- selected local adapter; OpenAlex keys are free and include a free daily quota,
223
- but high-volume work should check current credit limits. PubMed is a
261
+ selected local adapter, while OpenAlex and PubMed can also be selected in
262
+ remote hosted mode or a custom remote endpoint. PubMed local mode is a
224
263
  biomedical-specific `npx` runtime and remains opt-in. Zotero needs the local
225
- Zotero desktop app and Zoty setup. Overleaf is manual and credentialed.
264
+ Zotero desktop app and Zoty setup. Overleaf is a manual setup integration with
265
+ a generated safe dotenv-loading wrapper after `mcp setup`.
226
266
  Crossref and broad paper-search aggregators are kept as fallback/manual entries
227
267
  until a project explicitly needs them.
228
268
 
269
+ Codex automatic registration supports custom remote endpoints when the URL is
270
+ stored in project config with `--url`. If the endpoint URL is kept private via
271
+ `--url-env`, Codex automatic registration is not available because the Codex CLI
272
+ currently has no `--url-env` option. Either re-enable with
273
+ `--url <url>` if the endpoint URL may be stored in Codex config, or manually run
274
+ `codex mcp add <server> --url "$MCP_URL_ENV_VAR"` from a shell where the env var
275
+ is set.
276
+ An explicit `--mode remote-custom` override is not enough by itself; smoke and
277
+ probe report `missing-remote-url` until the project has either a stored URL or a
278
+ URL env var configured.
279
+
229
280
  Generated projects include a committed `.env.example` with empty MCP variables
230
281
  and ignore filled `.env` or `.env.local` files. Regenerate the example with
231
282
  `npm run mcp:dotenv`. `mcp doctor`, `mcp smoke`, and `mcp probe` check the
@@ -237,11 +288,20 @@ live tools by themselves. Your MCP client must load the generated snippet, and
237
288
  the referenced commands must be available on your machine or runnable through
238
289
  `uvx`/`npx`. `mcp install` only runs finite setup commands such as the arXiv
239
290
  tool install; it deliberately does not launch stdio MCP servers.
291
+ `mcp setup overleaf --mode local --env-file .env.local` creates a local wrapper
292
+ that loads secrets at runtime and records non-secret facts in
293
+ `docs/agent/capability-lock.json`.
294
+ `configs/capabilities.yaml` records intended project capabilities. The
295
+ capability lock records observed setup facts such as MCP setup/client/probe
296
+ state and project-local skill install/update/remove actions. The lock is
297
+ non-secret and should never contain API keys, tokens, cookies, or env values.
240
298
  Use `mcp smoke` for a non-launching readiness pass before wiring a client: it
241
299
  checks required env vars, manual/local-service status, and whether runtime
242
300
  commands are visible on `PATH`.
243
301
  Use `mcp probe` only when you intentionally want to start selected MCP server
244
- processes and verify a real stdio JSON-RPC handshake.
302
+ processes and verify a real stdio JSON-RPC handshake. Remote MCP endpoints are
303
+ not started locally; probe reports that the remote endpoint is configured and
304
+ does not perform network-dependent checks.
245
305
 
246
306
  ## Validate This Package
247
307
 
File without changes
File without changes
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_AGENT, SUPPORTED_SKILL_AGENT_TARGETS } from "./agents.js";
2
2
  import { type Runner } from "./runner.js";
3
- import { type McpToolCommandKey } from "./stack.js";
3
+ import { type McpToolCommandKey, type ResolvedMcpServer } from "./stack.js";
4
4
  import { formatMcpDotenv, listMcpEnvironmentEntries } from "./mcp-env.js";
5
5
  import { type McpProbeResult as ProbeResult } from "./mcp-probe.js";
6
6
  export { formatMcpDotenv, listMcpEnvironmentEntries };
@@ -12,6 +12,14 @@ export interface CapabilityState {
12
12
  preset: string;
13
13
  scope: "project-local";
14
14
  mcp_servers: string[];
15
+ mcp_server_modes: Record<string, string>;
16
+ mcp_server_remote: Record<string, McpRemoteConfig>;
17
+ }
18
+ export interface McpRemoteConfig {
19
+ url?: string;
20
+ url_env?: string;
21
+ transport: "streamable-http";
22
+ bearer_token_env_var?: string;
15
23
  }
16
24
  export interface InitializeCapabilitiesOptions {
17
25
  preset?: string;
@@ -23,6 +31,12 @@ export interface CapabilityCommandResult {
23
31
  count?: number;
24
32
  skills?: string[];
25
33
  servers?: string[];
34
+ skipped?: McpSkippedTool[];
35
+ }
36
+ export interface McpSkippedTool {
37
+ server: string;
38
+ reason: string;
39
+ next?: string;
26
40
  }
27
41
  export interface InstalledSkill {
28
42
  name: string;
@@ -42,6 +56,110 @@ export interface McpProbeOptions {
42
56
  env?: NodeJS.ProcessEnv;
43
57
  timeoutMs?: number;
44
58
  clientVersion?: string;
59
+ mode?: string;
60
+ }
61
+ export interface RenderedMcpSnippet {
62
+ fileName: string;
63
+ content: string;
64
+ }
65
+ export interface CapabilityLock {
66
+ version: number;
67
+ generator: {
68
+ name: "create-academic-research";
69
+ version?: string;
70
+ updated_at?: string;
71
+ };
72
+ mcp: Record<string, CapabilityLockMcpServer>;
73
+ skills: CapabilityLockSkills;
74
+ }
75
+ export interface CapabilityLockSkills {
76
+ preset?: string;
77
+ agent?: string;
78
+ explicit_skill_ids?: string[];
79
+ last_action?: "install" | "update" | "remove";
80
+ status?: "ready" | "updated" | "removed";
81
+ updated_at?: string;
82
+ sources: Record<string, CapabilityLockSkillSource>;
83
+ skills: Record<string, CapabilityLockSkillEntry>;
84
+ }
85
+ export interface CapabilityLockSkillSource {
86
+ source: string;
87
+ skill_ids?: string[];
88
+ action: "install" | "update" | "remove";
89
+ status: "ready" | "updated" | "removed";
90
+ updated_at?: string;
91
+ }
92
+ export interface CapabilityLockSkillEntry extends CapabilityLockSkillSource {
93
+ root?: string;
94
+ path?: string;
95
+ }
96
+ export interface CapabilityLockMcpServer {
97
+ selected_mode?: string;
98
+ connection_mode?: string;
99
+ setup?: {
100
+ status: "ready" | "planned" | "missing" | "skipped";
101
+ server_path?: string;
102
+ wrapper_path?: string;
103
+ env_file?: string;
104
+ updated_at?: string;
105
+ };
106
+ clients?: Record<string, {
107
+ status: "registered" | "removed" | "manual" | "unsupported";
108
+ updated_at?: string;
109
+ }>;
110
+ probe?: {
111
+ status: string;
112
+ detail: string;
113
+ updated_at?: string;
114
+ };
115
+ }
116
+ export interface McpLifecycleStatus {
117
+ servers: McpLifecycleServerStatus[];
118
+ }
119
+ export interface McpLifecycleServerStatus {
120
+ id: string;
121
+ selected: boolean;
122
+ mode: string;
123
+ mode_key: string;
124
+ connection_mode: string;
125
+ state: string;
126
+ env: "ok" | "missing-required" | "missing-recommended" | "n/a";
127
+ install: string;
128
+ snippet: "available" | "missing" | "none";
129
+ client: string;
130
+ probe: string;
131
+ next: string;
132
+ }
133
+ export interface McpLifecycleOptions {
134
+ env?: NodeJS.ProcessEnv;
135
+ }
136
+ export interface McpSetupOptions {
137
+ mode?: string;
138
+ envFile?: string;
139
+ env?: NodeJS.ProcessEnv;
140
+ dryRun?: boolean;
141
+ }
142
+ export interface McpSetupResult {
143
+ ok: boolean;
144
+ server: string;
145
+ mode: string;
146
+ commands: string[];
147
+ created: string[];
148
+ warnings: string[];
149
+ errors: string[];
150
+ next: string[];
151
+ }
152
+ export interface McpClientOptions {
153
+ agent?: string;
154
+ mode?: string;
155
+ dryRun?: boolean;
156
+ }
157
+ export interface McpClientResult {
158
+ ok: boolean;
159
+ server: string;
160
+ agent: string;
161
+ command: string[];
162
+ instructions: string[];
45
163
  }
46
164
  interface SkillInstallOptions {
47
165
  agent?: string;
@@ -59,14 +177,25 @@ export declare function removeSkills(root: string, skills: string[], runner?: Ru
59
177
  export declare function updateSkills(root: string, runner?: Runner): Promise<CapabilityCommandResult>;
60
178
  export declare function enableMcpServers(root: string, servers: string[], options?: {
61
179
  agent?: string;
180
+ mode?: string;
181
+ remote?: Partial<McpRemoteConfig>;
62
182
  }): Promise<CapabilityCommandResult>;
63
183
  export declare function disableMcpServers(root: string, servers: string[], options?: {
64
184
  agent?: string;
65
185
  }): Promise<CapabilityCommandResult>;
66
- export declare function mcpToolCommands(servers: string[], key?: McpToolCommandKey): string[][];
67
- export declare function mcpToolCommandTexts(servers: string[], key?: McpToolCommandKey): string[];
186
+ export declare function mcpToolCommands(servers: string[], key?: McpToolCommandKey, modes?: Record<string, string | undefined>): string[][];
187
+ export declare function mcpToolCommandTexts(servers: string[], key?: McpToolCommandKey, modes?: Record<string, string | undefined>): string[];
68
188
  export declare function installMcpTools(root: string, servers: string[], runner?: Runner): Promise<CapabilityCommandResult>;
69
189
  export declare function uninstallMcpTools(root: string, servers: string[], runner?: Runner): Promise<CapabilityCommandResult>;
70
190
  export declare function doctorMcpServers(root: string, options?: McpDoctorOptions): Promise<McpDoctorResult>;
71
191
  export declare function probeMcpServers(root: string, servers: string[], options?: McpProbeOptions): Promise<ProbeResult>;
192
+ export declare function renderMcpSnippet(state: CapabilityState): RenderedMcpSnippet;
193
+ export declare function renderCapabilityProfile(state: CapabilityState): string;
194
+ export declare function renderMcpSetup(state: CapabilityState): string;
195
+ export declare function getMcpLifecycleStatus(root: string, options?: McpLifecycleOptions): Promise<McpLifecycleStatus>;
196
+ export declare function readCapabilityLock(root: string): Promise<CapabilityLock>;
197
+ export declare function setupMcpServer(root: string, serverName: string, options?: McpSetupOptions, runner?: Runner): Promise<McpSetupResult>;
198
+ export declare function clientAddMcpServer(root: string, serverName: string, options?: McpClientOptions, runner?: Runner): Promise<McpClientResult>;
199
+ export declare function clientRemoveMcpServer(root: string, serverName: string, options?: McpClientOptions, runner?: Runner): Promise<McpClientResult>;
200
+ export declare function resolveMcpServerForState(state: CapabilityState, serverName: string, mode?: string): ResolvedMcpServer;
72
201
  export declare function assertKnownMcpServers(servers: string[]): void;