@codions/portta 0.0.0-develop.157.sha-ae5ce5e → 0.0.0-develop.162.sha-7b40859
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.
- package/dist/assets/skills/portta-workflows/SKILL.md +11 -6
- package/dist/cli.js +143 -80
- package/dist/documentation.json +1 -1
- package/dist/host.js +55 -8
- package/dist/runtime/VERSION +1 -1
- package/package.json +1 -1
package/dist/host.js
CHANGED
|
@@ -46312,6 +46312,9 @@ var AvailableBranchSchema = external_exports.object({
|
|
|
46312
46312
|
var AvailableBranchesQuerySchema = external_exports.object({
|
|
46313
46313
|
includeRemote: BooleanLikeSchema.optional()
|
|
46314
46314
|
});
|
|
46315
|
+
var RemoveWorktreeQuerySchema = external_exports.object({
|
|
46316
|
+
force: BooleanLikeSchema.optional()
|
|
46317
|
+
});
|
|
46315
46318
|
var NumberLikePathParamSchema = external_exports.union([
|
|
46316
46319
|
external_exports.number().int().nonnegative(),
|
|
46317
46320
|
external_exports.string().regex(/^\d+$/).transform((value) => Number(value))
|
|
@@ -47245,6 +47248,7 @@ var apiContract = defineRoutes({
|
|
|
47245
47248
|
summary: "Remove a worktree",
|
|
47246
47249
|
path: apiPaths.removeWorktree,
|
|
47247
47250
|
pathParams: WorktreeNameParamsSchema,
|
|
47251
|
+
query: RemoveWorktreeQuerySchema,
|
|
47248
47252
|
responses: {
|
|
47249
47253
|
200: OkResponseSchema,
|
|
47250
47254
|
...commonErrorResponses
|
|
@@ -49084,6 +49088,21 @@ var NodeGitGateway = class {
|
|
|
49084
49088
|
const result = tryRunGit(["diff", "HEAD", "--no-color"], cwd);
|
|
49085
49089
|
return result.ok ? result.stdout : "";
|
|
49086
49090
|
}
|
|
49091
|
+
/**
|
|
49092
|
+
* Commits reachable from HEAD and from nothing else that would survive this
|
|
49093
|
+
* worktree: not on an origin branch, not on the project's main branch. It
|
|
49094
|
+
* answers "would deleting this branch lose work", which `aheadCount` cannot:
|
|
49095
|
+
* with no upstream and no remote at all, every commit counts as ahead.
|
|
49096
|
+
*/
|
|
49097
|
+
countUnsavedCommits(cwd, baseBranch) {
|
|
49098
|
+
const count = (args) => {
|
|
49099
|
+
const result = tryRunGit(args, cwd);
|
|
49100
|
+
return result.ok ? parseInt(result.stdout, 10) || 0 : null;
|
|
49101
|
+
};
|
|
49102
|
+
const excludingBase = baseBranch ? count(["rev-list", "--count", "HEAD", "--not", "--remotes=origin", baseBranch]) : null;
|
|
49103
|
+
if (excludingBase !== null) return excludingBase;
|
|
49104
|
+
return count(["rev-list", "--count", "HEAD", "--not", "--remotes=origin"]) ?? 0;
|
|
49105
|
+
}
|
|
49087
49106
|
listUnpushedCommits(cwd) {
|
|
49088
49107
|
let result = tryRunGit(["log", "--oneline", "@{upstream}..HEAD"], cwd);
|
|
49089
49108
|
if (!result.ok) {
|
|
@@ -52664,9 +52683,23 @@ var LifecycleService = class {
|
|
|
52664
52683
|
throw this.wrapOperationError(error61);
|
|
52665
52684
|
}
|
|
52666
52685
|
}
|
|
52667
|
-
|
|
52686
|
+
/**
|
|
52687
|
+
* Removing a worktree deletes its branch with `--force`, so anything living
|
|
52688
|
+
* only there is gone. Uncommitted changes and unpushed commits therefore
|
|
52689
|
+
* refuse the removal unless the caller says to discard them.
|
|
52690
|
+
*/
|
|
52691
|
+
async removeWorktree(branch, options = {}) {
|
|
52668
52692
|
try {
|
|
52669
52693
|
const resolved2 = await this.resolveExistingWorktree(branch);
|
|
52694
|
+
if (!options.force) {
|
|
52695
|
+
const unsaved = this.describeUnsavedWork(resolved2.entry);
|
|
52696
|
+
if (unsaved) {
|
|
52697
|
+
throw new LifecycleError(
|
|
52698
|
+
`Worktree has ${unsaved}: ${branch}. Commit or push them, or remove with --force to discard them.`,
|
|
52699
|
+
409
|
|
52700
|
+
);
|
|
52701
|
+
}
|
|
52702
|
+
}
|
|
52670
52703
|
await this.removeResolvedWorktree(resolved2);
|
|
52671
52704
|
} catch (error61) {
|
|
52672
52705
|
throw this.wrapOperationError(error61);
|
|
@@ -52677,15 +52710,21 @@ var LifecycleService = class {
|
|
|
52677
52710
|
const resolvedWorktrees = await this.resolveAllWorktrees();
|
|
52678
52711
|
const sessionName = buildProjectSessionName(this.deps.projectRoot);
|
|
52679
52712
|
const removedBranches = [];
|
|
52713
|
+
const keptBranches = [];
|
|
52680
52714
|
for (const resolved2 of resolvedWorktrees) {
|
|
52681
52715
|
const branch = resolved2.entry.branch ?? resolved2.entry.path;
|
|
52682
52716
|
if (await this.deps.sessions.hasWindow(sessionName, buildWorktreeWindowName(branch))) {
|
|
52683
52717
|
continue;
|
|
52684
52718
|
}
|
|
52719
|
+
const unsaved = this.describeUnsavedWork(resolved2.entry);
|
|
52720
|
+
if (unsaved) {
|
|
52721
|
+
keptBranches.push({ branch, reason: unsaved });
|
|
52722
|
+
continue;
|
|
52723
|
+
}
|
|
52685
52724
|
await this.removeResolvedWorktree(resolved2);
|
|
52686
52725
|
removedBranches.push(branch);
|
|
52687
52726
|
}
|
|
52688
|
-
return { removedBranches };
|
|
52727
|
+
return { removedBranches, keptBranches };
|
|
52689
52728
|
} catch (error61) {
|
|
52690
52729
|
throw this.wrapOperationError(error61);
|
|
52691
52730
|
}
|
|
@@ -53182,6 +53221,14 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
|
|
|
53182
53221
|
}
|
|
53183
53222
|
return cleanupErrors.length > 0 ? cleanupErrors.join("; ") : null;
|
|
53184
53223
|
}
|
|
53224
|
+
/** What this worktree holds that exists nowhere else, or null when it is safe to delete. */
|
|
53225
|
+
describeUnsavedWork(entry) {
|
|
53226
|
+
const status = this.deps.git.readWorktreeStatus(entry.path);
|
|
53227
|
+
if (status.dirty) return "uncommitted changes";
|
|
53228
|
+
const commits = this.deps.git.countUnsavedCommits(entry.path, this.deps.config.workspace.mainBranch);
|
|
53229
|
+
if (commits > 0) return `${commits} commit${commits === 1 ? "" : "s"} that are only here`;
|
|
53230
|
+
return null;
|
|
53231
|
+
}
|
|
53185
53232
|
ensureNoUncommittedChanges(entry) {
|
|
53186
53233
|
const status = this.deps.git.readWorktreeStatus(entry.path);
|
|
53187
53234
|
if (status.dirty) {
|
|
@@ -53278,7 +53325,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
|
|
|
53278
53325
|
const cleanupErrors = [];
|
|
53279
53326
|
for (const branch of [...branches].reverse()) {
|
|
53280
53327
|
try {
|
|
53281
|
-
await this.removeWorktree(branch);
|
|
53328
|
+
await this.removeWorktree(branch, { force: true });
|
|
53282
53329
|
} catch (error61) {
|
|
53283
53330
|
cleanupErrors.push(`rollback failed for ${branch}: ${toErrorMessage2(error61)}`);
|
|
53284
53331
|
}
|
|
@@ -58969,14 +59016,14 @@ ${resolvedPrompt}` : conversationContext;
|
|
|
58969
59016
|
201
|
|
58970
59017
|
);
|
|
58971
59018
|
}
|
|
58972
|
-
async function apiDeleteWorktree(project, name) {
|
|
59019
|
+
async function apiDeleteWorktree(project, name, force) {
|
|
58973
59020
|
return project.withRemovingBranch(name, async () => {
|
|
58974
59021
|
log.info(`[worktree:rm] name=${name}`);
|
|
58975
59022
|
const worktree = project.runtime.projectRuntime.getWorktreeByBranch(name);
|
|
58976
59023
|
const environmentId = worktree ? environmentIdForWorkspace(project.environments.projectEnvironments(), worktree.worktreeId) : null;
|
|
58977
59024
|
const environment = environmentId ? project.environments.environmentForProject(environmentId) : null;
|
|
58978
59025
|
if (environment) await project.environments.destroyEnvironmentRecord(environment);
|
|
58979
|
-
await project.runtime.lifecycleService.removeWorktree(name);
|
|
59026
|
+
await project.runtime.lifecycleService.removeWorktree(name, { force });
|
|
58980
59027
|
log.debug(`[worktree:rm] done name=${name}`);
|
|
58981
59028
|
return jsonResponse({ ok: true });
|
|
58982
59029
|
});
|
|
@@ -59163,9 +59210,9 @@ function worktreeRoutes(deps) {
|
|
|
59163
59210
|
const app = projectRouter();
|
|
59164
59211
|
projectRoute(app, deps, "fetchWorktrees", "Worktrees", (project) => apiGetWorktrees(project));
|
|
59165
59212
|
projectRoute(app, deps, "createWorktree", "Worktrees", (project, { body }) => apiCreateWorktree(project, body));
|
|
59166
|
-
projectRoute(app, deps, "removeWorktree", "Worktrees", (project, { params }) => {
|
|
59213
|
+
projectRoute(app, deps, "removeWorktree", "Worktrees", (project, { params, query: query2 }) => {
|
|
59167
59214
|
const name = worktreeName(params.name);
|
|
59168
|
-
return name instanceof Response ? name : apiDeleteWorktree(project, name);
|
|
59215
|
+
return name instanceof Response ? name : apiDeleteWorktree(project, name, query2.force === true);
|
|
59169
59216
|
});
|
|
59170
59217
|
projectRoute(app, deps, "openWorktree", "Worktrees", (project, { params, body }) => {
|
|
59171
59218
|
const name = worktreeName(params.name);
|
|
@@ -72223,7 +72270,7 @@ function createDaemonTaskflowHost(context) {
|
|
|
72223
72270
|
port: hostListen(env2).port,
|
|
72224
72271
|
workflowBuiltinsDir: taskflowAssets(env2).workflowBuiltinsDir,
|
|
72225
72272
|
version: env2.PORTTA_VERSION || "0.0.0-local",
|
|
72226
|
-
buildDate: true ? "2026-09-
|
|
72273
|
+
buildDate: true ? "2026-09-17T23:23:40Z" : (/* @__PURE__ */ new Date()).toISOString(),
|
|
72227
72274
|
environmentStore: createEnvironmentStore(paths.database),
|
|
72228
72275
|
hostEnvironmentProvider: new HostEnvironmentProvider(),
|
|
72229
72276
|
devContainerProvider: new DevContainerProvider(),
|
package/dist/runtime/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.0.0-develop.
|
|
1
|
+
0.0.0-develop.162.sha-7b40859
|
package/package.json
CHANGED