everything-dev 2.0.0-rc.8 → 2.0.0-rc.9

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 (115) hide show
  1. package/dist/apps/upload/src/client.cjs +7 -1
  2. package/dist/apps/upload/src/client.cjs.map +1 -1
  3. package/dist/apps/upload/src/client.mjs +7 -1
  4. package/dist/apps/upload/src/client.mjs.map +1 -1
  5. package/dist/auth-login.cjs +24 -1
  6. package/dist/auth-login.cjs.map +1 -1
  7. package/dist/auth-login.mjs +24 -1
  8. package/dist/auth-login.mjs.map +1 -1
  9. package/dist/auth-session.cjs +4 -2
  10. package/dist/auth-session.cjs.map +1 -1
  11. package/dist/auth-session.mjs +4 -2
  12. package/dist/auth-session.mjs.map +1 -1
  13. package/dist/cdn-deploy.cjs +11 -7
  14. package/dist/cdn-deploy.cjs.map +1 -1
  15. package/dist/cdn-deploy.mjs +11 -7
  16. package/dist/cdn-deploy.mjs.map +1 -1
  17. package/dist/cli/import.cjs +1140 -0
  18. package/dist/cli/import.cjs.map +1 -0
  19. package/dist/cli/import.mjs +1126 -0
  20. package/dist/cli/import.mjs.map +1 -0
  21. package/dist/cli/init.cjs +11 -4
  22. package/dist/cli/init.cjs.map +1 -1
  23. package/dist/cli/init.d.cts +8 -2
  24. package/dist/cli/init.d.mts +8 -2
  25. package/dist/cli/init.mjs +11 -5
  26. package/dist/cli/init.mjs.map +1 -1
  27. package/dist/cli.cjs +55 -0
  28. package/dist/cli.cjs.map +1 -1
  29. package/dist/cli.mjs +55 -0
  30. package/dist/cli.mjs.map +1 -1
  31. package/dist/commands/import.cjs +49 -0
  32. package/dist/commands/import.cjs.map +1 -0
  33. package/dist/commands/import.mjs +46 -0
  34. package/dist/commands/import.mjs.map +1 -0
  35. package/dist/commands/keys.cjs +24 -3
  36. package/dist/commands/keys.cjs.map +1 -1
  37. package/dist/commands/keys.mjs +24 -3
  38. package/dist/commands/keys.mjs.map +1 -1
  39. package/dist/config.d.cts +1 -0
  40. package/dist/config.d.mts +1 -0
  41. package/dist/contract.cjs +89 -0
  42. package/dist/contract.cjs.map +1 -1
  43. package/dist/contract.d.cts +190 -1
  44. package/dist/contract.d.mts +190 -1
  45. package/dist/contract.meta.cjs +16 -0
  46. package/dist/contract.meta.cjs.map +1 -1
  47. package/dist/contract.meta.d.cts +26 -0
  48. package/dist/contract.meta.d.mts +26 -0
  49. package/dist/contract.meta.mjs +16 -0
  50. package/dist/contract.meta.mjs.map +1 -1
  51. package/dist/contract.mjs +84 -1
  52. package/dist/contract.mjs.map +1 -1
  53. package/dist/custody-signer.cjs +70 -0
  54. package/dist/custody-signer.cjs.map +1 -0
  55. package/dist/custody-signer.mjs +68 -0
  56. package/dist/custody-signer.mjs.map +1 -0
  57. package/dist/descriptor/schema.cjs +8 -5
  58. package/dist/descriptor/schema.cjs.map +1 -1
  59. package/dist/descriptor/schema.d.cts +1 -0
  60. package/dist/descriptor/schema.d.mts +1 -0
  61. package/dist/descriptor/schema.mjs +8 -5
  62. package/dist/descriptor/schema.mjs.map +1 -1
  63. package/dist/descriptor/serialize.cjs +1 -1
  64. package/dist/descriptor/serialize.cjs.map +1 -1
  65. package/dist/descriptor/serialize.mjs +1 -1
  66. package/dist/descriptor/serialize.mjs.map +1 -1
  67. package/dist/index.cjs +6 -0
  68. package/dist/index.d.cts +2 -2
  69. package/dist/index.d.mts +2 -2
  70. package/dist/index.mjs +2 -2
  71. package/dist/outlayer-login.cjs +54 -0
  72. package/dist/outlayer-login.cjs.map +1 -0
  73. package/dist/outlayer-login.mjs +54 -0
  74. package/dist/outlayer-login.mjs.map +1 -0
  75. package/dist/plugin.cjs +2 -0
  76. package/dist/plugin.cjs.map +1 -1
  77. package/dist/plugin.d.cts +74 -0
  78. package/dist/plugin.d.mts +74 -0
  79. package/dist/plugin.mjs +2 -0
  80. package/dist/plugin.mjs.map +1 -1
  81. package/dist/publish.cjs +145 -22
  82. package/dist/publish.cjs.map +1 -1
  83. package/dist/publish.mjs +147 -24
  84. package/dist/publish.mjs.map +1 -1
  85. package/dist/source-archive.cjs +51 -0
  86. package/dist/source-archive.cjs.map +1 -0
  87. package/dist/source-archive.mjs +50 -0
  88. package/dist/source-archive.mjs.map +1 -0
  89. package/dist/storage-upload.cjs +6 -1
  90. package/dist/storage-upload.cjs.map +1 -1
  91. package/dist/storage-upload.mjs +6 -1
  92. package/dist/storage-upload.mjs.map +1 -1
  93. package/dist/types.cjs +5 -1
  94. package/dist/types.cjs.map +1 -1
  95. package/dist/types.d.cts +2 -0
  96. package/dist/types.d.mts +2 -0
  97. package/dist/types.mjs +5 -1
  98. package/dist/types.mjs.map +1 -1
  99. package/dist/utils/workspace-subtree.cjs +37 -0
  100. package/dist/utils/workspace-subtree.cjs.map +1 -0
  101. package/dist/utils/workspace-subtree.mjs +36 -0
  102. package/dist/utils/workspace-subtree.mjs.map +1 -0
  103. package/dist/version-manifest-deploy.cjs +4 -2
  104. package/dist/version-manifest-deploy.cjs.map +1 -1
  105. package/dist/version-manifest-deploy.mjs +4 -2
  106. package/dist/version-manifest-deploy.mjs.map +1 -1
  107. package/dist/version-manifest-resolve.cjs +2 -1
  108. package/dist/version-manifest-resolve.cjs.map +1 -1
  109. package/dist/version-manifest-resolve.d.cts +3 -0
  110. package/dist/version-manifest-resolve.d.mts +3 -0
  111. package/dist/version-manifest-resolve.mjs +2 -1
  112. package/dist/version-manifest-resolve.mjs.map +1 -1
  113. package/package.json +3 -2
  114. package/skills/cli-reference/SKILL.md +17 -1
  115. package/skills/init-upgrade/SKILL.md +76 -3
