@jskit-ai/agent-docs 0.1.77 → 0.1.79

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.
@@ -212,7 +212,9 @@ That matters because JSKIT maintenance policy changes over time. If the scaffold
212
212
 
213
213
  `jskit app verify` is worth noticing specifically. Linting, tests, and builds check your source code and runtime behavior. The JSKIT part of that flow runs `doctor`, which checks JSKIT-managed app state: installed package visibility, lock-file-backed managed files, and other JSKIT-specific health rules. It is there because a JSKIT app is not only code. It is also a descriptor-driven managed project.
214
214
 
215
- The starter scaffold also writes `.github/workflows/verify.yml`. That workflow stays intentionally small: it runs `npm run verify` for the normal GitHub Actions gate and leaves browser/auth/database-heavy review flows to app-specific local or CI setups. The `--against <base-ref>` review mode exists in the CLI for local pre-merge checks and for advanced CI pipelines, but it is not assumed by the starter scaffold.
215
+ The starter scaffold also writes `.github/workflows/jskit-verify.yml`. JSKIT generates and owns that workflow as a projection of installed package `ci` contracts. The baseline runs checkout, Node setup, `npm ci`, and `npm run verify`. Packages can add job environment values, service containers, and explicit `before-verify` steps without taking ownership of the whole YAML file. For example, the database runtime adds migrations before verification and its MySQL driver adds a MariaDB service with synthetic CI-only credentials and `DB_CLIENT=mysql2`.
216
+
217
+ The workflow content hash is recorded in `.jskit/lock.json`. Package lifecycle commands refresh it when installed requirements change and refuse to overwrite a workflow that differs from its recorded version. Application-specific CI belongs in another workflow. Use `npx jskit app sync-ci` to refresh an unmodified managed file, or `npx jskit app sync-ci --force` when you explicitly intend to replace an edited file that is already recorded as JSKIT-owned. The `--against <base-ref>` review mode still exists for local pre-merge checks and advanced CI pipelines, but the starter workflow does not assume it.
216
218
 
217
219
  The surface-specific script names are also worth noticing early, even in this tiny app. `dev:home`, `server:home`, and `build:home` are the first concrete places where surface selection shows up in the scaffold. They work by setting `VITE_SURFACE=home` on the client side and `SERVER_SURFACE=home` on the server side. In this first chapter, where `home` is the only surface, those variants behave almost the same as the default commands. Later, once more surfaces exist, those scripts become the simplest way to run or build just one surface at a time.
218
220
 
@@ -761,7 +763,7 @@ That keeps the ownership boundary clear: `packages/main` stays composition-only,
761
763
 
762
764
  The `.jskit/lock.json` file is also important. Treat it like JSKIT's own lock and state file. It records which runtime packages JSKIT believes are installed and which managed changes they introduced. When you use `jskit add`, `jskit update`, or generators that depend on installed package state, this file is part of the source of truth. It belongs in version control, and you should not hand-edit it.
763
765
 
764
- This file is narrower than `package.json`. `package.json` lists every npm dependency the app needs, including plain libraries such as Vue, Fastify, and Vuetify. `.jskit/lock.json` only tracks JSKIT package-install state: which JSKIT runtime packages were installed into the app and which files, text mutations, and dependency entries JSKIT is managing on their behalf.
766
+ This file is narrower than `package.json`. `package.json` lists every npm dependency the app needs, including plain libraries such as Vue, Fastify, and Vuetify. `.jskit/lock.json` tracks JSKIT package-install state: which JSKIT runtime packages were installed, which files, text mutations, and dependency entries JSKIT manages on their behalf, and the owned hash of app-level projections such as the composed CI workflow.
765
767
 
766
768
  On a brand-new default app, the lock file is telling you that the app-local package and the standard shell package are installed from the start:
767
769
 
@@ -799,6 +801,12 @@ On a brand-new default app, the lock file is telling you that the app-local pack
799
801
  "text": { "...": "..." }
800
802
  }
801
803
  }
