@dbx-tools/projen 0.9.93 → 0.9.99

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
@@ -308,6 +308,18 @@ Built-in tag mixins set runtime defaults for `shared`, `node`, `cli`, `server`,
308
308
  and `ui`. Repo-specific mixins layer package-specific dependencies,
309
309
  scripts, and generated files on top.
310
310
 
311
+ Every workspace root exposes a generic development watcher:
312
+
313
+ ```sh
314
+ bun run dev:watch [--debounce-ms 15000] [--restart-key r] <command> [args...]
315
+ ```
316
+
317
+ It restarts after watched writes have been quiet for 15 seconds. Command paths,
318
+ `--cwd`, and `--filter` identify the owning package; its transitive workspace
319
+ dependencies are watched with the shared generated/dependency/test/temp ignores.
320
+ Press the configured key for an immediate restart. The demo uses this task to
321
+ run its concrete server entrypoint; the `server` tag does not assume one.
322
+
311
323
  AppKit 0.81's `appkitServerConfig()` is the preferred tsdown preset for a
312
324
  consumer app using conventional compiled `server/agents/*/agent.ts` entries. It
313
325
  does not replace this engine's package discovery, Bun browser build, source-run
@@ -326,6 +338,22 @@ wrong fix, since the consumer authors no JSX and cannot know a transitive
326
338
  dependency started to. The option is inert without JSX in the graph: it selects
327
339
  how JSX syntax compiles and adds no lib, global, or type dependency.
328
340
 
341
+ Keep the generated tsconfigs package-local. Each package build config owns its
342
+ `rootDir`, declaration output, package-specific globals, and publish boundary.
343
+ Projen also places a no-emit config in each `test/` directory so TypeScript 6,
344
+ editors, and type-aware ESLint resolve the nearest project for test files. A
345
+ single config per runtime folder would merge package output boundaries and would
346
+ remove that nearest-config behavior. The runtime tag mixins already centralize
347
+ the environment differences without replacing the package configs.
348
+
349
+ Compilation preserves TypeScript's incremental cache. The root compile task
350
+ passes the package configs to batched `tsc --build` processes, and each config
351
+ retains its own `tsconfig.tsbuildinfo`. Synthesis also retains Projen's native
352
+ change detection: unchanged generated files are not rewritten, and dependency
353
+ installation runs only when the generated root manifest changes or
354
+ `node_modules` is absent. Repository discovery is process-cached so every child
355
+ package reuses the root probe instead of invoking `git`, `ssh`, and `gh` again.
356
+
329
357
  ## Work With Package Discovery
330
358
 
331
359
  ```ts
@@ -485,13 +513,15 @@ bun run release --publish local --install never
485
513
  bun run release --local-registry false --local-pypi auto
486
514
  bun run release --demo-deploy
487
515
  bun run release --no-release-notes
516
+ bun run release --release-notes-text "# Release 1.2.3"
517
+ bun run release --release-notes-file ./notes.md
488
518
  bun run release --release-notes-instructions "Focus on operator-visible changes."
489
519
  ```
490
520
 
491
- `--demo-deploy` is off by default. After tagging and any local registry
492
- publication it runs `bun run demo:deploy`, which stages the AppKit demo
493
- from locally compiled Node packages and locally built Python wheels, resolves
494
- the configured/default workspace profile through `@dbx-tools/auth`,
521
+ `--demo-deploy` is off by default and requires `--profile <name>`. After tagging
522
+ and any local registry publication it runs `bun run demo:deploy`, which stages
523
+ the AppKit demo from locally compiled Node packages and locally built Python
524
+ wheels, resolves only the selected workspace profile through `@dbx-tools/auth`,
495
525
  force-refreshes its token with interactive login fallback, and deploys it. That
496
526
  step is local only and is not recorded in the annotated tag.
497
527
 