@@ -1 +1 @@
1
- {"version":3,"file":"version-manifest-resolve.mjs","names":[],"sources":["../src/version-manifest-resolve.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n type WorkspaceVersionManifest,\n WorkspaceVersionManifestSchema,\n} from \"every-plugin/version-manifest\";\nimport { bundleUrlToStagedPath, resolveContained } from \"./resolver\";\n\n/**\n * Version-manifest slot resolution (atomic-deploys 04): a config slot's\n * `pin` ({ manifest, integrity }) resolves to the derived entry-level fields\n * every consumer needs. The cache is keyed by the full pin — the pinned\n * bytes are immutable, so a verified entry is cached for the process\n * lifetime and serves as last-known-good if the origin later fails; a fetch\n * or SRI failure with nothing cached propagates (a boot-time resolution\n * failure fails the deploy, which is the platform's rollback).\n */\n\nexport interface ResolvedSlotVersion {\n /** Absolute URL of the content-hashed container entry. */\n entryUrl: string;\n entryIntegrity: string;\n /** Absolute URL of the hashed browser manifest (mf-manifest), when present. */\n browserManifestUrl?: string;\n /** Absolute URL of the content-hashed SSR entry, when present. */\n ssrEntryUrl?: string;\n ssrIntegrity?: string;\n /** Full per-file digest map of the dist (object path → SRI), when the\n * pinned manifest carries one — the diff base for skip-unchanged uploads. */\n files?: Record<string, string>;\n}\n\nexport interface SlotPin {\n /** versioned manifest filename, relative to the slot's production base */\n manifest: string;\n /** the manifest document's own SRI */\n integrity: string;\n}\n\nconst cache = new Map<string, ResolvedSlotVersion>();\n\nexport function clearSlotVersionCache(): void {\n cache.clear();\n}\n\nfunction fetchText(url: string, fetchImpl: typeof fetch): Promise<string> {\n return fetchImpl(url).then((response) => {\n if (!response.ok) throw new Error(`version manifest fetch failed: ${response.status}`);\n return response.text();\n });\n}\n\nfunction slotVersionFromManifest(\n base: string,\n manifest: WorkspaceVersionManifest,\n): ResolvedSlotVersion {\n const trimmedBase = base.replace(/\\/$/, \"\");\n return {\n entryUrl: `${trimmedBase}/${manifest.entry}`,\n entryIntegrity: manifest.entryIntegrity,\n ...(manifest.browserManifest\n ? { browserManifestUrl: `${trimmedBase}/${manifest.browserManifest.file}` }\n : {}),\n ...(manifest.ssr\n ? {\n ssrEntryUrl: `${trimmedBase}/${manifest.ssr.entry}`,\n ssrIntegrity: manifest.ssr.integrity,\n }\n : {}),\n ...(manifest.files ? { files: manifest.files } : {}),\n };\n}\n\n/**\n * Staged-slot preference (ADR 0020/0021 self-contained tier): when a runtime\n * stages its own namespace under `BOS_BUNDLE_DIR`, a slot resolves from the\n * staged dist's own version manifest instead of the config's pin — pinned\n * manifest bytes that predate the image (deploy lag after a release bump)\n * cannot exist in the staged namespace, so their hashed files would 404 the\n * disk and fall through to the network, where the stale immutable bytes\n * still answer 200 and boot a foreign build. The staged manifest is trusted\n * (staged by the image build itself) and skipped entirely when the slot is\n * absent from the staged namespace or the pinned manifest is present (the\n * normal healthy case, which keeps the pin's SRI check).\n */\nfunction readStagedSlotVersion(base: string, pin: SlotPin): ResolvedSlotVersion | null {\n const bundleDir = process.env.BOS_BUNDLE_DIR;\n if (!bundleDir) return null;\n\n const slotDir = bundleUrlToStagedPath(base, bundleDir);\n if (!slotDir || !existsSync(slotDir)) return null;\n\n const pinnedManifestPath = resolveContained(slotDir, pin.manifest);\n if (!pinnedManifestPath || existsSync(pinnedManifestPath)) return null;\n\n const versionsDir = path.join(slotDir, \"versions\");\n if (!existsSync(versionsDir)) return null;\n const manifests = readdirSync(versionsDir)\n .filter((name) => name.endsWith(\".json\"))\n .map((name) => path.join(versionsDir, name))\n .filter((file) => statSync(file).isFile())\n .sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs || (a < b ? -1 : 1));\n if (manifests.length === 0) return null;\n const manifestPath = manifests[0];\n if (!manifestPath) return null;\n\n try {\n const manifest = WorkspaceVersionManifestSchema.parse(\n JSON.parse(readFileSync(manifestPath, \"utf8\")),\n );\n return slotVersionFromManifest(base, manifest);\n } catch {\n return null;\n }\n}\n\nexport async function resolveSlotVersion(input: {\n base: string;\n pin: SlotPin;\n fetchImpl?: typeof fetch;\n}): Promise<ResolvedSlotVersion> {\n const key = `${input.base}::${input.pin.manifest}::${input.pin.integrity}`;\n // content-addressed: a verified pin is cached for the process lifetime and\n // never refetched — the cache IS the last-known-good\n const cached = cache.get(key);\n if (cached) return cached;\n\n const staged = readStagedSlotVersion(input.base, input.pin);\n if (staged) {\n cache.set(key, staged);\n return staged;\n }\n\n const manifestUrl = `${input.base.replace(/\\/$/, \"\")}/${input.pin.manifest.replace(/^\\//, \"\")}`;\n const body = await fetchText(manifestUrl, input.fetchImpl ?? fetch);\n const computed = `sha384-${createHash(\"sha384\").update(body).digest(\"base64\")}`;\n if (computed !== input.pin.integrity) {\n throw new Error(\n `[SRI] version manifest integrity mismatch for ${manifestUrl}\\n Expected: ${input.pin.integrity}\\n Computed: ${computed}`,\n );\n }\n const manifest: WorkspaceVersionManifest = WorkspaceVersionManifestSchema.parse(JSON.parse(body));\n\n const resolved = slotVersionFromManifest(input.base, manifest);\n cache.set(key, resolved);\n return resolved;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"version-manifest-resolve.mjs","names":[],"sources":["../src/version-manifest-resolve.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n type SourceRef,\n type WorkspaceVersionManifest,\n WorkspaceVersionManifestSchema,\n} from \"every-plugin/version-manifest\";\nimport { bundleUrlToStagedPath, resolveContained } from \"./resolver\";\n\n/**\n * Version-manifest slot resolution (atomic-deploys 04): a config slot's\n * `pin` ({ manifest, integrity }) resolves to the derived entry-level fields\n * every consumer needs. The cache is keyed by the full pin — the pinned\n * bytes are immutable, so a verified entry is cached for the process\n * lifetime and serves as last-known-good if the origin later fails; a fetch\n * or SRI failure with nothing cached propagates (a boot-time resolution\n * failure fails the deploy, which is the platform's rollback).\n */\n\nexport interface ResolvedSlotVersion {\n /** Absolute URL of the content-hashed container entry. */\n entryUrl: string;\n entryIntegrity: string;\n /** Absolute URL of the hashed browser manifest (mf-manifest), when present. */\n browserManifestUrl?: string;\n /** Absolute URL of the content-hashed SSR entry, when present. */\n ssrEntryUrl?: string;\n ssrIntegrity?: string;\n /** Full per-file digest map of the dist (object path → SRI), when the\n * pinned manifest carries one — the diff base for skip-unchanged uploads. */\n files?: Record<string, string>;\n /** Source archive reference from the pinned manifest (publish.sourcePublish). */\n source?: SourceRef;\n}\n\nexport interface SlotPin {\n /** versioned manifest filename, relative to the slot's production base */\n manifest: string;\n /** the manifest document's own SRI */\n integrity: string;\n}\n\nconst cache = new Map<string, ResolvedSlotVersion>();\n\nexport function clearSlotVersionCache(): void {\n cache.clear();\n}\n\nfunction fetchText(url: string, fetchImpl: typeof fetch): Promise<string> {\n return fetchImpl(url).then((response) => {\n if (!response.ok) throw new Error(`version manifest fetch failed: ${response.status}`);\n return response.text();\n });\n}\n\nfunction slotVersionFromManifest(\n base: string,\n manifest: WorkspaceVersionManifest,\n): ResolvedSlotVersion {\n const trimmedBase = base.replace(/\\/$/, \"\");\n return {\n entryUrl: `${trimmedBase}/${manifest.entry}`,\n entryIntegrity: manifest.entryIntegrity,\n ...(manifest.browserManifest\n ? { browserManifestUrl: `${trimmedBase}/${manifest.browserManifest.file}` }\n : {}),\n ...(manifest.ssr\n ? {\n ssrEntryUrl: `${trimmedBase}/${manifest.ssr.entry}`,\n ssrIntegrity: manifest.ssr.integrity,\n }\n : {}),\n ...(manifest.files ? { files: manifest.files } : {}),\n ...(manifest.source ? { source: manifest.source } : {}),\n };\n}\n\n/**\n * Staged-slot preference (ADR 0020/0021 self-contained tier): when a runtime\n * stages its own namespace under `BOS_BUNDLE_DIR`, a slot resolves from the\n * staged dist's own version manifest instead of the config's pin — pinned\n * manifest bytes that predate the image (deploy lag after a release bump)\n * cannot exist in the staged namespace, so their hashed files would 404 the\n * disk and fall through to the network, where the stale immutable bytes\n * still answer 200 and boot a foreign build. The staged manifest is trusted\n * (staged by the image build itself) and skipped entirely when the slot is\n * absent from the staged namespace or the pinned manifest is present (the\n * normal healthy case, which keeps the pin's SRI check).\n */\nfunction readStagedSlotVersion(base: string, pin: SlotPin): ResolvedSlotVersion | null {\n const bundleDir = process.env.BOS_BUNDLE_DIR;\n if (!bundleDir) return null;\n\n const slotDir = bundleUrlToStagedPath(base, bundleDir);\n if (!slotDir || !existsSync(slotDir)) return null;\n\n const pinnedManifestPath = resolveContained(slotDir, pin.manifest);\n if (!pinnedManifestPath || existsSync(pinnedManifestPath)) return null;\n\n const versionsDir = path.join(slotDir, \"versions\");\n if (!existsSync(versionsDir)) return null;\n const manifests = readdirSync(versionsDir)\n .filter((name) => name.endsWith(\".json\"))\n .map((name) => path.join(versionsDir, name))\n .filter((file) => statSync(file).isFile())\n .sort((a, b) => statSync(b).mtimeMs - statSync(a).mtimeMs || (a < b ? -1 : 1));\n if (manifests.length === 0) return null;\n const manifestPath = manifests[0];\n if (!manifestPath) return null;\n\n try {\n const manifest = WorkspaceVersionManifestSchema.parse(\n JSON.parse(readFileSync(manifestPath, \"utf8\")),\n );\n return slotVersionFromManifest(base, manifest);\n } catch {\n return null;\n }\n}\n\nexport async function resolveSlotVersion(input: {\n base: string;\n pin: SlotPin;\n fetchImpl?: typeof fetch;\n}): Promise<ResolvedSlotVersion> {\n const key = `${input.base}::${input.pin.manifest}::${input.pin.integrity}`;\n // content-addressed: a verified pin is cached for the process lifetime and\n // never refetched — the cache IS the last-known-good\n const cached = cache.get(key);\n if (cached) return cached;\n\n const staged = readStagedSlotVersion(input.base, input.pin);\n if (staged) {\n cache.set(key, staged);\n return staged;\n }\n\n const manifestUrl = `${input.base.replace(/\\/$/, \"\")}/${input.pin.manifest.replace(/^\\//, \"\")}`;\n const body = await fetchText(manifestUrl, input.fetchImpl ?? fetch);\n const computed = `sha384-${createHash(\"sha384\").update(body).digest(\"base64\")}`;\n if (computed !== input.pin.integrity) {\n throw new Error(\n `[SRI] version manifest integrity mismatch for ${manifestUrl}\\n Expected: ${input.pin.integrity}\\n Computed: ${computed}`,\n );\n }\n const manifest: WorkspaceVersionManifest = WorkspaceVersionManifestSchema.parse(JSON.parse(body));\n\n const resolved = slotVersionFromManifest(input.base, manifest);\n cache.set(key, resolved);\n return resolved;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "everything-dev",
3
- "version": "2.0.0-rc.8",
3
+ "version": "2.0.0-rc.9",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=20.11"
@@ -243,10 +243,11 @@
243
243
  "dotenv": "^17.3.1",
244
244
  "effect": "4.0.0-rc.117",
245
245
  "@everything-dev/upload-app": "workspace:^",
246
- "every-plugin": "^3.0.0-rc.5",
246
+ "every-plugin": "^3.0.0-rc.6",
247
247
  "execa": "^9.5.2",
248
248
  "glob": "^13.0.6",
249
249
  "near-kit": "^0.20.2",
250
+ "@outlayer/sdk": "0.1.0-alpha.4",
250
251
  "pg": "^8.12.0",
251
252
  "tar": "^7.4.3",
252
253
  "yaml": "2.9.0",
@@ -9,7 +9,7 @@ metadata:
9
9
 
10
10
  # CLI Command Reference
11
11
 
12
- 19 `bos` commands organised by workflow category.
12
+ 20 `bos` commands organised by workflow category.
13
13
 
14
14
  ## Development
15
15
 
@@ -119,6 +119,22 @@ bos upgrade --no-sync # only upgrade packages, skip template sync
119
119
 
120
120
  → [`init-upgrade`](.) skill for catalog strategy, legacy import rewrites, and upgrade+publish flow.
121
121
 
122
+ ### `bos import`
123
+
124
+ Import a workspace subtree (e.g. `plugins/auth`) from an upstream — a GitHub repo, a local directory, a `bos://` published runtime, or (default) the authored config's extends chain. Chain-resolved sources walk outward to the nearest ancestor declaring the workspace; when the ancestor publishes source archives (`publish.sourcePublish`, ADR 0030) the import byte-sources from the pinned, SRI-verified archive (no GitHub needed, `repository` optional) and falls back to the chain's `repository` (pinned to the manifest's git sha, HEAD otherwise) only when no archive exists. Per-file classification is snapshot-baselined; diverging migration chains are reconciled — applied local entries are kept verbatim, colliding upstream migrations are renumbered and appended, journal rebuilt. Unresolvable conflicts (content drift on an applied migration, unreadable journal) hold the chain and gate the run (exit 1) unless `--yes` or an interactive confirmation.
125
+
126
+ **Flags:** `--from <bos://<account>/<gateway> | owner/repo[@ref] | url | dir>` (optional — extends chain when omitted) `--yes` `--dry-run` `--no-install` `--json`
127
+
128
+ ```bash
129
+ bos import plugins/auth # resolved through the extends chain
130
+ bos import plugins/auth --from bos://base.near/base # chain of a published runtime
131
+ bos import plugins/auth --from NEARBuilders/everything-dev@v2.1.0
132
+ bos import plugins/auth --from ./local-checkout --dry-run
133
+ bos import plugins/auth --from owner/repo --yes
134
+ ```
135
+
136
+ → [`init-upgrade`](.) skill for source resolution, classification buckets, migration-chain reconciliation, route deltas, and the `.bos/import-report.md` report.
137
+
122
138
  ### `bos status`
123
139
 
124
140
  Show project health: package versions, parent reachability, last sync, env file status, and update availability.
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: init-upgrade
3
- description: bos init, bos sync, and bos upgrade workflows — template download, snapshot-based conflict detection, package version bumps, and how init/sync select and own files. Use when scaffolding new projects, syncing upstream changes, or upgrading framework packages.
3
+ description: bos init, bos sync, bos import, and bos upgrade workflows — template download, snapshot-based conflict detection, workspace import from upstream repos with divergence reporting, package version bumps, and how init/sync select and own files. Use when scaffolding new projects, syncing upstream changes, importing a workspace subtree from another repo, or upgrading framework packages.
4
4
  metadata:
5
- sources: "packages/everything-dev/src/cli/init.ts,packages/everything-dev/src/cli/sync.ts,packages/everything-dev/src/cli/upgrade.ts,packages/everything-dev/src/cli/snapshot.ts,packages/everything-dev/src/cli.ts,packages/everything-dev/src/merge.ts"
5
+ sources: "packages/everything-dev/src/cli/init.ts,packages/everything-dev/src/cli/sync.ts,packages/everything-dev/src/cli/import.ts,packages/everything-dev/src/commands/import.ts,packages/everything-dev/src/cli/upgrade.ts,packages/everything-dev/src/cli/snapshot.ts,packages/everything-dev/src/cli.ts,packages/everything-dev/src/merge.ts"
6
6
  ---
7
7
 
8
8
  > **Config form:** the authored config is `bos.app.ts` (canonical, preferred when both exist). A legacy `bos.config.json` is still supported for older children. Where this doc says `bos.config.json` for the *local authored file*, read "the authored config". The published artifact on FastKV keeps the key name `bos.config.json`.
9
9
 
10
- # bos init, sync, upgrade
10
+ # bos init, sync, import, upgrade
11
11
 
12
12
  ## bos init
13
13
 
@@ -182,6 +182,76 @@ bos upgrade --dry-run # Preview without making changes
182
182
 
183
183
  Workspace packages use `catalog:` refs so a single version bump in root catalog propagates everywhere. Skips `workspace:*` and `file:` refs.
184
184
 
185
+ ## bos import
186
+
187
+ Imports a workspace subtree (e.g. `plugins/auth`) from an upstream GitHub repo or a local directory — no clone of the full history, just a tarball (or direct local read) of one ref. The upstream can also be resolved through the authored config's `extends` chain (a bos:// URL centric source — see below):
188
+
189
+ ```bash
190
+ bos import plugins/auth # resolved through the extends chain
191
+ bos import plugins/auth --from bos://base.near/base
192
+ bos import plugins/auth --from NEARBuilders/everything-dev
193
+ bos import plugins/auth --from NEARBuilders/everything-dev@v2.1.0
194
+ bos import plugins/auth --from NEARBuilders/everything-dev@everything-dev@2.0.0-rc.8
195
+ bos import plugins/auth --from https://github.com/owner/repo@develop
196
+ bos import plugins/auth --from ./local-checkout --dry-run
197
+ bos import plugins/auth --from owner/repo --yes
198
+ ```
199
+
200
+ **Flags:** `--from <bos://<account>/<gateway> | owner/repo[@ref] | url | dir>` (optional — resolve through the extends chain when omitted), `--yes`, `--dry-run`, `--no-install`, `--json`. The GitHub ref splits on the **first** `@`, so changesets-style tags keep their own `@`.
201
+
202
+ ### Source resolution
203
+
204
+ `--from` takes three shapes:
205
+
206
+ - **`bos://<account>/<gateway>`** — the config published to FastKV by that runtime. The extends chain of that runtime is walked outward to the **nearest ancestor whose own config declares the workspace locally** (`local:<workspace-path>`); the tarball comes from that ancestor's `repository` field (continuing rootward when the declaring runtime itself lacks one).
207
+ - **omitted** — same chain walk, starting from the authored `bos.app.ts` (v2 config only). Errors when the workspace is declared locally in the child (you own it — nothing to import), when no runtime in the chain declares the workspace, or when no ancestor along the chain carries a `repository`.
208
+ - **`<owner/repo>[@ref]`, GitHub URL, or local dir** — explicit source, unchanged.
209
+
210
+ **Ref pinning:** the ancestor's published config pins each workspace to an immutable version manifest. When the ancestor publishes source archives (`publish.sourcePublish` on its authored config, ADR 0030), the import **byte-sources** from the pinned archive: the manifest itself is SRI-verified against the config slot pin, the archive URL + server SRI come from the manifest's `source` field, the bytes are SRI-verified and extracted (repo-root-relative — a drop-in for the GitHub tarball root), and no GitHub dependency exists (the parent's `repository` may be absent or private). If archive fetch fails or its SRI mismatches, the import falls back to the chain-resolved GitHub coordinate with a `Note:`. When the manifest records no `source`, GitHub remains the source: a recorded `git sha` pins the exact deployed commit; otherwise the import falls back to the **default branch (HEAD)** with a `Note:` line. The report's Source section shows both layers: the `bos:// …` extends ref, the source archive URL when used, and the dereferenced `repository @ ref`.
211
+
212
+ ### Classification
213
+
214
+ Each file shared between the local workspace and the upstream subtree is classified against a baseline: `.bos/import-snapshot.json` (written by previous imports), falling back to `.bos/sync-snapshot.json`.
215
+
216
+ | Bucket | Meaning | Action |
217
+ |---|---|---|
218
+ | added | upstream-only | written |
219
+ | unchanged | identical content | nothing (baseline recorded) |
220
+ | updated | local matches baseline, upstream moved | overwritten with upstream (backed up first) |
221
+ | preserved-local | local-only, upstream lacks it | never deleted |
222
+ | preserved-local-edit | upstream matches baseline, local edited | local wins, untouched |
223
+ | merged | diverged `package.json` | structured merge — template wins shared keys, local-only keys and deps preserved |
224
+ | conflict | both changed since baseline, or no baseline exists | gated |
225
+
226
+ Local-only files are never deleted, even when upstream no longer carries them.
227
+
228
+ ### Gating
229
+
230
+ Conflicts — and a migration chain that cannot be applied verbatim (next section) — gate the import:
231
+
232
+ - **Non-TTY without `--yes`:** nothing is written, the report is emitted, exit 1. `--yes` applies upstream over conflicting files (local copies backed up to `.bos/import-backup/<timestamp>/`) and proceeds.
233
+ - **TTY:** an interactive confirm (default No; declining exits 1).
234
+
235
+ A diverged `package.json` is never a conflict when both sides parse — it merges instead.
236
+
237
+ ### Migration chain reconciliation
238
+
239
+ When both sides have `src/db/migrations/` journals, the chain is **reconciled** instead of overwritten:
240
+
241
+ - **Applied entries win.** Every local journal entry is presumed applied to the database and is kept verbatim — never renumbered or rehashed.
242
+ - **Colliding upstream migrations are renumbered and appended.** An upstream entry that shares an idx or lands below the local tail but is not present locally is renumbered after the local tail in upstream order: upstream `0011_team-member-role` with a local tail at idx 12 becomes `0013_team-member-role`. The `.sql` file is copied to the new name, `meta/<idx>_snapshot.json` is renamed to match, and the migration journal under `meta` (`_journal.json`) is rebuilt (local entries verbatim + appended entries carrying upstream's `when`/`version`).
243
+ - **Content matching keeps repeat imports convergent.** An upstream entry whose SQL content hash matches a local entry (e.g. one imported under a renumbered tag earlier) is treated as already imported — nothing is appended twice.
244
+ - **Report.** The import report and console output show the kept set (applied), the appended set (`fromTag → toTag`, new idx), and what the next boot will apply versus what is already applied. Renamed snapshots record upstream intermediate schema states — review `drizzle-kit generate` output against the merged chain before generating new migrations.
245
+ - **Held back.** Only unresolvable drift holds the chain now: a shared tag whose SQL content differs locally (already-applied hashes would drift), or an unreadable journal. Held chain files are not written; the rest of the workspace imports normally. A held chain gates the run even when no other file conflicts.
246
+
247
+ ### Route-set delta
248
+
249
+ Both sides' contract surface is scanned for literal `.route({ method, path })` pairs — the monolithic `<workspace>/src/contract.ts` plus any split `<workspace>/src/contract/**` files, unioned per side (so a monolithic local contract compares correctly against a re-export + split-file upstream). The report lists ours-only and theirs-only `METHOD path` routes so API drift is visible before you port local routes onto the new upstream contract.
250
+
251
+ ### Report and baselines
252
+
253
+ Every run — dry-run, refused, or applied — writes `.bos/import-report.md`: summary table, conflict checklist with reasons and held markers, the migration-chain reconciliation plan (kept/appended/held), route delta, bucket lists, and next steps. Written and unchanged files are recorded to `.bos/import-snapshot.json` (and merged into `.bos/sync-snapshot.json` when one exists) so the next import detects drift instead of starting from zero.
254
+
185
255
  ## bos publish
186
256
 
187
257
  See `everything-dev#publish-sync` for the full publish workflow. A quick reference:
@@ -206,6 +276,8 @@ Unknown keys go after known keys. See `everything-dev#extends-config` for full o
206
276
 
207
277
  **"Sync reports conflicted files."** Your local edits diverged from the snapshot; upgrade applies the template version and leaves your copy in `.bos/sync-backup/` — diff and merge back, or `bos sync --force` deliberately.
208
278
 
279
+ **"Import a workspace from the base platform."** `bos import <workspace> --dry-run` (defaults to the extends chain; or `--from <owner/repo>` for an explicit upstream) first, read `.bos/import-report.md` for the conflict/migration/route picture, then real-run: plain invoke prompts in a TTY, `--yes` applies upstream over conflicts (backed up), and a flagged migration chain stays held until reconciliation.
280
+
209
281
  **"Upgrade framework packages."** `bos upgrade --dry-run` first, then `bos upgrade` — it bumps the root catalog, rewrites workspace refs to `catalog:`, syncs the template, and rewrites legacy imports.
210
282
 
211
283
  ## What comes back when it refuses
@@ -214,5 +286,6 @@ Unknown keys go after known keys. See `everything-dev#extends-config` for full o
214
286
  |---|---|
215
287
  | file listed as `conflicted` in sync results | local file modified since the snapshot AND the template changed — take the template version (your copy is backed up at `.bos/sync-backup/`) or re-apply your change on top |
216
288
  | sync keeps skipping my file | app-owned files that diverged from the snapshot are skipped without `--force`; framework-owned files always update when the template changes |
289
+ | import exits 1 listing files | unresolvable conflicts (or a held migration chain) — read `.bos/import-report.md`, then re-run with `--yes` to apply upstream (local copies land in `.bos/import-backup/`), or port local changes manually first |
217
290
  | `Circular extends detected while resolving upgrade source` | the upgrade source's extends chain loops — resolve from a non-cyclic parent |
218
291
  | init copies fewer files than expected | `buildInitPatterns` filters to the selected plugins + their routes; pass `--overrides ui,api,host` to widen the scaffold |