@johndaskovsky/nightshift 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.
Files changed (41) hide show
  1. package/README.md +263 -0
  2. package/bin/nightshift.js +6 -0
  3. package/dist/cli/commands/init.d.ts +3 -0
  4. package/dist/cli/commands/init.d.ts.map +1 -0
  5. package/dist/cli/commands/init.js +97 -0
  6. package/dist/cli/commands/init.js.map +1 -0
  7. package/dist/cli/commands/update.d.ts +3 -0
  8. package/dist/cli/commands/update.d.ts.map +1 -0
  9. package/dist/cli/commands/update.js +92 -0
  10. package/dist/cli/commands/update.js.map +1 -0
  11. package/dist/cli/index.d.ts +4 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +45 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/core/config-merger.d.ts +14 -0
  16. package/dist/core/config-merger.d.ts.map +1 -0
  17. package/dist/core/config-merger.js +70 -0
  18. package/dist/core/config-merger.js.map +1 -0
  19. package/dist/core/scaffolder.d.ts +24 -0
  20. package/dist/core/scaffolder.d.ts.map +1 -0
  21. package/dist/core/scaffolder.js +54 -0
  22. package/dist/core/scaffolder.js.map +1 -0
  23. package/dist/core/templates.d.ts +10 -0
  24. package/dist/core/templates.d.ts.map +1 -0
  25. package/dist/core/templates.js +30 -0
  26. package/dist/core/templates.js.map +1 -0
  27. package/dist/index.d.ts +5 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +5 -0
  30. package/dist/index.js.map +1 -0
  31. package/package.json +36 -0
  32. package/templates/agents/nightshift-dev.md +187 -0
  33. package/templates/agents/nightshift-manager.md +192 -0
  34. package/templates/agents/nightshift-qa.md +102 -0
  35. package/templates/commands/nightshift-add-task.md +96 -0
  36. package/templates/commands/nightshift-archive.md +67 -0
  37. package/templates/commands/nightshift-create.md +85 -0
  38. package/templates/commands/nightshift-start.md +78 -0
  39. package/templates/commands/nightshift-test-task.md +88 -0
  40. package/templates/commands/nightshift-update-table.md +81 -0
  41. package/templates/opencode.jsonc +92 -0
