mainsequence 9.0.4.dev34__py3-none-any.whl → 9.0.5.dev35__py3-none-any.whl
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.
- agent_scaffold/AGENTS.md +2 -2
- agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +13 -5
- agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +2 -1
- agent_scaffold/skills/maintenance/code_repository_maintenance/SKILL.md +87 -52
- agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +21 -10
- agent_scaffold/skills/sdk_code_repository_execution/SKILL.md +1 -1
- mainsequence/cli/api.py +0 -30
- mainsequence/cli/cli.py +48 -240
- mainsequence/cli/local_ops.py +0 -64
- mainsequence/cli/ssh_utils.py +0 -74
- mainsequence/client/models_helpers.py +18 -10
- {mainsequence-9.0.4.dev34.dist-info → mainsequence-9.0.5.dev35.dist-info}/METADATA +1 -1
- {mainsequence-9.0.4.dev34.dist-info → mainsequence-9.0.5.dev35.dist-info}/RECORD +17 -17
- {mainsequence-9.0.4.dev34.dist-info → mainsequence-9.0.5.dev35.dist-info}/WHEEL +0 -0
- {mainsequence-9.0.4.dev34.dist-info → mainsequence-9.0.5.dev35.dist-info}/entry_points.txt +0 -0
- {mainsequence-9.0.4.dev34.dist-info → mainsequence-9.0.5.dev35.dist-info}/licenses/LICENSE +0 -0
- {mainsequence-9.0.4.dev34.dist-info → mainsequence-9.0.5.dev35.dist-info}/top_level.txt +0 -0
agent_scaffold/AGENTS.md
CHANGED
|
@@ -65,8 +65,8 @@ bundle. Platform skills are installed separately under
|
|
|
65
65
|
- CodeRepository context, local SDK execution, repository structure, and
|
|
66
66
|
implementation routing:
|
|
67
67
|
`.agents/skills/mainsequence/sdk_code_repository_execution/SKILL.md`
|
|
68
|
-
- Local environment repair, authentication, explicitly requested updates,
|
|
69
|
-
|
|
68
|
+
- Local environment repair, authentication, explicitly requested updates,
|
|
69
|
+
dependency sync after a dependency change, and publishing with Git:
|
|
70
70
|
`.agents/skills/mainsequence/maintenance/code_repository_maintenance/SKILL.md`
|
|
71
71
|
- Blocker analysis, failure classification, and SDK/platform contract mismatches:
|
|
72
72
|
`.agents/skills/mainsequence/maintenance/bug_auditor/SKILL.md`
|
|
@@ -241,17 +241,24 @@ mainsequence code-repository current --debug --json
|
|
|
241
241
|
```
|
|
242
242
|
|
|
243
243
|
Declare the FastAPI resource in `.mainsequence/workflows/`, validate the
|
|
244
|
-
workflow against the backend template, then
|
|
245
|
-
|
|
244
|
+
workflow against the backend template, then commit and push the tested commit
|
|
245
|
+
with Git and inspect the result:
|
|
246
246
|
|
|
247
247
|
```bash
|
|
248
|
-
|
|
248
|
+
git commit -m "Release Command Center API"
|
|
249
|
+
git push
|
|
249
250
|
mainsequence code-repository resources list --filter resource_type=fastapi
|
|
250
251
|
```
|
|
251
252
|
|
|
253
|
+
When the dependencies changed, run `mainsequence code-repository sync --path .`
|
|
254
|
+
before the commit and include the refreshed `uv.lock` and `requirements.txt`.
|
|
255
|
+
The command runs no Git command and makes no platform request.
|
|
256
|
+
|
|
252
257
|
Verify that:
|
|
253
258
|
|
|
254
|
-
-
|
|
259
|
+
- the push went to the intended Git branch
|
|
260
|
+
- when the workflow sets a `tag_regex`, the repository's CI tagged the pushed
|
|
261
|
+
commit with a matching tag; without a `tag_regex` every push deploys
|
|
255
262
|
- the workflow declaration identifies the tested FastAPI source path
|
|
256
263
|
- resource discovery found that path at the exact deployed commit
|
|
257
264
|
- Django resolved and built the exact image for the workflow event
|
|
@@ -261,7 +268,8 @@ Verify that:
|
|
|
261
268
|
|
|
262
269
|
Enable automatic deployment in the repository workflow when the route paths,
|
|
263
270
|
resource path, and frontend contracts are stable enough for future repository
|
|
264
|
-
events to promote exact images.
|
|
271
|
+
events to promote exact images. Automatic deployment and its `tag_regex` are
|
|
272
|
+
set in the workflow file only; a release update does not accept them.
|
|
265
273
|
|
|
266
274
|
### 6. Verify the deployed API
|
|
267
275
|
|
|
@@ -61,7 +61,8 @@ This skill audits. It does not implement by default.
|
|
|
61
61
|
- RBAC and access issues:
|
|
62
62
|
`.agents/skills/mainsequence/platform_operations/access_control_and_sharing/SKILL.md`
|
|
63
63
|
- environment repair, authentication refresh, SDK updates, managed skill
|
|
64
|
-
refresh, and
|
|
64
|
+
refresh, dependency sync, and publishing with Git after the failure is
|
|
65
|
+
classified:
|
|
65
66
|
`.agents/skills/mainsequence/maintenance/code_repository_maintenance/SKILL.md`
|
|
66
67
|
|
|
67
68
|
## Read First
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mainsequence-code-repository-maintenance
|
|
3
|
-
description: Maintain an existing Main Sequence CodeRepository checkout using the SDK-version-matched CLI. Use for inspecting repository state, building or repairing .venv, refreshing local authentication, performing explicitly requested SDK, skill, or AGENTS.md updates,
|
|
3
|
+
description: Maintain an existing Main Sequence CodeRepository checkout using the SDK-version-matched CLI. Use for inspecting repository state, building or repairing .venv, refreshing local authentication, performing explicitly requested SDK, skill, or AGENTS.md updates, refreshing dependency files with CodeRepository sync, publishing changes with Git, or diagnosing a partially completed maintenance workflow.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Main Sequence CodeRepository Maintenance
|
|
@@ -16,7 +16,8 @@ workflows.
|
|
|
16
16
|
Own:
|
|
17
17
|
|
|
18
18
|
- local CodeRepository inspection and maintenance sequencing;
|
|
19
|
-
- `.venv`, SDK, managed skill, `AGENTS.md`, and Git
|
|
19
|
+
- `.venv`, SDK, managed skill, `AGENTS.md`, dependency sync, and Git publishing
|
|
20
|
+
workflows;
|
|
20
21
|
- precondition checks, explicit approval gates, and partial-failure diagnosis.
|
|
21
22
|
|
|
22
23
|
Do not own:
|
|
@@ -208,60 +209,96 @@ preserve the previous valid managed tree. Because this operation can update
|
|
|
208
209
|
this skill, reload the refreshed `code_repository_maintenance/SKILL.md` before starting
|
|
209
210
|
another maintenance routine.
|
|
210
211
|
|
|
211
|
-
##
|
|
212
|
+
## Sync Dependencies After A Dependency Change
|
|
212
213
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
Before execution:
|
|
214
|
+
Run CodeRepository sync only after the dependencies changed, for example after
|
|
215
|
+
editing `[project.dependencies]` in `pyproject.toml`:
|
|
217
216
|
|
|
218
217
|
```bash
|
|
219
|
-
|
|
220
|
-
git diff --stat
|
|
221
|
-
mainsequence code-repository sync --path . -m "<specific commit message>" --dry-run
|
|
218
|
+
mainsequence code-repository sync --path .
|
|
222
219
|
```
|
|
223
220
|
|
|
224
|
-
|
|
225
|
-
|
|
221
|
+
In the project root it runs `uv lock`, `uv sync`, and the locked runtime export
|
|
222
|
+
`uv export --locked --no-dev --no-hashes` into `requirements.txt`. It accepts
|
|
223
|
+
only `--path`. It sends no request to the platform, creates no SSH or deploy
|
|
224
|
+
key, changes no version, and runs no `git add`, `commit`, `tag`, or `push`.
|
|
225
|
+
Review the changed `uv.lock` and `requirements.txt` and publish them with the
|
|
226
|
+
dependency change.
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
a detached checkout and rejects a Git branch that is not registered under the
|
|
229
|
-
logical CodeRepository. Do not bypass that validation or supply a CodeRepositoryBranch UID
|
|
230
|
-
manually. Register or select the correct Git branch first.
|
|
228
|
+
## Publish With Git
|
|
231
229
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
that future version, rejects an invalid or existing local tag, prints the
|
|
235
|
-
complete plan, and returns without generating an SSH key, querying private
|
|
236
|
-
remote refs, changing dependencies or repository files, or mutating Git state.
|
|
237
|
-
|
|
238
|
-
After review:
|
|
230
|
+
Publish only when the user intends to commit and push the reviewed changes.
|
|
231
|
+
Commit and push with Git as usual:
|
|
239
232
|
|
|
240
233
|
```bash
|
|
241
|
-
|
|
234
|
+
git status --short
|
|
235
|
+
git diff --stat
|
|
236
|
+
git add <reviewed paths>
|
|
237
|
+
git commit -m "<specific commit message>"
|
|
238
|
+
git push
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Review every pending file and stage only the files that belong to the change.
|
|
242
|
+
Do not continue when unrelated or unexplained changes would be included. Push
|
|
243
|
+
to the attached branch that `mainsequence code-repository current` resolved; a
|
|
244
|
+
detached checkout or an unregistered branch is a preflight failure.
|
|
245
|
+
|
|
246
|
+
The platform deploys from the push according to the repository's
|
|
247
|
+
`.mainsequence/workflows/*.yaml`. A declaration's `tag_regex` decides which
|
|
248
|
+
pushes deploy:
|
|
249
|
+
|
|
250
|
+
- omitted or `null`: every push to the branch deploys;
|
|
251
|
+
- a regular expression: a push deploys only when a matching tag points at the
|
|
252
|
+
branch's latest commit.
|
|
253
|
+
|
|
254
|
+
Automatic deployment and `tag_regex` are set in the workflow file only; a
|
|
255
|
+
`ResourceRelease` or `Job` update does not accept them. The Main Sequence
|
|
256
|
+
platform does not create tag names and the CLI does not tag. Versions and
|
|
257
|
+
release tags belong to the repository: the version is raised in
|
|
258
|
+
`pyproject.toml` (for example `uv version --bump patch`) in the commit to
|
|
259
|
+
release, and the repository's own CI creates the tag. Do not create or push a
|
|
260
|
+
release tag by hand unless the user asks for it. When the user wants tag-based
|
|
261
|
+
releases and the repository has no such CI yet, propose a workflow like this
|
|
262
|
+
example and wait for approval before adding it:
|
|
263
|
+
|
|
264
|
+
```yaml
|
|
265
|
+
# Example: .github/workflows/release.yml in the CodeRepository
|
|
266
|
+
name: release
|
|
267
|
+
on:
|
|
268
|
+
push:
|
|
269
|
+
branches: [main]
|
|
270
|
+
concurrency:
|
|
271
|
+
group: release-main
|
|
272
|
+
cancel-in-progress: false
|
|
273
|
+
permissions:
|
|
274
|
+
contents: write
|
|
275
|
+
jobs:
|
|
276
|
+
release:
|
|
277
|
+
runs-on: ubuntu-latest
|
|
278
|
+
steps:
|
|
279
|
+
- uses: actions/checkout@v4
|
|
280
|
+
with:
|
|
281
|
+
fetch-depth: 0
|
|
282
|
+
- uses: astral-sh/setup-uv@v6
|
|
283
|
+
- run: uv sync --locked
|
|
284
|
+
- run: uv run pytest
|
|
285
|
+
- name: Tag the version declared in pyproject.toml
|
|
286
|
+
run: |
|
|
287
|
+
TAG="v$(uv version --short)"
|
|
288
|
+
if git rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
|
|
289
|
+
echo "$TAG already exists; nothing to release"
|
|
290
|
+
exit 0
|
|
291
|
+
fi
|
|
292
|
+
git tag "$TAG" "$GITHUB_SHA"
|
|
293
|
+
git push origin "refs/tags/$TAG"
|
|
242
294
|
```
|
|
243
295
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
invalid or existing local tag;
|
|
251
|
-
3. registers a new or inaccessible key through the owning CodeRepository and verifies a dry-run push with
|
|
252
|
-
that forced identity;
|
|
253
|
-
4. queries the exact tag ref on `origin` and stops if it exists or cannot be checked;
|
|
254
|
-
5. applies the patch version bump and verifies it matches the preview;
|
|
255
|
-
6. runs `uv lock` and `uv sync`;
|
|
256
|
-
7. exports locked production requirements;
|
|
257
|
-
8. stages and commits the changes;
|
|
258
|
-
9. creates the returned annotated tag unchanged; and
|
|
259
|
-
10. atomically pushes the explicit branch and tag refs with `--follow-tags`.
|
|
260
|
-
|
|
261
|
-
Do not offer alternate bump modes, a no-push mode, or a hand-written sequence
|
|
262
|
-
of equivalent commands. Do not call `sync-after-commit` or any backend repair
|
|
263
|
-
endpoint. The GitHub branch-push webhook owns backend repository
|
|
264
|
-
reconciliation.
|
|
296
|
+
With that example, a `tag_regex` such as `^v[0-9]+\.[0-9]+\.[0-9]+$` deploys
|
|
297
|
+
only the commits CI tagged. Details:
|
|
298
|
+
<https://mainsequence-sdk.github.io/mainsequence-sdk/knowledge/infrastructure/scheduling_jobs/>
|
|
299
|
+
|
|
300
|
+
Do not call `sync-after-commit` or any backend repair endpoint. The GitHub
|
|
301
|
+
branch-push webhook owns backend repository reconciliation.
|
|
265
302
|
|
|
266
303
|
## Diagnose Partial Completion Before Retrying
|
|
267
304
|
|
|
@@ -273,12 +310,10 @@ Never rerun an entire mutating workflow blindly.
|
|
|
273
310
|
environment, and the failed command before retrying.
|
|
274
311
|
- After a skill refresh failure, keep the previous managed tree and identify
|
|
275
312
|
whether the SDK or platform lane failed.
|
|
276
|
-
- After a sync failure, inspect `
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
A blind sync retry may create another patch bump or collide with an existing
|
|
281
|
-
commit or tag.
|
|
313
|
+
- After a dependency sync failure, inspect `pyproject.toml`, `uv.lock`, and the
|
|
314
|
+
exact failing `uv` output; the command stops at the first failing step.
|
|
315
|
+
- After a push failure, inspect `git status`, `git log -1`, and the upstream
|
|
316
|
+
branch before retrying.
|
|
282
317
|
|
|
283
318
|
## Validate And Report
|
|
284
319
|
|
|
@@ -289,7 +324,7 @@ documentation, and the changed files. Report:
|
|
|
289
324
|
- the code repository path and installed SDK version;
|
|
290
325
|
- files or generated state changed;
|
|
291
326
|
- validation run and its result;
|
|
292
|
-
- whether changes remain local or were committed
|
|
327
|
+
- whether changes remain local or were committed and pushed;
|
|
293
328
|
- any remaining authentication, environment, Git, or webhook verification
|
|
294
329
|
gap.
|
|
295
330
|
|
|
@@ -217,24 +217,33 @@ For deployed APIs, agents, or other supported resources:
|
|
|
217
217
|
|
|
218
218
|
### 6.1 Automatic ResourceRelease deployment
|
|
219
219
|
|
|
220
|
-
`automatic_deployment` is the automated deployment opt-in flag on a `ResourceRelease`. It means
|
|
220
|
+
`automatic_deployment` is the automated deployment opt-in flag on a `ResourceRelease`. It means a Git push can rotate an existing release to the pushed CodeRepository commit for the same resource path.
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
Automatic deployment and its `tag_regex` are set in the repository's `.mainsequence/workflows/*.yaml` only. A `ResourceRelease` or `Job` update does not accept `automatic_deployment` or `automatic_redeployment_policy`; the SDK models expose both as read-only fields. Change the workflow file, commit it, and push it.
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
The declaration's `tag_regex` decides which pushes deploy:
|
|
225
|
+
|
|
226
|
+
- omitted or `null`: every push to the branch deploys
|
|
227
|
+
- a regular expression: a push deploys only when a matching tag points at the branch's latest commit
|
|
228
|
+
|
|
229
|
+
The platform does not create or name tags. Release tags come from the repository's own CI, for example a GitHub Actions workflow that tags the version declared in `pyproject.toml` after the tests pass. The maintenance skill `.agents/skills/mainsequence/maintenance/code_repository_maintenance/SKILL.md` has an example. `mainsequence code-repository sync` only refreshes `uv.lock`, the local environment, and `requirements.txt`; it does not commit, tag, or push.
|
|
230
|
+
|
|
231
|
+
When `automatic_deployment=True`, a qualifying push may create a unified `DeploymentRun` with `target_type="resource_release"` and source `repository_event`. That run:
|
|
232
|
+
|
|
233
|
+
- reads the pushed commit
|
|
225
234
|
- resolves the current code repository resource at the release's existing resource path
|
|
226
235
|
- resolves supporting resources required by the release kind
|
|
227
236
|
- creates or resolves the code repository image for that commit
|
|
228
237
|
- redeploys the existing release to the current resource, README, and code repository image
|
|
229
238
|
- records state, phase, outcome, revision context, artifact context, steps, logs, result, and errors on the deployment run
|
|
230
239
|
|
|
231
|
-
This is not a local development shortcut. It does not deploy unpushed local files. The
|
|
240
|
+
This is not a local development shortcut. It does not deploy unpushed local files. The commit must be pushed, carry a matching tag when the workflow sets a `tag_regex`, and code repository resource discovery must find the resource at the same path for that commit.
|
|
232
241
|
|
|
233
242
|
Enable `automatic_deployment` only when:
|
|
234
243
|
|
|
235
|
-
- the release should track the
|
|
244
|
+
- the release should track the branch's pushed commits, or its tagged releases when a `tag_regex` is set
|
|
236
245
|
- the resource path is stable across commits
|
|
237
|
-
- the
|
|
246
|
+
- the pushed branch, and its tags when a `tag_regex` is set, are an acceptable deployment source for that release
|
|
238
247
|
- required supporting resources are available for the current commit
|
|
239
248
|
- the team accepts CI/CD-style rotation for this release
|
|
240
249
|
|
|
@@ -244,7 +253,7 @@ Keep `automatic_deployment` disabled when:
|
|
|
244
253
|
- each release rotation needs human approval
|
|
245
254
|
- the resource path or entrypoint is still moving
|
|
246
255
|
- API or widget contracts are not stable enough for automatic rotation
|
|
247
|
-
- the
|
|
256
|
+
- the pushed branch is not the intended deployment source
|
|
248
257
|
|
|
249
258
|
Declare opted-in releases in the repository workflow and validate the file
|
|
250
259
|
against the backend template. Repository events create deployment runs.
|
|
@@ -276,7 +285,8 @@ When reviewing an orchestration task, look for:
|
|
|
276
285
|
- no run/log verification after creation
|
|
277
286
|
- unsafe use of `--strict`
|
|
278
287
|
- workflows depending on laptop-specific file paths instead of Artifacts
|
|
279
|
-
- `automatic_deployment` enabled without an explicit decision about
|
|
288
|
+
- `automatic_deployment` enabled without an explicit decision about push-driven CI/CD rotation and `tag_regex`
|
|
289
|
+
- client code that tries to set `automatic_deployment` or `automatic_redeployment_policy` through a release or Job update instead of the workflow file
|
|
280
290
|
- assumptions that automatic deployment will deploy local unpushed changes
|
|
281
291
|
- automatic release rotation where the resource path or required supporting resources are not stable
|
|
282
292
|
- tasks that are really resource/release problems rather than simple job problems
|
|
@@ -297,7 +307,8 @@ Do not claim success until you have checked:
|
|
|
297
307
|
- runs and logs were inspected when execution success matters
|
|
298
308
|
- resources and releases were verified when deployment success matters
|
|
299
309
|
- `automatic_deployment` is intentionally enabled or disabled on each release
|
|
300
|
-
-
|
|
310
|
+
- the workflow's `tag_regex` is intentional, and the repository's CI creates matching tags when one is set
|
|
311
|
+
- automatic deployment runs were inspected when push-driven rotation matters
|
|
301
312
|
- automatic deployment results match the intended commit, resource, README, image, and terminal status
|
|
302
313
|
|
|
303
314
|
If the workflow uses `.mainsequence/workflows/`, also check:
|
|
@@ -320,7 +331,7 @@ If the workflow uses Artifacts, also check:
|
|
|
320
331
|
- a Job workflow cannot resolve an exact source image
|
|
321
332
|
- an automatically deployed Job has no persisted synchronized CodeRepositoryBranch commit
|
|
322
333
|
- the workflow depends on local file paths that should be platform Artifacts
|
|
323
|
-
- automatic deployment is requested but the deployment source branch
|
|
334
|
+
- automatic deployment is requested but the deployment source branch or its `tag_regex` is unclear
|
|
324
335
|
- automatic deployment is requested but the resource path or required README is not stable
|
|
325
336
|
- the task is actually about RBAC policy rather than orchestration
|
|
326
337
|
- the task is actually about producer semantics rather than platform execution
|
|
@@ -54,7 +54,7 @@ Do not let this skill become a domain manual.
|
|
|
54
54
|
- CodeRepository audits, blocker analysis, and upstream SDK assessment:
|
|
55
55
|
`.agents/skills/mainsequence/maintenance/bug_auditor/SKILL.md`
|
|
56
56
|
- local environment repair, CodeRepository authentication refresh, SDK updates,
|
|
57
|
-
managed skill refresh, and
|
|
57
|
+
managed skill refresh, dependency sync, and publishing with Git:
|
|
58
58
|
`.agents/skills/mainsequence/maintenance/code_repository_maintenance/SKILL.md`
|
|
59
59
|
- jobs, schedules, artifacts, images, resources, and releases:
|
|
60
60
|
`.agents/skills/mainsequence/platform_operations/orchestration_and_releases/SKILL.md`
|
mainsequence/cli/api.py
CHANGED
|
@@ -949,36 +949,6 @@ def get_code_repository_repository(
|
|
|
949
949
|
raise ApiError(f"GitHubRepositoryBinding fetch failed: {e}") from e
|
|
950
950
|
|
|
951
951
|
|
|
952
|
-
def render_code_repository_branch_default_redeployment_tag(
|
|
953
|
-
code_repository_branch_uid: str,
|
|
954
|
-
*,
|
|
955
|
-
version: str,
|
|
956
|
-
) -> str:
|
|
957
|
-
normalized_uid = str(code_repository_branch_uid).strip()
|
|
958
|
-
normalized_version = str(version).strip()
|
|
959
|
-
if not normalized_uid:
|
|
960
|
-
raise ApiError("CodeRepositoryBranch UID is required.")
|
|
961
|
-
if not normalized_version:
|
|
962
|
-
raise ApiError("CodeRepository version is required.")
|
|
963
|
-
|
|
964
|
-
r = authed(
|
|
965
|
-
"POST",
|
|
966
|
-
f"/api/v1/code-repository-branches/{normalized_uid}/default-redeployment-tag/",
|
|
967
|
-
{"version": normalized_version},
|
|
968
|
-
)
|
|
969
|
-
if not r.ok:
|
|
970
|
-
raise ApiError(f"Default redeployment tag rendering failed ({r.status_code}).")
|
|
971
|
-
payload = r.json()
|
|
972
|
-
if not isinstance(payload, dict):
|
|
973
|
-
raise ApiError("Default redeployment tag rendering returned an unexpected payload.")
|
|
974
|
-
if str(payload.get("version") or "").strip() != normalized_version:
|
|
975
|
-
raise ApiError("Default redeployment tag rendering returned another version.")
|
|
976
|
-
tag_name = str(payload.get("tag_name") or "").strip()
|
|
977
|
-
if not tag_name:
|
|
978
|
-
raise ApiError("Default redeployment tag rendering returned no tag name.")
|
|
979
|
-
return tag_name
|
|
980
|
-
|
|
981
|
-
|
|
982
952
|
def resolve_code_repository_branch_uid(code_repository_branch_ref: str) -> str:
|
|
983
953
|
payload = get_code_repository_branch(code_repository_branch_ref)
|
|
984
954
|
normalized_uid = str(payload.get("uid") or "").strip()
|
mainsequence/cli/cli.py
CHANGED
|
@@ -7,9 +7,8 @@ MainSequence CLI entrypoint.
|
|
|
7
7
|
Parity with VS Code extension:
|
|
8
8
|
- settings set-backend
|
|
9
9
|
- logout (clear tokens)
|
|
10
|
-
- code-repository freeze-env (compile environment)
|
|
11
10
|
- code-repository build_local_venv (create local .venv from pyproject + uv sync)
|
|
12
|
-
- code-repository sync (uv
|
|
11
|
+
- code-repository sync (uv lock + uv sync + requirements.txt export; no Git, no backend request)
|
|
13
12
|
- code-repository build-docker-env (docker build + devcontainer config)
|
|
14
13
|
- local `.env` provisioning during set-up-locally writes the backend endpoint and no credential
|
|
15
14
|
- refresh-token (renew the saved session; it belongs to the machine, not to a checkout)
|
|
@@ -159,7 +158,6 @@ from .api import (
|
|
|
159
158
|
remove_secret_user_from_view,
|
|
160
159
|
remove_team_user_from_edit,
|
|
161
160
|
remove_team_user_from_view,
|
|
162
|
-
render_code_repository_branch_default_redeployment_tag,
|
|
163
161
|
repo_name_from_git_url,
|
|
164
162
|
resolve_code_repository,
|
|
165
163
|
run_code_repository_job,
|
|
@@ -188,11 +186,8 @@ from .local_ops import (
|
|
|
188
186
|
ensure_venv,
|
|
189
187
|
git_origin,
|
|
190
188
|
normalize_path,
|
|
191
|
-
run_cmd,
|
|
192
189
|
run_uv,
|
|
193
190
|
uv_export_requirements,
|
|
194
|
-
uv_preview_patch_version,
|
|
195
|
-
uv_project_version,
|
|
196
191
|
)
|
|
197
192
|
from .model_filters import build_cli_model_filter_rows, parse_cli_model_filters
|
|
198
193
|
from .pydantic_cli import (
|
|
@@ -206,12 +201,8 @@ from .ssh_utils import (
|
|
|
206
201
|
open_folder,
|
|
207
202
|
open_signed_terminal,
|
|
208
203
|
repository_ssh_key_paths,
|
|
209
|
-
require_ssh_git_origin,
|
|
210
204
|
start_agent_and_add_key,
|
|
211
|
-
verify_git_push_access,
|
|
212
205
|
verify_git_remote_access,
|
|
213
|
-
verify_git_remote_tag_absent,
|
|
214
|
-
verify_git_tag_absent,
|
|
215
206
|
)
|
|
216
207
|
from .ui import error, info, print_kv, print_table, status, success, warn
|
|
217
208
|
|
|
@@ -7288,259 +7279,76 @@ def code_repository_build_local_venv(
|
|
|
7288
7279
|
success(f"Local .venv built for Python requirement {python_request}.")
|
|
7289
7280
|
|
|
7290
7281
|
|
|
7291
|
-
@code_repository.command("freeze-env")
|
|
7292
|
-
def code_repository_freeze_env(
|
|
7293
|
-
code_repository_id: str | None = typer.Argument(
|
|
7294
|
-
None, help="Optional CodeRepository UID assertion against the current Git worktree"
|
|
7295
|
-
),
|
|
7296
|
-
path: str | None = typer.Option(None, "--path", help="CodeRepository directory"),
|
|
7297
|
-
ensure_uv: bool = typer.Option(
|
|
7298
|
-
True,
|
|
7299
|
-
"--ensure-uv/--no-ensure-uv",
|
|
7300
|
-
help="Allow resolving uv from PATH when it is not present inside .venv.",
|
|
7301
|
-
),
|
|
7302
|
-
):
|
|
7303
|
-
"""
|
|
7304
|
-
Export locked runtime dependencies into `requirements.txt` using `uv`.
|
|
7305
|
-
|
|
7306
|
-
Development dependency groups are excluded from the runtime export.
|
|
7307
|
-
|
|
7308
|
-
Parameters
|
|
7309
|
-
----------
|
|
7310
|
-
code_repository_id:
|
|
7311
|
-
Optional CodeRepository UID assertion against the current Git worktree.
|
|
7312
|
-
path:
|
|
7313
|
-
Explicit local path.
|
|
7314
|
-
ensure_uv:
|
|
7315
|
-
Allow resolving `uv` from PATH when it is not present inside `.venv`.
|
|
7316
|
-
|
|
7317
|
-
Examples
|
|
7318
|
-
--------
|
|
7319
|
-
```bash
|
|
7320
|
-
mainsequence code-repository freeze-env code-repository-uid-123
|
|
7321
|
-
mainsequence code-repository freeze-env --path .
|
|
7322
|
-
mainsequence code-repository freeze-env --path . --no-ensure-uv
|
|
7323
|
-
```
|
|
7324
|
-
"""
|
|
7325
|
-
code_repository_dir = _resolve_code_repository_dir(code_repository_id, path)
|
|
7326
|
-
ensure_venv(code_repository_dir)
|
|
7327
|
-
|
|
7328
|
-
uv = (
|
|
7329
|
-
ensure_uv_installed(code_repository_dir)
|
|
7330
|
-
if ensure_uv
|
|
7331
|
-
else (ensure_venv(code_repository_dir).uv or None)
|
|
7332
|
-
)
|
|
7333
|
-
if not uv:
|
|
7334
|
-
error("uv not found in .venv and --no-ensure-uv was used.")
|
|
7335
|
-
raise typer.Exit(1)
|
|
7336
|
-
|
|
7337
|
-
with status("Exporting requirements.txt via uv..."):
|
|
7338
|
-
uv_export_requirements(
|
|
7339
|
-
uv,
|
|
7340
|
-
cwd=code_repository_dir,
|
|
7341
|
-
locked=True,
|
|
7342
|
-
no_dev=True,
|
|
7343
|
-
no_hashes=True,
|
|
7344
|
-
output_file="requirements.txt",
|
|
7345
|
-
)
|
|
7346
|
-
|
|
7347
|
-
success(f"Wrote: {code_repository_dir / 'requirements.txt'}")
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
7282
|
@code_repository.command("sync")
|
|
7351
7283
|
def code_repository_sync(
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
path: str | None = typer.Option(None, "--path", help="CodeRepository directory"),
|
|
7357
|
-
message_opt: str | None = typer.Option(None, "--message", "-m", help="Git commit message"),
|
|
7358
|
-
dry_run: bool = typer.Option(
|
|
7359
|
-
False,
|
|
7360
|
-
"--dry-run",
|
|
7361
|
-
help=(
|
|
7362
|
-
"Run read-only preflight and print steps without generating keys or "
|
|
7363
|
-
"changing the CodeRepository"
|
|
7364
|
-
),
|
|
7284
|
+
path: str | None = typer.Option(
|
|
7285
|
+
None,
|
|
7286
|
+
"--path",
|
|
7287
|
+
help="Project root that holds pyproject.toml (default: the current directory)",
|
|
7365
7288
|
),
|
|
7366
7289
|
):
|
|
7367
7290
|
"""
|
|
7368
|
-
|
|
7291
|
+
Refresh the project's dependency files after a dependency change.
|
|
7369
7292
|
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7293
|
+
Runs three `uv` steps in the project root:
|
|
7294
|
+
|
|
7295
|
+
1. `uv lock`
|
|
7296
|
+
2. `uv sync`
|
|
7297
|
+
3. `uv export --locked --no-dev --no-hashes` into `requirements.txt`
|
|
7298
|
+
|
|
7299
|
+
The command changes local files only. It sends no request to the platform,
|
|
7300
|
+
creates no SSH or deploy key, changes no version, and runs no Git command.
|
|
7301
|
+
Review the changed files, then commit and push them yourself. Release tags,
|
|
7302
|
+
when a repository uses them, are created by the repository's own CI.
|
|
7378
7303
|
|
|
7379
7304
|
Parameters
|
|
7380
7305
|
----------
|
|
7381
|
-
message:
|
|
7382
|
-
Commit message. Can be passed positionally or via `--message`.
|
|
7383
|
-
code_repository_id:
|
|
7384
|
-
Optional CodeRepository UID assertion against the current Git worktree.
|
|
7385
7306
|
path:
|
|
7386
|
-
|
|
7387
|
-
dry_run:
|
|
7388
|
-
Run read-only preflight and print the plan without generating keys or
|
|
7389
|
-
changing CodeRepository files, dependencies, Git state, or backend state.
|
|
7307
|
+
Project root. Defaults to the current directory.
|
|
7390
7308
|
|
|
7391
7309
|
Examples
|
|
7392
7310
|
--------
|
|
7393
7311
|
```bash
|
|
7394
|
-
mainsequence code-repository sync
|
|
7395
|
-
mainsequence code-repository sync
|
|
7396
|
-
mainsequence code-repository sync -m "Preview only" --path . --dry-run
|
|
7312
|
+
mainsequence code-repository sync
|
|
7313
|
+
mainsequence code-repository sync --path .
|
|
7397
7314
|
```
|
|
7398
7315
|
"""
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
message = message if message is not None else message_opt
|
|
7404
|
-
code_repository_dir = _resolve_code_repository_dir(code_repository_id, path)
|
|
7405
|
-
|
|
7406
|
-
safe_message = (
|
|
7407
|
-
str(message or "").replace("\r", " ").replace("\n", " ").replace('"', "'").strip()
|
|
7408
|
-
)
|
|
7409
|
-
if not safe_message:
|
|
7410
|
-
error("Commit message is required.")
|
|
7316
|
+
project_dir = normalize_path(path) if path else pathlib.Path.cwd()
|
|
7317
|
+
if not project_dir.is_dir():
|
|
7318
|
+
error(f"Folder does not exist: {project_dir}")
|
|
7411
7319
|
raise typer.Exit(1)
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
code_repository_dir=code_repository_dir,
|
|
7417
|
-
)
|
|
7418
|
-
code_repository_ref = str(get_code_repository_context().code_repository_uid or "").strip()
|
|
7419
|
-
except ApiError as exc:
|
|
7420
|
-
error(f"CodeRepository sync preflight failed: {exc}")
|
|
7421
|
-
raise typer.Exit(1) from exc
|
|
7422
|
-
|
|
7423
|
-
info(
|
|
7424
|
-
"CodeRepository sync preflight resolved "
|
|
7425
|
-
f"Git branch {git_branch!r} to CodeRepositoryBranch {code_repository_branch_uid}."
|
|
7426
|
-
)
|
|
7427
|
-
|
|
7428
|
-
origin = git_origin(code_repository_dir)
|
|
7429
|
-
repo_name = repo_name_from_git_url(origin) or code_repository_dir.name
|
|
7430
|
-
try:
|
|
7431
|
-
require_ssh_git_origin(origin)
|
|
7432
|
-
except ValueError as exc:
|
|
7433
|
-
error(f"CodeRepository sync preflight failed: {exc}")
|
|
7434
|
-
raise typer.Exit(1) from exc
|
|
7435
|
-
|
|
7436
|
-
try:
|
|
7437
|
-
ensure_venv(code_repository_dir)
|
|
7438
|
-
uv = ensure_uv_installed(code_repository_dir)
|
|
7439
|
-
current_version = uv_project_version(uv, cwd=code_repository_dir)
|
|
7440
|
-
next_version = uv_preview_patch_version(uv, cwd=code_repository_dir)
|
|
7441
|
-
tag = render_code_repository_branch_default_redeployment_tag(
|
|
7442
|
-
code_repository_branch_uid,
|
|
7443
|
-
version=next_version,
|
|
7444
|
-
)
|
|
7445
|
-
verify_git_tag_absent(code_repository_dir, tag)
|
|
7446
|
-
except (ApiError, RuntimeError) as exc:
|
|
7447
|
-
error(f"CodeRepository sync tag preflight failed: {exc}")
|
|
7448
|
-
raise typer.Exit(1) from exc
|
|
7449
|
-
|
|
7450
|
-
steps = [
|
|
7451
|
-
"preview uv patch version",
|
|
7452
|
-
"request backend default redeployment tag",
|
|
7453
|
-
"verify backend tag does not exist locally",
|
|
7454
|
-
"ensure repository SSH key",
|
|
7455
|
-
"register a new or inaccessible SSH key through the owning CodeRepository",
|
|
7456
|
-
"git push --dry-run --follow-tags origin HEAD:refs/heads/<branch>",
|
|
7457
|
-
"verify exact backend tag does not exist remotely",
|
|
7458
|
-
"uv version --bump patch",
|
|
7459
|
-
"verify bumped version matches the preflight version",
|
|
7460
|
-
"uv lock",
|
|
7461
|
-
"uv sync",
|
|
7462
|
-
"uv export (locked) -> requirements.txt",
|
|
7463
|
-
"git add -A",
|
|
7464
|
-
f'git commit -m "{safe_message}"',
|
|
7465
|
-
"git tag -a <backend tag> -m <backend tag>",
|
|
7466
|
-
"git push --atomic --follow-tags origin HEAD:refs/heads/<branch> refs/tags/<backend tag>:refs/tags/<backend tag>",
|
|
7467
|
-
]
|
|
7468
|
-
|
|
7469
|
-
print_kv(
|
|
7470
|
-
"Sync release",
|
|
7471
|
-
[
|
|
7472
|
-
("Current version", current_version),
|
|
7473
|
-
("Next version", next_version),
|
|
7474
|
-
("Branch tag", tag),
|
|
7475
|
-
],
|
|
7476
|
-
)
|
|
7477
|
-
print_table("Sync plan", ["Step"], [[s] for s in steps])
|
|
7478
|
-
|
|
7479
|
-
if dry_run:
|
|
7480
|
-
warn("Dry run: read-only preflight complete; no changes made.")
|
|
7481
|
-
return
|
|
7482
|
-
|
|
7483
|
-
try:
|
|
7484
|
-
_key_path, _public_key, env = _ensure_code_repository_repository_ssh_access(
|
|
7485
|
-
origin=origin,
|
|
7486
|
-
code_repository_ref=code_repository_ref,
|
|
7487
|
-
verify_access=lambda ssh_env: verify_git_push_access(
|
|
7488
|
-
code_repository_dir,
|
|
7489
|
-
git_branch,
|
|
7490
|
-
ssh_env,
|
|
7491
|
-
),
|
|
7320
|
+
if not (project_dir / "pyproject.toml").is_file():
|
|
7321
|
+
error(
|
|
7322
|
+
f"pyproject.toml not found in {project_dir}. "
|
|
7323
|
+
"Run this command in the project root or pass --path."
|
|
7492
7324
|
)
|
|
7493
|
-
|
|
7494
|
-
error(f"CodeRepository sync SSH preflight failed: {exc}")
|
|
7495
|
-
raise typer.Exit(1) from exc
|
|
7325
|
+
raise typer.Exit(1)
|
|
7496
7326
|
|
|
7497
7327
|
try:
|
|
7498
|
-
|
|
7328
|
+
uv = ensure_uv_installed(project_dir)
|
|
7329
|
+
with status("Locking, syncing and exporting dependencies via uv..."):
|
|
7330
|
+
run_uv(uv, ["lock"], cwd=project_dir)
|
|
7331
|
+
run_uv(uv, ["sync"], cwd=project_dir)
|
|
7332
|
+
# `uv sync` can prune ad hoc packages from `.venv`, including a `uv`
|
|
7333
|
+
# executable that was installed there by hand.
|
|
7334
|
+
uv = ensure_uv_installed(project_dir)
|
|
7335
|
+
uv_export_requirements(
|
|
7336
|
+
uv,
|
|
7337
|
+
cwd=project_dir,
|
|
7338
|
+
locked=True,
|
|
7339
|
+
no_dev=True,
|
|
7340
|
+
no_hashes=True,
|
|
7341
|
+
output_file="requirements.txt",
|
|
7342
|
+
)
|
|
7499
7343
|
except RuntimeError as exc:
|
|
7500
|
-
error(f"CodeRepository sync
|
|
7344
|
+
error(f"CodeRepository sync failed: {exc}")
|
|
7501
7345
|
raise typer.Exit(1) from exc
|
|
7502
7346
|
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
f"CodeRepository sync version verification failed: uv produced {version}; "
|
|
7509
|
-
f"preflight expected {next_version}."
|
|
7510
|
-
)
|
|
7511
|
-
raise typer.Exit(1)
|
|
7512
|
-
run_uv(uv, ["lock"], cwd=code_repository_dir, env=env)
|
|
7513
|
-
run_uv(uv, ["sync"], cwd=code_repository_dir, env=env)
|
|
7514
|
-
# `uv sync` can prune ad hoc packages from `.venv`, including a `uv`
|
|
7515
|
-
# executable that was installed there just for this workflow.
|
|
7516
|
-
uv = ensure_uv_installed(code_repository_dir)
|
|
7517
|
-
uv_export_requirements(
|
|
7518
|
-
uv,
|
|
7519
|
-
cwd=code_repository_dir,
|
|
7520
|
-
locked=True,
|
|
7521
|
-
no_dev=True,
|
|
7522
|
-
no_hashes=True,
|
|
7523
|
-
output_file="requirements.txt",
|
|
7524
|
-
)
|
|
7525
|
-
|
|
7526
|
-
run_cmd(["git", "add", "-A"], cwd=code_repository_dir, env=env)
|
|
7527
|
-
run_cmd(["git", "commit", "-m", safe_message], cwd=code_repository_dir, env=env)
|
|
7528
|
-
run_cmd(["git", "tag", "-a", tag, "-m", tag], cwd=code_repository_dir, env=env)
|
|
7529
|
-
run_cmd(
|
|
7530
|
-
[
|
|
7531
|
-
"git",
|
|
7532
|
-
"push",
|
|
7533
|
-
"--atomic",
|
|
7534
|
-
"--follow-tags",
|
|
7535
|
-
"origin",
|
|
7536
|
-
f"HEAD:refs/heads/{git_branch}",
|
|
7537
|
-
f"refs/tags/{tag}:refs/tags/{tag}",
|
|
7538
|
-
],
|
|
7539
|
-
cwd=code_repository_dir,
|
|
7540
|
-
env=env,
|
|
7541
|
-
)
|
|
7542
|
-
|
|
7543
|
-
success(f"Synced: {repo_name}")
|
|
7347
|
+
success(f"Dependencies synced in {project_dir}.")
|
|
7348
|
+
info(
|
|
7349
|
+
"Nothing was committed or pushed. Review uv.lock and requirements.txt, "
|
|
7350
|
+
"then commit and push them yourself."
|
|
7351
|
+
)
|
|
7544
7352
|
|
|
7545
7353
|
|
|
7546
7354
|
@code_repository.command("build-docker-env")
|
mainsequence/cli/local_ops.py
CHANGED
|
@@ -11,7 +11,6 @@ Local operations shared by several commands:
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
-
import json
|
|
15
14
|
import os
|
|
16
15
|
import pathlib
|
|
17
16
|
import shutil
|
|
@@ -102,69 +101,6 @@ def run_uv(
|
|
|
102
101
|
run_cmd([str(uv_path), *args], cwd=cwd, env=env)
|
|
103
102
|
|
|
104
103
|
|
|
105
|
-
def uv_project_version(
|
|
106
|
-
uv_path: pathlib.Path,
|
|
107
|
-
cwd: pathlib.Path,
|
|
108
|
-
env: dict[str, str] | None = None,
|
|
109
|
-
) -> str:
|
|
110
|
-
"""Return the current package version reported by ``uv version --short``."""
|
|
111
|
-
result = subprocess.run(
|
|
112
|
-
[str(uv_path), "version", "--short"],
|
|
113
|
-
cwd=str(cwd),
|
|
114
|
-
env=env,
|
|
115
|
-
capture_output=True,
|
|
116
|
-
text=True,
|
|
117
|
-
)
|
|
118
|
-
if result.returncode != 0:
|
|
119
|
-
detail = (result.stderr or result.stdout or "").strip()
|
|
120
|
-
suffix = f": {detail}" if detail else ""
|
|
121
|
-
raise RuntimeError(
|
|
122
|
-
f"Command failed ({result.returncode}): {uv_path} version --short{suffix}"
|
|
123
|
-
)
|
|
124
|
-
version = (result.stdout or "").strip()
|
|
125
|
-
if not version:
|
|
126
|
-
raise RuntimeError("uv version --short returned an empty package version.")
|
|
127
|
-
return version.splitlines()[-1].strip()
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def uv_preview_patch_version(
|
|
131
|
-
uv_path: pathlib.Path,
|
|
132
|
-
cwd: pathlib.Path,
|
|
133
|
-
env: dict[str, str] | None = None,
|
|
134
|
-
) -> str:
|
|
135
|
-
"""Return the version ``uv version --bump patch`` would produce without mutation."""
|
|
136
|
-
result = subprocess.run(
|
|
137
|
-
[
|
|
138
|
-
str(uv_path),
|
|
139
|
-
"version",
|
|
140
|
-
"--bump",
|
|
141
|
-
"patch",
|
|
142
|
-
"--dry-run",
|
|
143
|
-
"--output-format",
|
|
144
|
-
"json",
|
|
145
|
-
],
|
|
146
|
-
cwd=str(cwd),
|
|
147
|
-
env=env,
|
|
148
|
-
capture_output=True,
|
|
149
|
-
text=True,
|
|
150
|
-
)
|
|
151
|
-
if result.returncode != 0:
|
|
152
|
-
detail = (result.stderr or result.stdout or "").strip()
|
|
153
|
-
suffix = f": {detail}" if detail else ""
|
|
154
|
-
raise RuntimeError(
|
|
155
|
-
f"Command failed ({result.returncode}): {uv_path} version --bump patch "
|
|
156
|
-
f"--dry-run --output-format json{suffix}"
|
|
157
|
-
)
|
|
158
|
-
try:
|
|
159
|
-
payload = json.loads(result.stdout or "")
|
|
160
|
-
except json.JSONDecodeError as exc:
|
|
161
|
-
raise RuntimeError("uv version patch preview returned invalid JSON.") from exc
|
|
162
|
-
version = payload.get("version") if isinstance(payload, dict) else None
|
|
163
|
-
if not isinstance(version, str) or not version.strip():
|
|
164
|
-
raise RuntimeError("uv version patch preview returned no package version.")
|
|
165
|
-
return version.strip()
|
|
166
|
-
|
|
167
|
-
|
|
168
104
|
def git_origin(code_repository_dir: pathlib.Path) -> str:
|
|
169
105
|
"""
|
|
170
106
|
Return git remote origin URL.
|
mainsequence/cli/ssh_utils.py
CHANGED
|
@@ -148,80 +148,6 @@ def verify_git_remote_access(repo_url: str, env: dict[str, str]) -> None:
|
|
|
148
148
|
)
|
|
149
149
|
|
|
150
150
|
|
|
151
|
-
def verify_git_push_access(
|
|
152
|
-
repo_dir: str | pathlib.Path,
|
|
153
|
-
branch: str,
|
|
154
|
-
env: dict[str, str],
|
|
155
|
-
) -> None:
|
|
156
|
-
rc, out, err = run(
|
|
157
|
-
"git",
|
|
158
|
-
"push",
|
|
159
|
-
"--dry-run",
|
|
160
|
-
"--follow-tags",
|
|
161
|
-
"origin",
|
|
162
|
-
f"HEAD:refs/heads/{branch}",
|
|
163
|
-
env=env,
|
|
164
|
-
cwd=str(repo_dir),
|
|
165
|
-
)
|
|
166
|
-
if rc != 0:
|
|
167
|
-
detail = (err or out).strip()
|
|
168
|
-
raise RuntimeError(
|
|
169
|
-
"Git push access verification failed" + (f": {detail}" if detail else ".")
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def verify_git_tag_absent(repo_dir: str | pathlib.Path, tag_name: str) -> None:
|
|
174
|
-
"""Reject an invalid tag or one that already exists in the local repository."""
|
|
175
|
-
tag = str(tag_name or "").strip()
|
|
176
|
-
if not tag or "\n" in tag or "\r" in tag:
|
|
177
|
-
raise RuntimeError("Git tag must contain one non-empty line.")
|
|
178
|
-
ref = f"refs/tags/{tag}"
|
|
179
|
-
rc, out, err = run("git", "check-ref-format", ref, cwd=str(repo_dir))
|
|
180
|
-
if rc != 0:
|
|
181
|
-
detail = (err or out).strip()
|
|
182
|
-
raise RuntimeError(f"Invalid Git tag: {tag}" + (f": {detail}" if detail else "."))
|
|
183
|
-
rc, out, err = run("git", "show-ref", "--verify", "--quiet", ref, cwd=str(repo_dir))
|
|
184
|
-
if rc == 0:
|
|
185
|
-
raise RuntimeError(f"Git tag already exists locally: {tag}")
|
|
186
|
-
if rc != 1:
|
|
187
|
-
detail = (err or out).strip()
|
|
188
|
-
raise RuntimeError(
|
|
189
|
-
f"Could not check whether Git tag already exists: {tag}"
|
|
190
|
-
+ (f": {detail}" if detail else ".")
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
def verify_git_remote_tag_absent(
|
|
195
|
-
repo_dir: str | pathlib.Path,
|
|
196
|
-
tag_name: str,
|
|
197
|
-
env: dict[str, str],
|
|
198
|
-
) -> None:
|
|
199
|
-
"""Reject an exact tag that already exists on origin using the forced identity."""
|
|
200
|
-
tag = str(tag_name or "").strip()
|
|
201
|
-
if not tag or "\n" in tag or "\r" in tag:
|
|
202
|
-
raise RuntimeError("Git tag must contain one non-empty line.")
|
|
203
|
-
ref = f"refs/tags/{tag}"
|
|
204
|
-
rc, out, err = run(
|
|
205
|
-
"git",
|
|
206
|
-
"ls-remote",
|
|
207
|
-
"--exit-code",
|
|
208
|
-
"--refs",
|
|
209
|
-
"--tags",
|
|
210
|
-
"origin",
|
|
211
|
-
ref,
|
|
212
|
-
env=env,
|
|
213
|
-
cwd=str(repo_dir),
|
|
214
|
-
)
|
|
215
|
-
if rc == 0:
|
|
216
|
-
raise RuntimeError(f"Git tag already exists remotely: {tag}")
|
|
217
|
-
if rc != 2:
|
|
218
|
-
detail = (err or out).strip()
|
|
219
|
-
raise RuntimeError(
|
|
220
|
-
f"Could not check whether Git tag exists remotely: {tag}"
|
|
221
|
-
+ (f": {detail}" if detail else ".")
|
|
222
|
-
)
|
|
223
|
-
|
|
224
|
-
|
|
225
151
|
def start_agent_and_add_key(key_path: pathlib.Path) -> dict:
|
|
226
152
|
env = os.environ.copy()
|
|
227
153
|
# try existing agent
|
|
@@ -105,15 +105,17 @@ class AutomaticRedeploymentPolicy(BaseModel):
|
|
|
105
105
|
...,
|
|
106
106
|
title="Tag Regex",
|
|
107
107
|
description=(
|
|
108
|
-
"Regular expression matched against
|
|
109
|
-
"
|
|
108
|
+
"Regular expression matched against repository tags, set by `tag_regex` "
|
|
109
|
+
"in the repository's `.mainsequence/workflows/*.yaml`. Null deploys every "
|
|
110
|
+
"push; a regex deploys only when a matching tag points at the branch's "
|
|
111
|
+
"latest commit."
|
|
110
112
|
),
|
|
111
113
|
examples=[None, r"^v(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$"],
|
|
112
114
|
)
|
|
113
115
|
policy_revision: PositiveInt | None = Field(
|
|
114
116
|
default=None,
|
|
115
117
|
title="Policy Revision",
|
|
116
|
-
description=
|
|
118
|
+
description="Read-only backend-owned immutable revision.",
|
|
117
119
|
examples=[1, 3],
|
|
118
120
|
)
|
|
119
121
|
|
|
@@ -278,13 +280,18 @@ class Job(CurrentCodeRepositoryBranchCollectionMixin, BaseObjectOrm, BasePydanti
|
|
|
278
280
|
automatic_deployment: bool = Field(
|
|
279
281
|
default=False,
|
|
280
282
|
description=(
|
|
281
|
-
"Whether future qualifying
|
|
282
|
-
"this Job to another exact image. It never selects an initial image."
|
|
283
|
+
"Read-only. Whether future qualifying repository pushes may promote "
|
|
284
|
+
"this Job to another exact image. It never selects an initial image. "
|
|
285
|
+
"It is set in the repository's `.mainsequence/workflows/*.yaml`; a Job "
|
|
286
|
+
"update does not accept it."
|
|
283
287
|
),
|
|
284
288
|
)
|
|
285
289
|
automatic_redeployment_policy: AutomaticRedeploymentPolicy | None = Field(
|
|
286
290
|
default=None,
|
|
287
|
-
description=(
|
|
291
|
+
description=(
|
|
292
|
+
"Read-only standalone Job promotion policy, set in the repository's "
|
|
293
|
+
"workflow file. Target-owned backing Jobs return null."
|
|
294
|
+
),
|
|
288
295
|
)
|
|
289
296
|
|
|
290
297
|
|
|
@@ -1018,8 +1025,9 @@ class ResourceRelease(
|
|
|
1018
1025
|
default=False,
|
|
1019
1026
|
title="Automatic Deployment",
|
|
1020
1027
|
description=(
|
|
1021
|
-
"Whether repository
|
|
1022
|
-
"
|
|
1028
|
+
"Read-only. Whether repository pushes rotate this release to the pushed "
|
|
1029
|
+
"commit. It is set in the repository's `.mainsequence/workflows/*.yaml`; "
|
|
1030
|
+
"a release update does not accept it."
|
|
1023
1031
|
),
|
|
1024
1032
|
examples=[False, True],
|
|
1025
1033
|
)
|
|
@@ -1027,8 +1035,8 @@ class ResourceRelease(
|
|
|
1027
1035
|
default=None,
|
|
1028
1036
|
title="Automatic Redeployment Policy",
|
|
1029
1037
|
description=(
|
|
1030
|
-
"
|
|
1031
|
-
"
|
|
1038
|
+
"Read-only tag matching policy and its current immutable revision, set "
|
|
1039
|
+
"by `tag_regex` in the repository's workflow file."
|
|
1032
1040
|
),
|
|
1033
1041
|
)
|
|
1034
1042
|
COLLECTION_CREATE_SUPPORTED: ClassVar[bool] = False
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
agent_scaffold/AGENTS.md,sha256=
|
|
1
|
+
agent_scaffold/AGENTS.md,sha256=W91rpnyQuoQIa-3dsebIYyuwnbGLvkmuq_8X5k2hTAw,6399
|
|
2
2
|
agent_scaffold/skills/a2a_sdk_execution/SKILL.md,sha256=NKtcXibE8TxZzKzz1KzJ2cVZ_EeuJJkb660U6wLvZ3s,11809
|
|
3
|
-
agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md,sha256=
|
|
3
|
+
agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md,sha256=EEU3eZGgOmY0KOWTgDZ5RJIrLtM8p6yqK894jM7-ySg,14357
|
|
4
4
|
agent_scaffold/skills/mainsequence-inference/SKILL.md,sha256=IrVnpuzFMZ3_x5oSH4OiPZsZ5jFf_aKdxEynrQhnRZE,11627
|
|
5
|
-
agent_scaffold/skills/maintenance/bug_auditor/SKILL.md,sha256=
|
|
6
|
-
agent_scaffold/skills/maintenance/code_repository_maintenance/SKILL.md,sha256=
|
|
5
|
+
agent_scaffold/skills/maintenance/bug_auditor/SKILL.md,sha256=CCKs7edyZ9RK-WtAgXJXucokJFXZxk8sRUe0_imFtu8,8610
|
|
6
|
+
agent_scaffold/skills/maintenance/code_repository_maintenance/SKILL.md,sha256=IOslLL8QBsw_M_J1PHm9eLjUtUBBuxW69Tz2_lpnink,14324
|
|
7
7
|
agent_scaffold/skills/maintenance/metatables_transition/SKILL.md,sha256=PisgpytcksJnfZMS6aiPCmahsT3fm8DIwk_cefXA2qU,3759
|
|
8
8
|
agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md,sha256=o1rIlYAC7ejV7gKKf-BaglIZY1YkDO5Y27F6e2eK_94,8571
|
|
9
|
-
agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md,sha256=
|
|
10
|
-
agent_scaffold/skills/sdk_code_repository_execution/SKILL.md,sha256=
|
|
9
|
+
agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md,sha256=gxX9HidCJJSEd2Vd6cmiiodX3dFcbI5EmA-GoOhEmMY,16488
|
|
10
|
+
agent_scaffold/skills/sdk_code_repository_execution/SKILL.md,sha256=zly7MheB-Sjd0x6l_oPCOTBqkL2E4SSXwTlfSwdIPfQ,10196
|
|
11
11
|
mainsequence/__init__.py,sha256=70CbIo7ZG1mzi5uwkqDtVESunBE0RanHjeFg4ptfsA0,385
|
|
12
12
|
mainsequence/__main__.py,sha256=KuAP69uduS2ImrPIgNMzbGBRepZzjqvUONu5vFh4v4A,176
|
|
13
13
|
mainsequence/_request_identity.py,sha256=jiroPFVDM8vphEf9VXuggQJKUOGohfk7-pDwJSOILEw,1211
|
|
@@ -20,18 +20,18 @@ mainsequence/repository_identity_security.py,sha256=Cdywndhiy1zJFUPh-FfM90RjZ3Hg
|
|
|
20
20
|
mainsequence/runtime_flags.py,sha256=1eTM7VRRhnuZ_GXcmFhqAmdEKwyQYMyZcPsio88vJRQ,378
|
|
21
21
|
mainsequence/scaffold_skills.py,sha256=k0V6eKC5AwbHr9wB9UGMJNF-8eJ0_1izF4-BU01KHrg,10606
|
|
22
22
|
mainsequence/cli/__init__.py,sha256=sMWTnomCaISjnureLuXFRqOzkH2Y77uYEivsd-M6_8Y,28
|
|
23
|
-
mainsequence/cli/api.py,sha256=
|
|
23
|
+
mainsequence/cli/api.py,sha256=emn5UsIpQ0qvGLnW7MpNPYenQZjR4NJ6SGDKmLo6gHk,127404
|
|
24
24
|
mainsequence/cli/browser_auth.py,sha256=C-Sbpt0Pr9Pv3Z9dO80TMk7zPcaaZ-4zvW0tbRVMrTU,9863
|
|
25
|
-
mainsequence/cli/cli.py,sha256=
|
|
25
|
+
mainsequence/cli/cli.py,sha256=zo3ptVxluTYAIeIAluGQPwgFY-_vr0SO3BthCGuVK-0,268962
|
|
26
26
|
mainsequence/cli/code_repository_status.py,sha256=SHEnU8YSWFowPG6dEdE4Yd8CS1tIcJSE1MXFLfvD3Os,5975
|
|
27
27
|
mainsequence/cli/config.py,sha256=4AGDEUPAJ1GzoDX3FzYYFvGMKfeAXM38Kh7Yv-OQLQQ,45595
|
|
28
28
|
mainsequence/cli/docker_utils.py,sha256=eAnp9MI042cHWwKasA5IF2I7INL3A6tV2JX-cSIe7rc,10687
|
|
29
29
|
mainsequence/cli/doctor.py,sha256=_1XHd72jheRDt7dEJHd6hbBSSpCPpMwwFDUOLcdkii8,4550
|
|
30
|
-
mainsequence/cli/local_ops.py,sha256=
|
|
30
|
+
mainsequence/cli/local_ops.py,sha256=15XzdIxooWqUYgWDnKB81KCmXrCdYd3AGCVazVHD1MQ,4363
|
|
31
31
|
mainsequence/cli/model_filters.py,sha256=4Lo2l8d_giQ4PI5an1s4g9fHXNR5l7rPyTT8EvgMXJk,4668
|
|
32
32
|
mainsequence/cli/pydantic_cli.py,sha256=zmFNYv14NrjgXbOszY9qmzDBu-0-J5S2Ado-eMIIyEQ,6674
|
|
33
33
|
mainsequence/cli/sdk_utils.py,sha256=SFuSzh8WDNf21mLiDa51K8Fqe5XiLWh2KhHj8zUjCXo,2701
|
|
34
|
-
mainsequence/cli/ssh_utils.py,sha256=
|
|
34
|
+
mainsequence/cli/ssh_utils.py,sha256=m7HgFHZQ545sxY9igfQLpaNjWHm4SiN9VwCkAuGy2yw,11124
|
|
35
35
|
mainsequence/cli/ui.py,sha256=memd6pmjALfGj8zndGCx_z80ztQeqTcOvcofU0un34U,2277
|
|
36
36
|
mainsequence/client/__init__.py,sha256=lsr9JWxeVqOG0KRoHErW5M40ACPSR7SAEE508dTN5XM,672
|
|
37
37
|
mainsequence/client/agent_runtime_models.py,sha256=lay0DN3lN5p6-3ajVsaHvPgcmrURFwrNfTb6upoImm4,66642
|
|
@@ -42,7 +42,7 @@ mainsequence/client/exceptions.py,sha256=xx2L4l3OMNsTybbYkiTKK398ahnutEascM0It35
|
|
|
42
42
|
mainsequence/client/github_issues.py,sha256=pSTUw3UPrmE6wqnpoJctartTaNSq6iu6PQRrd8hip6I,14568
|
|
43
43
|
mainsequence/client/inference.py,sha256=iMg3l5DGW6PQeVkz38Z3lTpxryMO14CTK6gIRHLYUBE,7368
|
|
44
44
|
mainsequence/client/models_foundry.py,sha256=iN1jJzDokfniEQF0Ac5eepAB7L5pVjJnKavaHLP7BHA,36310
|
|
45
|
-
mainsequence/client/models_helpers.py,sha256=
|
|
45
|
+
mainsequence/client/models_helpers.py,sha256=CTT7FxgQNNF9ubAiI731ssaVv7L_JWtgDBKlMpMpRVE,46213
|
|
46
46
|
mainsequence/client/models_user.py,sha256=BU_hfn4-4KqYz3nsaPlXuYZmUG6_-7YM892mkM92Zyo,37613
|
|
47
47
|
mainsequence/client/observability.py,sha256=_WrDKCaNk_TXmKElKCXC1inork6Exxxe8FRY4m1GI9s,16008
|
|
48
48
|
mainsequence/client/utils.py,sha256=fQur4p-ojLWTMcNWlYWx7uZKbGNEc4c2kJq1Wl_w070,31925
|
|
@@ -52,9 +52,9 @@ mainsequence/instrumentation/utils.py,sha256=b-ihjSioAepeLfMpudM2SqCtvnxMqIXileH
|
|
|
52
52
|
mainsequence/server/__init__.py,sha256=559DiiBcCP6veWRmK2mXUEbsl7gbZofTvsbTUFjn0VE,82
|
|
53
53
|
mainsequence/server/caller_assertions.py,sha256=a7V5_zgpyiEe8oKO4JRRGf05FjZaiXAyAyqMXSTJJvI,9845
|
|
54
54
|
mainsequence/server/fastapi.py,sha256=tD1aVuJOgoBTu7H8bs9IldPNYRT4fhkr1leN3KZP1pI,10521
|
|
55
|
-
mainsequence-9.0.
|
|
56
|
-
mainsequence-9.0.
|
|
57
|
-
mainsequence-9.0.
|
|
58
|
-
mainsequence-9.0.
|
|
59
|
-
mainsequence-9.0.
|
|
60
|
-
mainsequence-9.0.
|
|
55
|
+
mainsequence-9.0.5.dev35.dist-info/licenses/LICENSE,sha256=b6Ecsk8wjsEby3lbSzdljR6hHiFGHBizt9iWV2p1c_I,1074
|
|
56
|
+
mainsequence-9.0.5.dev35.dist-info/METADATA,sha256=HYSJqUwGcWWmlNcxp4vUjFKfu44zc95InZpazsy2LRQ,7435
|
|
57
|
+
mainsequence-9.0.5.dev35.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
58
|
+
mainsequence-9.0.5.dev35.dist-info/entry_points.txt,sha256=XGAOq3-mF2lWWpeRJvoaWyMarRcK167mH1g124aGdUs,88
|
|
59
|
+
mainsequence-9.0.5.dev35.dist-info/top_level.txt,sha256=BFeblM_Q9q0cUWBvTxnfWcWQEHtf5XZi9nOS-Gdfwus,28
|
|
60
|
+
mainsequence-9.0.5.dev35.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|