@lenne.tech/cli 1.23.0 → 1.24.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.
@@ -301,6 +301,18 @@ const NewCommand = {
301
301
  else {
302
302
  renameSpinner.succeed(`Renamed nest-base → ${projectDir} in projects/api`);
303
303
  }
304
+ // Flip .claude/upstream.json from the template-self default to the
305
+ // downstream shape so `/upstream-pr` can contribute core fixes back
306
+ // to nest-base. Independent of the rename above — run it even if
307
+ // the rename failed. Non-fatal when the file is absent.
308
+ const upstreamResult = (0, workspace_integration_1.reconfigureUpstreamForDownstream)({
309
+ apiDir: apiDest,
310
+ filesystem,
311
+ upstreamBranch: apiBranch,
312
+ });
313
+ if (upstreamResult.updated) {
314
+ info('Configured .claude/upstream.json for downstream contributions');
315
+ }
304
316
  }
305
317
  // Persist apiMode + frameworkMode for downstream generators.
306
318
  if (apiResult.method !== 'link') {
@@ -559,6 +559,18 @@ const NewCommand = {
559
559
  catch (err) {
560
560
  renameSpinner.warn(`Auto-rename failed (${err.message}). Run \`bun run rename ${projectDir}\` manually inside projects/api.`);
561
561
  }
562
+ // Flip .claude/upstream.json from the template-self default to the
563
+ // downstream shape so `/upstream-pr` can contribute core fixes back
564
+ // to nest-base. Independent of the rename above — run it even if the
565
+ // rename failed. Non-fatal when the file is absent.
566
+ const upstreamResult = (0, workspace_integration_1.reconfigureUpstreamForDownstream)({
567
+ apiDir: apiDest,
568
+ filesystem,
569
+ upstreamBranch: apiBranch,
570
+ });
571
+ if (upstreamResult.updated) {
572
+ info('Configured .claude/upstream.json for downstream contributions');
573
+ }
562
574
  }
563
575
  // Create lt.config.json for API
564
576
  // Note: frameworkMode is persisted under meta so that subsequent `lt
@@ -376,9 +376,25 @@ const NewCommand = {
376
376
  }
377
377
  return `created server symlink ${name}`;
378
378
  }
