@wairon/cli 5.0.2-dev.5 → 5.0.2-dev.7
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/cli/index.js +160 -18
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +100 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var init_defaults = __esm({
|
|
|
65
65
|
copilot: ".github/prompts",
|
|
66
66
|
codex: ".codex/agents"
|
|
67
67
|
};
|
|
68
|
-
WAIRON_VERSION = "5.0.2-dev.
|
|
68
|
+
WAIRON_VERSION = "5.0.2-dev.7";
|
|
69
69
|
GITHUB_REPO = "SYW-Apps/Waffle-AIron";
|
|
70
70
|
ARCHITECT_AGENT_ID = "agent-architect";
|
|
71
71
|
ARCHITECT_TEMPLATE_ID = "architect";
|
|
@@ -703,7 +703,7 @@ var init_template = __esm({
|
|
|
703
703
|
});
|
|
704
704
|
|
|
705
705
|
// src/models/specs.ts
|
|
706
|
-
var import_zod6, SpecIdSchema, SpecStatusSchema, BoundaryItemSchema, RequirementItemSchema, DatabaseSpecSchema, DiagramConfigSchema, SURFACE_AUDIENCES, SurfaceAudienceSchema, SystemPublicInterfaceSchema, SystemSpecSchema, PublicInterfaceTypeSchema, PublicInterfaceSchema, TrustedLinkSchema, LintAllowSchema, LintConfigSchema, ExtDataSchema, LifecycleEntrypointSchema, SubsystemSpecSchema, ComponentTypeSchema, PATTERN_TYPES, PortalTypeSchema, DispatchBindingSchema, DurabilitySchema, PatternRefSchema, EventBindingSchema, ComponentSpecSchema, HttpMethodSchema, TransportSchema, EndpointSchema, SEMANTIC_GUARANTEES, GuaranteeSchema, MethodParamSchema, MethodSignatureSchema, InterfaceSpecSchema, NarrativeStepTypeSchema, LoopKindSchema, SwitchCaseSchema, CatchClauseSchema, ParallelBranchSchema, NarrativeStepSchema, NarrativeDetailSchema, ConformanceTierSchema, MethodImplementationSchema, ImplementationSpecSchema, TypeKindSchema, TypeFieldSchema, TypeMethodSchema, InvariantSchema, TypeSpecSchema, SurfaceOriginSchema, SurfaceTypeDefSchema, SurfaceContractEntrySchema, SurfaceSnapshotSchema, GroupSpecSchema;
|
|
706
|
+
var import_zod6, SpecIdSchema, SpecStatusSchema, BoundaryItemSchema, RequirementItemSchema, DatabaseSpecSchema, DiagramConfigSchema, SURFACE_AUDIENCES, SurfaceAudienceSchema, SystemPublicInterfaceSchema, SystemSpecSchema, PublicInterfaceTypeSchema, PublicInterfaceSchema, TrustedLinkSchema, LintAllowSchema, LintConfigSchema, ExtDataSchema, LifecycleEntrypointSchema, SubsystemSpecSchema, ComponentTypeSchema, PATTERN_TYPES, PortalTypeSchema, DispatchBindingSchema, DurabilitySchema, PatternRefSchema, EventBindingSchema, ExternalLinkTypeSchema, ExternalLinkSchema, ComponentSpecSchema, HttpMethodSchema, TransportSchema, EndpointSchema, SEMANTIC_GUARANTEES, GuaranteeSchema, MethodParamSchema, MethodSignatureSchema, InterfaceSpecSchema, NarrativeStepTypeSchema, LoopKindSchema, SwitchCaseSchema, CatchClauseSchema, ParallelBranchSchema, NarrativeStepSchema, NarrativeDetailSchema, ConformanceTierSchema, MethodImplementationSchema, ImplementationSpecSchema, TypeKindSchema, TypeFieldSchema, TypeMethodSchema, InvariantSchema, TypeSpecSchema, SurfaceOriginSchema, SurfaceTypeDefSchema, SurfaceContractEntrySchema, SurfaceSnapshotSchema, GroupSpecSchema;
|
|
707
707
|
var init_specs = __esm({
|
|
708
708
|
"src/models/specs.ts"() {
|
|
709
709
|
"use strict";
|
|
@@ -907,6 +907,13 @@ var init_specs = __esm({
|
|
|
907
907
|
event: import_zod6.z.string().optional(),
|
|
908
908
|
description: import_zod6.z.string().optional()
|
|
909
909
|
});
|
|
910
|
+
ExternalLinkTypeSchema = import_zod6.z.enum(["implementation", "informative"]);
|
|
911
|
+
ExternalLinkSchema = import_zod6.z.object({
|
|
912
|
+
url: import_zod6.z.string(),
|
|
913
|
+
/** Defaults to 'informative' so an untyped link never silently satisfies the source requirement. */
|
|
914
|
+
type: ExternalLinkTypeSchema.default("informative"),
|
|
915
|
+
label: import_zod6.z.string().optional()
|
|
916
|
+
});
|
|
910
917
|
ComponentSpecSchema = import_zod6.z.object({
|
|
911
918
|
id: SpecIdSchema,
|
|
912
919
|
name: import_zod6.z.string(),
|
|
@@ -932,6 +939,11 @@ var init_specs = __esm({
|
|
|
932
939
|
patterns: import_zod6.z.array(PatternRefSchema).optional(),
|
|
933
940
|
/** Optional component variant — a declared, base-anchored specialization of this component's stereotype (resolved against the variant registry; UNKNOWN_VARIANT / VARIANT_BASE_MISMATCH). */
|
|
934
941
|
variant: import_zod6.z.string().optional(),
|
|
942
|
+
/** Opaque external references (see ExternalLinkSchema) — documented URLs wairon does
|
|
943
|
+
* not fetch or validate. An `implementation` link is the external source-of-record and
|
|
944
|
+
* satisfies the source requirement for a source-less implementation (suppresses
|
|
945
|
+
* MISSING_SOURCE_PATH); `informative` links are context only. */
|
|
946
|
+
externalLinks: import_zod6.z.array(ExternalLinkSchema).optional(),
|
|
935
947
|
/** Per-spec lint suppressions (see LintConfigSchema). */
|
|
936
948
|
lint: LintConfigSchema.optional(),
|
|
937
949
|
/** Opaque pack/tool extension data (see ExtDataSchema) — preserved verbatim. */
|
|
@@ -2652,6 +2664,7 @@ function buildCanvasModel(issues = []) {
|
|
|
2652
2664
|
...ownerOf.has(comp.id) ? { owner: ownerOf.get(comp.id) } : {},
|
|
2653
2665
|
owns: comp.owns.filter((o) => componentIds.has(o)),
|
|
2654
2666
|
dependsOn: comp.dependsOn,
|
|
2667
|
+
...comp.externalLinks && comp.externalLinks.length ? { externalLinks: comp.externalLinks } : {},
|
|
2655
2668
|
interfaces: compInterfaces.map((i) => ({
|
|
2656
2669
|
id: i.id,
|
|
2657
2670
|
name: i.name,
|
|
@@ -6072,6 +6085,14 @@ var MODEL = __MODEL_JSON__;
|
|
|
6072
6085
|
if (!exposes || !openApiAllowed()) return '';
|
|
6073
6086
|
return '<div class="openbtn"><button class="tbtn" data-openapi-tag="' + esc(tag || '') + '">\\u25A4 View OpenAPI \\u2197</button></div>';
|
|
6074
6087
|
}
|
|
6088
|
+
// "Open in Specs" \u2014 deep-links the focused spec into the hosted Specs value
|
|
6089
|
+
// editor via a host hook (opts.onOpenSpec). Hidden when no host provides it
|
|
6090
|
+
// (standalone file, shared page): those have no editor to open. kind is the
|
|
6091
|
+
// spec layer, id its qualified spec id.
|
|
6092
|
+
function openSpecButton(kind, id) {
|
|
6093
|
+
if (typeof opts === 'undefined' || !opts || typeof opts.onOpenSpec !== 'function') return '';
|
|
6094
|
+
return '<div class="openbtn"><button class="tbtn" data-openspec-kind="' + kind + '" data-openspec-id="' + esc(id) + '">\\u270E Open in Specs \\u2197</button></div>';
|
|
6095
|
+
}
|
|
6075
6096
|
|
|
6076
6097
|
function renderPanel() {
|
|
6077
6098
|
var head = '', body = '';
|
|
@@ -6094,7 +6115,8 @@ var MODEL = __MODEL_JSON__;
|
|
|
6094
6115
|
+ (scopeFocus ? staticChip('current view') : '')
|
|
6095
6116
|
+ chip(c.subsystem, 'subsystem', c.subsystem)
|
|
6096
6117
|
+ (scopeFocus ? '' : openViewButton('component', c.id, c.owns.length > 0))
|
|
6097
|
-
+ openApiButton(componentExposesApi(c), c.apiTag)
|
|
6118
|
+
+ openApiButton(componentExposesApi(c), c.apiTag)
|
|
6119
|
+
+ openSpecButton('component', c.id);
|
|
6098
6120
|
|
|
6099
6121
|
var linkedTypes = MODEL.types.filter(function (t) { return t.componentClass === c.id; });
|
|
6100
6122
|
if (linkedTypes.length) {
|
|
@@ -6104,6 +6126,14 @@ var MODEL = __MODEL_JSON__;
|
|
|
6104
6126
|
}
|
|
6105
6127
|
body += '<p class="desc">' + esc(c.description) + '</p>';
|
|
6106
6128
|
|
|
6129
|
+
if (c.externalLinks && c.externalLinks.length) {
|
|
6130
|
+
body += section('External links', c.externalLinks.length, c.externalLinks.map(function (l) {
|
|
6131
|
+
var label = l.label || l.url;
|
|
6132
|
+
var tag = l.type === 'implementation' ? staticChip('source') : '';
|
|
6133
|
+
return '<div class="method">' + tag + '<a href="' + esc(l.url) + '" target="_blank" rel="noopener" style="color:var(--accent);word-break:break-all">' + esc(label) + ' \\u2197</a></div>';
|
|
6134
|
+
}).join(''), true);
|
|
6135
|
+
}
|
|
6136
|
+
|
|
6107
6137
|
var depInner = (c.dependsOn.length ? c.dependsOn.map(function (d) { return chip(d, 'component', d); }).join('') : '<span class="desc">none</span>')
|
|
6108
6138
|
+ (c.owns.length ? '<div style="margin-top:8px"><b style="font-size:11px">Owns:</b><br>' + c.owns.map(function (d) { return chip(d, 'component', d); }).join('') + '</div>' : '');
|
|
6109
6139
|
body += section('Dependencies', c.dependsOn.length + c.owns.length, depInner, true);
|
|
@@ -6178,7 +6208,8 @@ var MODEL = __MODEL_JSON__;
|
|
|
6178
6208
|
MODEL.types.forEach(function (t2) { if (t2.id === focusId) ty = t2; });
|
|
6179
6209
|
if (ty) {
|
|
6180
6210
|
head = '<h2>' + esc(ty.name) + '</h2>' + staticChip('\\u00AB' + ty.kind + '\\u00BB')
|
|
6181
|
-
+ (ty.subsystem ? chip(ty.subsystem, 'subsystem', ty.subsystem) : staticChip('system-level shared'))
|
|
6211
|
+
+ (ty.subsystem ? chip(ty.subsystem, 'subsystem', ty.subsystem) : staticChip('system-level shared'))
|
|
6212
|
+
+ openSpecButton('type', ty.id);
|
|
6182
6213
|
|
|
6183
6214
|
if (ty.componentClass) {
|
|
6184
6215
|
head += '<div style="margin-top:6px"><b style="font-size:11px">Class Component:</b> ' + chip(ty.componentClass, 'component', ty.componentClass) + '</div>';
|
|
@@ -6254,7 +6285,8 @@ var MODEL = __MODEL_JSON__;
|
|
|
6254
6285
|
+ (s.status ? staticChip(s.status) : '')
|
|
6255
6286
|
+ (scopeFocus ? staticChip('current view') : '')
|
|
6256
6287
|
+ (scopeFocus ? '' : openViewButton('subsystem', s.id, subKids > 0))
|
|
6257
|
-
+ openApiButton(subsystemExposesApi(s.id), '')
|
|
6288
|
+
+ openApiButton(subsystemExposesApi(s.id), '')
|
|
6289
|
+
+ openSpecButton('subsystem', s.id);
|
|
6258
6290
|
body += '<p class="desc">' + esc(s.description) + '</p>';
|
|
6259
6291
|
if (s.trustedLinks.length) {
|
|
6260
6292
|
body += section('Trusted links (fast lanes)', s.trustedLinks.length, s.trustedLinks.map(function (t2) {
|
|
@@ -6312,6 +6344,16 @@ var MODEL = __MODEL_JSON__;
|
|
|
6312
6344
|
});
|
|
6313
6345
|
})(oapis[oi]);
|
|
6314
6346
|
}
|
|
6347
|
+
var ospecs = panel.querySelectorAll('[data-openspec-kind]');
|
|
6348
|
+
for (var si = 0; si < ospecs.length; si++) {
|
|
6349
|
+
(function (b) {
|
|
6350
|
+
b.addEventListener('click', function () {
|
|
6351
|
+
if (typeof opts !== 'undefined' && opts && typeof opts.onOpenSpec === 'function') {
|
|
6352
|
+
opts.onOpenSpec(b.getAttribute('data-openspec-kind'), b.getAttribute('data-openspec-id') || '');
|
|
6353
|
+
}
|
|
6354
|
+
});
|
|
6355
|
+
})(ospecs[si]);
|
|
6356
|
+
}
|
|
6315
6357
|
var flows = panel.querySelectorAll('[data-flow-comp]');
|
|
6316
6358
|
for (var j = 0; j < flows.length; j++) {
|
|
6317
6359
|
(function (b) {
|
|
@@ -6324,6 +6366,23 @@ var MODEL = __MODEL_JSON__;
|
|
|
6324
6366
|
}
|
|
6325
6367
|
|
|
6326
6368
|
renderPanel();
|
|
6369
|
+
// Stage G: a deep link may focus a component and/or open a method's narrative
|
|
6370
|
+
// modal once the seeded view + DOM + cy graph exist. The host parses the URL hash
|
|
6371
|
+
// into opts.initialSelect / opts.initialFlow \u2014 both carry the component id, so this
|
|
6372
|
+
// works whether the seeded view is the component itself or its parent subsystem
|
|
6373
|
+
// (a leaf component has no meaningful "inside", so Specs deep-links open the parent
|
|
6374
|
+
// and focus the component here).
|
|
6375
|
+
(function () {
|
|
6376
|
+
if (typeof opts === 'undefined' || !opts) return;
|
|
6377
|
+
var f = opts.initialFlow, s = opts.initialSelect;
|
|
6378
|
+
var focusComp = (f && f.comp) || (s && s.comp);
|
|
6379
|
+
if (focusComp && compById[focusComp]) {
|
|
6380
|
+
try { select('component', focusComp, true); } catch (e) { /* ignore */ }
|
|
6381
|
+
}
|
|
6382
|
+
if (f && f.comp && f.method && compById[f.comp]) {
|
|
6383
|
+
try { openFlow(f.comp, f.method, f.mode === 'steps' ? 'steps' : 'flow'); } catch (e) { /* ignore */ }
|
|
6384
|
+
}
|
|
6385
|
+
})();
|
|
6327
6386
|
})();
|
|
6328
6387
|
</script>
|
|
6329
6388
|
</body>
|
|
@@ -8436,13 +8495,16 @@ var init_conformance = __esm({
|
|
|
8436
8495
|
if (isInChainedSubproject(component.subsystem, ctx)) continue;
|
|
8437
8496
|
const draft = ctx.isImplementationDraft(impl);
|
|
8438
8497
|
if (!impl.sourcePath) {
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8498
|
+
const hasExternalSource = (component.externalLinks ?? []).some((l) => l.type === "implementation");
|
|
8499
|
+
if (!hasExternalSource) {
|
|
8500
|
+
ctx.addIssue(
|
|
8501
|
+
"warning",
|
|
8502
|
+
"MISSING_SOURCE_PATH",
|
|
8503
|
+
`Implementation "${impl.id}" declares no sourcePath \u2014 its contract "${impl.contract}" cannot be structurally checked against code.`,
|
|
8504
|
+
impl.id,
|
|
8505
|
+
draft
|
|
8506
|
+
);
|
|
8507
|
+
}
|
|
8446
8508
|
continue;
|
|
8447
8509
|
}
|
|
8448
8510
|
const lookup = lookups.get(normalizeSourcePath(impl.sourcePath));
|
|
@@ -12705,6 +12767,28 @@ function buildGraphModel(level) {
|
|
|
12705
12767
|
...t.subsystem ? { parentId: t.subsystem } : {}
|
|
12706
12768
|
});
|
|
12707
12769
|
}
|
|
12770
|
+
const componentByInterface = /* @__PURE__ */ new Map();
|
|
12771
|
+
for (const c of model.components) {
|
|
12772
|
+
for (const intf of c.interfaces) componentByInterface.set(intf.id, c.id);
|
|
12773
|
+
}
|
|
12774
|
+
for (const impl of loadImplementationSpecs()) {
|
|
12775
|
+
const componentId = componentByInterface.get(impl.contract);
|
|
12776
|
+
if (!componentId) continue;
|
|
12777
|
+
nodes.push({
|
|
12778
|
+
id: impl.id,
|
|
12779
|
+
label: impl.name,
|
|
12780
|
+
kind: "implementation",
|
|
12781
|
+
level: 4,
|
|
12782
|
+
parentId: componentId,
|
|
12783
|
+
...impl.status ? { status: impl.status } : {}
|
|
12784
|
+
});
|
|
12785
|
+
candidates.push({ from: componentId, to: impl.id, edgeKind: "owns" });
|
|
12786
|
+
}
|
|
12787
|
+
for (const c of model.components) {
|
|
12788
|
+
for (const memberId of c.owns) {
|
|
12789
|
+
candidates.push({ from: c.id, to: memberId, edgeKind: "owns" });
|
|
12790
|
+
}
|
|
12791
|
+
}
|
|
12708
12792
|
for (const e of model.edges) {
|
|
12709
12793
|
candidates.push({ from: e.from, to: e.to, edgeKind: "depends_on" });
|
|
12710
12794
|
}
|
|
@@ -27670,6 +27754,7 @@ function removeIdentityProviderRecord(dataDir, id) {
|
|
|
27670
27754
|
}
|
|
27671
27755
|
var PROJECT_CREATE_CAPABILITY = "project:create";
|
|
27672
27756
|
var PROJECT_WRITE_CAPABILITY = "project:write";
|
|
27757
|
+
var PROJECT_READ_CAPABILITY = "project:read";
|
|
27673
27758
|
var POLICY_MANAGE_CAPABILITY = "project:admin";
|
|
27674
27759
|
function carriesInstancePermission(cfg, principal, capability) {
|
|
27675
27760
|
return authorize(cfg.dataDir, principal, capability, "instance", "").value === "yes";
|
|
@@ -27734,6 +27819,19 @@ function recordProjectProfileSelection(root, selection) {
|
|
|
27734
27819
|
writeYamlFile(AI_PATHS.projectConfig(), raw);
|
|
27735
27820
|
});
|
|
27736
27821
|
}
|
|
27822
|
+
function readProjectType(root) {
|
|
27823
|
+
return runWithProjectRoot(root, () => {
|
|
27824
|
+
const raw = readYamlFile(AI_PATHS.projectConfig());
|
|
27825
|
+
return raw?.projectType ?? "backend";
|
|
27826
|
+
});
|
|
27827
|
+
}
|
|
27828
|
+
function writeProjectType(root, projectType) {
|
|
27829
|
+
runWithProjectRoot(root, () => {
|
|
27830
|
+
const raw = readYamlFile(AI_PATHS.projectConfig()) ?? {};
|
|
27831
|
+
raw["projectType"] = projectType;
|
|
27832
|
+
writeYamlFile(AI_PATHS.projectConfig(), raw);
|
|
27833
|
+
});
|
|
27834
|
+
}
|
|
27737
27835
|
function requestPackNames(request) {
|
|
27738
27836
|
const sel = request.profileSelection;
|
|
27739
27837
|
if (!sel) return [];
|
|
@@ -27928,6 +28026,32 @@ function reconcileProjectPolicy(cfg, credential, projectId) {
|
|
|
27928
28026
|
);
|
|
27929
28027
|
return result;
|
|
27930
28028
|
}
|
|
28029
|
+
function getProjectConfig(cfg, credential, projectId) {
|
|
28030
|
+
const principal = requirePrincipal4(cfg, credential);
|
|
28031
|
+
if (authorize(cfg.dataDir, principal, PROJECT_READ_CAPABILITY, "project", projectId).value !== "yes") {
|
|
28032
|
+
throw new ForbiddenError(
|
|
28033
|
+
"reading a project's configuration requires project:read over the project"
|
|
28034
|
+
);
|
|
28035
|
+
}
|
|
28036
|
+
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
28037
|
+
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
28038
|
+
const projectType = readProjectType(root);
|
|
28039
|
+
const locked = runWithProjectRoot(root, () => hostCore.readLockRecord() !== null);
|
|
28040
|
+
return { projectType, locked };
|
|
28041
|
+
}
|
|
28042
|
+
function setProjectType(cfg, credential, projectId, projectType) {
|
|
28043
|
+
const principal = requirePrincipal4(cfg, credential);
|
|
28044
|
+
if (authorize(cfg.dataDir, principal, PROJECT_WRITE_CAPABILITY, "project", projectId).value !== "yes") {
|
|
28045
|
+
throw new ForbiddenError(
|
|
28046
|
+
"changing a project's configuration requires project:write over the project"
|
|
28047
|
+
);
|
|
28048
|
+
}
|
|
28049
|
+
const root = resolveProjectRoot(cfg.dataDir, principal, projectId);
|
|
28050
|
+
if (!root) throw new Error(`Unknown project "${projectId}".`);
|
|
28051
|
+
writeProjectType(root, projectType);
|
|
28052
|
+
const locked = runWithProjectRoot(root, () => hostCore.readLockRecord() !== null);
|
|
28053
|
+
return { projectType, locked };
|
|
28054
|
+
}
|
|
27931
28055
|
function getPackPolicy(cfg, credential) {
|
|
27932
28056
|
requirePrincipal4(cfg, credential);
|
|
27933
28057
|
return getPackPolicyRecord(cfg.dataDir) ?? PERMISSIVE_DEFAULT_POLICY;
|
|
@@ -27991,7 +28115,7 @@ function handlePolicyRequest(cfg, credential, req, res, body, url) {
|
|
|
27991
28115
|
|
|
27992
28116
|
// src/server/identity.ts
|
|
27993
28117
|
var PROJECT_ADMIN_CAPABILITY2 = "project:admin";
|
|
27994
|
-
var
|
|
28118
|
+
var PROJECT_READ_CAPABILITY2 = "project:read";
|
|
27995
28119
|
var PROJECT_WRITE_CAPABILITY2 = "project:write";
|
|
27996
28120
|
function requireInstanceProjectAdmin(cfg, principal, what) {
|
|
27997
28121
|
if (authorize(cfg.dataDir, principal, PROJECT_ADMIN_CAPABILITY2, "instance", "").value !== "yes") {
|
|
@@ -28137,7 +28261,7 @@ function revokeToken(cfg, credential, tokenId) {
|
|
|
28137
28261
|
}
|
|
28138
28262
|
function mintSelfToken(cfg, credential, projectId, write) {
|
|
28139
28263
|
const principal = requirePrincipal5(cfg, credential);
|
|
28140
|
-
if (authorize(cfg.dataDir, principal,
|
|
28264
|
+
if (authorize(cfg.dataDir, principal, PROJECT_READ_CAPABILITY2, "project", projectId).value !== "yes") {
|
|
28141
28265
|
throw new ForbiddenError("caller lacks project:read on the requested project");
|
|
28142
28266
|
}
|
|
28143
28267
|
if (write && authorize(cfg.dataDir, principal, PROJECT_WRITE_CAPABILITY2, "project", projectId).value !== "yes") {
|
|
@@ -28783,7 +28907,7 @@ function audienceDistance(resolution, targetProjectId) {
|
|
|
28783
28907
|
// src/server/landscape.ts
|
|
28784
28908
|
var yamlLib = __toESM(require("js-yaml"));
|
|
28785
28909
|
var PROJECT_ADMIN_CAPABILITY3 = "project:admin";
|
|
28786
|
-
var
|
|
28910
|
+
var PROJECT_READ_CAPABILITY3 = "project:read";
|
|
28787
28911
|
var PROJECT_WRITE_CAPABILITY3 = "project:write";
|
|
28788
28912
|
function requirePrincipal6(cfg, credential) {
|
|
28789
28913
|
const principal = authenticateCredential(cfg.dataDir, credential);
|
|
@@ -28797,7 +28921,7 @@ function readView(cfg, principal) {
|
|
|
28797
28921
|
if (isInstanceAdmin(principal)) {
|
|
28798
28922
|
return { all: true, projectIds: /* @__PURE__ */ new Set(), unitIds: /* @__PURE__ */ new Set(), contextUnitIds: /* @__PURE__ */ new Set() };
|
|
28799
28923
|
}
|
|
28800
|
-
const read = visibleScopes(cfg.dataDir, principal,
|
|
28924
|
+
const read = visibleScopes(cfg.dataDir, principal, PROJECT_READ_CAPABILITY3);
|
|
28801
28925
|
const admin = visibleScopes(cfg.dataDir, principal, PROJECT_ADMIN_CAPABILITY3);
|
|
28802
28926
|
const unitIds = /* @__PURE__ */ new Set([...actionableUnitIds(read), ...actionableUnitIds(admin)]);
|
|
28803
28927
|
const contextUnitIds = new Set(
|
|
@@ -28812,13 +28936,13 @@ function readView(cfg, principal) {
|
|
|
28812
28936
|
}
|
|
28813
28937
|
function requireLandscapeReach(cfg, principal, view, what) {
|
|
28814
28938
|
if (view.all || view.projectIds.size > 0 || view.unitIds.size > 0) return;
|
|
28815
|
-
if (permitsCap(cfg, principal,
|
|
28939
|
+
if (permitsCap(cfg, principal, PROJECT_READ_CAPABILITY3, "instance", "") || permitsCap(cfg, principal, PROJECT_ADMIN_CAPABILITY3, "instance", "")) {
|
|
28816
28940
|
return;
|
|
28817
28941
|
}
|
|
28818
28942
|
throw new ForbiddenError(`${what} requires project:read reach`);
|
|
28819
28943
|
}
|
|
28820
28944
|
function requireObserverScope(cfg, principal, observerProjectId) {
|
|
28821
|
-
const covered = permitsCap(cfg, principal,
|
|
28945
|
+
const covered = permitsCap(cfg, principal, PROJECT_READ_CAPABILITY3, "project", observerProjectId) || permitsCap(cfg, principal, PROJECT_WRITE_CAPABILITY3, "project", observerProjectId);
|
|
28822
28946
|
if (!covered) {
|
|
28823
28947
|
throw new ForbiddenError("caller lacks scope over the current project");
|
|
28824
28948
|
}
|
|
@@ -30876,6 +31000,12 @@ function evaluateProjectPolicy2(cfg, credential, projectId) {
|
|
|
30876
31000
|
function reconcileProjectPolicy2(cfg, credential, projectId) {
|
|
30877
31001
|
return reconcileProjectPolicy(cfg, credential, projectId);
|
|
30878
31002
|
}
|
|
31003
|
+
function getProjectConfig2(cfg, credential, projectId) {
|
|
31004
|
+
return getProjectConfig(cfg, credential, projectId);
|
|
31005
|
+
}
|
|
31006
|
+
function setProjectType2(cfg, credential, projectId, projectType) {
|
|
31007
|
+
return setProjectType(cfg, credential, projectId, projectType);
|
|
31008
|
+
}
|
|
30879
31009
|
function listProducers2(cfg, credential, project2) {
|
|
30880
31010
|
return listProducers(cfg, credential, project2);
|
|
30881
31011
|
}
|
|
@@ -34178,6 +34308,12 @@ function opsPolicyEvaluate(cfg, sessionId, url, res) {
|
|
|
34178
34308
|
function opsPolicyReconcile(cfg, sessionId, body, res) {
|
|
34179
34309
|
sendJson(res, 200, reconcileProjectPolicy2(cfg, sessionId, String(body?.projectId ?? "")));
|
|
34180
34310
|
}
|
|
34311
|
+
function opsGetProjectConfig(cfg, sessionId, url, res) {
|
|
34312
|
+
sendJson(res, 200, getProjectConfig2(cfg, sessionId, q(url, "projectId") ?? ""));
|
|
34313
|
+
}
|
|
34314
|
+
function opsSetProjectConfig(cfg, sessionId, body, res) {
|
|
34315
|
+
sendJson(res, 200, setProjectType2(cfg, sessionId, String(body?.projectId ?? ""), String(body?.projectType ?? "")));
|
|
34316
|
+
}
|
|
34181
34317
|
function opsListProducers(cfg, sessionId, url, res) {
|
|
34182
34318
|
sendJson(res, 200, { producers: listProducers2(cfg, sessionId, q(url, "projectId") ?? "") });
|
|
34183
34319
|
}
|
|
@@ -34410,6 +34546,12 @@ async function handleWebRequest(cfg, req, res, body, url, ctx) {
|
|
|
34410
34546
|
if (req.method === "POST" && parts.length === 4 && parts[2] === "packs" && parts[3] === "adopt") {
|
|
34411
34547
|
return opsAdoptProjectPack(cfg, sessionId, body, res);
|
|
34412
34548
|
}
|
|
34549
|
+
if (req.method === "GET" && parts.length === 3 && parts[2] === "config") {
|
|
34550
|
+
return opsGetProjectConfig(cfg, sessionId, url, res);
|
|
34551
|
+
}
|
|
34552
|
+
if (req.method === "POST" && parts.length === 3 && parts[2] === "config") {
|
|
34553
|
+
return opsSetProjectConfig(cfg, sessionId, body, res);
|
|
34554
|
+
}
|
|
34413
34555
|
if (req.method === "GET" && parts.length === 3 && parts[2] === "policy") {
|
|
34414
34556
|
return opsPolicyEvaluate(cfg, sessionId, url, res);
|
|
34415
34557
|
}
|