package/README.md ADDED
@@ -0,0 +1,263 @@
1
+ ```
2
+ * . . . * . +
3
+ _ _ _ _ _ ____ _ _ __ _ *
4
+ | \ | (_) __ _| |__ | |_ / ___|| |__ (_)/ _| |_ .
5
+ | \| | |/ _` | '_ \| __| \___ \| '_ \| | |_| __| (
6
+ | |\ | | (_| | | | | |_ ___) | | | | | _| |_ *
7
+ |_| \_|_|\__, |_| |_|\__| |____/|_| |_|_|_| \__|
8
+ * |___/ . + . *
9
+ ```
10
+
11
+ Long-running unsupervised agent framework
12
+
13
+ A batch processing framework for AI agents. Define a table of items, write task instructions, and let a three-agent system (manager, dev, QA) work through them autonomously with built-in retries, self-improvement, and independent verification.
14
+
15
+ Nightshift runs inside [OpenCode](https://opencode.ai/) as a set of custom agents, commands, and skills. There is no traditional source code -- the entire framework is defined through Markdown, CSV, YAML, and JSONC configuration files.
16
+
17
+ ## How It Works
18
+
19
+ A **shift** is a batch job. It contains a CSV table of items to process and one or more task definitions that describe what to do with each item. Three agents collaborate to execute the work:
20
+
21
+ - **Manager** -- reads shift state, picks the next item, delegates to dev and QA, updates statuses. The sole writer of `table.csv`.
22
+ - **Dev** -- executes task steps on a single item, self-validates, retries up to 3 times, and refines task steps for future items.
23
+ - **QA** -- independently verifies the dev's work against validation criteria. Strictly read-only.
24
+
25
+ Each item-task moves through a state machine:
26
+
27
+ ```
28
+ todo --> in_progress --> qa --> done
29
+ \ /
30
+ -> failed
31
+ ```
32
+
33
+ ## Prerequisites
34
+
35
+ - [OpenCode](https://opencode.ai/) AI assistant
36
+
37
+ ## Installation
38
+
39
+ Install the Nightshift CLI globally:
40
+
41
+ ```bash
42
+ npm install -g @jdaskovsky/nightshift
43
+ ```
44
+
45
+ Then initialize Nightshift in your project:
46
+
47
+ ```bash
48
+ cd your-project
49
+ nightshift init
50
+ ```
51
+
52
+ This creates the `.nightshift/` and `.opencode/` directories, writes agent and command files, and merges the Nightshift agent block into `opencode.jsonc`.
53
+
54
+ To regenerate framework files after upgrading the CLI:
55
+
56
+ ```bash
57
+ nightshift update
58
+ ```
59
+
60
+ `update` overwrites the agent and command files and re-merges `opencode.jsonc` while preserving your non-Nightshift configuration. It does not touch `.nightshift/` shift data.
61
+
62
+ ## Quick Start
63
+
64
+ All commands run inside the OpenCode assistant.
65
+
66
+ ### 1. Create a shift
67
+
68
+ ```
69
+ /nightshift-create my-batch-job
70
+ ```
71
+
72
+ This scaffolds `.nightshift/my-batch-job/` with a `manager.md` and an empty `table.csv`. Add data to the table. The items should have all of the metadata needed to process the tasks.
73
+
74
+ ### 2. Add a task
75
+
76
+ ```
77
+ /nightshift-add-task my-batch-job
78
+ ```
79
+
80
+ The command asks you to describe what the agent should do, what tools it needs, step-by-step instructions, and how to verify success. It creates a task file (e.g., `create-page.md`) with three sections:
81
+
82
+ ```markdown
83
+ ## Configuration
84
+
85
+ - tools: playwright
86
+
87
+ ## Steps
88
+
89
+ 1. Navigate to {url}
90
+ 2. Click the "Add Page" button
91
+ 3. Fill in the title field with {page_title}
92
+ 4. Click "Publish"
93
+
94
+ ## Validation
95
+
96
+ - Page exists at the expected URL
97
+ - Page title matches {page_title}
98
+ ```
99
+
100
+ Steps use `{column_name}` placeholders that get substituted with each row's data at execution time.
101
+
102
+ ### 3. Add items to the table
103
+
104
+ ```
105
+ /nightshift-update-table my-batch-job
106
+ ```
107
+
108
+ Add rows with the metadata columns your tasks reference. The resulting `table.csv` looks like:
109
+
110
+ ```csv
111
+ row,url,page_title,create-page
112
+ 1,https://example.com/site1,Welcome,todo
113
+ 2,https://example.com/site2,About Us,todo
114
+ 3,https://example.com/site3,Contact,todo
115
+ ```
116
+
117
+ Each task gets a status column initialized to `todo`.
118
+
119
+ ### 4. Run the shift
120
+
121
+ ```
122
+ /nightshift-start my-batch-job
123
+ ```
124
+
125
+ The manager agent takes over: it reads the table, picks the next `todo` item, delegates to the dev agent, sends successful results to QA, updates statuses, and loops until everything is `done` or `failed`.
126
+
127
+ ### 5. Test a single task (optional)
128
+
129
+ ```
130
+ /nightshift-test-task my-batch-job
131
+ ```
132
+
133
+ Runs one task on one row through both dev and QA agents **without modifying any state**. Useful for debugging task definitions before running a full shift.
134
+
135
+ ### 6. Archive a completed shift
136
+
137
+ ```
138
+ /nightshift-archive my-batch-job
139
+ ```
140
+
141
+ Moves the shift to `.nightshift/archive/YYYY-MM-DD-my-batch-job/`.
142
+
143
+ ## Commands Reference
144
+
145
+ | Command | Purpose |
146
+ |---------|---------|
147
+ | `/nightshift-create <name>` | Scaffold a new shift directory with manager.md and table.csv |
148
+ | `/nightshift-add-task <name>` | Add a task definition to an existing shift |
149
+ | `/nightshift-update-table <name>` | Add rows, update metadata, or reset failed items |
150
+ | `/nightshift-start <name>` | Begin or resume shift execution |
151
+ | `/nightshift-test-task <name>` | Dry-run a single task on a single row |
152
+ | `/nightshift-archive <name>` | Move a completed shift to the archive |
153
+
154
+ All commands accept a shift name as an argument, or prompt interactively if omitted.
155
+
156
+ ## Shift Structure
157
+
158
+ ```
159
+ .nightshift/
160
+ my-batch-job/
161
+ manager.md # Shift config: name, task order, progress counters
162
+ table.csv # Items and their per-task statuses
163
+ create-page.md # Task definition (Configuration, Steps, Validation)
164
+ update-cms.md # Another task definition
165
+ archive/
166
+ 2026-02-08-old-job/ # Archived shift (date-prefixed)
167
+ ```
168
+
169
+ ### manager.md
170
+
171
+ Tracks task execution order and progress. Updated automatically by the manager agent.
172
+
173
+ ```markdown
174
+ ## Shift Configuration
175
+
176
+ - name: my-batch-job
177
+ - created: 2026-02-08
178
+
179
+ ## Task Order
180
+
181
+ 1. create-page
182
+ 2. update-cms
183
+
184
+ ## Progress
185
+
186
+ - Total items: 3
187
+ - Completed: 1
188
+ - Failed: 0
189
+ - Remaining: 2
190
+ ```
191
+
192
+ ### table.csv
193
+
194
+ Each row is an item. Metadata columns hold the data tasks need. Status columns (one per task) track progress.
195
+
196
+ ```csv
197
+ row,url,page_title,create-page,update-cms
198
+ 1,https://example.com/site1,Welcome,done,in_progress
199
+ 2,https://example.com/site2,About Us,todo,todo
200
+ 3,https://example.com/site3,Contact,todo,todo
201
+ ```
202
+
203
+ Status values: `todo`, `in_progress`, `qa`, `done`, `failed`.
204
+
205
+ ### Task files
206
+
207
+ Each task has three sections. Only the Steps section is modified during execution (by the dev agent's self-improvement loop).
208
+
209
+ | Section | Purpose | Mutable by Dev |
210
+ |---------|---------|----------------|
211
+ | Configuration | Declares tools and optional model | No |
212
+ | Steps | Numbered instructions with `{placeholder}` substitution | Yes |
213
+ | Validation | Independently verifiable success criteria | No |
214
+
215
+ ## Execution Details
216
+
217
+ ### Item processing order
218
+
219
+ The manager iterates rows in order, tasks in the order listed in `manager.md`. Tasks within a row are sequential -- task 2 cannot start until task 1 is `done`. A `failed` task blocks all subsequent tasks for that row.
220
+
221
+ ### Dev agent retry loop
222
+
223
+ The dev agent gets up to 3 attempts per item (1 initial + 2 retries). On each attempt it:
224
+
225
+ 1. Substitutes `{placeholder}` values from the current row
226
+ 2. Executes steps sequentially, stopping on failure
227
+ 3. Refines the Steps section based on what it learned
228
+ 4. Self-validates against the Validation criteria
229
+ 5. Retries from scratch if self-validation fails and attempts remain
230
+
231
+ Step refinements persist to the task file, so subsequent items benefit from earlier learnings.
232
+
233
+ ### QA verification
234
+
235
+ After a successful dev execution, the QA agent independently checks every validation criterion using read-only tools (file reads, grep, Playwright). It reports per-criterion pass/fail with specific evidence. All criteria must pass for `done`; any failure means `failed`.
236
+
237
+ ### Resumability
238
+
239
+ If a shift is interrupted, `/nightshift-start` picks up where it left off. The manager resets any stale `in_progress` or `qa` statuses back to `todo` on startup, then continues processing remaining items.
240
+
241
+ ### Graceful degradation
242
+
243
+ A single item failure never stops the entire shift. The manager marks the failed item and moves on to the next one.
244
+
245
+ ## Agent Permissions
246
+
247
+ | Agent | Write | Edit | Bash | Delegation | Playwright |
248
+ |-------|-------|------|------|------------|------------|
249
+ | Manager | yes | yes | denied | dev, qa only | no |
250
+ | Dev | yes | yes | `mkdir` only | none | yes |
251
+ | QA | no | no | denied | none | yes |
252
+
253
+ ## Project Layout
254
+
255
+ ```
256
+ night-shift/
257
+ opencode.jsonc # Agent definitions and permissions
258
+ .nightshift/ # Active and archived shifts
259
+ .opencode/
260
+ agent/ # Manager, dev, and QA agent instructions
261
+ command/ # Slash command definitions
262
+ ```
263
+
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+
3
+ import("../dist/cli/index.js").then((mod) => mod.run()).catch((err) => {
4
+ console.error(err);
5
+ process.exit(1);
6
+ });
@@ -0,0 +1,3 @@
1
+ import { Command } from "commander";
2
+ export declare function createInitCommand(): Command;
3
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAepC,wBAAgB,iBAAiB,IAAI,OAAO,CAiG3C"}
@@ -0,0 +1,97 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import { scaffoldDirectories, writeAgentFiles, writeCommandFiles, } from "../../core/scaffolder.js";
5
+ import { mergeOpencodeConfig } from "../../core/config-merger.js";
6
+ export function createInitCommand() {
7
+ return new Command("init")
8
+ .description("Initialize Nightshift in the current project")
9
+ .option("-f, --force", "Overwrite all files without prompting")
10
+ .option("-y, --yes", "Skip confirmation prompts")
11
+ .action(async (options) => {
12
+ const targetDir = process.cwd();
13
+ const force = options.force ?? false;
14
+ const actions = [];
15
+ const warnings = [];
16
+ let hasError = false;
17
+ console.log(chalk.bold("\nInitializing Nightshift...\n"));
18
+ // Step 1: Scaffold directories
19
+ const dirSpinner = ora("Creating directories...").start();
20
+ try {
21
+ scaffoldDirectories(targetDir);
22
+ dirSpinner.succeed("Directories created");
23
+ }
24
+ catch (err) {
25
+ dirSpinner.fail("Failed to create directories");
26
+ console.error(chalk.red(err instanceof Error ? err.message : String(err)));
27
+ process.exit(1);
28
+ }
29
+ // Step 2: Write agent files
30
+ const agentSpinner = ora("Writing agent files...").start();
31
+ try {
32
+ const result = writeAgentFiles({
33
+ targetDir,
34
+ force,
35
+ onWrite: (path, action) => actions.push({ path, action }),
36
+ });
37
+ agentSpinner.succeed(`Agent files written (${result.actions.length} files)`);
38
+ }
39
+ catch (err) {
40
+ agentSpinner.fail("Failed to write agent files");
41
+ warnings.push(`Agent files: ${err instanceof Error ? err.message : String(err)}`);
42
+ hasError = true;
43
+ }
44
+ // Step 3: Write command files
45
+ const cmdSpinner = ora("Writing command files...").start();
46
+ try {
47
+ const result = writeCommandFiles({
48
+ targetDir,
49
+ force,
50
+ onWrite: (path, action) => actions.push({ path, action }),
51
+ });
52
+ cmdSpinner.succeed(`Command files written (${result.actions.length} files)`);
53
+ }
54
+ catch (err) {
55
+ cmdSpinner.fail("Failed to write command files");
56
+ warnings.push(`Command files: ${err instanceof Error ? err.message : String(err)}`);
57
+ hasError = true;
58
+ }
59
+ // Step 4: Merge opencode.jsonc
60
+ const configSpinner = ora("Configuring opencode.jsonc...").start();
61
+ try {
62
+ const result = mergeOpencodeConfig(targetDir);
63
+ configSpinner.succeed(`opencode.jsonc ${result.action}`);
64
+ actions.push({ path: result.path, action: result.action });
65
+ }
66
+ catch (err) {
67
+ configSpinner.fail("Failed to configure opencode.jsonc");
68
+ warnings.push(`Config merge: ${err instanceof Error ? err.message : String(err)}`);
69
+ hasError = true;
70
+ }
71
+ // Summary
72
+ console.log(chalk.bold("\n--- Summary ---\n"));
73
+ if (actions.length > 0) {
74
+ for (const { path, action } of actions) {
75
+ const relativePath = path.replace(targetDir + "/", "");
76
+ const icon = action === "created" ? chalk.green("+") :
77
+ action === "updated" ? chalk.yellow("~") :
78
+ chalk.dim("-");
79
+ console.log(` ${icon} ${relativePath} (${action})`);
80
+ }
81
+ }
82
+ if (warnings.length > 0) {
83
+ console.log(chalk.yellow("\nWarnings:"));
84
+ for (const w of warnings) {
85
+ console.log(chalk.yellow(` ! ${w}`));
86
+ }
87
+ }
88
+ console.log(chalk.bold("\n--- Next Steps ---\n"));
89
+ console.log(" 1. Open your project in OpenCode");
90
+ console.log(" 2. Run " + chalk.cyan("/nightshift-create") + " to create your first shift");
91
+ console.log("");
92
+ if (hasError) {
93
+ process.exit(1);
94
+ }
95
+ });
96
+ }
97
+ //# 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,3 @@
1
+ import { Command } from "commander";
2
+ export declare function createUpdateCommand(): Command;
3
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,wBAAgB,mBAAmB,IAAI,OAAO,CA4F7C"}
@@ -0,0 +1,92 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import { scaffoldDirectories, writeAgentFiles, writeCommandFiles, } from "../../core/scaffolder.js";
5
+ import { mergeOpencodeConfig } from "../../core/config-merger.js";
6
+ export function createUpdateCommand() {
7
+ return new Command("update")
8
+ .description("Regenerate Nightshift framework files from the current CLI version")
9
+ .option("-y, --yes", "Skip confirmation prompts")
10
+ .action(async (_options) => {
11
+ const targetDir = process.cwd();
12
+ const actions = [];
13
+ const warnings = [];
14
+ let hasError = false;
15
+ console.log(chalk.bold("\nUpdating Nightshift files...\n"));
16
+ // Ensure directories exist
17
+ const dirSpinner = ora("Ensuring directories...").start();
18
+ try {
19
+ scaffoldDirectories(targetDir);
20
+ dirSpinner.succeed("Directories verified");
21
+ }
22
+ catch (err) {
23
+ dirSpinner.fail("Failed to verify directories");
24
+ console.error(chalk.red(err instanceof Error ? err.message : String(err)));
25
+ process.exit(1);
26
+ }
27
+ // Overwrite agent files
28
+ const agentSpinner = ora("Updating agent files...").start();
29
+ try {
30
+ const result = writeAgentFiles({
31
+ targetDir,
32
+ force: true,
33
+ onWrite: (path, action) => actions.push({ path, action }),
34
+ });
35
+ agentSpinner.succeed(`Agent files updated (${result.actions.length} files)`);
36
+ }
37
+ catch (err) {
38
+ agentSpinner.fail("Failed to update agent files");
39
+ warnings.push(`Agent files: ${err instanceof Error ? err.message : String(err)}`);
40
+ hasError = true;
41
+ }
42
+ // Overwrite command files
43
+ const cmdSpinner = ora("Updating command files...").start();
44
+ try {
45
+ const result = writeCommandFiles({
46
+ targetDir,
47
+ force: true,
48
+ onWrite: (path, action) => actions.push({ path, action }),
49
+ });
50
+ cmdSpinner.succeed(`Command files updated (${result.actions.length} files)`);
51
+ }
52
+ catch (err) {
53
+ cmdSpinner.fail("Failed to update command files");
54
+ warnings.push(`Command files: ${err instanceof Error ? err.message : String(err)}`);
55
+ hasError = true;
56
+ }
57
+ // Re-merge opencode.jsonc
58
+ const configSpinner = ora("Updating opencode.jsonc...").start();
59
+ try {
60
+ const result = mergeOpencodeConfig(targetDir);
61
+ configSpinner.succeed(`opencode.jsonc ${result.action}`);
62
+ actions.push({ path: result.path, action: result.action });
63
+ }
64
+ catch (err) {
65
+ configSpinner.fail("Failed to update opencode.jsonc");
66
+ warnings.push(`Config merge: ${err instanceof Error ? err.message : String(err)}`);
67
+ hasError = true;
68
+ }
69
+ // Summary
70
+ console.log(chalk.bold("\n--- Summary ---\n"));
71
+ if (actions.length > 0) {
72
+ for (const { path, action } of actions) {
73
+ const relativePath = path.replace(targetDir + "/", "");
74
+ const icon = action === "created" ? chalk.green("+") :
75
+ action === "updated" ? chalk.yellow("~") :
76
+ chalk.dim("-");
77
+ console.log(` ${icon} ${relativePath} (${action})`);
78
+ }
79
+ }
80
+ if (warnings.length > 0) {
81
+ console.log(chalk.yellow("\nWarnings:"));
82
+ for (const w of warnings) {
83
+ console.log(chalk.yellow(` ! ${w}`));
84
+ }
85
+ }
86
+ console.log(chalk.bold("\nUpdate complete.\n"));
87
+ if (hasError) {
88
+ process.exit(1);
89
+ }
90
+ });
91
+ }
92
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Command } from "commander";
2
+ export declare function createProgram(): Command;
3
+ export declare function run(): Promise<void>;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+BpC,wBAAgB,aAAa,IAAI,OAAO,CAYvC;AAED,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAGzC"}
@@ -0,0 +1,45 @@
1
+ import { Command } from "commander";
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { createInitCommand } from "./commands/init.js";
6
+ import { createUpdateCommand } from "./commands/update.js";
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ function getVersion() {
10
+ try {
11
+ // Resolve package.json relative to compiled output (dist/cli/) or source (src/cli/)
12
+ const candidates = [
13
+ resolve(__dirname, "..", "..", "package.json"),
14
+ resolve(__dirname, "..", "package.json"),
15
+ ];
16
+ for (const candidate of candidates) {
17
+ try {
18
+ const pkg = JSON.parse(readFileSync(candidate, "utf-8"));
19
+ return pkg.version ?? "0.0.0";
20
+ }
21
+ catch {
22
+ continue;
23
+ }
24
+ }
25
+ return "0.0.0";
26
+ }
27
+ catch {
28
+ return "0.0.0";
29
+ }
30
+ }
31
+ export function createProgram() {
32
+ const program = new Command();
33
+ program
34
+ .name("nightshift")
35
+ .description("CLI installer for the Nightshift AI agent orchestration framework")
36
+ .version(getVersion());
37
+ program.addCommand(createInitCommand());
38
+ program.addCommand(createUpdateCommand());
39
+ return program;
40
+ }
41
+ export async function run() {
42
+ const program = createProgram();
43
+ await program.parseAsync(process.argv);
44
+ }
45
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,oFAAoF;QACpF,MAAM,UAAU,GAAG;YACjB,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;YAC9C,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC;SACzC,CAAC;QACF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;gBACzD,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,YAAY,CAAC;SAClB,WAAW,CAAC,mEAAmE,CAAC;SAChF,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAEzB,OAAO,CAAC,UAAU,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,UAAU,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAE1C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface MergeResult {
2
+ action: "created" | "merged";
3
+ path: string;
4
+ }
5
+ /**
6
+ * Create or merge opencode.jsonc in the target project.
7
+ *
8
+ * Strategy:
9
+ * - If no file exists: copy the full template
10
+ * - If file exists: parse it, merge only the three Nightshift agent entries
11
+ * into the "agent" block, preserving everything else including comments
12
+ */
13
+ export declare function mergeOpencodeConfig(targetDir: string): MergeResult;
14
+ //# sourceMappingURL=config-merger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-merger.d.ts","sourceRoot":"","sources":["../../src/core/config-merger.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAyDlE"}
@@ -0,0 +1,70 @@
1
+ import { readFileSync, writeFileSync, existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import * as jsonc from "jsonc-parser";
4
+ import { getTemplatePath } from "./templates.js";
5
+ /** The three Nightshift agent keys */
6
+ const NIGHTSHIFT_AGENT_KEYS = [
7
+ "nightshift-manager",
8
+ "nightshift-dev",
9
+ "nightshift-qa",
10
+ ];
11
+ /**
12
+ * Create or merge opencode.jsonc in the target project.
13
+ *
14
+ * Strategy:
15
+ * - If no file exists: copy the full template
16
+ * - If file exists: parse it, merge only the three Nightshift agent entries
17
+ * into the "agent" block, preserving everything else including comments
18
+ */
19
+ export function mergeOpencodeConfig(targetDir) {
20
+ const targetPath = join(targetDir, "opencode.jsonc");
21
+ const templatePath = getTemplatePath("opencode.jsonc");
22
+ const templateContent = readFileSync(templatePath, "utf-8");
23
+ if (!existsSync(targetPath)) {
24
+ // No existing file — write the full template
25
+ writeFileSync(targetPath, templateContent, "utf-8");
26
+ return { action: "created", path: targetPath };
27
+ }
28
+ // Existing file — merge the agent block
29
+ const existingContent = readFileSync(targetPath, "utf-8");
30
+ const templateTree = jsonc.parseTree(templateContent);
31
+ const existingTree = jsonc.parseTree(existingContent);
32
+ if (!templateTree || !existingTree) {
33
+ throw new Error("Failed to parse opencode.jsonc files");
34
+ }
35
+ // Extract agent definitions from template
36
+ const templateAgents = {};
37
+ for (const key of NIGHTSHIFT_AGENT_KEYS) {
38
+ const node = jsonc.findNodeAtLocation(templateTree, ["agent", key]);
39
+ if (node) {
40
+ templateAgents[key] = jsonc.getNodeValue(node);
41
+ }
42
+ }
43
+ // Apply edits to the existing content
44
+ let result = existingContent;
45
+ // Check if "agent" key exists
46
+ const agentNode = jsonc.findNodeAtLocation(existingTree, ["agent"]);
47
+ if (!agentNode) {
48
+ // No "agent" block exists — add one with the Nightshift agents
49
+ const agentBlock = {};
50
+ for (const key of NIGHTSHIFT_AGENT_KEYS) {
51
+ agentBlock[key] = templateAgents[key];
52
+ }
53
+ const edits = jsonc.modify(result, ["agent"], agentBlock, {
54
+ formattingOptions: { tabSize: 2, insertSpaces: true, eol: "\n" },
55
+ });
56
+ result = jsonc.applyEdits(result, edits);
57
+ }
58
+ else {
59
+ // "agent" block exists — update each Nightshift agent entry
60
+ for (const key of NIGHTSHIFT_AGENT_KEYS) {
61
+ const edits = jsonc.modify(result, ["agent", key], templateAgents[key], {
62
+ formattingOptions: { tabSize: 2, insertSpaces: true, eol: "\n" },
63
+ });
64
+ result = jsonc.applyEdits(result, edits);
65
+ }
66
+ }
67
+ writeFileSync(targetPath, result, "utf-8");
68
+ return { action: "merged", path: targetPath };
69
+ }
70
+ //# sourceMappingURL=config-merger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-merger.js","sourceRoot":"","sources":["../../src/core/config-merger.ts"],"names":[],"mappings":"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"}