379
- // Git initialization (after npm install which is done in setupServer)
379
+ // For the experimental nest-base template, flip .claude/upstream.json
380
+ // from the template-self default to the downstream shape so
381
+ // `/upstream-pr` can contribute core fixes back to nest-base. The
382
+ // standalone clone lands directly at `projectDir`. Non-fatal when the
383
+ // file is absent (older templates).
384
+ if (experimental) {
385
+ const upstreamResult = (0, workspace_integration_1.reconfigureUpstreamForDownstream)({
386
+ apiDir: projectDir,
387
+ filesystem,
388
+ upstreamBranch: branch,
389
+ });
390
+ if (upstreamResult.updated) {
391
+ info('Configured .claude/upstream.json for downstream contributions');
392
+ }
393
+ }
394
+ // Git initialization (after npm install which is done in setupServer).
395
+ // When cwd is not inside a repo, `git rev-parse` exits 128 — treat as false.
380
396
  if (git) {
381
- const inGit = (_2 = (yield system.run('git rev-parse --is-inside-work-tree'))) === null || _2 === void 0 ? void 0 : _2.trim();
397
+ const inGit = (_2 = (yield system.run('git rev-parse --is-inside-work-tree 2>/dev/null || echo false'))) === null || _2 === void 0 ? void 0 : _2.trim();
382
398
  if (inGit !== 'true') {
383
399
  // Determine initGit with priority: CLI > config > interactive
384
400
  let initializeGit;
@@ -40,6 +40,7 @@ exports.detectSubProjectContext = detectSubProjectContext;
40
40
  exports.detectWorkspaceLayout = detectWorkspaceLayout;
41
41
  exports.findWorkspaceRoot = findWorkspaceRoot;
42
42
  exports.isNonInteractive = isNonInteractive;
43
+ exports.reconfigureUpstreamForDownstream = reconfigureUpstreamForDownstream;
43
44
  exports.runExperimentalNestBaseRename = runExperimentalNestBaseRename;
44
45
  exports.runStandaloneWorkspaceGate = runStandaloneWorkspaceGate;
45
46
  exports.shouldProceedAsStandalone = shouldProceedAsStandalone;
@@ -140,6 +141,60 @@ function isNonInteractive(noConfirmFlag) {
140
141
  // process.stdin may be undefined in some test runners — guard.
141
142
  return Boolean(process.stdin && process.stdin.isTTY === false);
142
143
  }
144
+ /**
145
+ * Reconfigure the cloned nest-base template's `.claude/upstream.json`
146
+ * into its downstream shape.
147
+ *
148
+ * WHY: nest-base ships `.claude/upstream.json` with `isTemplate: true`
149
+ * and `upstream: null` — the template-self default. The `/upstream-pr`
150
+ * slash command and the `contributing-upstream` skill key off
151
+ * `isTemplate` and refuse to open upstream PRs when it is still `true`
152
+ * ("this repo IS the template"). The template's own notes document a
153
+ * manual post-fork step (flip `isTemplate` to false, fill `upstream`)
154
+ * that humans and agents both forget. The `bun run rename` step only
155
+ * rewrites four files and never touches this one, so without this
156
+ * helper every scaffolded project keeps `isTemplate: true` and can
157
+ * never contribute core fixes back to nest-base.
158
+ *
159
+ * Behaviour:
160
+ * - Missing file (or unparseable JSON) → `{ updated: false }`, no
161
+ * throw. Older templates may not ship the file at all; that is not
162
+ * an error, just nothing to do.
163
+ * - Otherwise sets `isTemplate = false` and
164
+ * `upstream = { repo, branch }`, preserving `$schema` and
165
+ * `syncedPaths` exactly as the template defined them.
166
+ *
167
+ * Idempotent: running twice yields identical output.
168
+ */
169
+ function reconfigureUpstreamForDownstream(options) {
170
+ const { apiDir, filesystem, upstreamBranch, upstreamRepo } = options;
171
+ const upstreamPath = filesystem.path(apiDir, '.claude', 'upstream.json');
172
+ // Non-fatal when absent — older templates may not ship the file.
173
+ if (filesystem.exists(upstreamPath) !== 'file') {
174
+ return { updated: false };
175
+ }
176
+ const current = filesystem.read(upstreamPath, 'json');
177
+ if (!current) {
178
+ // Unparseable / empty JSON — leave it untouched rather than risk
179
+ // clobbering hand-edited content with a guessed shape.
180
+ return { updated: false };
181
+ }
182
+ const next = Object.assign(Object.assign({}, current), {
183
+ // The whole point of the fix: this is a fork, not the template.
184
+ isTemplate: false,
185
+ // Replace the template-self notes (no longer applicable) with a
186
+ // short downstream-appropriate marker. Kept as a fixed array so the
187
+ // operation is idempotent.
188
+ notes: [
189
+ 'Downstream project forked from the nest-base template.',
190
+ 'Core fixes flow back upstream via the /upstream-pr command.',
191
+ ], upstream: {
192
+ branch: upstreamBranch !== null && upstreamBranch !== void 0 ? upstreamBranch : 'main',
193
+ repo: upstreamRepo !== null && upstreamRepo !== void 0 ? upstreamRepo : 'lenneTech/nest-base',
194
+ } });
195
+ filesystem.write(upstreamPath, next, { jsonIndent: 2 });
196
+ return { updated: true };
197
+ }
143
198
  /**
144
199
  * Run the experimental `bun run rename <projectDir>` step. Only relevant
145
200
  * for the `--next` nest-base template (it ships hard-coded `nest-base`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lenne.tech/cli",
3
- "version": "1.23.0",
3
+ "version": "1.24.1",
4
4
  "description": "lenne.Tech CLI: lt",
5
5
  "keywords": [
6
6
  "lenne.Tech",