@decohere/scaffold 0.0.1-dev.100

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 (208) hide show
  1. package/commonjs/src/add-api.action.js +37 -0
  2. package/commonjs/src/add-api.command.js +39 -0
  3. package/commonjs/src/add.command.js +22 -0
  4. package/commonjs/src/add.module.js +24 -0
  5. package/commonjs/src/auth0-configure.action.js +28 -0
  6. package/commonjs/src/auth0-configure.command.js +24 -0
  7. package/commonjs/src/auth0-login.action.js +28 -0
  8. package/commonjs/src/auth0-login.command.js +23 -0
  9. package/commonjs/src/auth0.command.js +22 -0
  10. package/commonjs/src/auth0.module.js +28 -0
  11. package/commonjs/src/cli.js +7 -0
  12. package/commonjs/src/create.command.js +22 -0
  13. package/commonjs/src/create.module.js +24 -0
  14. package/commonjs/src/domain/prompt.js +62 -0
  15. package/commonjs/src/index.js +48 -0
  16. package/commonjs/src/models/compose.model.js +258 -0
  17. package/commonjs/src/models/config-yaml.model.js +86 -0
  18. package/commonjs/src/models/const.js +30 -0
  19. package/commonjs/src/models/dev-container.model.js +172 -0
  20. package/commonjs/src/models/docker-image.model.js +277 -0
  21. package/commonjs/src/models/env-file.model.js +48 -0
  22. package/commonjs/src/models/gitignore.model.js +48 -0
  23. package/commonjs/src/models/launch-json.model.js +70 -0
  24. package/commonjs/src/models/package-json.model.js +156 -0
  25. package/commonjs/src/models/project.model.js +132 -0
  26. package/commonjs/src/models/source-file.js +4 -0
  27. package/commonjs/src/models/tsconfig.model.js +32 -0
  28. package/commonjs/src/models/vitest-config.model.js +33 -0
  29. package/commonjs/src/models/vscode-settings.model.js +29 -0
  30. package/commonjs/src/program.js +64 -0
  31. package/commonjs/src/resolve-target-dir.js +17 -0
  32. package/commonjs/src/services/scaffold.service.js +60 -0
  33. package/commonjs/src/version.js +55 -0
  34. package/commonjs/src/webapi/api-name.js +93 -0
  35. package/commonjs/src/webapi/auth0-commands.js +250 -0
  36. package/commonjs/src/webapi/authorize-scopes.js +79 -0
  37. package/commonjs/src/webapi/cli-options.js +99 -0
  38. package/commonjs/src/webapi/const.js +54 -0
  39. package/commonjs/src/webapi/create-api.js +265 -0
  40. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.js +164 -0
  41. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  42. package/commonjs/src/webapi/devcontainer/host-scripts.js +50 -0
  43. package/commonjs/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  44. package/commonjs/src/webapi/devcontainer/templates/initialize.sh +169 -0
  45. package/commonjs/src/webapi/devcontainer/templates/post-create.sh +35 -0
  46. package/commonjs/src/webapi/devcontainer/templates/post-start.sh +65 -0
  47. package/commonjs/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  48. package/commonjs/src/webapi/features/auth.feature.js +408 -0
  49. package/commonjs/src/webapi/features/auth0-cli.js +472 -0
  50. package/commonjs/src/webapi/features/biome-format.js +47 -0
  51. package/commonjs/src/webapi/features/database.feature.js +432 -0
  52. package/commonjs/src/webapi/features/finalize.feature.js +93 -0
  53. package/commonjs/src/webapi/features/postman.feature.js +322 -0
  54. package/commonjs/src/webapi/models/api-package-json.model.js +58 -0
  55. package/commonjs/src/webapi/models/auth-config.model.js +24 -0
  56. package/commonjs/src/webapi/models/controller-source-file.model.js +190 -0
  57. package/commonjs/src/webapi/models/github-ci.model.js +193 -0
  58. package/commonjs/src/webapi/models/main-source-file.model.js +165 -0
  59. package/commonjs/src/webapi/models/production-dockerfile.model.js +75 -0
  60. package/commonjs/src/webapi/models/sample-files.model.js +58 -0
  61. package/commonjs/src/webapi/models/webapi-image.model.js +25 -0
  62. package/commonjs/src/webapi/postman/hello-openapi.js +173 -0
  63. package/commonjs/src/webapi/postman/local-view.js +182 -0
  64. package/commonjs/src/webapi/postman/openapi-to-postman.js +200 -0
  65. package/commonjs/src/webapi/workspace-readme.js +109 -0
  66. package/commonjs/src/webapi.action.js +28 -0
  67. package/commonjs/src/webapi.command.js +43 -0
  68. package/es6/src/add-api.action.js +27 -0
  69. package/es6/src/add-api.command.js +29 -0
  70. package/es6/src/add.command.js +12 -0
  71. package/es6/src/add.module.js +14 -0
  72. package/es6/src/auth0-configure.action.js +18 -0
  73. package/es6/src/auth0-configure.command.js +14 -0
  74. package/es6/src/auth0-login.action.js +18 -0
  75. package/es6/src/auth0-login.command.js +13 -0
  76. package/es6/src/auth0.command.js +12 -0
  77. package/es6/src/auth0.module.js +18 -0
  78. package/es6/src/cli.js +3 -0
  79. package/es6/src/create.command.js +12 -0
  80. package/es6/src/create.module.js +14 -0
  81. package/es6/src/domain/prompt.js +41 -0
  82. package/es6/src/index.js +9 -0
  83. package/es6/src/models/compose.model.js +254 -0
  84. package/es6/src/models/config-yaml.model.js +74 -0
  85. package/es6/src/models/const.js +20 -0
  86. package/es6/src/models/dev-container.model.js +162 -0
  87. package/es6/src/models/docker-image.model.js +235 -0
  88. package/es6/src/models/env-file.model.js +44 -0
  89. package/es6/src/models/gitignore.model.js +38 -0
  90. package/es6/src/models/launch-json.model.js +60 -0
  91. package/es6/src/models/package-json.model.js +141 -0
  92. package/es6/src/models/project.model.js +117 -0
  93. package/es6/src/models/source-file.js +1 -0
  94. package/es6/src/models/tsconfig.model.js +22 -0
  95. package/es6/src/models/vitest-config.model.js +23 -0
  96. package/es6/src/models/vscode-settings.model.js +19 -0
  97. package/es6/src/program.js +46 -0
  98. package/es6/src/resolve-target-dir.js +7 -0
  99. package/es6/src/services/scaffold.service.js +50 -0
  100. package/es6/src/version.js +34 -0
  101. package/es6/src/webapi/api-name.js +57 -0
  102. package/es6/src/webapi/auth0-commands.js +185 -0
  103. package/es6/src/webapi/authorize-scopes.js +55 -0
  104. package/es6/src/webapi/cli-options.js +34 -0
  105. package/es6/src/webapi/const.js +21 -0
  106. package/es6/src/webapi/create-api.js +245 -0
  107. package/es6/src/webapi/devcontainer/codebase-rag-mcp.js +154 -0
  108. package/es6/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  109. package/es6/src/webapi/devcontainer/host-scripts.js +29 -0
  110. package/es6/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  111. package/es6/src/webapi/devcontainer/templates/initialize.sh +169 -0
  112. package/es6/src/webapi/devcontainer/templates/post-create.sh +35 -0
  113. package/es6/src/webapi/devcontainer/templates/post-start.sh +65 -0
  114. package/es6/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  115. package/es6/src/webapi/features/auth.feature.js +357 -0
  116. package/es6/src/webapi/features/auth0-cli.js +406 -0
  117. package/es6/src/webapi/features/biome-format.js +40 -0
  118. package/es6/src/webapi/features/database.feature.js +422 -0
  119. package/es6/src/webapi/features/finalize.feature.js +83 -0
  120. package/es6/src/webapi/features/postman.feature.js +256 -0
  121. package/es6/src/webapi/models/api-package-json.model.js +53 -0
  122. package/es6/src/webapi/models/auth-config.model.js +20 -0
  123. package/es6/src/webapi/models/controller-source-file.model.js +181 -0
  124. package/es6/src/webapi/models/github-ci.model.js +186 -0
  125. package/es6/src/webapi/models/main-source-file.model.js +161 -0
  126. package/es6/src/webapi/models/production-dockerfile.model.js +66 -0
  127. package/es6/src/webapi/models/sample-files.model.js +40 -0
  128. package/es6/src/webapi/models/webapi-image.model.js +18 -0
  129. package/es6/src/webapi/postman/hello-openapi.js +166 -0
  130. package/es6/src/webapi/postman/local-view.js +167 -0
  131. package/es6/src/webapi/postman/openapi-to-postman.js +177 -0
  132. package/es6/src/webapi/workspace-readme.js +88 -0
  133. package/es6/src/webapi.action.js +18 -0
  134. package/es6/src/webapi.command.js +33 -0
  135. package/package.json +36 -0
  136. package/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  137. package/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  138. package/src/webapi/devcontainer/templates/initialize.sh +169 -0
  139. package/src/webapi/devcontainer/templates/post-create.sh +35 -0
  140. package/src/webapi/devcontainer/templates/post-start.sh +65 -0
  141. package/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  142. package/types/src/add-api.action.d.ts +13 -0
  143. package/types/src/add-api.command.d.ts +7 -0
  144. package/types/src/add.command.d.ts +6 -0
  145. package/types/src/add.module.d.ts +14 -0
  146. package/types/src/auth0-configure.action.d.ts +7 -0
  147. package/types/src/auth0-configure.command.d.ts +6 -0
  148. package/types/src/auth0-login.action.d.ts +4 -0
  149. package/types/src/auth0-login.command.d.ts +6 -0
  150. package/types/src/auth0.command.d.ts +6 -0
  151. package/types/src/auth0.module.d.ts +18 -0
  152. package/types/src/cli.d.ts +2 -0
  153. package/types/src/create.command.d.ts +6 -0
  154. package/types/src/create.module.d.ts +14 -0
  155. package/types/src/domain/prompt.d.ts +4 -0
  156. package/types/src/index.d.ts +13 -0
  157. package/types/src/models/compose.model.d.ts +73 -0
  158. package/types/src/models/config-yaml.model.d.ts +27 -0
  159. package/types/src/models/const.d.ts +20 -0
  160. package/types/src/models/dev-container.model.d.ts +49 -0
  161. package/types/src/models/docker-image.model.d.ts +90 -0
  162. package/types/src/models/env-file.model.d.ts +16 -0
  163. package/types/src/models/gitignore.model.d.ts +9 -0
  164. package/types/src/models/launch-json.model.d.ts +7 -0
  165. package/types/src/models/package-json.model.d.ts +36 -0
  166. package/types/src/models/project.model.d.ts +60 -0
  167. package/types/src/models/source-file.d.ts +11 -0
  168. package/types/src/models/tsconfig.model.d.ts +5 -0
  169. package/types/src/models/vitest-config.model.d.ts +5 -0
  170. package/types/src/models/vscode-settings.model.d.ts +7 -0
  171. package/types/src/program.d.ts +3 -0
  172. package/types/src/resolve-target-dir.d.ts +5 -0
  173. package/types/src/services/scaffold.service.d.ts +22 -0
  174. package/types/src/version.d.ts +6 -0
  175. package/types/src/webapi/api-name.d.ts +14 -0
  176. package/types/src/webapi/auth0-commands.d.ts +11 -0
  177. package/types/src/webapi/authorize-scopes.d.ts +7 -0
  178. package/types/src/webapi/cli-options.d.ts +6 -0
  179. package/types/src/webapi/const.d.ts +19 -0
  180. package/types/src/webapi/create-api.d.ts +15 -0
  181. package/types/src/webapi/devcontainer/codebase-rag-mcp.d.ts +32 -0
  182. package/types/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  183. package/types/src/webapi/devcontainer/host-scripts.d.ts +7 -0
  184. package/types/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  185. package/types/src/webapi/devcontainer/templates/initialize.sh +169 -0
  186. package/types/src/webapi/devcontainer/templates/post-create.sh +35 -0
  187. package/types/src/webapi/devcontainer/templates/post-start.sh +65 -0
  188. package/types/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  189. package/types/src/webapi/features/auth.feature.d.ts +10 -0
  190. package/types/src/webapi/features/auth0-cli.d.ts +84 -0
  191. package/types/src/webapi/features/biome-format.d.ts +5 -0
  192. package/types/src/webapi/features/database.feature.d.ts +7 -0
  193. package/types/src/webapi/features/finalize.feature.d.ts +2 -0
  194. package/types/src/webapi/features/postman.feature.d.ts +16 -0
  195. package/types/src/webapi/models/api-package-json.model.d.ts +18 -0
  196. package/types/src/webapi/models/auth-config.model.d.ts +26 -0
  197. package/types/src/webapi/models/controller-source-file.model.d.ts +46 -0
  198. package/types/src/webapi/models/github-ci.model.d.ts +9 -0
  199. package/types/src/webapi/models/main-source-file.model.d.ts +54 -0
  200. package/types/src/webapi/models/production-dockerfile.model.d.ts +18 -0
  201. package/types/src/webapi/models/sample-files.model.d.ts +7 -0
  202. package/types/src/webapi/models/webapi-image.model.d.ts +12 -0
  203. package/types/src/webapi/postman/hello-openapi.d.ts +19 -0
  204. package/types/src/webapi/postman/local-view.d.ts +17 -0
  205. package/types/src/webapi/postman/openapi-to-postman.d.ts +62 -0
  206. package/types/src/webapi/workspace-readme.d.ts +18 -0
  207. package/types/src/webapi.action.d.ts +14 -0
  208. package/types/src/webapi.command.d.ts +11 -0
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env bash
2
+ # Runs on the host before the container is created (devcontainer initializeCommand).
3
+ # Creates bind-mount sources as the host user so Docker does not create them as root.
4
+ # Optional npm / gh / MCP setup is y/N on a TTY; no TTY skips.
5
+ set -euo pipefail
6
+
7
+ root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
+ here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ # shellcheck source=tty-prompt.sh
10
+ source "$here/tty-prompt.sh"
11
+
12
+ npm_dir="$root/.devcontainer/npm-auth"
13
+ gh_dir="$root/.devcontainer/gh-auth"
14
+ gh_env="$root/.devcontainer/gh.env"
15
+ cursor_dir="$root/.cursor"
16
+ RAG_ENV="$cursor_dir/codebase-rag.env"
17
+
18
+ run_codebase_rag_mcp() {
19
+ local script="$here/codebase-rag-mcp.ts"
20
+ CODEBASE_RAG_WORKSPACE="$root" node --experimental-strip-types "$script" "$@"
21
+ }
22
+
23
+ load_rag_env() {
24
+ RAG_URL=""
25
+ RAG_TOKEN=""
26
+ [[ -f "$RAG_ENV" ]] || return 0
27
+ # shellcheck disable=SC1090
28
+ set -a
29
+ # shellcheck disable=SC1090
30
+ source "$RAG_ENV"
31
+ set +a
32
+ RAG_URL="${CODEBASE_RAG_MCP_URL:-}"
33
+ RAG_TOKEN="${CODEBASE_RAG_MCP_TOKEN:-}"
34
+ }
35
+
36
+ write_rag_env() {
37
+ mkdir -p "$(dirname "$RAG_ENV")"
38
+ umask 077
39
+ cat >"$RAG_ENV" <<EOF
40
+ # Written by .devcontainer/initialize.sh. Not in git.
41
+ CODEBASE_RAG_MCP_URL=${RAG_URL}
42
+ CODEBASE_RAG_MCP_TOKEN=${RAG_TOKEN}
43
+ CODEBASE_RAG_MCP_ROOT=${root}
44
+ EOF
45
+ chmod 600 "$RAG_ENV"
46
+ if [[ -n "$RAG_URL" && -n "$RAG_TOKEN" ]]; then
47
+ run_codebase_rag_mcp merge || true
48
+ fi
49
+ }
50
+
51
+ seed_rag_from_host_mcp() {
52
+ local mcp="${HOME}/.cursor/mcp.json"
53
+ [[ -f "$mcp" ]] || return 1
54
+ command -v node >/dev/null 2>&1 || return 1
55
+ run_codebase_rag_mcp seed-print "$mcp"
56
+ }
57
+
58
+ ensure_cursor_dir() {
59
+ mkdir -p "$cursor_dir"
60
+ }
61
+
62
+ ensure_auth_dir() {
63
+ local dir="$1"
64
+ if ! mkdir -p "$dir" 2>/dev/null; then
65
+ echo "Cannot create $dir (permission denied)." >&2
66
+ echo "The scaffold container likely left .devcontainer root-owned. Fix with:" >&2
67
+ echo " sudo chown -R \"$USER:$USER\" \"$root\"" >&2
68
+ exit 1
69
+ fi
70
+ {
71
+ echo "*"
72
+ echo "!.gitignore"
73
+ } >"$dir/.gitignore"
74
+ }
75
+
76
+ ensure_gh_env() {
77
+ if [[ -d "$gh_env" ]]; then
78
+ echo "Refusing to start: $gh_env is a directory (left by a prior bind mount). Remove it and rebuild." >&2
79
+ exit 1
80
+ fi
81
+ touch "$gh_env"
82
+ }
83
+
84
+ setup_npm_auth() {
85
+ if [[ -f "$npm_dir/.npmrc" ]]; then
86
+ echo "npm auth: using $npm_dir/.npmrc"
87
+ return 0
88
+ fi
89
+ if ! prompt_yn "Configure npm auth for this workspace?"; then
90
+ echo "npm auth: skipped"
91
+ return 0
92
+ fi
93
+ if [[ -f "${HOME}/.npmrc" ]]; then
94
+ cp -a "${HOME}/.npmrc" "$npm_dir/.npmrc"
95
+ echo "npm auth: copied ~/.npmrc → $npm_dir/.npmrc"
96
+ return 0
97
+ fi
98
+ echo "npm auth: no ~/.npmrc — log in inside the container if prompted"
99
+ }
100
+
101
+ setup_gh_auth() {
102
+ if [[ -f "$gh_dir/hosts.yml" ]]; then
103
+ echo "gh auth: using $gh_dir/hosts.yml"
104
+ return 0
105
+ fi
106
+ if ! prompt_yn "Configure GitHub CLI auth for this workspace?"; then
107
+ echo "gh auth: skipped"
108
+ return 0
109
+ fi
110
+ if [[ -f "${HOME}/.config/gh/hosts.yml" ]]; then
111
+ cp -a "${HOME}/.config/gh/hosts.yml" "$gh_dir/hosts.yml"
112
+ [[ -f "${HOME}/.config/gh/config.yml" ]] &&
113
+ cp -a "${HOME}/.config/gh/config.yml" "$gh_dir/config.yml"
114
+ echo "gh auth: copied ~/.config/gh → $gh_dir"
115
+ return 0
116
+ fi
117
+ echo "gh auth: no ~/.config/gh/hosts.yml — log in inside the container if prompted"
118
+ }
119
+
120
+ setup_codebase_rag_env() {
121
+ load_rag_env
122
+ if [[ -n "$RAG_URL" && -n "$RAG_TOKEN" ]]; then
123
+ write_rag_env
124
+ echo "codebase-rag MCP: using $RAG_ENV"
125
+ return 0
126
+ fi
127
+
128
+ local seeded
129
+ if seeded="$(seed_rag_from_host_mcp 2>/dev/null)"; then
130
+ if prompt_yn "Found codebase-rag in ~/.cursor/mcp.json. Use it for this workspace?" y; then
131
+ RAG_URL="$(printf '%s\n' "$seeded" | sed -n '1p')"
132
+ RAG_TOKEN="$(printf '%s\n' "$seeded" | sed -n '2p')"
133
+ write_rag_env
134
+ echo "codebase-rag MCP: imported HTTP server from ~/.cursor/mcp.json → $RAG_ENV"
135
+ return 0
136
+ fi
137
+ fi
138
+
139
+ if ! prompt_yn "Configure codebase RAG MCP (semantic search)?"; then
140
+ RAG_URL=""
141
+ RAG_TOKEN=""
142
+ write_rag_env
143
+ echo "codebase-rag MCP: skipped"
144
+ return 0
145
+ fi
146
+
147
+ printf '%s\n' "Empty URL skips. Example: https://rag.example.com/mcp" >/dev/tty
148
+ printf '%s' "MCP URL: " >/dev/tty
149
+ read_tty RAG_URL
150
+ RAG_URL="$(printf '%s' "$RAG_URL" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
151
+ if [[ -z "$RAG_URL" ]]; then
152
+ RAG_TOKEN=""
153
+ write_rag_env
154
+ echo "codebase-rag MCP: skipped"
155
+ return 0
156
+ fi
157
+ printf '%s' "Bearer token (hidden): " >/dev/tty
158
+ read_tty RAG_TOKEN hidden
159
+ write_rag_env
160
+ echo "codebase-rag MCP: saved $RAG_ENV"
161
+ }
162
+
163
+ ensure_auth_dir "$npm_dir"
164
+ ensure_auth_dir "$gh_dir"
165
+ ensure_gh_env
166
+ ensure_cursor_dir
167
+ setup_npm_auth
168
+ setup_gh_auth
169
+ setup_codebase_rag_env
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env bash
2
+ # Runs after container create and when workspace content updates
3
+ # (devcontainer postCreateCommand / updateContentCommand).
4
+ # Installs deps when missing or when the lockfile changed; skips otherwise.
5
+ set -euo pipefail
6
+
7
+ root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
+ cd "$root"
9
+
10
+ lockfile="pnpm-lock.yaml"
11
+ stamp="node_modules/.decohere-pnpm-lock.sha"
12
+
13
+ current_hash=""
14
+ if [[ -f "$lockfile" ]]; then
15
+ current_hash="$(sha256sum "$lockfile" | awk '{print $1}')"
16
+ elif [[ -f package.json ]]; then
17
+ current_hash="$(sha256sum package.json | awk '{print $1}')"
18
+ fi
19
+
20
+ if [[ -d node_modules/.bin ]] && [[ -n "$current_hash" ]] && [[ -f "$stamp" ]] && [[ "$(cat "$stamp")" == "$current_hash" ]]; then
21
+ echo "node_modules: up to date, skipping pnpm install"
22
+ exit 0
23
+ fi
24
+
25
+ echo "node_modules: installing dependencies (first create may take a while)..."
26
+ if [[ -f "$lockfile" ]]; then
27
+ pnpm install --frozen-lockfile
28
+ else
29
+ pnpm install
30
+ fi
31
+
32
+ if [[ -n "$current_hash" ]]; then
33
+ mkdir -p node_modules
34
+ printf '%s\n' "$current_hash" >"$stamp"
35
+ fi
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env bash
2
+ # Runs on every container start (devcontainer postStartCommand).
3
+ # Optional npm / gh login is y/N on a TTY. Install is post-create.sh.
4
+ # MCP merge also runs here for later reconnects; the Compose service command
5
+ # merges before Cursor attaches (postStart is too late for the first snapshot).
6
+ set -euo pipefail
7
+
8
+ here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
9
+ root="$(cd "$here/.." && pwd)"
10
+ # shellcheck source=tty-prompt.sh
11
+ source "$here/tty-prompt.sh"
12
+
13
+ CODEBASE_RAG_WORKSPACE="$root" node --experimental-strip-types "$here/codebase-rag-mcp.ts" merge ||
14
+ echo "codebase-rag MCP: merge skipped" >&2
15
+
16
+ AUTH_REGISTRY="https://registry.npmjs.org"
17
+
18
+ ensure_npm_auth() {
19
+ if npm whoami --registry "$AUTH_REGISTRY" >/dev/null 2>&1; then
20
+ echo "npm: logged in as $(npm whoami --registry "$AUTH_REGISTRY")"
21
+ return 0
22
+ fi
23
+
24
+ if prompt_yn "Log in to npm?"; then
25
+ echo "npm: starting login..."
26
+ npm login --registry "$AUTH_REGISTRY" </dev/tty >/dev/tty
27
+ return 0
28
+ fi
29
+
30
+ echo "npm: skipped. Open a terminal and run: npm login" >&2
31
+ echo " (creds persist in .devcontainer/npm-auth/)" >&2
32
+ return 1
33
+ }
34
+
35
+ ensure_gh_auth() {
36
+ if ! command -v gh >/dev/null 2>&1; then
37
+ echo "gh: not installed in this container" >&2
38
+ return 1
39
+ fi
40
+
41
+ if gh auth status >/dev/null 2>&1; then
42
+ echo "gh: $(gh auth status 2>&1 | head -n1)"
43
+ return 0
44
+ fi
45
+
46
+ local token="${GH_TOKEN:-${GITHUB_TOKEN:-}}"
47
+ if [[ -n "$token" ]]; then
48
+ echo "gh: authenticating from GH_TOKEN..."
49
+ printf '%s\n' "$token" | gh auth login --with-token
50
+ return 0
51
+ fi
52
+
53
+ if prompt_yn "Log in to GitHub CLI (gh)?"; then
54
+ echo "gh: starting login..."
55
+ gh auth login </dev/tty >/dev/tty
56
+ return 0
57
+ fi
58
+
59
+ echo "gh: skipped. Open a terminal and run: gh auth login" >&2
60
+ echo " (creds persist in .devcontainer/gh-auth/; or set GH_TOKEN in .devcontainer/gh.env)" >&2
61
+ return 1
62
+ }
63
+
64
+ ensure_npm_auth || true
65
+ ensure_gh_auth || true
@@ -0,0 +1,38 @@
1
+ can_prompt() {
2
+ [[ -r /dev/tty && -w /dev/tty ]]
3
+ }
4
+
5
+ read_tty() {
6
+ local var="$1"
7
+ local hidden="${2:-}"
8
+ local value=""
9
+ if [[ -n "$hidden" ]]; then
10
+ read -r -s value </dev/tty || true
11
+ printf '\n' >/dev/tty
12
+ else
13
+ read -r value </dev/tty || true
14
+ fi
15
+ printf -v "$var" '%s' "$value"
16
+ }
17
+
18
+ # Returns 0 for yes. Default is n unless the second argument is y.
19
+ prompt_yn() {
20
+ local question="$1"
21
+ local default="${2:-n}"
22
+ local reply=""
23
+ if ! can_prompt; then
24
+ return 1
25
+ fi
26
+ local hint="y/N"
27
+ if [[ "$default" == "y" ]]; then
28
+ hint="Y/n"
29
+ fi
30
+ printf '%s [%s] ' "$question" "$hint" >/dev/tty
31
+ read_tty reply
32
+ reply="$(printf '%s' "$reply" | tr '[:upper:]' '[:lower:]' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
33
+ if [[ -z "$reply" ]]; then
34
+ [[ "$default" == "y" ]]
35
+ return
36
+ fi
37
+ [[ "$reply" == "y" || "$reply" == "yes" ]]
38
+ }
@@ -0,0 +1,10 @@
1
+ import type { Feature } from "../../services/scaffold.service.js";
2
+ export type AuthOptions = {
3
+ authProvider?: "auth0" | "none";
4
+ issuerBaseUrl?: string;
5
+ audience?: string;
6
+ databaseProvider?: "none" | "postgres/typeorm";
7
+ adminUsername?: string;
8
+ adminPassword?: string;
9
+ };
10
+ export declare const AuthFeature: Feature<AuthOptions>;
@@ -0,0 +1,84 @@
1
+ /** Management API scopes needed for API, SPA, connections, and admin users. */
2
+ declare const REQUIRED_SCOPES: string;
3
+ /** Default API scopes matching Hello CASL Authorize decorators. */
4
+ export declare const HELLO_API_SCOPES: readonly ["read:Hello", "create:Hello", "update:Hello", "delete:Hello"];
5
+ export declare const DB_CONNECTION_NAME = "Username-Password-Authentication";
6
+ export declare class Auth0AuthError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ export interface Auth0Tenant {
10
+ name: string;
11
+ active?: boolean;
12
+ }
13
+ export declare function isInstalled(): boolean;
14
+ export declare function listTenants(): Auth0Tenant[];
15
+ /** Device/URL login (`--no-input`) so Docker can print a host-browser URL. */
16
+ export declare function login(): boolean;
17
+ export declare function listApis(): Array<{
18
+ identifier: string;
19
+ name: string;
20
+ }>;
21
+ export declare function createApi(name: string, identifier: string, scopes?: readonly string[]): {
22
+ identifier: string;
23
+ };
24
+ export declare function listApiScopes(identifier: string): string[];
25
+ /** Assign API permissions to a user (Authorization Core). Idempotent when already granted. */
26
+ export declare function assignUserPermissions(userId: string, audience: string, permissions: readonly string[]): void;
27
+ /**
28
+ * Replace an API's scopes and enable RBAC policy enforcement.
29
+ * Auth0 CLI `--scopes` replaces the full set.
30
+ */
31
+ export declare function updateApiScopes(identifier: string, scopes?: readonly string[]): void;
32
+ /** True when Auth0 refuses create because the tenant hit its Applications quota. */
33
+ export declare function isAuth0EntityLimitError(err: unknown): boolean;
34
+ /**
35
+ * Actionable message when Auth0 will not create another application.
36
+ * Does not suggest reusing unrelated apps — free tenants must delete unused ones.
37
+ */
38
+ export declare function formatSpaEntityLimitError(appName: string, apps: Auth0App[]): string;
39
+ export declare function createSpaApp(name: string, callbackUrls: string | readonly string[]): {
40
+ client_id: string;
41
+ };
42
+ export type Auth0App = {
43
+ client_id: string;
44
+ name: string;
45
+ };
46
+ export declare function listApps(): Auth0App[];
47
+ export declare function updateSpaCallbacks(clientId: string, callbackUrls: string | readonly string[]): void;
48
+ /**
49
+ * Create a Postman SPA, or reuse an existing app with the same name (re-scaffold).
50
+ * Always returns a client_id suitable for Postman auth0ClientId.
51
+ * On Auth0 application-quota errors, throws a clear delete-apps message (no cross-app reuse).
52
+ */
53
+ export declare function ensureSpaApp(name: string, callbackUrls: string | readonly string[]): {
54
+ client_id: string;
55
+ reused: boolean;
56
+ };
57
+ /** Enable a database connection for an application (required for username/password login). */
58
+ export declare function enableConnectionForClient(connectionName: string, clientId: string): void;
59
+ export type AdminDatabaseUser = {
60
+ user_id: string;
61
+ email: string;
62
+ password: string;
63
+ username: string;
64
+ };
65
+ /** Strong default password when the scaffolder caller leaves password blank. */
66
+ export declare function generateAdminPassword(): string;
67
+ /** Look up a user by email (Management API users-by-email). */
68
+ export declare function findUserByEmail(email: string): {
69
+ user_id: string;
70
+ email: string;
71
+ } | null;
72
+ /** Reset password so a re-scaffold can write a known password to .env. */
73
+ export declare function updateUserPassword(userId: string, password: string): void;
74
+ /**
75
+ * Create a DB connection root-admin user for local / Postman login.
76
+ * If the user already exists, look them up, reset password to `input.password`,
77
+ * and return that identity so callers can still write .env credentials.
78
+ */
79
+ export declare function createAdminDatabaseUser(input: {
80
+ email: string;
81
+ password: string;
82
+ username: string;
83
+ }): AdminDatabaseUser;
84
+ export { REQUIRED_SCOPES };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Format/lint-fix all files in the scaffolded workspace with Biome.
3
+ * Prefer a global `biome` binary (builder image); fall back to `npx`.
4
+ */
5
+ export declare function formatScaffoldedFiles(targetDir: string, paths?: string[]): void;
@@ -0,0 +1,7 @@
1
+ import type { Feature } from "../../services/scaffold.service.js";
2
+ export type DatabaseOptions = {
3
+ databaseProvider?: "none" | "postgres/typeorm";
4
+ /** When true, merge into an existing workspace (\`webapi add\`). */
5
+ add?: boolean;
6
+ };
7
+ export declare const DatabaseFeature: Feature<DatabaseOptions>;
@@ -0,0 +1,2 @@
1
+ import type { Feature } from "../../services/scaffold.service.js";
2
+ export declare const FinalizeFeature: Feature;
@@ -0,0 +1,16 @@
1
+ import type { Feature } from "../../services/scaffold.service.js";
2
+ import { type Auth0Env } from "../postman/openapi-to-postman.js";
3
+ /** Postman OAuth callback URLs (popup + "Authorize using browser"). */
4
+ declare const POSTMAN_CALLBACKS: readonly ["https://oauth.pstmn.io/v1/callback", "https://oauth.pstmn.io/v1/browser-callback"];
5
+ /** Scopes requested for Auth0 access tokens (OIDC + Hello CASL permissions). */
6
+ declare const POSTMAN_SCOPES: string;
7
+ export type PostmanOptions = {
8
+ postmanProvider?: "api" | "local" | "none";
9
+ apiKey?: string;
10
+ workspaceId?: string;
11
+ };
12
+ /** Build Postman collection: OpenAPI routes + Auth0 auth overlay. */
13
+ export declare function buildHybridPostmanCollection(projectName: string, auth?: Auth0Env): Promise<import("../postman/openapi-to-postman.js").PostmanCollection>;
14
+ export declare const PostmanFeature: Feature<PostmanOptions>;
15
+ export { buildHelloOpenApiDocument } from "../postman/hello-openapi.js";
16
+ export { POSTMAN_CALLBACKS, POSTMAN_SCOPES };
@@ -0,0 +1,18 @@
1
+ import type { KeyedModel, SourceFile } from "../../models/source-file.js";
2
+ /**
3
+ * Builder for `projects/<api>/package.json`.
4
+ *
5
+ * Starts with the core cortex + crucible deps. Features can call
6
+ * `addDependency` / `addDevDependency` to extend.
7
+ */
8
+ export declare class ApiPackageJson implements KeyedModel {
9
+ private readonly workspaceName;
10
+ private readonly apiName;
11
+ readonly key: string;
12
+ private readonly _dependencies;
13
+ private readonly _devDependencies;
14
+ constructor(workspaceName: string, apiName?: string);
15
+ addDependency(name: string, version: string): this;
16
+ addDevDependency(name: string, version: string): this;
17
+ files(): SourceFile[];
18
+ }
@@ -0,0 +1,26 @@
1
+ import type { KeyedModel, SourceFile } from "../../models/source-file.js";
2
+ export type AdminUserConfig = {
3
+ sub: string;
4
+ email: string;
5
+ password: string;
6
+ username: string;
7
+ };
8
+ export type AuthConfig = {
9
+ issuerBaseUrl: string;
10
+ audience: string;
11
+ adminUser?: AdminUserConfig;
12
+ };
13
+ /**
14
+ * Data-carrier model for auth configuration.
15
+ *
16
+ * Registered by AuthFeature when auth0 is configured. Other features (e.g.
17
+ * PostmanFeature) retrieve it via workspace.getModel(WELL_KNOWN_FILES.AUTH_CONFIG).
18
+ * Produces no files — exists solely so features can communicate auth details.
19
+ */
20
+ export declare class AuthConfigModel implements KeyedModel {
21
+ readonly config: AuthConfig;
22
+ readonly key: string;
23
+ constructor(config: AuthConfig);
24
+ setAdminUser(adminUser: AdminUserConfig): void;
25
+ files(): SourceFile[];
26
+ }
@@ -0,0 +1,46 @@
1
+ import type { KeyedModel, SourceFile } from "../../models/source-file.js";
2
+ /**
3
+ * A controller method. Features call `addDecorator()` to prepend decorators
4
+ * before the HTTP verb decorator (e.g. `@AllowAnonymous` before `@Get()`).
5
+ */
6
+ export declare class ControllerMethod {
7
+ readonly name: string;
8
+ private readonly _httpDecorator;
9
+ private readonly _params;
10
+ private readonly _extraDecorators;
11
+ private _body;
12
+ private _isAsync;
13
+ constructor(name: string, _httpDecorator: string, _params: string, isAsync: boolean, body: string[]);
14
+ addDecorator(decorator: string): this;
15
+ /** Replace the method body lines (used by features that extend generated behaviour). */
16
+ setBody(body: string[]): this;
17
+ setAsync(isAsync?: boolean): this;
18
+ render(): string[];
19
+ }
20
+ /**
21
+ * Model for `projects/api/src/controllers/hello.controller.ts`.
22
+ *
23
+ * Pre-initialised with all routes and their HTTP decorators. Features mutate
24
+ * the model via `getMethod(name).addDecorator(...)`, `addDecorator(...)` (class
25
+ * level), `addCortexImport(...)`, `addImport(...)`, and `addConstructorParam(...)`.
26
+ */
27
+ export declare class ControllerSourceFile implements KeyedModel {
28
+ readonly key: string;
29
+ private readonly _cortexImports;
30
+ private readonly _extraImportGroups;
31
+ private readonly _classDecorators;
32
+ /** Explicit @inject — design:paramtypes can collapse to Object under SWC when the class is still undefined at decorate time. */
33
+ private readonly _ctorParams;
34
+ private readonly _methods;
35
+ /** Retrieve a method by name to mutate its decorators. */
36
+ getMethod(name: string): ControllerMethod;
37
+ /** Add a class-level decorator (e.g. `@Authorize`). */
38
+ addDecorator(decorator: string): this;
39
+ /** Add a named import from `@decohere/cortex`. */
40
+ addCortexImport(name: string, typeOnly?: boolean): this;
41
+ /** Add a named import from any other module. */
42
+ addImport(name: string, from: string, typeOnly?: boolean): this;
43
+ /** Add a constructor parameter (e.g. an injected dependency). */
44
+ addConstructorParam(param: string): this;
45
+ files(): SourceFile[];
46
+ }
@@ -0,0 +1,9 @@
1
+ import type { KeyedModel, SourceFile } from "../../models/source-file.js";
2
+ /**
3
+ * Minimal GitHub Actions for scaffolded apps: lint ∥ test, build gate on default branch,
4
+ * npm publish after CI (skips private packages). No default forge docker --push.
5
+ */
6
+ export declare class GithubCiWorkflows implements KeyedModel {
7
+ readonly key: string;
8
+ files(): SourceFile[];
9
+ }
@@ -0,0 +1,54 @@
1
+ import type { KeyedModel, SourceFile } from "../../models/source-file.js";
2
+ export type TypeOrmImport = {
3
+ className: string;
4
+ importPath: string;
5
+ };
6
+ export type ServiceImport = TypeOrmImport & {
7
+ scope?: "singleton" | "request";
8
+ };
9
+ /**
10
+ * Model for `projects/api/src/main.ts`.
11
+ *
12
+ * Starts with the minimal HTTP + YAML config setup. Features mutate the model
13
+ * by calling addSideEffectImport / addImport / addBuilderCall / addEntity /
14
+ * addRepository. files() renders whatever has been accumulated.
15
+ */
16
+ export declare class MainSourceFile implements KeyedModel {
17
+ private readonly appName;
18
+ readonly key: string;
19
+ private readonly _sideEffectImports;
20
+ private readonly _extraImports;
21
+ private readonly _builderCalls;
22
+ private readonly _entities;
23
+ private readonly _repositories;
24
+ private readonly _services;
25
+ private _dataSourceName;
26
+ private _typeOrmSeed;
27
+ constructor(appName: string);
28
+ /** Adds a bare side-effect import, e.g. `@decohere/cortex/auth`. */
29
+ addSideEffectImport(path: string): this;
30
+ /** Adds a named import, e.g. `import { Foo } from "bar"`. */
31
+ addImport(name: string, from: string, typeOnly?: boolean): this;
32
+ /**
33
+ * Adds a builder call inserted after `.withConfiguration()` and before
34
+ * `.withServices()`. Pass the call without leading dot, e.g. `.withAuth()`.
35
+ */
36
+ addBuilderCall(call: string): this;
37
+ /** Adds a TypeORM entity — import and entry in `withTypeOrm({ entities })`. */
38
+ addEntity(entity: TypeOrmImport): this;
39
+ /** Adds a TypeORM repository — import and entry in `withTypeOrm({ repositories })`. */
40
+ addRepository(repo: TypeOrmImport): this;
41
+ /** Adds a service registered in `.withServices()`. */
42
+ addService(service: ServiceImport): this;
43
+ /**
44
+ * Datasource name passed to `withTypeOrm({ name })`. Must match
45
+ * `database.dataSources[].name` in config.yaml.
46
+ */
47
+ setDataSourceName(name: string): this;
48
+ /**
49
+ * Inline seed callback body for `withTypeOrm({ seed })`.
50
+ * Receives `dataSource` in scope. Example: `await dataSource.getRepository(User).save(...)`.
51
+ */
52
+ setTypeOrmSeed(seedBody: string): this;
53
+ files(): SourceFile[];
54
+ }
@@ -0,0 +1,18 @@
1
+ import type { KeyedModel, SourceFile } from "../../models/source-file.js";
2
+ /**
3
+ * Production Dockerfile for each API, in the API's own folder: `projects/<name>/Dockerfile`.
4
+ * That is where `forge docker` and `forge package` look for a deployable, and the folder is
5
+ * the Docker build context.
6
+ *
7
+ * The image copies `.package/`, which `forge package` writes before Docker runs: the API's
8
+ * compiled code, the workspace libraries it imports, and a real (symlink-free) `node_modules`
9
+ * of the third-party packages it reaches. So the image build installs nothing, runs no
10
+ * workspace tooling, and needs no npm token.
11
+ */
12
+ export declare class WebapiProductionDockerfile implements KeyedModel {
13
+ private readonly apiNames;
14
+ readonly key: string;
15
+ constructor(apiNames?: readonly string[]);
16
+ files(): SourceFile[];
17
+ }
18
+ export declare function renderProductionDockerfile(apiName: string): string;
@@ -0,0 +1,7 @@
1
+ import type { SourceFile, SourceFileProvider } from "../../models/source-file.js";
2
+ export declare class SampleConfigModel implements SourceFileProvider {
3
+ files(): SourceFile[];
4
+ }
5
+ export declare class SampleServiceModel implements SourceFileProvider {
6
+ files(): SourceFile[];
7
+ }
@@ -0,0 +1,12 @@
1
+ import { DockerfileModel } from "../../models/docker-image.model.js";
2
+ /**
3
+ * Scaffolded app `.devcontainer/Dockerfile` — thin `FROM` the published base image.
4
+ * Optional feature layers (e.g. postgresql-client) append via `addLayer`.
5
+ */
6
+ export declare class WebapiDevContainer extends DockerfileModel {
7
+ constructor(baseImage?: string);
8
+ files(): {
9
+ filePath: string;
10
+ content: string;
11
+ }[];
12
+ }
@@ -0,0 +1,19 @@
1
+ /** Minimal OpenAPI 3 document shape used for Postman conversion. */
2
+ export type ScaffoldOpenApiDocument = {
3
+ openapi: "3.0.3";
4
+ info: {
5
+ title: string;
6
+ version: string;
7
+ description?: string;
8
+ };
9
+ servers?: Array<{
10
+ url: string;
11
+ description?: string;
12
+ }>;
13
+ paths: Record<string, Record<string, unknown>>;
14
+ };
15
+ /**
16
+ * Canonical Hello WebAPI OpenAPI document used to generate Postman requests.
17
+ * Keep paths aligned with scaffolded HelloController (`/hello`, `/hello/{id}`).
18
+ */
19
+ export declare function buildHelloOpenApiDocument(projectName: string): ScaffoldOpenApiDocument;