@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,13 @@
1
+ import { type Action, ActionResponse } from "@decohere/nexus/cli";
2
+ export type AddApiOptions = {
3
+ apiName?: string;
4
+ d?: string;
5
+ database?: string;
6
+ auth?: string;
7
+ postman?: string;
8
+ yes?: boolean;
9
+ install?: string;
10
+ };
11
+ export declare class AddApiAction implements Action<AddApiOptions> {
12
+ run(options: AddApiOptions): Promise<ActionResponse>;
13
+ }
@@ -0,0 +1,7 @@
1
+ import { DecohereCommand } from "@decohere/nexus/cli";
2
+ import { AddApiAction } from "./add-api.action.js";
3
+ export declare class AddApiCommand extends DecohereCommand {
4
+ get actions(): (typeof AddApiAction)[];
5
+ constructor(name: string);
6
+ action(fn: (...args: unknown[]) => void | Promise<void>): this;
7
+ }
@@ -0,0 +1,6 @@
1
+ import type { Actions } from "@decohere/nexus/cli";
2
+ import { type CommandHandler, type CommandResponse, type CommandType, DecohereCommand } from "@decohere/nexus/cli";
3
+ export declare class AddCommand extends DecohereCommand {
4
+ constructor(commands: Record<string, CommandType>, handler: CommandHandler);
5
+ run(_actions: Actions, _options: never): Promise<CommandResponse>;
6
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleManifest } from "@decohere/nexus/cli";
2
+ import { AddCommand } from "./add.command.js";
3
+ import { AddApiAction } from "./add-api.action.js";
4
+ import { AddApiCommand } from "./add-api.command.js";
5
+ export declare class AddModule extends ModuleManifest {
6
+ readonly id = "add";
7
+ readonly command: typeof AddCommand;
8
+ readonly commands: {
9
+ api: typeof AddApiCommand;
10
+ };
11
+ readonly actions: {
12
+ api: typeof AddApiAction;
13
+ };
14
+ }
@@ -0,0 +1,7 @@
1
+ import { type Action, ActionResponse } from "@decohere/nexus/cli";
2
+ export type Auth0ConfigureOptions = {
3
+ d?: string;
4
+ };
5
+ export declare class Auth0ConfigureAction implements Action<Auth0ConfigureOptions> {
6
+ run(options: Auth0ConfigureOptions): Promise<ActionResponse>;
7
+ }
@@ -0,0 +1,6 @@
1
+ import { DecohereCommand } from "@decohere/nexus/cli";
2
+ import { Auth0ConfigureAction } from "./auth0-configure.action.js";
3
+ export declare class Auth0ConfigureCommand extends DecohereCommand {
4
+ get actions(): (typeof Auth0ConfigureAction)[];
5
+ constructor(name: string);
6
+ }
@@ -0,0 +1,4 @@
1
+ import { type Action, ActionResponse } from "@decohere/nexus/cli";
2
+ export declare class Auth0LoginAction implements Action {
3
+ run(): Promise<ActionResponse>;
4
+ }
@@ -0,0 +1,6 @@
1
+ import { DecohereCommand } from "@decohere/nexus/cli";
2
+ import { Auth0LoginAction } from "./auth0-login.action.js";
3
+ export declare class Auth0LoginCommand extends DecohereCommand {
4
+ get actions(): (typeof Auth0LoginAction)[];
5
+ constructor(name: string);
6
+ }
@@ -0,0 +1,6 @@
1
+ import type { Actions } from "@decohere/nexus/cli";
2
+ import { type CommandHandler, type CommandResponse, type CommandType, DecohereCommand } from "@decohere/nexus/cli";
3
+ export declare class Auth0Command extends DecohereCommand {
4
+ constructor(commands: Record<string, CommandType>, handler: CommandHandler);
5
+ run(_actions: Actions, _options: never): Promise<CommandResponse>;
6
+ }
@@ -0,0 +1,18 @@
1
+ import { ModuleManifest } from "@decohere/nexus/cli";
2
+ import { Auth0Command } from "./auth0.command.js";
3
+ import { Auth0ConfigureAction } from "./auth0-configure.action.js";
4
+ import { Auth0ConfigureCommand } from "./auth0-configure.command.js";
5
+ import { Auth0LoginAction } from "./auth0-login.action.js";
6
+ import { Auth0LoginCommand } from "./auth0-login.command.js";
7
+ export declare class Auth0Module extends ModuleManifest {
8
+ readonly id = "auth0";
9
+ readonly command: typeof Auth0Command;
10
+ readonly commands: {
11
+ login: typeof Auth0LoginCommand;
12
+ configure: typeof Auth0ConfigureCommand;
13
+ };
14
+ readonly actions: {
15
+ login: typeof Auth0LoginAction;
16
+ configure: typeof Auth0ConfigureAction;
17
+ };
18
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { Actions } from "@decohere/nexus/cli";
2
+ import { type CommandHandler, type CommandResponse, type CommandType, DecohereCommand } from "@decohere/nexus/cli";
3
+ export declare class CreateCommand extends DecohereCommand {
4
+ constructor(commands: Record<string, CommandType>, handler: CommandHandler);
5
+ run(_actions: Actions, _options: never): Promise<CommandResponse>;
6
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleManifest } from "@decohere/nexus/cli";
2
+ import { CreateCommand } from "./create.command.js";
3
+ import { WebapiAction } from "./webapi.action.js";
4
+ import { WebapiCommand } from "./webapi.command.js";
5
+ export declare class CreateModule extends ModuleManifest {
6
+ readonly id = "create";
7
+ readonly command: typeof CreateCommand;
8
+ readonly commands: {
9
+ webapi: typeof WebapiCommand;
10
+ };
11
+ readonly actions: {
12
+ webapi: typeof WebapiAction;
13
+ };
14
+ }
@@ -0,0 +1,4 @@
1
+ /** Release stdin so the process can exit after interactive prompts. */
2
+ export declare function closePrompt(): void;
3
+ export declare function ask(question: string, fallback?: string): Promise<string>;
4
+ export declare function pick<T>(label: string, items: T[], display: (item: T) => string): Promise<T | null>;
@@ -0,0 +1,13 @@
1
+ export { AddModule } from "./add.module.js";
2
+ export type { AddApiOptions } from "./add-api.action.js";
3
+ export { AddApiAction } from "./add-api.action.js";
4
+ export { Auth0Module } from "./auth0.module.js";
5
+ export type { Auth0ConfigureOptions } from "./auth0-configure.action.js";
6
+ export { Auth0ConfigureAction } from "./auth0-configure.action.js";
7
+ export { Auth0LoginAction } from "./auth0-login.action.js";
8
+ export { CreateModule } from "./create.module.js";
9
+ export { runCli } from "./program.js";
10
+ export type { ApiOptions } from "./webapi/create-api.js";
11
+ export { scaffoldApi } from "./webapi/create-api.js";
12
+ export type { WebapiOptions } from "./webapi.action.js";
13
+ export { WebapiAction } from "./webapi.action.js";
@@ -0,0 +1,73 @@
1
+ import type { KeyedModel } from "./source-file.js";
2
+ export type ComposeNetworkRef = string | {
3
+ /** Network key under `networks:` on this service */
4
+ [networkKey: string]: {
5
+ aliases?: string[];
6
+ };
7
+ };
8
+ export interface ComposeHealthcheck {
9
+ test: string[];
10
+ interval?: string;
11
+ timeout?: string;
12
+ retries?: number;
13
+ }
14
+ export interface ComposeService {
15
+ build?: string;
16
+ image?: string;
17
+ container_name?: string;
18
+ /** Quoted in YAML (`0:0` must not parse as a number). */
19
+ user?: string;
20
+ env_file?: string[];
21
+ environment?: Record<string, string>;
22
+ ports?: string[];
23
+ volumes?: string[];
24
+ command?: string;
25
+ restart?: string;
26
+ depends_on?: string[];
27
+ /** Compose profiles (service only starts when profile is enabled). */
28
+ profiles?: string[];
29
+ /** Attach to compose networks (string name or map with aliases). */
30
+ networks?: ComposeNetworkRef[];
31
+ healthcheck?: ComposeHealthcheck;
32
+ }
33
+ export type ComposeNetwork = {
34
+ /** Fixed Docker network name (shareable across compose projects). */
35
+ name: string;
36
+ external?: boolean;
37
+ };
38
+ /**
39
+ * Live builder for `docker-compose.yml`.
40
+ *
41
+ * Features call `addService` / `addVolume` / `addNetwork` in their scaffold phases.
42
+ * Loaded with `fromFile` (`decohere add api`), additions merge into the existing file:
43
+ * services, networks and volumes already there are left untouched, comments kept.
44
+ */
45
+ export declare class DockerCompose implements KeyedModel {
46
+ readonly key: string;
47
+ private _projectName;
48
+ private readonly _headerComments;
49
+ private readonly _services;
50
+ private readonly _volumes;
51
+ private readonly _networks;
52
+ private readonly _envFiles;
53
+ private _existing;
54
+ /** Load an existing compose file so `decohere add api` can merge into it. */
55
+ static fromFile(absolutePath: string): DockerCompose;
56
+ /** True when the service is defined (in the loaded file or added since). */
57
+ hasService(name: string): boolean;
58
+ /** Compose project name (`name:` top-level) — isolates containers/volumes. */
59
+ setProjectName(name: string): this;
60
+ /** File-level `#` comments rendered above `name:` / `services:`. */
61
+ addHeaderComment(...lines: string[]): this;
62
+ addService(name: string, config: ComposeService): this;
63
+ files(): {
64
+ filePath: string;
65
+ content: string;
66
+ }[];
67
+ addVolume(name: string): this;
68
+ addNetwork(key: string, network: ComposeNetwork): this;
69
+ /** Append an env_file path to an existing service. */
70
+ addEnvFile(serviceName: string, filePath: string): this;
71
+ getContent(): string;
72
+ private mergeIntoExisting;
73
+ }
@@ -0,0 +1,27 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ /**
3
+ * Builder for a YAML config file (e.g. config/config.yaml or config/config.dev.yaml).
4
+ *
5
+ * Starts with a base section passed to the constructor. Features call
6
+ * `addSection(yaml)` during their scaffold phase to append their own block.
7
+ * `files()` joins all sections with a blank line separator.
8
+ */
9
+ export declare class ConfigYaml implements KeyedModel {
10
+ readonly key: string;
11
+ private readonly filePath;
12
+ private readonly _sections;
13
+ constructor(key: string, filePath: string, baseContent: string);
14
+ addSection(yaml: string): this;
15
+ /** True when a datasource with this `name:` already appears in the file. */
16
+ hasDataSource(name: string): boolean;
17
+ hasDataSources(): boolean;
18
+ /**
19
+ * Insert a `dataSources` list item. Used by `webapi add` so we do not write a
20
+ * second top-level `database:` key (YAML last-key-wins).
21
+ */
22
+ appendDataSource(item: string): this;
23
+ static fromFile(key: string, relativePath: string, absolutePath: string): ConfigYaml;
24
+ files(): SourceFile[];
25
+ }
26
+ /** Insert a YAML list item under `dataSources:`; append a new `database:` block if missing. */
27
+ export declare function injectYamlDataSource(yaml: string, item: string): string;
@@ -0,0 +1,20 @@
1
+ export declare const WELL_KNOWN_FILES: {
2
+ VSCODE_SETTINGS: string;
3
+ LAUNCH_JSON: string;
4
+ DOCKER_COMPOSE: string;
5
+ DEVCONTAINER_JSON: string;
6
+ DOCKERFILE: string;
7
+ PRODUCTION_DOCKERFILE: string;
8
+ GITHUB_CI: string;
9
+ PACKAGE_JSON: string;
10
+ API_PACKAGE_JSON: string;
11
+ TSCONFIG: string;
12
+ VITEST_CONFIG: string;
13
+ MAIN_TS: string;
14
+ CONTROLLER_TS: string;
15
+ CONFIG_YAML: string;
16
+ CONFIG_DEV_YAML: string;
17
+ GITIGNORE: string;
18
+ AUTH_CONFIG: string;
19
+ ENV_FILE: string;
20
+ };
@@ -0,0 +1,49 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ /**
3
+ * Model for `.devcontainer/devcontainer.json`.
4
+ *
5
+ * Features call builder methods (`addExtension`, `forwardPort`, etc.) during
6
+ * their configure phase. `MonoRepoScaffold` calls `files()` at render time.
7
+ */
8
+ export type PortAttributes = {
9
+ label?: string;
10
+ /** When true, host port must match the container port (no random remap). */
11
+ requireLocalPort?: boolean;
12
+ onAutoForward?: "notify" | "openBrowser" | "openPreview" | "silent" | "ignore";
13
+ };
14
+ export declare class DevContainer implements KeyedModel {
15
+ readonly key: string;
16
+ private readonly _extensions;
17
+ private readonly _ports;
18
+ private readonly _portAttributes;
19
+ private _mounts;
20
+ private _workspaceFolder;
21
+ private _postCreateCommand?;
22
+ private _updateContentCommand?;
23
+ private _postStartCommand?;
24
+ private _initializeCommand?;
25
+ private _remoteUser;
26
+ private _useCompose;
27
+ private _existing;
28
+ /**
29
+ * Load an existing devcontainer.json so `decohere add api` can merge into it.
30
+ * Only extensions, forwarded ports and port attributes are merged; everything else is kept.
31
+ */
32
+ static fromFile(absolutePath: string): DevContainer;
33
+ constructor();
34
+ /** In-container path Cursor/VS Code opens (Agents window uses the basename). */
35
+ setWorkspaceFolder(folder: string): this;
36
+ private bindMount;
37
+ addExtension(...ids: string[]): this;
38
+ forwardPort(...ports: number[]): this;
39
+ setPortAttributes(port: number, attrs: PortAttributes): this;
40
+ setPostCreateCommand(cmd: string): this;
41
+ setUpdateContentCommand(cmd: string): this;
42
+ setPostStartCommand(cmd: string): this;
43
+ setInitializeCommand(cmd: string): this;
44
+ setRemoteUser(user: string): this;
45
+ useCompose(): this;
46
+ files(): SourceFile[];
47
+ private mergeIntoExisting;
48
+ private build;
49
+ }