804
+ },
805
+ "managed": {
806
+ "ciWorkflow": {
807
+ "path": ".github/workflows/jskit-verify.yml",
808
+ "hash": "<generated-sha256>"
809
+ }
802
810
  }
803
811
  }
804
812
  ```
@@ -81,7 +81,17 @@ This gives you a clean ownership split:
81
81
 
82
82
  That split is worth keeping in mind through the rest of the guide. When you see `npm run verify`, read it as "run the app's JSKIT baseline verification policy, then any app-specific extra verification hook".
83
83
 
84
- The starter scaffold also includes `.github/workflows/verify.yml`. That workflow is intentionally conservative: it runs `npm run verify` and does not assume that every app can stand up full browser, auth, seed-data, and database verification inside hosted CI.
84
+ The starter scaffold also includes `.github/workflows/jskit-verify.yml`. This is a JSKIT-managed projection, not a static template. Installed package descriptors can contribute CI environment values, services, and preparation steps through their top-level `ci` contract. JSKIT composes those contributions and renders one verification workflow in this order: checkout, Node setup, `npm ci`, package-contributed `before-verify` steps, and `npm run verify`.
85
+
86
+ For example, `database-runtime` contributes the `database-migrations` step, while `database-runtime-mysql` contributes the MariaDB service and matching synthetic CI-only `DB_*` values. `DB_CLIENT` remains the canonical `mysql2` value. Local `.env` values are never copied into the workflow.
87
+
88
+ The workflow path and generated content hash live under `managed.ciWorkflow` in `.jskit/lock.json`. Package add, remove, update, and app-wide package updates refresh this projection. If the workflow no longer matches its recorded hash, JSKIT refuses to overwrite it during those operations. Move application-specific jobs to another workflow, then explicitly regenerate the managed projection with:
89
+
90
+ ```bash
91
+ npx jskit app sync-ci
92
+ ```
93
+
94
+ The command refuses to replace an edited workflow unless you explicitly run `npx jskit app sync-ci --force`. Even with `--force`, it replaces the file only when `.jskit/lock.json` already records JSKIT ownership. It does not claim an unrecorded `.github/workflows/jskit-verify.yml` or remove a customized legacy `.github/workflows/verify.yml`.
85
95
 
86
96
  If your app uses a non-default npm registry for JSKIT packages, pass it to the maintained CLI command rather than hard-coding it in the scaffold. For example:
87
97
 
@@ -563,6 +573,7 @@ That state lives in `.jskit/lock.json`, which is why lifecycle commands all star
563
573
  - which package is installed
564
574
  - which install options were used
565
575
  - which files, text mutations, dependency entries, and migrations it owns
576
+ - the path and content hash of the composed JSKIT CI workflow
566
577
 
567
578
  The easiest way to think about the lifecycle is:
568
579
 
@@ -571,6 +582,8 @@ The easiest way to think about the lifecycle is:
571
582
  3. `jskit position element ...` reapplies just the positioning layer
572
583
  4. `jskit remove package ...` removes the managed state
573
584
 
585
+ Package add, update, and remove also recompose `.github/workflows/jskit-verify.yml` from the complete installed package set. No individual package owns that file through `mutations.files`; it is one app-level projection with contributions from many descriptors.
586
+
574
587
  That is a better mental model than thinking of these as three unrelated commands.
575
588
 
576
589
  ### `update` re-applies one installed package
@@ -692,6 +705,7 @@ In the current CLI, that includes checks such as:
692
705
  - installed package entries in `.jskit/lock.json`
693
706
  - whether managed files recorded in the lock still exist
694
707
  - whether installed packages are still visible in the package registry
708
+ - whether package CI contributions compose without conflicts and match the managed workflow service, environment, preparation steps, and ordering
695
709
  - explicit `transport` passed to high-level CRUD hooks such as `useCrudList()`, `useCrudView()`, and `useCrudAddEdit()`, where the shared CRUD resource should derive the JSON:API transport automatically
696
710
  - certain JSKIT-specific app checks, such as invalid raw `mdi-*` icon literals in Vue templates when the app uses Vuetify's `mdi-svg` iconset
697
711
  - UI verification receipts for current dirty UI files in git, via `.jskit/verification/ui.json`
@@ -725,7 +739,7 @@ That is a different job from:
725
739
 
726
740
  Those commands can all pass while JSKIT-managed state is still inconsistent. `doctor` is the command that checks that JSKIT's own view of the app still makes sense.
727
741
 
728
- That is exactly why the starter scaffold routes `npm run verify` through `jskit app verify`.
742
+ That is exactly why the starter scaffold routes `npm run verify` through `jskit app verify`. CI structure is checked before lint, test, client-test, and build scripts, so a stale database service or missing migration step fails directly instead of surfacing later as an opaque provider boot failure.
729
743
 
730
744
  It belongs there because JSKIT apps are not only source trees. They also have:
731
745
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.77",
3
+ "version": "0.1.79",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -71,6 +71,27 @@ Exports
71
71
  Local functions
72
72
  - `normalizeAuthServiceDecorator(entry)`
73
73
 
74
+ ### `src/server/booleanFlag.js`
75
+ Exports
76
+ - `parseBooleanFlag(value, fallback = false)`
77
+
78
+ ### `src/server/devAuth.js`
79
+ Exports
80
+ - `assertDevAuthPolicy(policy = {})`
81
+ - `DEV_AUTH_SECRET_HEADER`
82
+ - `ensureDevAuthExchangeAvailable(policy = {}, request = null)`
83
+ - `ensureDevAuthRuntimeAvailable(policy = {}, request = null)`
84
+ - `isLocalDevAuthRequest(request)`
85
+ - `resolveDevAuthPolicy({ enabled = false, nodeEnv = "development", secret = "" } = {})`
86
+ - `resolveDevAuthPolicyFromEnv(env = {})`
87
+ Local functions
88
+ - `normalizeRequestHostname(request)`
89
+ - `normalizeLoopbackIp(value)`
90
+ - `isLoopbackIp(value)`
91
+ - `isLoopbackHostname(value)`
92
+ - `requestHeader(request, name = "")`
93
+ - `secretMatches(value = "", expected = "")`
94
+
74
95
  ### `src/server/inviteTokens.js`
75
96
  Exports
76
97
  - `OPAQUE_INVITE_TOKEN_HASH_PREFIX`
@@ -162,7 +183,6 @@ Exports
162
183
  Exports
163
184
  - `FastifyAuthPolicyServiceProvider`
164
185
  Local functions
165
- - `parseBoolean(value, fallback = false)`
166
186
  - `parseList(value)`
167
187
  - `defaultHasPermission({ permission, permissions = [] } = {})`
168
188
 
@@ -80,18 +80,27 @@ Local functions
80
80
  - `isoFromNow(seconds)`
81
81
  - `isExpiredIso(value)`
82
82
  - `isNormalSession(session)`
83
+ - `isDevAuthSession(session)`
84
+ - `isAuthenticatingSession(session)`
83
85
  - `normalizeDisplayName(value, email)`
84
86
  - `createId(prefix)`
85
87
  - `safeRequestCookies(request)`
88
+ - `unauthenticatedAuthResult(clearSession = false)`
86
89
  - `cookieOptions(isProduction, maxAge)`
87
90
  - `clearCookieOptions(isProduction)`
88
91
  - `buildProfile(user)`
89
92
  - `buildActor(user, profile = null)`
93
+ - `buildAuthResult({ user, session, appProfile = null })`
94
+ - `requireProfileResult(profile, methodName)`
90
95
  - `buildAuthPayload({ user, session, profileProjector, profileOptions = {} })`
96
+ - `findExistingAppProfile(user, profileProjector)`
97
+ - `buildSessionAuthPayload({ devAuth, profileProjector, request, session, user })`
91
98
  - `buildAccessToken({ user, session, secret, ttlSeconds = ACCESS_TTL_SECONDS })`
92
99
  - `buildSessionPayload({ user, session, refreshToken, secret })`
93
100
  - `validatePasswordInput(password)`
94
101
  - `validateEmailInput(email)`
102
+ - `devLoginAsValidationError(fieldErrors = {})`
103
+ - `devLoginAsUserNotFound({ email = "", userId = "" } = {})`
95
104
  - `normalizeInvitationInput(value = null)`
96
105
  - `maybeSendRecoveryEmail(config, recoveryUrl, email)`
97
106
 
@@ -110,7 +119,6 @@ Exports
110
119
  - `AuthLocalServiceProvider`
111
120
  - `resolveLocalBackendMode(scope)`
112
121
  Local functions
113
- - `parseBoolean(value, fallback = false)`
114
122
  - `resolveRuntimeEnv(scope)`
115
123
  - `assertSelectedAuthProvider(env)`
116
124
  - `resolveStoreDir(env)`
@@ -118,6 +126,7 @@ Local functions
118
126
  - `resolveSmtpConfig(env)`
119
127
  - `resolveAppPublicUrl(env, { smtpConfigured })`
120
128
  - `resolveConfig(scope)`
129
+ - `createLazyProfileProjector(scope)`
121
130
 
122
131
  ### `src/server/providers/AuthProviderServiceProvider.js`
123
132
  Exports
@@ -24,10 +24,6 @@ Exports
24
24
  Local functions
25
25
  - `normalizeLocalReturnToPath(value, { fallback = "" } = {})`
26
26
 
27
- ### `src/server/lib/actions/auth.contributor.js`
28
- Exports
29
- - `devLoginAsAction`
30
-
31
27
  ### `src/server/lib/authCookies.js`
32
28
  Exports
33
29
  - `safeRequestCookies(request)`
@@ -106,19 +102,11 @@ Exports
106
102
  - `assertDevAuthBootstrapConfig(config, { userProfilesRepository = null } = {})`
107
103
  - `authenticateDevAuthRequest({ request, accessToken = "", refreshToken = "" }, { config, userProfilesRepository = null } = {})`
108
104
  - `createDevAuthSession(profile, config)`
109
- - `ensureDevAuthBootstrapAvailable(config, request)`
110
105
  - `isDevAuthToken(token)`
111
106
  - `resolveDevAuthConfig({ enabled = false, secret = "", nodeEnv = "development", jwtAudience = "authenticated", accessTtlSeconds = DEFAULT_DEV_AUTH_ACCESS_TTL_SECONDS, refreshTtlSeconds = DEFAULT_DEV_AUTH_REFRESH_TTL_SECONDS } = {})`
112
107
  - `resolveDevAuthProfile(input = {}, { userProfilesRepository = null, validationError } = {})`
113
108
  Local functions
114
- - `parseBoolean(value, fallback = false)`
115
109
  - `normalizePositiveInteger(value, fallback)`
116
- - `normalizeRequestHostname(request)`
117
- - `resolveDirectRemoteAddress(request)`
118
- - `normalizeLoopbackIp(value)`
119
- - `isLoopbackIp(value)`
120
- - `isLoopbackHostname(value)`
121
- - `isLocalDevAuthRequest(request)`
122
110
  - `stripDevAuthTokenPrefix(token)`
123
111
  - `buildProfileFromTokenClaims(payload)`
124
112
  - `resolveProfileFromTokenClaims(payload, { userProfilesRepository = null } = {})`
@@ -136,7 +124,6 @@ Exports
136
124
  Exports
137
125
  - `createService`
138
126
  - `__testables`
139
- - `devLoginAsAction`
140
127
 
141
128
  ### `src/server/lib/oauthFlows.js`
142
129
  Exports
@@ -228,15 +215,12 @@ Exports
228
215
  - `AuthSupabaseServiceProvider`
229
216
  Local functions
230
217
  - `splitCsv(value)`
231
- - `parseBoolean(value, fallback = false)`
232
218
  - `normalizeRecord(value)`
233
219
  - `normalizeOAuthProviderConfigList(value)`
234
220
  - `resolveOAuthConfigFromAppConfig(appConfig)`
235
221
  - `resolveAllowedReturnToOrigins({ appConfig = {}, appPublicUrl = "" } = {})`
236
222
  - `resolveAuthProviderConfig(env, appConfig = {})`
237
223
  - `resolveAuthProfileMode(appConfig = {})`
238
- - `isDevAuthBypassEnabledForRegistration(env)`
239
- - `isDevAuthBypassRequested(env)`
240
224
  - `createProviderIdentityProfileSyncService({ authProviderId = "supabase" } = {})`
241
225
  - `resolveCommonDependencies(scope)`
242
226
  - `resolveRuntimeEnv(scope)`
@@ -258,7 +258,6 @@ Exports
258
258
  Exports
259
259
  - `AuthWebServiceProvider`
260
260
  Local functions
261
- - `parseBoolean(value, fallback = false)`
262
261
  - `resolveDevAuthBootstrapEnabled(scope)`
263
262
 
264
263
  ### `src/server/routes/authRoutes.js`
@@ -198,26 +198,6 @@ Local functions
198
198
  Exports
199
199
  - `resolveActionUser(context, input)`
200
200
 
201
- ### `src/server/previewUserProvisioning.js`
202
- Exports
203
- - `DEFAULT_AUTH_PROVIDER`
204
- - `DEFAULT_DISPLAY_NAME`
205
- - `DEFAULT_EMAIL`
206
- - `ensurePreviewUser(db, profileInput = {})`
207
- - `normalizePreviewUserProfile(profile = {})`
208
- - `profileFromUserRow(user = {}, fallback = {})`
209
- Local functions
210
- - `normalizeText(value = "")`
211
- - `normalizeLowerText(value = "")`
212
- - `normalizeUsername(value = "")`
213
- - `usernameBaseFromEmail(email = "")`
214
- - `buildUsernameCandidate(baseUsername = "", suffix = 0)`
215
- - `isDuplicateError(error)`
216
- - `resolveUniqueUsername(db, baseUsername = "", { excludeUserId = "" } = {})`
217
- - `findPreviewUser(db, profile = {})`
218
- - `ensurePreviewUserRow(db, profile = {})`
219
- - `ensureUserSettings(db, user = {})`
220
-
221
201
  ### `src/server/profileSyncLifecycleContributorRegistry.js`
222
202
  Exports
223
203
  - `PROFILE_SYNC_LIFECYCLE_CONTRIBUTOR_TAG`
@@ -114,25 +114,6 @@ Exports
114
114
  - `routeParamsValidator`
115
115
  - `workspaceSlugParamsValidator`
116
116
 
117
- ### `src/server/previewWorkspaceProvisioning.js`
118
- Exports
119
- - `buildWorkspaceBaseSlug(profile = {})`
120
- - `buildWorkspaceName(profile = {})`
121
- - `ensurePreviewWorkspace(db, user = {}, profile = {}, { appConfig = {}, tenancyMode = "" } = {})`
122
- - `normalizeWorkspaceResult(workspace = null)`
123
- Local functions
124
- - `normalizeText(value = "")`
125
- - `normalizeLowerText(value = "")`
126
- - `workspaceSlugPart(value = "")`
127
- - `usernameBaseFromEmail(email = "")`
128
- - `buildWorkspaceSlugCandidate(baseSlug = "", suffix = 0)`
129
- - `isDuplicateError(error)`
130
- - `resolveUniqueWorkspaceSlug(db, baseSlug = "", { excludeWorkspaceId = "" } = {})`
131
- - `hasWorkspaceTables(db)`
132
- - `findPreviewWorkspace(db, user = {}, { isPersonal = true } = {})`
133
- - `ensureWorkspaceSettings(db, workspace = {})`
134
- - `ensureOwnerMembership(db, workspace = {}, user = {})`
135
-
136
117
  ### `src/server/registerWorkspaceBootstrap.js`
137
118
  Exports
138
119
  - `registerWorkspaceBootstrap(app)`
@@ -33,12 +33,13 @@ Exports
33
33
 
34
34
  ### `src/server/index.js`
35
35
  Exports
36
- - `createApp({ appName, appTitle = null, template = DEFAULT_TEMPLATE, target = null, initialBundles = DEFAULT_INITIAL_BUNDLES, tenancyMode = null, force = false, dryRun = false, cwd = process.cwd() })`
36
+ - `createApp({ appName, appTitle = null, template = DEFAULT_TEMPLATE, target = null, initialBundles = DEFAULT_INITIAL_BUNDLES, playwrightVersion = DEFAULT_PLAYWRIGHT_VERSION, tenancyMode = null, force = false, dryRun = false, cwd = process.cwd() })`
37
37
  - `runCli(argv, { stdout = process.stdout, stderr = process.stderr, stdin = process.stdin, cwd = process.cwd(), readlineFactory = createReadlineInterface } = {})`
38
38
  Local functions
39
39
  - `toAppTitle(appName)`
40
40
  - `normalizeInitialBundlesPreset(value, { showUsage = true } = {})`
41
41
  - `normalizeTenancyMode(value, { showUsage = true } = {})`
42
+ - `normalizePlaywrightVersion(value, { showUsage = true } = {})`
42
43
  - `buildInitialSetupCommands(initialBundles)`
43
44
  - `validateAppName(appName, { showUsage = true } = {})`
44
45
  - `parseOptionWithValue(argv, index, optionName)`
@@ -73,6 +73,75 @@ Local functions
73
73
  - `collectPlannedCapabilityIssues(plannedPackageIds, packageRegistry)`
74
74
  - `collectExclusiveCapabilityIssues(plannedPackageIds, packageRegistry)`
75
75
 
76
+ ### `src/server/cliRuntime/ci/composer.js`
77
+ Exports
78
+ - `CiCompositionError`
79
+ - `composeCiContributions(packageEntries = [])`
80
+ Local functions
81
+ - `canonicalValue(value)`
82
+ - `valuesMatch(left, right)`
83
+ - `formatConflictValue(value)`
84
+ - `normalizePackageEntries(packageEntries = [])`
85
+ - `appendSource(sourceMap, key, packageId)`
86
+ - `conflict({ kind, id, existing, incoming, existingPackages, incomingPackage })`
87
+ - `sourcesToObject(sourceMap)`
88
+
89
+ ### `src/server/cliRuntime/ci/contract.js`
90
+ Exports
91
+ - `CI_STEP_PHASE_BEFORE_VERIFY`
92
+ - `CI_STEP_PHASES`
93
+ - `normalizeCiContribution(value, context = {})`
94
+ Local functions
95
+ - `isPlainObject(value)`
96
+ - `invalidCiContract(message, { descriptorPath = "", packageId = "" } = {})`
97
+ - `requirePlainObject(value, label, context)`
98
+ - `rejectUnknownKeys(value, allowedKeys, label, context)`
99
+ - `normalizeCiScalar(value, label, context)`
100
+ - `normalizeCiEnvironment(value, label, context)`
101
+ - `normalizeCiPorts(value, label, context)`
102
+ - `normalizeCiHealthCheck(value, label, context)`
103
+ - `normalizeCiService(value, index, context)`
104
+ - `normalizeCiStep(value, index, context)`
105
+
106
+ ### `src/server/cliRuntime/ci/githubWorkflow.js`
107
+ Exports
108
+ - `GENERATED_WORKFLOW_HEADER`
109
+ - `JSKIT_CI_WORKFLOW_RELATIVE_PATH`
110
+ - `LEGACY_CI_WORKFLOW_RELATIVE_PATH`
111
+ - `LEGACY_VERIFY_WORKFLOW_HASH`
112
+ - `buildGithubWorkflowDocument(model = {})`
113
+ - `parseGithubWorkflow(source = "")`
114
+ - `renderGithubServiceOptions(service = {})`
115
+ - `renderGithubWorkflow(model = {})`
116
+ Local functions
117
+ - `quoteDockerOptionValue(value)`
118
+ - `renderGithubService(service = {})`
119
+
120
+ ### `src/server/cliRuntime/ci/managedWorkflow.js`
121
+ Exports
122
+ - `assertAppManagedCiWorkflowUnmodified({ appRoot })`
123
+ - `assertManagedCiWorkflowUnmodified({ appRoot, lock, allowManagedOverwrite = false })`
124
+ - `composeInstalledPackageCi({ lock, packageRegistry, installedPackageIds = null })`
125
+ - `synchronizeAppCiWorkflow({ appRoot, allowManagedOverwrite = false, dryRun = false })`
126
+ - `synchronizeManagedCiWorkflow({ appRoot, lock, packageRegistry, installedPackageIds = null, touchedFiles = null, dryRun = false, allowManagedOverwrite = false })`
127
+ - `validateAppCiWorkflow({ appRoot })`
128
+ - `validateManagedCiWorkflow({ appRoot, lock, packageRegistry })`
129
+ Local functions
130
+ - `contentHash(content = "")`
131
+ - `collectInstalledPackageEntries({ lock, packageRegistry, installedPackageIds = null })`
132
+ - `managedCiRecord(lock = {})`
133
+ - `setManagedCiRecord(lock, record)`
134
+ - `recoveryError(message, { force = false } = {})`
135
+ - `inspectWorkflowOwnership({ appRoot, lock })`
136
+ - `createValidationIssue(code, message, details = {})`
137
+ - `formatRequirementPackages(packageIds = [])`
138
+ - `describeCiRequirements(model = {})`
139
+ - `normalizeActualEnvironment(value)`
140
+ - `collectEnvironmentIssues({ expected, actual, sources, issues })`
141
+ - `collectServiceIssues({ model, verifyJob, issues })`
142
+ - `collectStepIssues({ model, verifyJob, issues })`
143
+ - `loadAppCiContext(appRoot)`
144
+
76
145
  ### `src/server/cliRuntime/completion.js`
77
146
  Exports
78
147
  - `discoverPlacementTargets(appRoot)`
@@ -474,23 +543,6 @@ Local functions
474
543
  - `applyTextReplacements(sourceText = "", replacements = [])`
475
544
  - `collectCrudFormFieldCandidateFiles(appRoot = "")`
476
545
 
477
- ### `src/server/commandHandlers/appCommands/preparePreviewUser.js`
478
- Exports
479
- - `runAppPreparePreviewUserCommand(_ctx = {}, { appRoot = "", options = {}, stdout = process.stdout })`
480
- Local functions
481
- - `normalizeText(value = "")`
482
- - `normalizeLowerText(value = "")`
483
- - `profileFromOptions(options = {})`
484
- - `fileExists(filePath = "")`
485
- - `createAppRequire(appRoot = "")`
486
- - `importFreshModule(filePath = "")`
487
- - `loadKnexConfig(appRoot = "")`
488
- - `importAppPackageExport(appRoot = "", specifier = "", { required = true } = {})`
489
- - `writeProfile(profileFile = "", authProfile = {})`
490
- - `isTrueOption(value)`
491
- - `normalizeTenancyMode(value = "")`
492
- - `hasWorkspaceTables(db)`
493
-
494
546
  ### `src/server/commandHandlers/appCommands/release.js`
495
547
  Exports
496
548
  - `runAppReleaseCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
@@ -512,6 +564,10 @@ Exports
512
564
  Local functions
513
565
  - `ensureCommandSucceeded(result, label, { createCliError, cwd = "", stdout, stderr, quiet = false } = {})`
514
566
 
567
+ ### `src/server/commandHandlers/appCommands/syncCi.js`
568
+ Exports
569
+ - `runAppSyncCiCommand(ctx = {}, { appRoot = "", options = {}, stdout })`
570
+
515
571
  ### `src/server/commandHandlers/appCommands/updatePackages.js`
516
572
  Exports
517
573
  - `runAppUpdatePackagesCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
@@ -901,6 +957,11 @@ Exports
901
957
  ### `src/server/index.js`
902
958
  Exports
903
959
  - `runCli`
960
+ - `synchronizeAppCiWorkflow`
961
+ - `validateAppCiWorkflow`
962
+ - `composeCiContributions`
963
+ - `JSKIT_CI_WORKFLOW_RELATIVE_PATH`
964
+ - `renderGithubWorkflow`
904
965
 
905
966
  ### `src/server/shared/cliError.js`
906
967
  Exports