@hyperdreamer/pi-webui 1.10.7 → 1.11.0-beta.10
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 +17 -2
- package/dist/cli.js +265 -32
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/{CodeViewer-BIb2Wx8W.js → CodeViewer-CAf_j27u.js} +1 -1
- package/dist/client/assets/{UnifiedDiffViewer-DpWiGlQo.js → UnifiedDiffViewer-wBjEJWa1.js} +1 -1
- package/dist/client/assets/{index-DX583DEv.js → index-5EtDb9nj.js} +1197 -476
- package/dist/client/index.html +1 -1
- package/dist/config.js +52 -11
- package/dist/config.js.map +1 -1
- package/dist/pi-webui-plugins/workspace-memory/pi-webui-plugin.js +3 -2
- package/dist/pi-webui-plugins/workspace-tasks/pi-webui-plugin.js +1 -0
- package/dist/plugin-api.d.ts +30 -0
- package/dist/server/app.js +6 -1
- package/dist/server/app.js.map +1 -1
- package/dist/server/realtime/sessionEventHub.js +40 -5
- package/dist/server/realtime/sessionEventHub.js.map +1 -1
- package/dist/server/realtime/sessionStatusCoalescer.js +137 -0
- package/dist/server/realtime/sessionStatusCoalescer.js.map +1 -0
- package/dist/server/sessiond/sessionProxyRoutes.js +2 -0
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
- package/dist/server/sessiond.js +57 -5
- package/dist/server/sessiond.js.map +1 -1
- package/dist/server/sessions/modelPolicyCapability.js +88 -0
- package/dist/server/sessions/modelPolicyCapability.js.map +1 -0
- package/dist/server/sessions/modelPolicyTool.js +31 -0
- package/dist/server/sessions/modelPolicyTool.js.map +1 -0
- package/dist/server/sessions/modelTierRegistry.js +14 -0
- package/dist/server/sessions/modelTierRegistry.js.map +1 -1
- package/dist/server/sessions/modelTierSettingsRoutes.js +36 -0
- package/dist/server/sessions/modelTierSettingsRoutes.js.map +1 -0
- package/dist/server/sessions/modelTierSettingsService.js +100 -0
- package/dist/server/sessions/modelTierSettingsService.js.map +1 -0
- package/dist/server/sessions/piSessionService.js +1643 -433
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/sessionDefaultsRoutes.js +39 -0
- package/dist/server/sessions/sessionDefaultsRoutes.js.map +1 -1
- package/dist/server/sessions/sessionDefaultsService.js +36 -6
- package/dist/server/sessions/sessionDefaultsService.js.map +1 -1
- package/dist/server/sessions/sessionMetadataStore.js +107 -13
- package/dist/server/sessions/sessionMetadataStore.js.map +1 -1
- package/dist/server/sessions/sessionModelPolicy.js +118 -0
- package/dist/server/sessions/sessionModelPolicy.js.map +1 -0
- package/dist/server/sessions/sessionReorder.js +117 -0
- package/dist/server/sessions/sessionReorder.js.map +1 -0
- package/dist/server/sessions/sessionRouteFastifyOptions.js +8 -0
- package/dist/server/sessions/sessionRouteFastifyOptions.js.map +1 -0
- package/dist/server/sessions/sessionRoutes.js +208 -3
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/sessions/starterModelPolicyPreferenceStore.js +164 -0
- package/dist/server/sessions/starterModelPolicyPreferenceStore.js.map +1 -0
- package/dist/server/sessions/utilityModelExtension.js +199 -0
- package/dist/server/sessions/utilityModelExtension.js.map +1 -0
- package/dist/server/sessions/utilityModelResolver.js +77 -0
- package/dist/server/sessions/utilityModelResolver.js.map +1 -0
- package/dist/server/sessions/utilityModelSettingsRoutes.js +62 -0
- package/dist/server/sessions/utilityModelSettingsRoutes.js.map +1 -0
- package/dist/server/sessions/utilityModelSettingsService.js +101 -0
- package/dist/server/sessions/utilityModelSettingsService.js.map +1 -0
- package/dist/server/skills/optionalSkillInstall.js +69 -0
- package/dist/server/skills/optionalSkillInstall.js.map +1 -0
- package/dist/server/skills/optionalSkillInstaller.js +148 -0
- package/dist/server/skills/optionalSkillInstaller.js.map +1 -0
- package/dist/shared/apiTypes.d.ts +129 -3
- package/dist/shared/apiTypes.js +10 -0
- package/dist/shared/apiTypes.js.map +1 -1
- package/dist/shared/capabilities.js +15 -0
- package/dist/shared/capabilities.js.map +1 -1
- package/dist/shared/federatedRoutes.js +7 -0
- package/dist/shared/federatedRoutes.js.map +1 -1
- package/docs/assets/pi-webui-desktop.png +0 -0
- package/docs/config.md +61 -3
- package/docs/plugins.md +93 -16
- package/optional-skills/deterministic-subagent-driven-development/SKILL.md +224 -0
- package/optional-skills/deterministic-subagent-driven-development/pi-webui-skill.json +28 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/final-reviewer.md +132 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/implementer.md +101 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/re-reviewer.md +60 -0
- package/optional-skills/deterministic-subagent-driven-development/prompts/task-reviewer.md +80 -0
- package/optional-skills/deterministic-subagent-driven-development/references/capability-contract.md +174 -0
- package/optional-skills/deterministic-subagent-driven-development/references/plan-contract.md +268 -0
- package/optional-skills/deterministic-subagent-driven-development/references/state-machine.md +177 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/manifest.mjs +258 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/plan-policy.mjs +350 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/prompt-renderer.mjs +290 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/state-machine.mjs +1264 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/lib/state-store.mjs +532 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/sdd-state +3 -0
- package/optional-skills/deterministic-subagent-driven-development/scripts/sdd-state.mjs +349 -0
- package/optional-skills/deterministic-writing-plans/SKILL.md +232 -0
- package/optional-skills/deterministic-writing-plans/references/grammar.md +84 -0
- package/optional-skills/deterministic-writing-plans/templates/plan-skeleton.md +143 -0
- package/package.json +13 -9
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MODEL_TIERS, } from "../../shared/apiTypes.js";
|
|
1
2
|
import { isKnownThinkingLevel } from "../../shared/thinkingLevels.js";
|
|
2
3
|
import { normalizeRequestCwd } from "../workingDirectory.js";
|
|
3
4
|
export function registerSessionDefaultsRoutes(app, service, prefix = "") {
|
|
@@ -21,7 +22,19 @@ export function registerSessionDefaultsRoutes(app, service, prefix = "") {
|
|
|
21
22
|
}
|
|
22
23
|
function parseUpdate(value) {
|
|
23
24
|
const body = requireRecord(value);
|
|
25
|
+
requireAllowedFields(body, ["cwd", "model", "thinkingLevel", "starterModelPolicyPreference"], "session defaults update");
|
|
24
26
|
const cwd = normalizeRequestCwd(requireString(body["cwd"], "cwd"));
|
|
27
|
+
if (body["starterModelPolicyPreference"] !== undefined) {
|
|
28
|
+
if (body["model"] !== undefined || body["thinkingLevel"] !== undefined) {
|
|
29
|
+
throw new Error("A starter model policy preference update cannot include model or thinkingLevel");
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
cwd,
|
|
33
|
+
update: {
|
|
34
|
+
starterModelPolicyPreference: parseStarterModelPolicyPreference(body["starterModelPolicyPreference"]),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
25
38
|
const model = body["model"] === undefined ? undefined : parseModel(body["model"]);
|
|
26
39
|
const thinkingLevel = body["thinkingLevel"] === undefined ? undefined : requireThinkingLevel(body["thinkingLevel"]);
|
|
27
40
|
if (model === undefined && thinkingLevel === undefined)
|
|
@@ -34,6 +47,25 @@ function parseUpdate(value) {
|
|
|
34
47
|
},
|
|
35
48
|
};
|
|
36
49
|
}
|
|
50
|
+
function parseStarterModelPolicyPreference(value) {
|
|
51
|
+
const preference = requireRecord(value);
|
|
52
|
+
requireAllowedFields(preference, ["mode", "tier"], "starterModelPolicyPreference");
|
|
53
|
+
const mode = preference["mode"];
|
|
54
|
+
if (mode !== "exact" && mode !== "tiered") {
|
|
55
|
+
throw new Error("starterModelPolicyPreference mode must be exact or tiered");
|
|
56
|
+
}
|
|
57
|
+
const tier = preference["tier"];
|
|
58
|
+
if (tier !== undefined && !isModelTier(tier)) {
|
|
59
|
+
throw new Error(`starterModelPolicyPreference tier must be one of: ${MODEL_TIERS.join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
if (mode === "tiered" && tier === undefined) {
|
|
62
|
+
throw new Error("starterModelPolicyPreference tier is required in Tiered mode");
|
|
63
|
+
}
|
|
64
|
+
return tier === undefined ? { mode } : { mode, tier };
|
|
65
|
+
}
|
|
66
|
+
function isModelTier(value) {
|
|
67
|
+
return typeof value === "string" && MODEL_TIERS.some((tier) => tier === value);
|
|
68
|
+
}
|
|
37
69
|
function parseModel(value) {
|
|
38
70
|
const model = requireRecord(value);
|
|
39
71
|
return {
|
|
@@ -46,6 +78,13 @@ function requireThinkingLevel(value) {
|
|
|
46
78
|
throw new Error("Invalid thinkingLevel");
|
|
47
79
|
return value;
|
|
48
80
|
}
|
|
81
|
+
function requireAllowedFields(record, allowedFields, field) {
|
|
82
|
+
const allowed = new Set(allowedFields);
|
|
83
|
+
const unknownField = Object.keys(record).find((key) => !allowed.has(key));
|
|
84
|
+
if (unknownField !== undefined) {
|
|
85
|
+
throw new Error(`${field} has unknown field ${JSON.stringify(unknownField)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
49
88
|
function requireRecord(value) {
|
|
50
89
|
if (!isRecord(value))
|
|
51
90
|
throw new Error("Expected object body");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionDefaultsRoutes.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionDefaultsRoutes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sessionDefaultsRoutes.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionDefaultsRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,10 +10,18 @@ export class SessionDefaultsService {
|
|
|
10
10
|
}
|
|
11
11
|
async read(cwd) {
|
|
12
12
|
const settings = this.createSettingsManager(cwd, this.deps.agentDir);
|
|
13
|
-
const models = await
|
|
14
|
-
|
|
13
|
+
const [models, preferenceInspection] = await Promise.all([
|
|
14
|
+
this.availableModels(),
|
|
15
|
+
this.inspectStarterPreference(cwd),
|
|
16
|
+
]);
|
|
17
|
+
return this.response(settings, models, preferenceInspection);
|
|
15
18
|
}
|
|
16
19
|
async update(cwd, update) {
|
|
20
|
+
const preference = update.starterModelPolicyPreference;
|
|
21
|
+
if (preference !== undefined) {
|
|
22
|
+
await this.deps.starterModelPolicyPreferenceStore.replace(cwd, preference);
|
|
23
|
+
return await this.read(cwd);
|
|
24
|
+
}
|
|
17
25
|
const settings = this.createSettingsManager(cwd, this.deps.agentDir);
|
|
18
26
|
const models = await this.availableModels();
|
|
19
27
|
let model = configuredDefaultModel(settings, models);
|
|
@@ -44,17 +52,26 @@ export class SessionDefaultsService {
|
|
|
44
52
|
}
|
|
45
53
|
if (changed)
|
|
46
54
|
await settings.flush();
|
|
47
|
-
|
|
55
|
+
const preferenceInspection = await this.inspectStarterPreference(cwd);
|
|
56
|
+
return responseFor(models, model, thinkingLevel, thinkingLevels, preferenceInspection);
|
|
48
57
|
}
|
|
49
58
|
async availableModels() {
|
|
50
59
|
await this.deps.modelRuntime.refresh({ allowNetwork: false });
|
|
51
60
|
return [...this.deps.modelRuntime.getAvailableSnapshot()];
|
|
52
61
|
}
|
|
53
|
-
|
|
62
|
+
async inspectStarterPreference(cwd) {
|
|
63
|
+
try {
|
|
64
|
+
return await this.deps.starterModelPolicyPreferenceStore.inspect(cwd);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return { kind: "invalid", reason: errorMessage(error) };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
response(settings, models, preferenceInspection) {
|
|
54
71
|
const model = configuredDefaultModel(settings, models);
|
|
55
72
|
const thinkingLevels = this.thinkingLevelsForModel(model);
|
|
56
73
|
const thinkingLevel = effectiveThinkingLevel(settings.getDefaultThinkingLevel() ?? "off", thinkingLevels);
|
|
57
|
-
return responseFor(models, model, thinkingLevel, thinkingLevels);
|
|
74
|
+
return responseFor(models, model, thinkingLevel, thinkingLevels, preferenceInspection);
|
|
58
75
|
}
|
|
59
76
|
}
|
|
60
77
|
function defaultThinkingLevelsForModel(model) {
|
|
@@ -70,14 +87,24 @@ function configuredDefaultModel(settings, models) {
|
|
|
70
87
|
function effectiveThinkingLevel(configured, levels) {
|
|
71
88
|
return levels.includes(configured) ? configured : (levels[0] ?? "off");
|
|
72
89
|
}
|
|
73
|
-
function responseFor(models, model, thinkingLevel, thinkingLevels) {
|
|
90
|
+
function responseFor(models, model, thinkingLevel, thinkingLevels, preferenceInspection) {
|
|
74
91
|
return {
|
|
75
92
|
...(model === undefined ? {} : { model: modelToClientModel(model) }),
|
|
76
93
|
thinkingLevel,
|
|
77
94
|
models: models.map(modelToClientModel),
|
|
78
95
|
thinkingLevels: [...thinkingLevels],
|
|
96
|
+
...preferenceFields(preferenceInspection),
|
|
79
97
|
};
|
|
80
98
|
}
|
|
99
|
+
function preferenceFields(inspection) {
|
|
100
|
+
if (inspection.kind === "valid") {
|
|
101
|
+
return { starterModelPolicyPreference: { ...inspection.preference } };
|
|
102
|
+
}
|
|
103
|
+
if (inspection.kind === "invalid") {
|
|
104
|
+
return { starterModelPolicyPreferenceError: inspection.reason };
|
|
105
|
+
}
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
81
108
|
function modelToClientModel(model) {
|
|
82
109
|
return {
|
|
83
110
|
provider: model.provider,
|
|
@@ -87,4 +114,7 @@ function modelToClientModel(model) {
|
|
|
87
114
|
reasoning: model.reasoning,
|
|
88
115
|
};
|
|
89
116
|
}
|
|
117
|
+
function errorMessage(error) {
|
|
118
|
+
return error instanceof Error ? error.message : String(error);
|
|
119
|
+
}
|
|
90
120
|
//# sourceMappingURL=sessionDefaultsService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionDefaultsService.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionDefaultsService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAwB,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAsB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"sessionDefaultsService.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionDefaultsService.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,23 +2,61 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, join } from "node:path";
|
|
4
4
|
import { piWebUiDataDir } from "../../config.js";
|
|
5
|
+
export class SessionMetadataOrderConflictError extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super("Session pin state changed during reorder");
|
|
8
|
+
this.name = "SessionMetadataOrderConflictError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const defaultFileSystem = {
|
|
12
|
+
readFile,
|
|
13
|
+
mkdir,
|
|
14
|
+
writeFile,
|
|
15
|
+
rename,
|
|
16
|
+
unlink,
|
|
17
|
+
};
|
|
5
18
|
export function defaultSessionMetadataFilePath(env = process.env, cwd = process.cwd()) {
|
|
6
19
|
return join(piWebUiDataDir(env, cwd), "session-metadata.json");
|
|
7
20
|
}
|
|
8
21
|
export class SessionMetadataStore {
|
|
9
|
-
constructor(filePath = defaultSessionMetadataFilePath()) {
|
|
22
|
+
constructor(filePath = defaultSessionMetadataFilePath(), fileSystem = defaultFileSystem) {
|
|
10
23
|
this.filePath = filePath;
|
|
24
|
+
this.fileSystem = fileSystem;
|
|
11
25
|
this.operationQueue = Promise.resolve();
|
|
12
26
|
}
|
|
13
27
|
async get(sessionPath) {
|
|
14
28
|
const data = await this.read();
|
|
15
29
|
return data[sessionPath];
|
|
16
30
|
}
|
|
31
|
+
async snapshot() {
|
|
32
|
+
return await this.read();
|
|
33
|
+
}
|
|
17
34
|
async pin(sessionPath) {
|
|
18
|
-
await this.update(sessionPath, { pinned: true });
|
|
35
|
+
await this.update(sessionPath, (existing) => ({ ...withoutOrder(existing), pinned: true }));
|
|
19
36
|
}
|
|
20
37
|
async unpin(sessionPath) {
|
|
21
|
-
await this.update(sessionPath, { pinned: false });
|
|
38
|
+
await this.update(sessionPath, (existing) => ({ ...withoutOrder(existing), pinned: false }));
|
|
39
|
+
}
|
|
40
|
+
async clearOrder(sessionPath) {
|
|
41
|
+
await this.update(sessionPath, withoutOrder);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Atomically normalize a complete sibling group into positions matching
|
|
45
|
+
* `sessionPaths` order. Rejects the whole batch if any member's current
|
|
46
|
+
* pin state no longer matches `pinned`, since that means the group the
|
|
47
|
+
* caller validated is now stale.
|
|
48
|
+
*/
|
|
49
|
+
async replaceOrder(sessionPaths, scope, pinned) {
|
|
50
|
+
await this.exclusive(async () => {
|
|
51
|
+
const data = await this.read();
|
|
52
|
+
if (sessionPaths.some((path) => (data[path]?.pinned === true) !== pinned)) {
|
|
53
|
+
throw new SessionMetadataOrderConflictError();
|
|
54
|
+
}
|
|
55
|
+
sessionPaths.forEach((path, position) => {
|
|
56
|
+
data[path] = { ...data[path], order: { position, scope, pinned } };
|
|
57
|
+
});
|
|
58
|
+
await this.write(data);
|
|
59
|
+
});
|
|
22
60
|
}
|
|
23
61
|
async pinnedPaths() {
|
|
24
62
|
const data = await this.read();
|
|
@@ -26,11 +64,10 @@ export class SessionMetadataStore {
|
|
|
26
64
|
.filter(([, meta]) => meta.pinned === true)
|
|
27
65
|
.map(([path]) => path);
|
|
28
66
|
}
|
|
29
|
-
async update(sessionPath,
|
|
67
|
+
async update(sessionPath, mutate) {
|
|
30
68
|
await this.exclusive(async () => {
|
|
31
69
|
const data = await this.read();
|
|
32
|
-
|
|
33
|
-
data[sessionPath] = { ...existing, ...meta };
|
|
70
|
+
data[sessionPath] = mutate(data[sessionPath] ?? {});
|
|
34
71
|
await this.write(data);
|
|
35
72
|
});
|
|
36
73
|
}
|
|
@@ -48,7 +85,7 @@ export class SessionMetadataStore {
|
|
|
48
85
|
}
|
|
49
86
|
async read() {
|
|
50
87
|
try {
|
|
51
|
-
const value = JSON.parse(await readFile(this.filePath, "utf8"));
|
|
88
|
+
const value = JSON.parse(await this.fileSystem.readFile(this.filePath, "utf8"));
|
|
52
89
|
return parseMetadataFile(value);
|
|
53
90
|
}
|
|
54
91
|
catch (error) {
|
|
@@ -58,18 +95,23 @@ export class SessionMetadataStore {
|
|
|
58
95
|
}
|
|
59
96
|
}
|
|
60
97
|
async write(data) {
|
|
61
|
-
await mkdir(dirname(this.filePath), { recursive: true });
|
|
98
|
+
await this.fileSystem.mkdir(dirname(this.filePath), { recursive: true });
|
|
62
99
|
const tempPath = join(dirname(this.filePath), `.${basename(this.filePath)}.${String(process.pid)}.${Date.now().toString()}.${randomUUID()}.tmp`);
|
|
63
100
|
try {
|
|
64
|
-
await writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
65
|
-
await rename(tempPath, this.filePath);
|
|
101
|
+
await this.fileSystem.writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
102
|
+
await this.fileSystem.rename(tempPath, this.filePath);
|
|
66
103
|
}
|
|
67
104
|
catch (error) {
|
|
68
|
-
await unlink(tempPath).catch(() => undefined);
|
|
105
|
+
await this.fileSystem.unlink(tempPath).catch(() => undefined);
|
|
69
106
|
throw error;
|
|
70
107
|
}
|
|
71
108
|
}
|
|
72
109
|
}
|
|
110
|
+
function withoutOrder(metadata) {
|
|
111
|
+
const { order: _order, ...rest } = metadata;
|
|
112
|
+
void _order;
|
|
113
|
+
return rest;
|
|
114
|
+
}
|
|
73
115
|
function parseMetadataFile(value) {
|
|
74
116
|
if (!isRecord(value))
|
|
75
117
|
throw new Error("Invalid session metadata file");
|
|
@@ -83,7 +125,59 @@ function parseMetadataEntry(value) {
|
|
|
83
125
|
if (!isRecord(value))
|
|
84
126
|
throw new Error("Invalid session metadata entry");
|
|
85
127
|
const pinned = optionalBoolean(value, "pinned");
|
|
86
|
-
|
|
128
|
+
const order = parseOptionalOrder(value["order"]);
|
|
129
|
+
return {
|
|
130
|
+
...(pinned === undefined ? {} : { pinned }),
|
|
131
|
+
...(order === undefined ? {} : { order }),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function parseOptionalOrder(value) {
|
|
135
|
+
if (value === undefined)
|
|
136
|
+
return undefined;
|
|
137
|
+
if (!isRecord(value))
|
|
138
|
+
throw new Error("Invalid session metadata order");
|
|
139
|
+
const allowedKeys = new Set(["position", "scope", "pinned"]);
|
|
140
|
+
for (const key of Object.keys(value)) {
|
|
141
|
+
if (!allowedKeys.has(key))
|
|
142
|
+
throw new Error("Invalid session metadata order");
|
|
143
|
+
}
|
|
144
|
+
const position = value["position"];
|
|
145
|
+
if (typeof position !== "number" || !Number.isInteger(position) || position < 0 || !Number.isSafeInteger(position)) {
|
|
146
|
+
throw new Error("Invalid session metadata order");
|
|
147
|
+
}
|
|
148
|
+
const scope = parseOrderScope(value["scope"]);
|
|
149
|
+
const pinned = value["pinned"];
|
|
150
|
+
if (typeof pinned !== "boolean")
|
|
151
|
+
throw new Error("Invalid session metadata order");
|
|
152
|
+
return { position, scope, pinned };
|
|
153
|
+
}
|
|
154
|
+
function parseOrderScope(value) {
|
|
155
|
+
if (!isRecord(value))
|
|
156
|
+
throw new Error("Invalid session metadata order");
|
|
157
|
+
const kind = value["kind"];
|
|
158
|
+
if (kind === "root") {
|
|
159
|
+
const allowedKeys = new Set(["kind", "cwd"]);
|
|
160
|
+
for (const key of Object.keys(value)) {
|
|
161
|
+
if (!allowedKeys.has(key))
|
|
162
|
+
throw new Error("Invalid session metadata order");
|
|
163
|
+
}
|
|
164
|
+
const cwd = value["cwd"];
|
|
165
|
+
if (typeof cwd !== "string" || cwd === "")
|
|
166
|
+
throw new Error("Invalid session metadata order");
|
|
167
|
+
return { kind: "root", cwd };
|
|
168
|
+
}
|
|
169
|
+
if (kind === "children") {
|
|
170
|
+
const allowedKeys = new Set(["kind", "parentSessionPath"]);
|
|
171
|
+
for (const key of Object.keys(value)) {
|
|
172
|
+
if (!allowedKeys.has(key))
|
|
173
|
+
throw new Error("Invalid session metadata order");
|
|
174
|
+
}
|
|
175
|
+
const parentSessionPath = value["parentSessionPath"];
|
|
176
|
+
if (typeof parentSessionPath !== "string" || parentSessionPath === "")
|
|
177
|
+
throw new Error("Invalid session metadata order");
|
|
178
|
+
return { kind: "children", parentSessionPath };
|
|
179
|
+
}
|
|
180
|
+
throw new Error("Invalid session metadata order");
|
|
87
181
|
}
|
|
88
182
|
function optionalBoolean(record, key) {
|
|
89
183
|
const value = record[key];
|
|
@@ -94,7 +188,7 @@ function optionalBoolean(record, key) {
|
|
|
94
188
|
return value;
|
|
95
189
|
}
|
|
96
190
|
function isRecord(value) {
|
|
97
|
-
return typeof value === "object" && value !== null;
|
|
191
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
98
192
|
}
|
|
99
193
|
function isNodeErrorWithCode(error, code) {
|
|
100
194
|
return error instanceof Error && "code" in error && error.code === code;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionMetadataStore.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionMetadataStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"sessionMetadataStore.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionMetadataStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAcjD,MAAM,OAAO,iCAAkC,SAAQ,KAAK;IAC1D;QACE,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,mCAAmC,CAAC;IAClD,CAAC;CACF;AAUD,MAAM,iBAAiB,GAA8B;IACnD,QAAQ;IACR,KAAK;IACL,SAAS;IACT,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,UAAU,8BAA8B,CAAC,MAAyB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACtG,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,uBAAuB,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,OAAO,oBAAoB;IAG/B,YACmB,WAAW,8BAA8B,EAAE,EAC3C,aAAwC,iBAAiB;QADzD,aAAQ,GAAR,QAAQ,CAAmC;QAC3C,eAAU,GAAV,UAAU,CAA+C;QAJpE,mBAAc,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAKvD,CAAC;IAEJ,KAAK,CAAC,GAAG,CAAC,WAAmB;QAC3B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,OAAO,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,WAAmB;QAC3B,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9F,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,WAAmB;QAC7B,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC/F,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,WAAmB;QAClC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CAChB,YAA+B,EAC/B,KAA0B,EAC1B,MAAe;QAEf,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC,KAAK,MAAM,CAAC,EAAE,CAAC;gBAC1E,MAAM,IAAI,iCAAiC,EAAE,CAAC;YAChD,CAAC;YACD,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;gBACtC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC;YACrE,CAAC,CAAC,CAAC;YACH,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;aACxB,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;aAC1C,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAEO,KAAK,CAAC,MAAM,CAClB,WAAmB,EACnB,MAAsD;QAEtD,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/B,IAAI,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;YACpD,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,SAAS,CAAI,SAA2B;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;QACrC,IAAI,OAAO,GAAG,GAAS,EAAE,CAAC,SAAS,CAAC;QACpC,IAAI,CAAC,cAAc,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,OAAO,MAAM,SAAS,EAAE,CAAC;QAC3B,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,CAAC;YACH,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;YACzF,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,IAAqC;QACvD,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,IAAI,UAAU,EAAE,MAAM,CAAC,CAAC;QACjJ,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACxF,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC9D,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,SAAS,YAAY,CAAC,QAAyB;IAC7C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;IAC5C,KAAK,MAAM,CAAC;IACZ,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACvE,MAAM,MAAM,GAAoC,EAAE,CAAC;IACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,OAAO;QACL,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3C,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACxE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC7D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAC/E,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;IACnC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnH,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,OAAO,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACnF,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAC7F,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAC/B,CAAC;IACD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC;QAC3D,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAC/E,CAAC;QACD,MAAM,iBAAiB,GAAG,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACrD,IAAI,OAAO,iBAAiB,KAAK,QAAQ,IAAI,iBAAiB,KAAK,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACzH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,CAAC;IACjD,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,eAAe,CAAC,MAA+B,EAAE,GAAW;IACnE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;IACjF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc,EAAE,IAAY;IACvD,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AAC1E,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { MODEL_TIERS, } from "../../shared/apiTypes.js";
|
|
2
|
+
export const SESSION_MODEL_POLICY_CUSTOM_TYPE = "pi-webui.model-policy";
|
|
3
|
+
export function inspectSessionModelPolicy(entries, fallback) {
|
|
4
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
5
|
+
const entry = entries[index];
|
|
6
|
+
if (!isPolicyEntry(entry))
|
|
7
|
+
continue;
|
|
8
|
+
try {
|
|
9
|
+
return { kind: "persisted", policy: parsePolicyData(entry["data"]) };
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return {
|
|
13
|
+
kind: "invalid",
|
|
14
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
15
|
+
fallback: exactPolicy(fallback),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return { kind: "legacy", policy: exactPolicy(fallback) };
|
|
20
|
+
}
|
|
21
|
+
export function serializeSessionModelPolicy(policy) {
|
|
22
|
+
return {
|
|
23
|
+
version: 1,
|
|
24
|
+
mode: policy.mode,
|
|
25
|
+
exact: {
|
|
26
|
+
model: { provider: policy.exact.model.provider, id: policy.exact.model.id },
|
|
27
|
+
thinkingLevel: policy.exact.thinkingLevel,
|
|
28
|
+
},
|
|
29
|
+
...(policy.tier === undefined ? {} : { tier: policy.tier }),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function planSessionModelPolicyUpdate(current, update, resolveTier) {
|
|
33
|
+
if (update.mode === "exact") {
|
|
34
|
+
const exact = cloneExactModelSelection(update.exact);
|
|
35
|
+
return {
|
|
36
|
+
policy: {
|
|
37
|
+
mode: "exact",
|
|
38
|
+
exact,
|
|
39
|
+
...(current.tier === undefined ? {} : { tier: current.tier }),
|
|
40
|
+
},
|
|
41
|
+
target: cloneExactModelSelection(exact),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
policy: { mode: "tiered", exact: cloneExactModelSelection(current.exact), tier: update.tier },
|
|
46
|
+
target: cloneExactModelSelection(resolveTier(update.tier)),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function isPolicyEntry(value) {
|
|
50
|
+
return isRecord(value) && value["type"] === "custom" && value["customType"] === SESSION_MODEL_POLICY_CUSTOM_TYPE;
|
|
51
|
+
}
|
|
52
|
+
function parsePolicyData(value) {
|
|
53
|
+
const record = requireRecord(value, "policy data");
|
|
54
|
+
assertOnlyKeys(record, ["version", "mode", "exact", "tier"]);
|
|
55
|
+
if (record["version"] !== 1)
|
|
56
|
+
throw new Error("unsupported policy version");
|
|
57
|
+
const mode = record["mode"];
|
|
58
|
+
if (mode !== "exact" && mode !== "tiered")
|
|
59
|
+
throw new Error("invalid policy mode");
|
|
60
|
+
const exact = parseExactModelSelection(record["exact"]);
|
|
61
|
+
const hasTier = Object.prototype.hasOwnProperty.call(record, "tier");
|
|
62
|
+
if (!hasTier) {
|
|
63
|
+
if (mode === "tiered")
|
|
64
|
+
throw new Error("tiered policy is missing a canonical tier");
|
|
65
|
+
return { mode, exact };
|
|
66
|
+
}
|
|
67
|
+
const tier = record["tier"];
|
|
68
|
+
if (!isCanonicalModelTier(tier))
|
|
69
|
+
throw new Error("policy tier is not canonical");
|
|
70
|
+
return { mode, exact, tier };
|
|
71
|
+
}
|
|
72
|
+
function parseExactModelSelection(value) {
|
|
73
|
+
const record = requireRecord(value, "exact selection");
|
|
74
|
+
assertOnlyKeys(record, ["model", "thinkingLevel"]);
|
|
75
|
+
return {
|
|
76
|
+
model: parseModelReference(record["model"]),
|
|
77
|
+
thinkingLevel: nonBlankString(record["thinkingLevel"], "thinking level"),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function parseModelReference(value) {
|
|
81
|
+
const record = requireRecord(value, "model reference");
|
|
82
|
+
assertOnlyKeys(record, ["provider", "id"]);
|
|
83
|
+
return {
|
|
84
|
+
provider: nonBlankString(record["provider"], "provider"),
|
|
85
|
+
id: nonBlankString(record["id"], "model id"),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function requireRecord(value, field) {
|
|
89
|
+
if (!isRecord(value))
|
|
90
|
+
throw new Error(`${field} must be an object`);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
function assertOnlyKeys(record, allowedKeys) {
|
|
94
|
+
const unknownKey = Object.keys(record).find((key) => !allowedKeys.includes(key));
|
|
95
|
+
if (unknownKey !== undefined)
|
|
96
|
+
throw new Error(`unknown policy data key: ${unknownKey}`);
|
|
97
|
+
}
|
|
98
|
+
function nonBlankString(value, field) {
|
|
99
|
+
if (typeof value !== "string" || value.trim() === "")
|
|
100
|
+
throw new Error(`${field} must be a non-blank string`);
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
function isRecord(value) {
|
|
104
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
105
|
+
}
|
|
106
|
+
function isCanonicalModelTier(value) {
|
|
107
|
+
return typeof value === "string" && MODEL_TIERS.some((tier) => tier === value);
|
|
108
|
+
}
|
|
109
|
+
function exactPolicy(exact) {
|
|
110
|
+
return { mode: "exact", exact: cloneExactModelSelection(exact) };
|
|
111
|
+
}
|
|
112
|
+
function cloneExactModelSelection(selection) {
|
|
113
|
+
return {
|
|
114
|
+
model: { provider: selection.model.provider, id: selection.model.id },
|
|
115
|
+
thinkingLevel: selection.thinkingLevel,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=sessionModelPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionModelPolicy.js","sourceRoot":"","sources":["../../../src/server/sessions/sessionModelPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export class SessionReorderDomainError extends Error {
|
|
2
|
+
constructor(kind, message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.kind = kind;
|
|
5
|
+
this.name = "SessionReorderDomainError";
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Validate a complete reorder request against the full sibling/pin group
|
|
10
|
+
* derived from `catalog`. Requires exact identity-set equality between the
|
|
11
|
+
* submitted ordered sessions and every catalog session currently eligible
|
|
12
|
+
* for `request.scope`/`request.pinned`, so a stale client cannot silently
|
|
13
|
+
* drop or omit a sibling.
|
|
14
|
+
*/
|
|
15
|
+
export function validateSessionReorder(target, request, catalog) {
|
|
16
|
+
requireTargetIncluded(target, request);
|
|
17
|
+
requireDistinctIdentities(request.orderedSessions);
|
|
18
|
+
const byIdentity = catalogByIdentity(catalog);
|
|
19
|
+
const resolved = resolveOrderedSessions(request.orderedSessions, byIdentity);
|
|
20
|
+
requireDistinctPaths(request.orderedSessions, resolved);
|
|
21
|
+
const eligible = catalog.filter((session) => isEligibleForScope(session, request.scope, request.pinned));
|
|
22
|
+
const eligibleIdentities = new Set(eligible.map((session) => identityKey(session.cwd, session.id)));
|
|
23
|
+
const submittedIdentities = new Set(request.orderedSessions.map((ref) => identityKey(ref.cwd, ref.id)));
|
|
24
|
+
for (const ref of request.orderedSessions) {
|
|
25
|
+
if (!eligibleIdentities.has(identityKey(ref.cwd, ref.id))) {
|
|
26
|
+
throw new SessionReorderDomainError("conflict", `Session is no longer eligible for this reorder: ${ref.id}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const identity of eligibleIdentities) {
|
|
30
|
+
if (!submittedIdentities.has(identity)) {
|
|
31
|
+
throw new SessionReorderDomainError("conflict", "Session group changed during reorder");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const sessionPaths = resolved.map((session) => session.path);
|
|
35
|
+
const orderedSessions = request.orderedSessions.map((ref, manualOrder) => ({ ...ref, manualOrder }));
|
|
36
|
+
return { sessionPaths, response: { orderedSessions } };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Post-write guard: repeat the submitted-member existence, persistence,
|
|
40
|
+
* archive, scope, and pin checks against a freshly read catalog, but do not
|
|
41
|
+
* require exact identity-set equality so a session created concurrently with
|
|
42
|
+
* the write remains unordered at the top rather than failing the write.
|
|
43
|
+
*/
|
|
44
|
+
export function assertSubmittedSessionsCurrent(target, request, catalog) {
|
|
45
|
+
requireTargetIncluded(target, request);
|
|
46
|
+
requireDistinctIdentities(request.orderedSessions);
|
|
47
|
+
const byIdentity = catalogByIdentity(catalog);
|
|
48
|
+
for (const ref of request.orderedSessions) {
|
|
49
|
+
const session = byIdentity.get(identityKey(ref.cwd, ref.id));
|
|
50
|
+
if (session === undefined)
|
|
51
|
+
throw new SessionReorderDomainError("not-found", `Session not found: ${ref.id}`);
|
|
52
|
+
if (!isEligibleForScope(session, request.scope, request.pinned)) {
|
|
53
|
+
throw new SessionReorderDomainError("conflict", `Session changed during reorder: ${ref.id}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function requireTargetIncluded(target, request) {
|
|
58
|
+
const included = request.orderedSessions.some((ref) => ref.id === target.id && ref.cwd === target.cwd);
|
|
59
|
+
if (!included)
|
|
60
|
+
throw new SessionReorderDomainError("invalid", "Target session must be included in the ordered sessions");
|
|
61
|
+
}
|
|
62
|
+
function requireDistinctIdentities(orderedSessions) {
|
|
63
|
+
const identities = new Set();
|
|
64
|
+
for (const ref of orderedSessions) {
|
|
65
|
+
const identity = identityKey(ref.cwd, ref.id);
|
|
66
|
+
if (identities.has(identity)) {
|
|
67
|
+
throw new SessionReorderDomainError("invalid", "Duplicate session reference in reorder request");
|
|
68
|
+
}
|
|
69
|
+
identities.add(identity);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function catalogByIdentity(catalog) {
|
|
73
|
+
const byIdentity = new Map();
|
|
74
|
+
for (const session of catalog)
|
|
75
|
+
byIdentity.set(identityKey(session.cwd, session.id), session);
|
|
76
|
+
return byIdentity;
|
|
77
|
+
}
|
|
78
|
+
function resolveOrderedSessions(orderedSessions, byIdentity) {
|
|
79
|
+
return orderedSessions.map((ref) => {
|
|
80
|
+
const session = byIdentity.get(identityKey(ref.cwd, ref.id));
|
|
81
|
+
if (session === undefined)
|
|
82
|
+
throw new SessionReorderDomainError("not-found", `Session not found: ${ref.id}`);
|
|
83
|
+
return session;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function requireDistinctPaths(orderedSessions, resolved) {
|
|
87
|
+
const pathsSeen = new Map();
|
|
88
|
+
for (let index = 0; index < resolved.length; index += 1) {
|
|
89
|
+
const session = resolved[index];
|
|
90
|
+
const ref = orderedSessions[index];
|
|
91
|
+
if (session === undefined || ref === undefined)
|
|
92
|
+
continue;
|
|
93
|
+
const existing = pathsSeen.get(session.path);
|
|
94
|
+
if (existing !== undefined && (existing.id !== ref.id || existing.cwd !== ref.cwd)) {
|
|
95
|
+
throw new SessionReorderDomainError("invalid", "Distinct sessions resolved to the same persisted path");
|
|
96
|
+
}
|
|
97
|
+
pathsSeen.set(session.path, ref);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function isEligibleForScope(session, scope, pinned) {
|
|
101
|
+
if (session.archived === true)
|
|
102
|
+
return false;
|
|
103
|
+
if (session.persisted !== true)
|
|
104
|
+
return false;
|
|
105
|
+
if ((session.pinned === true) !== pinned)
|
|
106
|
+
return false;
|
|
107
|
+
if (scope.kind === "root") {
|
|
108
|
+
if (session.parentSessionPath !== undefined)
|
|
109
|
+
return false;
|
|
110
|
+
return session.cwd === scope.cwd;
|
|
111
|
+
}
|
|
112
|
+
return session.parentSessionPath === scope.parentSessionPath;
|
|
113
|
+
}
|
|
114
|
+
function identityKey(cwd, id) {
|
|
115
|
+
return JSON.stringify([cwd, id]);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=sessionReorder.js.map
|