sidecar-cli 0.1.3 → 0.1.4-rc.1
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 +32 -2
- package/dist/cli.js +21 -1
- package/dist/lib/instructions.js +40 -0
- package/dist/lib/paths.js +1 -0
- package/dist/services/capabilities-service.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -85,12 +85,41 @@ npm run dev -- --help
|
|
|
85
85
|
|
|
86
86
|
## Quick start
|
|
87
87
|
|
|
88
|
-
Initialize in a project directory:
|
|
88
|
+
1. Initialize in a project directory:
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
91
|
sidecar init
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
2. (Optional) Define shared instruction templates once:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
mkdir -p ~/.sidecar-cli/instructions
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Create template files such as:
|
|
101
|
+
|
|
102
|
+
- `~/.sidecar-cli/instructions/web-app.md`
|
|
103
|
+
- `~/.sidecar-cli/instructions/desktop-app.md`
|
|
104
|
+
|
|
105
|
+
3. Initialize with a shared template (writes project `instructions.md`):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
sidecar init --instructions-template web-app
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Or load directly from a specific file:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
sidecar init --instructions-file /absolute/path/to/instructions.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Notes:
|
|
118
|
+
|
|
119
|
+
- `--instructions-template <name>` resolves to `~/.sidecar-cli/instructions/<name>.md`.
|
|
120
|
+
- Use either `--instructions-template` or `--instructions-file` (not both).
|
|
121
|
+
- If `instructions.md` already exists, Sidecar will not overwrite it unless `--force` is used.
|
|
122
|
+
|
|
94
123
|
This creates:
|
|
95
124
|
|
|
96
125
|
- `.sidecar/sidecar.db`
|
|
@@ -100,6 +129,7 @@ This creates:
|
|
|
100
129
|
- `.sidecar/summary.md`
|
|
101
130
|
- `AGENTS.md` (repo root)
|
|
102
131
|
- `CLAUDE.md` (repo root)
|
|
132
|
+
- `instructions.md` (repo root, only when `--instructions-template` or `--instructions-file` is provided)
|
|
103
133
|
|
|
104
134
|
Use `--force` to overwrite Sidecar-managed files.
|
|
105
135
|
|
|
@@ -107,7 +137,7 @@ Use `--force` to overwrite Sidecar-managed files.
|
|
|
107
137
|
|
|
108
138
|
Global:
|
|
109
139
|
|
|
110
|
-
- `sidecar init [--force] [--name <project-name>] [--json]`
|
|
140
|
+
- `sidecar init [--force] [--name <project-name>] [--instructions-template <name>] [--instructions-file <path>] [--json]`
|
|
111
141
|
- `sidecar status [--json]`
|
|
112
142
|
- `sidecar preferences show [--json]`
|
|
113
143
|
- `sidecar ui [--no-open] [--port <port>] [--install-only] [--project <path>] [--reinstall]`
|
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { initializeSchema } from './db/schema.js';
|
|
|
9
9
|
import { findSidecarRoot, getSidecarPaths } from './lib/paths.js';
|
|
10
10
|
import { nowIso, humanTime, stringifyJson } from './lib/format.js';
|
|
11
11
|
import { SidecarError } from './lib/errors.js';
|
|
12
|
+
import { GLOBAL_INSTRUCTIONS_DIR, resolveInstructionsSource } from './lib/instructions.js';
|
|
12
13
|
import { jsonFailure, jsonSuccess, printJsonEnvelope } from './lib/output.js';
|
|
13
14
|
import { bannerDisabled, renderBanner } from './lib/banner.js';
|
|
14
15
|
import { getUpdateNotice } from './lib/update-check.js';
|
|
@@ -279,14 +280,21 @@ program
|
|
|
279
280
|
.description('Initialize Sidecar in the current directory')
|
|
280
281
|
.option('--force', 'Overwrite Sidecar files if they already exist')
|
|
281
282
|
.option('--name <project-name>', 'Project name (defaults to current directory name)')
|
|
283
|
+
.option('--instructions-template <name>', `Load instructions template by name from ${GLOBAL_INSTRUCTIONS_DIR} (example: "web-app")`)
|
|
284
|
+
.option('--instructions-file <path>', 'Load instructions from a specific markdown file path')
|
|
282
285
|
.option('--json', 'Print machine-readable JSON output')
|
|
283
|
-
.addHelpText('after', '\nExamples:\n $ sidecar init\n $ sidecar init --name "My Project"\n $ sidecar init --force --json')
|
|
286
|
+
.addHelpText('after', '\nExamples:\n $ sidecar init\n $ sidecar init --name "My Project"\n $ sidecar init --instructions-template web-app\n $ sidecar init --instructions-file ~/.sidecar-cli/instructions/desktop.md\n $ sidecar init --force --json')
|
|
284
287
|
.action((opts) => {
|
|
285
288
|
const command = 'init';
|
|
286
289
|
try {
|
|
287
290
|
const rootPath = process.cwd();
|
|
288
291
|
const sidecar = getSidecarPaths(rootPath);
|
|
289
292
|
const projectName = opts.name?.trim() || path.basename(rootPath);
|
|
293
|
+
const resolvedInstructions = resolveInstructionsSource({
|
|
294
|
+
templateName: opts.instructionsTemplate,
|
|
295
|
+
sourcePath: opts.instructionsFile,
|
|
296
|
+
cwd: rootPath,
|
|
297
|
+
});
|
|
290
298
|
if (fs.existsSync(sidecar.sidecarPath)) {
|
|
291
299
|
const stat = fs.lstatSync(sidecar.sidecarPath);
|
|
292
300
|
if (stat.isSymbolicLink()) {
|
|
@@ -315,6 +323,13 @@ program
|
|
|
315
323
|
files.push(sidecar.rootAgentsPath);
|
|
316
324
|
if (shouldWriteRootClaude)
|
|
317
325
|
files.push(sidecar.rootClaudePath);
|
|
326
|
+
if (resolvedInstructions) {
|
|
327
|
+
const canWriteInstructions = Boolean(opts.force) || !fs.existsSync(sidecar.rootInstructionsPath);
|
|
328
|
+
if (!canWriteInstructions) {
|
|
329
|
+
fail(`Refusing to overwrite ${sidecar.rootInstructionsPath}. Re-run with --force or choose another destination.`);
|
|
330
|
+
}
|
|
331
|
+
files.push(sidecar.rootInstructionsPath);
|
|
332
|
+
}
|
|
318
333
|
fs.mkdirSync(sidecar.sidecarPath, { recursive: true });
|
|
319
334
|
if (opts.force) {
|
|
320
335
|
for (const file of [
|
|
@@ -365,6 +380,9 @@ program
|
|
|
365
380
|
if (shouldWriteRootClaude) {
|
|
366
381
|
fs.writeFileSync(sidecar.rootClaudePath, renderClaudeMarkdown(projectName));
|
|
367
382
|
}
|
|
383
|
+
if (resolvedInstructions) {
|
|
384
|
+
fs.writeFileSync(sidecar.rootInstructionsPath, resolvedInstructions.content);
|
|
385
|
+
}
|
|
368
386
|
const db2 = new DatabaseSync(sidecar.dbPath);
|
|
369
387
|
const refreshed = refreshSummaryFile(db2, rootPath, 1, 10);
|
|
370
388
|
db2.close();
|
|
@@ -374,6 +392,7 @@ program
|
|
|
374
392
|
projectName,
|
|
375
393
|
filesCreated: files,
|
|
376
394
|
summaryGeneratedAt: refreshed.generatedAt,
|
|
395
|
+
instructionsSource: resolvedInstructions?.sourceLabel ?? null,
|
|
377
396
|
timestamp: nowIso(),
|
|
378
397
|
};
|
|
379
398
|
const shouldShowBanner = !opts.json && !bannerDisabled();
|
|
@@ -386,6 +405,7 @@ program
|
|
|
386
405
|
'Sidecar provides local project memory for decisions, work logs, tasks, and summaries.',
|
|
387
406
|
'Created:',
|
|
388
407
|
...data.filesCreated.map((f) => `- ${f}`),
|
|
408
|
+
...(resolvedInstructions ? ['', `Loaded instructions.md from ${resolvedInstructions.sourceLabel}`] : []),
|
|
389
409
|
'',
|
|
390
410
|
'Next step:',
|
|
391
411
|
'sidecar context',
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { SidecarError } from './errors.js';
|
|
5
|
+
export const GLOBAL_INSTRUCTIONS_DIR = path.join(os.homedir(), '.sidecar-cli', 'instructions');
|
|
6
|
+
function readInstructionsFile(sourcePath, sourceLabel) {
|
|
7
|
+
if (!fs.existsSync(sourcePath)) {
|
|
8
|
+
throw new SidecarError(`Instructions source not found: ${sourcePath}`);
|
|
9
|
+
}
|
|
10
|
+
const stat = fs.statSync(sourcePath);
|
|
11
|
+
if (!stat.isFile()) {
|
|
12
|
+
throw new SidecarError(`Instructions source is not a file: ${sourcePath}`);
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
sourcePath,
|
|
16
|
+
sourceLabel,
|
|
17
|
+
content: fs.readFileSync(sourcePath, 'utf8'),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function resolveInstructionsSource(opts) {
|
|
21
|
+
const templateName = opts.templateName?.trim();
|
|
22
|
+
const sourcePath = opts.sourcePath?.trim();
|
|
23
|
+
if (!templateName && !sourcePath)
|
|
24
|
+
return null;
|
|
25
|
+
if (templateName && sourcePath) {
|
|
26
|
+
throw new SidecarError('Use only one option: --instructions-template or --instructions-file.');
|
|
27
|
+
}
|
|
28
|
+
if (sourcePath) {
|
|
29
|
+
const resolvedPath = path.resolve(opts.cwd, sourcePath);
|
|
30
|
+
return readInstructionsFile(resolvedPath, `file:${resolvedPath}`);
|
|
31
|
+
}
|
|
32
|
+
const fileName = templateName?.endsWith('.md') ? templateName : `${templateName}.md`;
|
|
33
|
+
if (!fileName)
|
|
34
|
+
return null;
|
|
35
|
+
const globalPath = path.join(GLOBAL_INSTRUCTIONS_DIR, fileName);
|
|
36
|
+
if (!fs.existsSync(globalPath)) {
|
|
37
|
+
throw new SidecarError(`Instructions template "${templateName}" not found at ${globalPath}. Create it under ${GLOBAL_INSTRUCTIONS_DIR}.`);
|
|
38
|
+
}
|
|
39
|
+
return readInstructionsFile(globalPath, `template:${templateName}`);
|
|
40
|
+
}
|
package/dist/lib/paths.js
CHANGED
|
@@ -11,6 +11,7 @@ export function getSidecarPaths(rootPath) {
|
|
|
11
11
|
promptsPath: path.join(sidecarPath, 'prompts'),
|
|
12
12
|
rootAgentsPath: path.join(rootPath, 'AGENTS.md'),
|
|
13
13
|
rootClaudePath: path.join(rootPath, 'CLAUDE.md'),
|
|
14
|
+
rootInstructionsPath: path.join(rootPath, 'instructions.md'),
|
|
14
15
|
dbPath: path.join(sidecarPath, 'sidecar.db'),
|
|
15
16
|
configPath: path.join(sidecarPath, 'config.json'),
|
|
16
17
|
preferencesPath: path.join(sidecarPath, 'preferences.json'),
|
|
@@ -22,7 +22,7 @@ export function getCapabilitiesManifest(version) {
|
|
|
22
22
|
description: 'Initialize Sidecar in the current directory',
|
|
23
23
|
json_output: true,
|
|
24
24
|
arguments: [],
|
|
25
|
-
options: ['--force', '--name <project-name>', '--json'],
|
|
25
|
+
options: ['--force', '--name <project-name>', '--instructions-template <name>', '--instructions-file <path>', '--json'],
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
28
|
name: 'status',
|