@open-mercato/cezar 0.9.0-pr646.708 → 0.9.0
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/README.md +1 -17
- package/dist/config.d.ts +0 -14
- package/dist/config.js +0 -39
- package/dist/config.js.map +1 -1
- package/dist/core/claude-ui-mapper.d.ts +0 -9
- package/dist/core/claude-ui-mapper.js +2 -31
- package/dist/core/claude-ui-mapper.js.map +1 -1
- package/dist/core/codex-app-server-runner.js +18 -19
- package/dist/core/codex-app-server-runner.js.map +1 -1
- package/dist/core/opencode-server-runner.js +5 -25
- package/dist/core/opencode-server-runner.js.map +1 -1
- package/dist/core/tool-display.d.ts +1 -2
- package/dist/core/tool-display.js +1 -6
- package/dist/core/tool-display.js.map +1 -1
- package/dist/index.js +4 -40
- package/dist/index.js.map +1 -1
- package/dist/runs/auto-name.js +0 -6
- package/dist/runs/auto-name.js.map +1 -1
- package/dist/runs/store.js +9 -34
- package/dist/runs/store.js.map +1 -1
- package/dist/server/capabilities.d.ts +0 -6
- package/dist/server/capabilities.js +0 -6
- package/dist/server/capabilities.js.map +1 -1
- package/dist/server/server.d.ts +0 -8
- package/dist/server/server.js +7 -146
- package/dist/server/server.js.map +1 -1
- package/dist/server-install/engine.d.ts +0 -5
- package/dist/server-install/engine.js +0 -6
- package/dist/server-install/engine.js.map +1 -1
- package/dist/server-install/platforms/ubuntu-vps.d.ts +2 -11
- package/dist/server-install/platforms/ubuntu-vps.js +10 -123
- package/dist/server-install/platforms/ubuntu-vps.js.map +1 -1
- package/dist/server-install/types.d.ts +0 -39
- package/dist/server-install/types.js +0 -13
- package/dist/server-install/types.js.map +1 -1
- package/dist/skills-remote.d.ts +0 -11
- package/dist/skills-remote.js +2 -31
- package/dist/skills-remote.js.map +1 -1
- package/dist/skills.d.ts +0 -29
- package/dist/skills.js +14 -72
- package/dist/skills.js.map +1 -1
- package/dist/workflows/run.d.ts +10 -50
- package/dist/workflows/run.js +103 -216
- package/dist/workflows/run.js.map +1 -1
- package/dist/workspace/config.d.ts +0 -30
- package/dist/workspace/config.js +0 -5
- package/dist/workspace/config.js.map +1 -1
- package/dist/workspace/projects-cli.d.ts +0 -2
- package/dist/workspace/projects-cli.js +4 -21
- package/dist/workspace/projects-cli.js.map +1 -1
- package/dist/workspace/projects.d.ts +1 -5
- package/dist/workspace/projects.js +8 -5
- package/dist/workspace/projects.js.map +1 -1
- package/dist/workspace/semaphore.d.ts +2 -53
- package/dist/workspace/semaphore.js +5 -93
- package/dist/workspace/semaphore.js.map +1 -1
- package/package.json +1 -1
- package/web/dist/assets/centered-state-zzWBfO_1.js +43 -0
- package/web/dist/assets/command-ylf8-fG0.js +1 -0
- package/web/dist/assets/compare-variants-BcR3zdtB.js +1 -0
- package/web/dist/assets/dialog-BYr_BAil.js +1 -0
- package/web/dist/assets/diff-view-DPCR7gon.js +4 -0
- package/web/dist/assets/{dist-CqH67S8q.js → dist-Cw_CDvC3.js} +1 -1
- package/web/dist/assets/dropdown-menu-C3GD8eLA.js +1 -0
- package/web/dist/assets/git-toolbar-CiMaCi03.js +1 -0
- package/web/dist/assets/github-BJEZbEOp.js +1 -0
- package/web/dist/assets/index-DmW_TYjO.js +16 -0
- package/web/dist/assets/index-Qbs-JRWQ.css +2 -0
- package/web/dist/assets/loader-circle-CGwIVNTv.js +1 -0
- package/web/dist/assets/{project-router-BaWVyqc8.js → project-router-CT8Rt5Eu.js} +1 -1
- package/web/dist/assets/prompt-templates-DW7_d8Ys.js +15 -0
- package/web/dist/assets/repo-git-BkmyKcvN.js +1 -0
- package/web/dist/assets/{run-diff-Cksr4Dk5.js → run-diff-CxIDdRwy.js} +2 -2
- package/web/dist/assets/run-header-8nwDIWWO.js +1 -0
- package/web/dist/assets/skill-empty-hint-Cl3ESoPu.js +1 -0
- package/web/dist/assets/skills-BIpb0mqO.js +1 -0
- package/web/dist/assets/{tab-link-vtgjgL_M.js → tab-link-C_bk_Kvn.js} +1 -1
- package/web/dist/assets/task-changes-D1bJx2uW.js +1 -0
- package/web/dist/assets/task-commits-DlhB21mR.js +1 -0
- package/web/dist/assets/task-files-ChJDOFg5.js +2 -0
- package/web/dist/assets/task-thread-J7ckxJJh.js +9 -0
- package/web/dist/assets/tasks-table--V1pKwuK.js +1 -0
- package/web/dist/assets/use-desktop-CuDnWju1.js +3 -0
- package/web/dist/assets/workflows-BksgdYAQ.js +11 -0
- package/web/dist/assets/x-DgoqYQOJ.js +1 -0
- package/web/dist/index.html +12 -6
- package/dist/core/v1-text-coalescer.d.ts +0 -36
- package/dist/core/v1-text-coalescer.js +0 -72
- package/dist/core/v1-text-coalescer.js.map +0 -1
- package/web/dist/assets/centered-state-CLmJ67EV.js +0 -43
- package/web/dist/assets/commit-list-CSaWuw-x.js +0 -1
- package/web/dist/assets/compare-variants-B5BlnpUb.js +0 -1
- package/web/dist/assets/diff-view-CYKPGL2w.js +0 -6
- package/web/dist/assets/git-toolbar-CDII-3Uv.js +0 -1
- package/web/dist/assets/github-C7SNDPf3.js +0 -1
- package/web/dist/assets/index-CcfkF2Ey.js +0 -30
- package/web/dist/assets/index-DzroxqBG.css +0 -2
- package/web/dist/assets/lib-DPEZDBUN.js +0 -1
- package/web/dist/assets/repo-git-4l-2tm7d.js +0 -1
- package/web/dist/assets/run-header-B3kW2sWC.js +0 -1
- package/web/dist/assets/skill-empty-hint-DTUSp6Vl.js +0 -1
- package/web/dist/assets/skills-D7hPgl4y.js +0 -1
- package/web/dist/assets/task-changes-DvIUGL9a.js +0 -1
- package/web/dist/assets/task-commits-QD2JI3zj.js +0 -1
- package/web/dist/assets/task-files-BE7JDEwK.js +0 -2
- package/web/dist/assets/task-thread-CRjuPhsl.js +0 -9
- package/web/dist/assets/textarea-Bj_LCreg.js +0 -1
- package/web/dist/assets/use-desktop-4e8LLqMG.js +0 -3
- package/web/dist/assets/workflows-bPYx0nbO.js +0 -11
|
@@ -14,16 +14,10 @@
|
|
|
14
14
|
* `todos.json` (they get `HANDOFF_ONLY_INSTRUCTIONS` and an empty
|
|
15
15
|
* `CEZ_TODOS_FILE`), the Inbox nav item is gone and the inbox endpoints refuse.
|
|
16
16
|
* The per-task handoff journal is independent and runs either way.
|
|
17
|
-
*
|
|
18
|
-
* `singleProject` (spec 2026-07-21-cez-single-project): the workspace is
|
|
19
|
-
* deliberately constrained to the launch project when `CEZ_SINGLE_PROJECT=1`.
|
|
20
|
-
* Like the other opt-in capabilities, activation is strict: no other spelling
|
|
21
|
-
* enables it.
|
|
22
17
|
*/
|
|
23
18
|
export interface Capabilities {
|
|
24
19
|
localHandoff: boolean;
|
|
25
20
|
followups: boolean;
|
|
26
|
-
singleProject: boolean;
|
|
27
21
|
}
|
|
28
22
|
/** Canonical hostname of an authority: port and IPv6 brackets removed, IPv6
|
|
29
23
|
* expanded, zone id and FQDN trailing dot dropped, lowercased.
|
|
@@ -14,11 +14,6 @@
|
|
|
14
14
|
* `todos.json` (they get `HANDOFF_ONLY_INSTRUCTIONS` and an empty
|
|
15
15
|
* `CEZ_TODOS_FILE`), the Inbox nav item is gone and the inbox endpoints refuse.
|
|
16
16
|
* The per-task handoff journal is independent and runs either way.
|
|
17
|
-
*
|
|
18
|
-
* `singleProject` (spec 2026-07-21-cez-single-project): the workspace is
|
|
19
|
-
* deliberately constrained to the launch project when `CEZ_SINGLE_PROJECT=1`.
|
|
20
|
-
* Like the other opt-in capabilities, activation is strict: no other spelling
|
|
21
|
-
* enables it.
|
|
22
17
|
*/
|
|
23
18
|
import { followupsEnabled } from '../handoff.js';
|
|
24
19
|
/** Every IPv4 address in 127.0.0.0/8, anchored. Anchoring is load-bearing: a
|
|
@@ -120,7 +115,6 @@ export function resolveCapabilities(env = process.env, bindHost) {
|
|
|
120
115
|
// Deliberately not re-derived here: RunManager enforces the same predicate,
|
|
121
116
|
// and two spellings of "is the inbox on" would eventually disagree.
|
|
122
117
|
followups: followupsEnabled(env),
|
|
123
|
-
singleProject: env.CEZ_SINGLE_PROJECT === '1',
|
|
124
118
|
};
|
|
125
119
|
}
|
|
126
120
|
//# sourceMappingURL=capabilities.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/server/capabilities.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/server/capabilities.ts"],"names":[],"mappings":"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"}
|
package/dist/server/server.d.ts
CHANGED
|
@@ -114,14 +114,6 @@ export interface RemoveProjectResponse {
|
|
|
114
114
|
removed: true;
|
|
115
115
|
id: string;
|
|
116
116
|
}
|
|
117
|
-
/** `PATCH /api/projects/:projectId` (spec 2026-07-22-per-project-concurrency)
|
|
118
|
-
* — sets or clears a project's per-project `maxParallel`. The entry carries
|
|
119
|
-
* the same `status`/`branch` probe `GET /api/projects` attaches, so the
|
|
120
|
-
* cockpit sees one project shape. `null` in the request clears the override
|
|
121
|
-
* back to "inherit the workspace cap". */
|
|
122
|
-
export interface UpdateProjectResponse {
|
|
123
|
-
project: ProjectListEntry;
|
|
124
|
-
}
|
|
125
117
|
/** `GET/PUT /api/workspace/config` (multi-project spec, step 2.7) — the
|
|
126
118
|
* settings slice of `~/.cezar/config.json`: global knobs ONLY, never the
|
|
127
119
|
* project registry (that is `GET /api/projects`' job). */
|
package/dist/server/server.js
CHANGED
|
@@ -16,7 +16,7 @@ import { WORKFLOWS_DIR, loadWorkflows } from '../workflows/load.js';
|
|
|
16
16
|
import { QUICK_TASK_WORKFLOW, normalizeWorkflowDoc, skillStackOf, skillsToSteps, stepsIssue, workflowFileSchema, workflowStepSchema, } from '../workflows/types.js';
|
|
17
17
|
import { planChain, slugify } from '../planner.js';
|
|
18
18
|
import { discoverSkills } from '../skills.js';
|
|
19
|
-
import {
|
|
19
|
+
import { refreshTeamSkills, waitForTeamSkills } from '../skills-remote.js';
|
|
20
20
|
import { appendHandoffHeartbeat, handoffProgressExcerpt, readHandoff } from '../handoff.js';
|
|
21
21
|
import { markStarted, onTodosChanged, readTodos, removeTodo, todoTaskText } from '../todos.js';
|
|
22
22
|
import { isV2WireEventType } from '../runs/ui-event-sink.js';
|
|
@@ -24,7 +24,7 @@ import { removeWorktree, worktreeDiff, worktreeDiffStat, worktreeSizeBytes } fro
|
|
|
24
24
|
import { isReclaimable, reclaimWorktrees } from '../runs/retention.js';
|
|
25
25
|
import { getBranches, getCommit, getDiff, getLog, getRepoInfo, getStatus } from './git.js';
|
|
26
26
|
import { collectChanges, collectCommitChanges, collectRunCommits, commitAll, createOrSwitchBranch, imageMimeType, isOsOpenableImage, pushCurrentBranch, readWorktreePath, } from './git-changes.js';
|
|
27
|
-
import {
|
|
27
|
+
import { loadConfig, resolveWorktreeRetention } from '../config.js';
|
|
28
28
|
import { findConfigFile } from '../agent-config/catalog.js';
|
|
29
29
|
import { readConfigFile, writeConfigFile } from '../agent-config/files.js';
|
|
30
30
|
import { listAgentConfig } from '../agent-config/service.js';
|
|
@@ -236,18 +236,6 @@ const workspaceUiStateSchema = z
|
|
|
236
236
|
})
|
|
237
237
|
.passthrough()
|
|
238
238
|
.optional(),
|
|
239
|
-
// The user's curated selection of default (vendor) skills — `open-mercato/skills` — so the
|
|
240
|
-
// catalog is no longer forced in full. GLOBAL (here, not per-repo) because "which skills I
|
|
241
|
-
// want" describes the person, not a checkout, and must not depend on where cezar was launched
|
|
242
|
-
// (multi-project workspace). Tri-state, enforced in `discoverSkills`: an ABSENT key means "not
|
|
243
|
-
// curated" and every default skill still shows (opt-out default — no silent break on upgrade);
|
|
244
|
-
// a PRESENT array (even `[]`) shows only those names. Bounded like the `skillUsage` map: the
|
|
245
|
-
// file is GET/PUT wholesale, so an unbounded array is an unbounded write. Names match
|
|
246
|
-
// `lastTask.ref` (`.min(1).max(200)`). The client PUTs the whole array (shallow top-level merge).
|
|
247
|
-
importedSkills: z
|
|
248
|
-
.array(z.string().min(1).max(200))
|
|
249
|
-
.max(SKILL_USAGE_MAX_ENTRIES)
|
|
250
|
-
.optional(),
|
|
251
239
|
})
|
|
252
240
|
.passthrough();
|
|
253
241
|
const uiStateSchema = z
|
|
@@ -315,9 +303,6 @@ const uiStateSchema = z
|
|
|
315
303
|
.optional(),
|
|
316
304
|
// Skills promo banner (#391): set once the cockpit banner is dismissed, never unset.
|
|
317
305
|
// Server-persisted (not a cookie) so the "shown once" promise holds across browsers.
|
|
318
|
-
// Retained for backward compatibility — the banner is gone, replaced by the workspace-level
|
|
319
|
-
// `importedSkills` curation (see `workspaceUiStateSchema`); `.passthrough()` would preserve
|
|
320
|
-
// the key regardless, but keep it typed.
|
|
321
306
|
dismissedSkillsBanner: z.boolean().optional(),
|
|
322
307
|
})
|
|
323
308
|
.passthrough();
|
|
@@ -382,12 +367,9 @@ function foldedLength(task, stack) {
|
|
|
382
367
|
// "Continue"/"Send back" body (spec 003 / #401): every field optional, so an empty POST reopens
|
|
383
368
|
// the last session on the run's current backend (backward compat). A runner/model override lets
|
|
384
369
|
// the follow-up composer choose which engine handles the continuation. `text` stays bounded like
|
|
385
|
-
// the live-session message `text` (#429)
|
|
386
|
-
// follow-up composer is a full composer, so a screenshot pasted into it must reach the reopened
|
|
387
|
-
// session rather than being silently dropped.
|
|
370
|
+
// the live-session message `text` (#429).
|
|
388
371
|
const continueSchema = z.object({
|
|
389
372
|
text: z.string().max(100_000, 'text must be at most 100000 characters').optional(),
|
|
390
|
-
images: z.array(imageInputSchema).max(4).optional(),
|
|
391
373
|
runner: z.enum(['claude', 'codex', 'opencode']).optional(),
|
|
392
374
|
model: z.string().max(200).optional(),
|
|
393
375
|
});
|
|
@@ -511,18 +493,14 @@ export function createApp(deps) {
|
|
|
511
493
|
const workspaceSummary = async () => {
|
|
512
494
|
try {
|
|
513
495
|
const registry = (await loadWorkspaceConfig()).projects;
|
|
514
|
-
const bootProject = await resolveBootProject(registry);
|
|
515
|
-
const visible = capabilities().singleProject
|
|
516
|
-
? registry.filter((project) => project.id === bootProject)
|
|
517
|
-
: registry;
|
|
518
496
|
return {
|
|
519
497
|
// Explicit picks, not a spread: the registry schema passes unknown
|
|
520
498
|
// keys through, and `root` must never ride along onto health.
|
|
521
|
-
projects:
|
|
499
|
+
projects: registry.map((p) => ({
|
|
522
500
|
id: p.id,
|
|
523
501
|
name: p.name || basename(p.root),
|
|
524
502
|
})),
|
|
525
|
-
bootProject,
|
|
503
|
+
bootProject: await resolveBootProject(registry),
|
|
526
504
|
};
|
|
527
505
|
}
|
|
528
506
|
catch {
|
|
@@ -532,7 +510,6 @@ export function createApp(deps) {
|
|
|
532
510
|
// Hosted-mode gate (spec §"Deployment modes") — read per request so
|
|
533
511
|
// CEZ_REMOTE flips take effect live (and tests can toggle it).
|
|
534
512
|
const capabilities = () => resolveCapabilities(process.env, bindHost);
|
|
535
|
-
const singleProjectRefusal = (action) => ({ error: `single-project mode is enabled; ${action} is disabled` });
|
|
536
513
|
// Inbox live updates (spec 007). Opt-in (#471): no capability, no watcher —
|
|
537
514
|
// and since step 2.3 the per-dataDir watch is created lazily by the first
|
|
538
515
|
// SSE subscription (and torn down with the last), nothing to start here.
|
|
@@ -553,15 +530,7 @@ export function createApp(deps) {
|
|
|
553
530
|
};
|
|
554
531
|
// Non-boot projects build lazily on first scoped request; their managers
|
|
555
532
|
// count against the same workspace semaphore as the boot manager (step 2.5).
|
|
556
|
-
const contexts = deps.contexts ?? new ProjectContexts({
|
|
557
|
-
listProjects: async () => {
|
|
558
|
-
const selector = capabilities().singleProject
|
|
559
|
-
? { projectId: await resolveBootProject() }
|
|
560
|
-
: undefined;
|
|
561
|
-
return listProjects(selector);
|
|
562
|
-
},
|
|
563
|
-
semaphore: deps.semaphore,
|
|
564
|
-
});
|
|
533
|
+
const contexts = deps.contexts ?? new ProjectContexts({ listProjects, semaphore: deps.semaphore });
|
|
565
534
|
// Workspace-level SSE bus (step 2.8) — the registry mutators and the
|
|
566
535
|
// checkout flow (Phase 4) emit here; /api/workspace/events relays.
|
|
567
536
|
const workspaceEvents = deps.workspaceEvents ?? new WorkspaceEventBus();
|
|
@@ -843,10 +812,7 @@ export function createApp(deps) {
|
|
|
843
812
|
let projectsDir = defaultWorkspaceConfig().projectsDir;
|
|
844
813
|
try {
|
|
845
814
|
projectsDir = (await loadWorkspaceConfig()).projectsDir;
|
|
846
|
-
|
|
847
|
-
? { projectId: await resolveBootProject() }
|
|
848
|
-
: undefined;
|
|
849
|
-
projects = await listProjects(selector);
|
|
815
|
+
projects = await listProjects();
|
|
850
816
|
}
|
|
851
817
|
catch {
|
|
852
818
|
// unreadable workspace — degrade to the empty registry + defaults
|
|
@@ -872,9 +838,6 @@ export function createApp(deps) {
|
|
|
872
838
|
* Returns the status + body for the caller to answer with.
|
|
873
839
|
*/
|
|
874
840
|
const registerFolder = async (spelled, source) => {
|
|
875
|
-
if (capabilities().singleProject) {
|
|
876
|
-
return { status: 409, body: singleProjectRefusal('adding projects') };
|
|
877
|
-
}
|
|
878
841
|
// `~` is expanded for the same reason `/api/fs/browse` expands it: the
|
|
879
842
|
// dialog hands back absolute paths, but a hand-written body (curl, a
|
|
880
843
|
// future CLI) spells home the way a shell does.
|
|
@@ -1020,9 +983,6 @@ export function createApp(deps) {
|
|
|
1020
983
|
return ctx.store.listRuns().filter((run) => ACTIVE_RUN_STATUSES.has(run.status)).length;
|
|
1021
984
|
};
|
|
1022
985
|
app.delete('/api/projects/:projectId', async (c) => {
|
|
1023
|
-
if (capabilities().singleProject) {
|
|
1024
|
-
return c.json(singleProjectRefusal('removing projects'), 409);
|
|
1025
|
-
}
|
|
1026
986
|
const raw = c.req.param('projectId');
|
|
1027
987
|
// Same gate the scoped-route resolver applies, and the same 404 wording —
|
|
1028
988
|
// a malformed id is an unknown project, not a validation essay.
|
|
@@ -1078,78 +1038,6 @@ export function createApp(deps) {
|
|
|
1078
1038
|
const body = { removed: true, id };
|
|
1079
1039
|
return c.json(body);
|
|
1080
1040
|
});
|
|
1081
|
-
// Edit one field of an existing registry entry (spec
|
|
1082
|
-
// 2026-07-22-per-project-concurrency): the per-project concurrency ceiling.
|
|
1083
|
-
// A PATCH (not PUT) because it touches a single field, and a distinct route
|
|
1084
|
-
// from POST (register-a-folder) to keep register vs. edit semantics clear.
|
|
1085
|
-
// `maxParallel: null` clears the override back to "inherit the workspace
|
|
1086
|
-
// cap". Bounds mirror `workspaceProjectSchema` (config.ts) exactly, so a
|
|
1087
|
-
// value this route accepts can never be degraded away by the next load's
|
|
1088
|
-
// `.catch`.
|
|
1089
|
-
const updateProjectSchema = z.object({
|
|
1090
|
-
maxParallel: z.number().int().min(1).max(16).nullable(),
|
|
1091
|
-
});
|
|
1092
|
-
app.patch('/api/projects/:projectId', async (c) => {
|
|
1093
|
-
if (capabilities().singleProject) {
|
|
1094
|
-
return c.json(singleProjectRefusal('editing projects'), 409);
|
|
1095
|
-
}
|
|
1096
|
-
const raw = c.req.param('projectId');
|
|
1097
|
-
// Same gate + 404 wording as DELETE: a malformed id is an unknown project.
|
|
1098
|
-
if (!projectIdSchema.safeParse(raw).success) {
|
|
1099
|
-
return c.json({ error: `unknown project: ${raw}` }, 404);
|
|
1100
|
-
}
|
|
1101
|
-
const parsed = updateProjectSchema.safeParse(await c.req.json().catch(() => null));
|
|
1102
|
-
if (!parsed.success) {
|
|
1103
|
-
return c.json({ error: parsed.error.issues.map((i) => i.message).join('; ') }, 400);
|
|
1104
|
-
}
|
|
1105
|
-
// `default` is the boot alias the cockpit is allowed to use everywhere else.
|
|
1106
|
-
const id = raw === 'default' ? await resolveBootProject() : raw;
|
|
1107
|
-
const { maxParallel } = parsed.data;
|
|
1108
|
-
// Read-first (mirroring DELETE, server.ts:1252-1258): a well-formed but
|
|
1109
|
-
// unknown id must 404 WITHOUT rewriting the config — otherwise it would both
|
|
1110
|
-
// do a needless full-config tmp+rename and, on a read-only home, surface the
|
|
1111
|
-
// write failure as a 500 where the honest answer is 404.
|
|
1112
|
-
let known = false;
|
|
1113
|
-
try {
|
|
1114
|
-
known = (await loadWorkspaceConfig()).projects.some((p) => p.id === id);
|
|
1115
|
-
}
|
|
1116
|
-
catch {
|
|
1117
|
-
// unreadable workspace — treat as unknown; the read-only case answers 404,
|
|
1118
|
-
// not a 500 the caller cannot act on (same reasoning as DELETE).
|
|
1119
|
-
}
|
|
1120
|
-
if (!known)
|
|
1121
|
-
return c.json({ error: `unknown project: ${id}` }, 404);
|
|
1122
|
-
let updated;
|
|
1123
|
-
try {
|
|
1124
|
-
await mergeWriteWorkspaceConfig((config) => {
|
|
1125
|
-
const entry = config.projects.find((p) => p.id === id);
|
|
1126
|
-
if (!entry)
|
|
1127
|
-
return; // lost a race with a concurrent remove — answered below
|
|
1128
|
-
// null clears the override; a number sets it. Mutated in place so
|
|
1129
|
-
// `.passthrough()` keys on the entry survive.
|
|
1130
|
-
if (maxParallel === null)
|
|
1131
|
-
delete entry.maxParallel;
|
|
1132
|
-
else
|
|
1133
|
-
entry.maxParallel = maxParallel;
|
|
1134
|
-
updated = entry;
|
|
1135
|
-
});
|
|
1136
|
-
}
|
|
1137
|
-
catch (err) {
|
|
1138
|
-
// e.g. a read-only home — nothing was persisted (atomic tmp+rename).
|
|
1139
|
-
return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
|
|
1140
|
-
}
|
|
1141
|
-
// Raced with a concurrent removal between the read and the write.
|
|
1142
|
-
if (!updated)
|
|
1143
|
-
return c.json({ error: `unknown project: ${id}` }, 404);
|
|
1144
|
-
// The new ceiling takes effect WITHOUT a restart: refresh the shared
|
|
1145
|
-
// semaphore's snapshot and pump every manager — the same live-apply hook
|
|
1146
|
-
// `PUT /api/workspace/config` fires for a workspace-cap change.
|
|
1147
|
-
await deps.semaphore?.refresh();
|
|
1148
|
-
const body = {
|
|
1149
|
-
project: { ...updated, ...(await probeProjectStatus(updated.root)) },
|
|
1150
|
-
};
|
|
1151
|
-
return c.json(body);
|
|
1152
|
-
});
|
|
1153
1041
|
// ---- GUI clone (multi-project spec, step 4.3) ----------------------------
|
|
1154
1042
|
// "Add project → Clone from GitHub": clone into the checkout root, then
|
|
1155
1043
|
// register the result through `registerFolder` above (same guards, same
|
|
@@ -1167,9 +1055,6 @@ export function createApp(deps) {
|
|
|
1167
1055
|
checkoutId: z.string().trim().max(128).optional(),
|
|
1168
1056
|
});
|
|
1169
1057
|
app.post('/api/projects/checkout', async (c) => {
|
|
1170
|
-
if (capabilities().singleProject) {
|
|
1171
|
-
return c.json(singleProjectRefusal('adding projects'), 409);
|
|
1172
|
-
}
|
|
1173
1058
|
const parsed = checkoutSchema.safeParse(await c.req.json().catch(() => null));
|
|
1174
1059
|
if (!parsed.success)
|
|
1175
1060
|
return c.json({ error: 'url must be a GitHub repository' }, 400);
|
|
@@ -1320,9 +1205,6 @@ export function createApp(deps) {
|
|
|
1320
1205
|
// it is realpath-based. The independently configured browse root is read per
|
|
1321
1206
|
// request, so a successful settings save applies without a restart.
|
|
1322
1207
|
app.get('/api/fs/browse', async (c) => {
|
|
1323
|
-
if (capabilities().singleProject) {
|
|
1324
|
-
return c.json(singleProjectRefusal('folder browsing'), 409);
|
|
1325
|
-
}
|
|
1326
1208
|
const root = resolveBrowseRoot(await workspaceBrowseRoot());
|
|
1327
1209
|
const result = await browseDirectory({
|
|
1328
1210
|
root,
|
|
@@ -1345,23 +1227,6 @@ export function createApp(deps) {
|
|
|
1345
1227
|
await waitForTeamSkills(repoRoot);
|
|
1346
1228
|
return c.json(await discoverSkills(repoRoot));
|
|
1347
1229
|
});
|
|
1348
|
-
// The opt-in catalog for the "Import skills" panel: every skill a default
|
|
1349
|
-
// (vendor) repo offers — `open-mercato/skills` — regardless of import state,
|
|
1350
|
-
// so the panel can present them all with a per-skill toggle. Empty once a repo
|
|
1351
|
-
// configures its own `skillsRepos` (nothing is gated then). `wait=1` lets the
|
|
1352
|
-
// panel wait out a cold team-skill cache, same as `GET /skills` (spec 005).
|
|
1353
|
-
api.get('/skills/importable', async (c) => {
|
|
1354
|
-
const repoRoot = c.get('project').root;
|
|
1355
|
-
const gated = await gatedSkillsRepos(repoRoot);
|
|
1356
|
-
if (gated.size === 0)
|
|
1357
|
-
return c.json([]);
|
|
1358
|
-
if (c.req.query('wait') === '1')
|
|
1359
|
-
await waitForTeamSkills(repoRoot);
|
|
1360
|
-
const importable = getTeamSkillsCached(repoRoot)
|
|
1361
|
-
.filter((skill) => skill.team && gated.has(skill.team.repo))
|
|
1362
|
-
.map((skill) => ({ name: skill.name, description: skill.description }));
|
|
1363
|
-
return c.json(importable);
|
|
1364
|
-
});
|
|
1365
1230
|
// ---- GUI prefs (ui-state.json) --------------------------------------------
|
|
1366
1231
|
// The read path is shared with the CLI (`src/ui-state.ts`) so `cezar serve` can honour a
|
|
1367
1232
|
// preference set here — #391's dismissed skills banner — from one notion of the file.
|
|
@@ -1883,10 +1748,6 @@ export function createApp(deps) {
|
|
|
1883
1748
|
}
|
|
1884
1749
|
const result = manager.continueRun(id, {
|
|
1885
1750
|
text: parsed.data.text,
|
|
1886
|
-
images: parsed.data.images?.map((img) => ({
|
|
1887
|
-
type: 'image',
|
|
1888
|
-
source: { type: 'base64', media_type: img.mediaType, data: img.data },
|
|
1889
|
-
})),
|
|
1890
1751
|
runner: parsed.data.runner,
|
|
1891
1752
|
model: parsed.data.model,
|
|
1892
1753
|
});
|