@@ -500,6 +530,8 @@ After bump and configured validation, release writes
500
530
  --ephemeral -o`. The standard prompt forbids running tests or other validation
501
531
  commands. If Genie fails or writes an empty file, the step keeps going with a
502
532
  short git-log summary. `--no-release-notes` skips the file.
533
+ `--release-notes-text` writes supplied markdown directly, while
534
+ `--release-notes-file` copies a prepared markdown file. Both bypass Genie.
503
535
  `--release-notes-instructions` appends run-specific guidance to the standard
504
536
  Genie prompt. Notes are committed with the version bump and are not recorded in
505
537
  the annotated tag. They are skipped on `--no-bump` because that path requires an
@@ -510,7 +542,8 @@ already committed tree.
510
542
  installed while still regenerating versioned sources. Local release validation
511
543
  runs `eslint:fix` before branch preparation and bump, then runs the selected
512
544
  fail-closed tasks; CI remains check-only.
513
- `--no-validation` skips optional task checks locally and in CI, not version or immutable-source checks.
545
+ CI rebuilds the selected release artifacts instead of checking generated-source fingerprints.
546
+ `--no-validation` skips optional task checks locally and in CI, not workspace-version or immutable-source checks.
514
547
  `--no-docs` skips building and deploying the site, not package README validation.
515
548
  Scopes select artifacts, not the normal commit and tag-push transaction.
516
549
  The annotated tag records CI step selections, so publishing a selected scope does
@@ -576,10 +609,13 @@ release [options]
576
609
  | `--no-pypi` | skip Python build and publication, including local Python publication |
577
610
  | `--docs` | build and deploy docs for a selected scope |
578
611
  | `--no-docs` | skip documentation build and deployment |
579
- | `--no-validation` | skip optional release validation tasks; version/source checks remain mandatory |
612
+ | `--no-validation` | skip optional release validation tasks; workspace version checks remain mandatory |
580
613
  | `--no-release-notes` | skip writing docs/releases notes (Genie and git-log fallback) |
614
+ | `--release-notes-text <markdown>` | write supplied markdown without invoking Genie |
615
+ | `--release-notes-file <path>` | copy supplied markdown without invoking Genie |
581
616
  | `--release-notes-instructions <text>` | append custom instructions to the Genie release-notes prompt |
582
617
  | `--demo-deploy` | after tagging, stage and deploy the AppKit demo app (off by default) |
618
+ | `--profile <name>` | Databricks CLI profile for --demo-deploy |
583
619
  | `--no-local-publish` | skip publishing to configured local registries |
584
620
  | `--local-registry <auto\|false\|url>` | local npm registry selection (default: "auto") |
585
621
  | `--local-pypi <auto\|false\|url>` | local devpi registry selection (default: "auto") |
package/index.ts CHANGED
@@ -3,13 +3,14 @@
3
3
  // Hand edits are overwritten on the next watch; this file is read-only.
4
4
 
5
5
  export const PACKAGE_IDENTIFIER = "@dbx-tools/projen";
6
- export const PACKAGE_VERSION = "0.9.93";
6
+ export const PACKAGE_VERSION = "0.9.99";
7
7
  export * as barrels from "./src/barrels.ts";
8
8
  export * as bunApp from "./src/bun-app.ts";
9
9
  export * as bunWorkflow from "./src/bun-workflow.ts";
10
10
  export * as clean from "./src/clean.ts";
11
11
  export * as codegen from "./src/codegen.ts";
12
12
  export * as dbxToolsConfig from "./src/dbx-tools-config.ts";
13
+ export * as devWatch from "./src/dev-watch.ts";
13
14
  export * as engineRoot from "./src/engine-root.ts";
14
15
  export * as generated from "./src/generated.ts";
15
16
  export * as mixin from "./src/mixin.ts";
@@ -40,6 +41,7 @@ export { BUN_DEV_OVERRIDE, BUN_BUILD_OVERRIDE, BUN_APP_OVERRIDES, RootBunfigFile
40
41
  export { BUN_VERSION } from "./src/bun-workflow.ts";
41
42
  export { DBXToolsConfigDataSchema, DBXToolsConfig } from "./src/dbx-tools-config.ts";
42
43
  export type { DBXToolsConfigOptions, DBXToolsConfigData } from "./src/dbx-tools-config.ts";
44
+ export { DEV_WATCH_TASK, DEV_WATCH_SCRIPT, DEV_RESTART_DEBOUNCE_MS, DEV_RESTART_KEY, SERVER_WATCH_DISABLED_ENV } from "./src/dev-watch.ts";
43
45
  export { resolvePkgRoot } from "./src/engine-root.ts";
44
46
  export { PYTHON_GENERATED_PACKAGE, PYTHON_SYNC_PACKAGE } from "./src/generated.ts";
45
47
  export type { HeaderOpts } from "./src/generated.ts";
package/package.json CHANGED
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@clack/prompts": "^1.7.0",
33
- "@dbx-tools/core": "^0.9.93",
34
- "@dbx-tools/path": "^0.9.93",
35
- "@dbx-tools/shared-core": "^0.9.93",
33
+ "@dbx-tools/core": "^0.9.99",
34
+ "@dbx-tools/path": "^0.9.99",
35
+ "@dbx-tools/shared-core": "^0.9.99",
36
36
  "commander": "^15.0.0",
37
37
  "concurrently": "^10.0.3",
38
38
  "constructs": "^10.6.0",
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "main": "index.ts",
56
56
  "license": "Apache-2.0",
57
- "version": "0.9.93",
57
+ "version": "0.9.99",
58
58
  "types": "index.ts",
59
59
  "type": "module",
60
60
  "exports": {
@@ -0,0 +1,15 @@
1
+ /** Root task and CLI defaults for the generic development command watcher. */
2
+
3
+ /** Projen task exposed as `bun run dev:watch`. */
4
+ export const DEV_WATCH_TASK = "dev:watch";
5
+ /** Shipped task entrypoint invoked by {@link DEV_WATCH_TASK}. */
6
+ export const DEV_WATCH_SCRIPT = "dev-watch.ts";
7
+ /** Quiet period after the last watched change before restarting. */
8
+ export const DEV_RESTART_DEBOUNCE_MS = 15_000;
9
+ /** Interactive key that requests an immediate restart. */
10
+ export const DEV_RESTART_KEY = "r";
11
+ /**
12
+ * Process environment that skips wrapping or running the file watcher.
13
+ * Parsed with `configUtils.boolean` (`1` / `true` / `yes` disable watch).
14
+ */
15
+ export const SERVER_WATCH_DISABLED_ENV = "SERVER_WATCH_DISABLED";
@@ -109,6 +109,7 @@ const DEFAULT_ALLOW_BUILDS: AllowBuilds = {
109
109
  const DEFAULT_OVERRIDES: Readonly<Record<string, string>> = {
110
110
  bun: BUN_VERSION,
111
111
  glob: "^13.0.0",
112
+ "p-map": "7.0.8",
112
113
  };
113
114
 
114
115
  /**
package/src/project-js.ts CHANGED
@@ -12,7 +12,7 @@ import * as projectUtils from "@dbx-tools/core/project-utils";
12
12
  import { ignore, match } from "@dbx-tools/path";
13
13
  import { object, stringUtils, type OneOrMany } from "@dbx-tools/shared-core";
14
14
  import { type IConstruct } from "constructs";
15
- import { Component, LogLevel, Project, javascript, typescript } from "projen";
15
+ import { Component, LogLevel, Project, type Task, javascript, typescript } from "projen";
16
16
  import { JobPermission, type JobStep } from "projen/lib/github/workflows-model";
17
17
  import type { ReleaseProjectOptions } from "projen/lib/release";
18
18
  import { generateBarrels } from "./barrels.ts";
@@ -21,6 +21,7 @@ import { BUN_APP_OVERRIDES, RootBunfigFile } from "./bun-app.ts";
21
21
  import { BUN_VERSION } from "./bun-workflow.ts";
22
22
  import { codegenModulePaths, generateCodegen } from "./codegen.ts";
23
23
  import { DBXToolsConfig, type DBXToolsConfigOptions } from "./dbx-tools-config.ts";
24
+ import { DEV_WATCH_SCRIPT, DEV_WATCH_TASK } from "./dev-watch.ts";
24
25
  import { resolvePkgRoot } from "./engine-root.ts";
25
26
  import * as mixin from "./mixin.ts";
26
27
  import {
@@ -586,7 +587,6 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
586
587
  /** Release build prerequisites installed before repository validation tasks. */
587
588
  readonly releaseSetupSteps?: readonly JobStep[];
588
589
  /** Repository-specific synthesis commands run before release source verification. */
589
- readonly releaseSynthesisCommands?: readonly string[];
590
590
  /** Set to `false` to omit normal npm workspace publication. */
591
591
  readonly nodeRelease?: boolean;
592
592
  /** Unified dbx-tools release workflow, or no release surface. Defaults to `dbx-tools`. */
@@ -604,8 +604,9 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
604
604
  readonly extraWorkspaceMembers?: readonly string[];
605
605
  /**
606
606
  * Install workspace dependencies once from the custom root instead of once
607
- * per child project during post-synthesis. Defaults to `true`; set `false` to
608
- * preserve projen's native per-project install tasks.
607
+ * per child project during post-synthesis. Defaults to `true`; set `false`
608
+ * on the root to preserve every native child install, or on an individual
609
+ * child to retain that package's native install lifecycle.
609
610
  */
610
611
  readonly rootInstallOnly?: boolean;
611
612
  };
@@ -635,7 +636,7 @@ export class DBXToolsNodeProject
635
636
  rootTsconfig?: DBXToolsRootTsconfig;
636
637
  readonly extraWorkspaceMembers: readonly string[];
637
638
  readonly releaseBranch: string;
638
- private readonly rootInstallOnly: boolean;
639
+ readonly rootInstallOnly: boolean;
639
640
 
640
641
  constructor(options: DBXToolsJavaScriptProjectOptions = {}) {
641
642
  validateReleaseOptions(options);
@@ -683,18 +684,66 @@ export class DBXToolsNodeProject
683
684
  *
684
685
  * Every projen child has its own `NodePackage` post-synth hook, which otherwise
685
686
  * runs the install task against the same root workspace once per package. Clear
686
- * the public child install tasks while leaving dependency resolution and the
687
- * root's real install/install:ci tasks intact. Applied in root `preSynthesize`
688
- * so manually attached late children are included and repeated synths remain
689
- * idempotent.
687
+ * the public child install tasks and suppress Projen's protected install hook,
688
+ * while leaving the rest of `NodePackage.postSynthesize` (including dependency
689
+ * resolution) and the root's real install/install:ci tasks intact. A child can
690
+ * set `rootInstallOnly: false` when it owns a package-local dependency tree.
691
+ * Applied in root `preSynthesize` so manually attached late children are
692
+ * included and repeated synths remain idempotent.
690
693
  */
694
+ class RootInstallOnlyChild extends Component {
695
+ private readonly child: DBXToolsNodeProject | DBXToolsTypeScriptProject;
696
+ private readonly installDependencies: (trigger: unknown) => void;
697
+ private suppressed = false;
698
+
699
+ constructor(child: DBXToolsNodeProject | DBXToolsTypeScriptProject) {
700
+ super(child, "RootInstallOnly");
701
+ this.child = child;
702
+ const nodePackage = child.package as unknown as {
703
+ installDependencies(trigger: unknown): void;
704
+ };
705
+ if (typeof nodePackage.installDependencies !== "function") {
706
+ throw new Error("Projen NodePackage no longer exposes installDependencies");
707
+ }
708
+ this.installDependencies = nodePackage.installDependencies;
709
+ }
710
+
711
+ public override preSynthesize(): void {
712
+ const nodePackage = this.child.package as unknown as {
713
+ installDependencies(trigger: unknown): void;
714
+ };
715
+ if (
716
+ hasCustomInstallSteps(
717
+ this.child.package.installTask,
718
+ this.child.package.installAndUpdateLockfileCommand,
719
+ ) ||
720
+ hasCustomInstallSteps(this.child.package.installCiTask, this.child.package.installCommand)
721
+ ) {
722
+ if (this.suppressed) nodePackage.installDependencies = this.installDependencies;
723
+ this.suppressed = false;
724
+ return;
725
+ }
726
+ this.child.package.installTask.reset();
727
+ this.child.package.installCiTask.reset();
728
+ nodePackage.installDependencies = () => {};
729
+ this.suppressed = true;
730
+ }
731
+ }
732
+
733
+ function hasCustomInstallSteps(task: Task, defaultCommand: string): boolean {
734
+ if (task.steps.length === 0) return false;
735
+ if (task.steps.length !== 1) return true;
736
+ const step = task.steps[0]!;
737
+ return step.exec !== defaultCommand;
738
+ }
739
+
691
740
  export const ROOT_INSTALL_ONLY_MIXIN = mixin.create(
692
741
  (construct: IConstruct): construct is DBXToolsNodeProject | DBXToolsTypeScriptProject =>
693
742
  (construct instanceof DBXToolsNodeProject || construct instanceof DBXToolsTypeScriptProject) &&
694
- construct.parent !== undefined,
743
+ construct.parent !== undefined &&
744
+ construct.rootInstallOnly,
695
745
  (child) => {
696
- child.package.installTask.reset();
697
- child.package.installCiTask.reset();
746
+ if (!child.node.tryFindChild("RootInstallOnly")) new RootInstallOnlyChild(child);
698
747
  },
699
748
  );
700
749
 
@@ -716,7 +765,7 @@ export class DBXToolsTypeScriptProject
716
765
  rootTsconfig?: DBXToolsRootTsconfig;
717
766
  readonly extraWorkspaceMembers: readonly string[];
718
767
  readonly releaseBranch: string;
719
- private readonly rootInstallOnly: boolean;
768
+ readonly rootInstallOnly: boolean;
720
769
 
721
770
  constructor(options: DBXToolsTypeScriptProjectOptions) {
722
771
  validateReleaseOptions(options);
@@ -1070,6 +1119,11 @@ function resolveTags(p: DiscoveredPackage, tagPaths: Record<string, string[]>):
1070
1119
  function registerRootTasks(project: javascript.NodeProject): void {
1071
1120
  project.addTask("barrels", { execArgs: taskCommand("barrels.ts") });
1072
1121
  project.addTask("clean", { execArgs: taskCommand("clean.ts"), receiveArgs: true });
1122
+ project.addTask(DEV_WATCH_TASK, {
1123
+ description: "Restart a development command after watched changes settle",
1124
+ execArgs: taskCommand(DEV_WATCH_SCRIPT),
1125
+ receiveArgs: true,
1126
+ });
1073
1127
  project.addTask("sync", {
1074
1128
  execArgs: taskCommand("sync.ts"),
1075
1129
  receiveArgs: true,
@@ -1325,7 +1379,6 @@ function initProject(
1325
1379
  pythonRoot: options.releasePythonRoot,
1326
1380
  validationTasks: options.releaseValidationTasks,
1327
1381
  setupSteps: options.releaseSetupSteps,
1328
- synthesisCommands: options.releaseSynthesisCommands,
1329
1382
  });
1330
1383
  }
1331
1384
  }