harness-mcp-v2 3.2.19 → 3.2.21
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 +146 -75
- package/build/client/harness-client.d.ts.map +1 -1
- package/build/client/harness-client.js +32 -6
- package/build/client/harness-client.js.map +1 -1
- package/build/config.d.ts +10 -0
- package/build/config.d.ts.map +1 -1
- package/build/config.js +15 -0
- package/build/config.js.map +1 -1
- package/build/data/schemas/v0/pipeline.d.ts.map +1 -1
- package/build/data/schemas/v0/pipeline.js +1388 -580
- package/build/data/schemas/v0/pipeline.js.map +1 -1
- package/build/data/schemas/v0/template.d.ts.map +1 -1
- package/build/data/schemas/v0/template.js +1142 -166
- package/build/data/schemas/v0/template.js.map +1 -1
- package/build/data/schemas/v1/pipeline.d.ts.map +1 -1
- package/build/data/schemas/v1/pipeline.js +302 -90
- package/build/data/schemas/v1/pipeline.js.map +1 -1
- package/build/data/schemas/v1/template.d.ts.map +1 -1
- package/build/data/schemas/v1/template.js +708 -488
- package/build/data/schemas/v1/template.js.map +1 -1
- package/build/prompts/deploy-ai-agent.d.ts +3 -0
- package/build/prompts/deploy-ai-agent.d.ts.map +1 -0
- package/build/prompts/deploy-ai-agent.js +300 -0
- package/build/prompts/deploy-ai-agent.js.map +1 -0
- package/build/prompts/feature-flag-rollout.d.ts.map +1 -1
- package/build/prompts/feature-flag-rollout.js +19 -8
- package/build/prompts/feature-flag-rollout.js.map +1 -1
- package/build/prompts/index.d.ts.map +1 -1
- package/build/prompts/index.js +2 -0
- package/build/prompts/index.js.map +1 -1
- package/build/registry/extractors.d.ts +87 -10
- package/build/registry/extractors.d.ts.map +1 -1
- package/build/registry/extractors.js +426 -26
- package/build/registry/extractors.js.map +1 -1
- package/build/registry/index.d.ts.map +1 -1
- package/build/registry/index.js +34 -15
- package/build/registry/index.js.map +1 -1
- package/build/registry/scope-utils.d.ts +45 -0
- package/build/registry/scope-utils.d.ts.map +1 -1
- package/build/registry/scope-utils.js +78 -0
- package/build/registry/scope-utils.js.map +1 -1
- package/build/registry/toolsets/chaos-descriptions.d.ts +72 -20
- package/build/registry/toolsets/chaos-descriptions.d.ts.map +1 -1
- package/build/registry/toolsets/chaos-descriptions.js +435 -140
- package/build/registry/toolsets/chaos-descriptions.js.map +1 -1
- package/build/registry/toolsets/chaos.d.ts.map +1 -1
- package/build/registry/toolsets/chaos.js +967 -193
- package/build/registry/toolsets/chaos.js.map +1 -1
- package/build/registry/toolsets/feature-flags.d.ts.map +1 -1
- package/build/registry/toolsets/feature-flags.js +888 -85
- package/build/registry/toolsets/feature-flags.js.map +1 -1
- package/build/registry/toolsets/governance.d.ts.map +1 -1
- package/build/registry/toolsets/governance.js +4 -0
- package/build/registry/toolsets/governance.js.map +1 -1
- package/build/registry/toolsets/iacm.d.ts.map +1 -1
- package/build/registry/toolsets/iacm.js +787 -11
- package/build/registry/toolsets/iacm.js.map +1 -1
- package/build/registry/toolsets/infrastructure.d.ts.map +1 -1
- package/build/registry/toolsets/infrastructure.js +30 -5
- package/build/registry/toolsets/infrastructure.js.map +1 -1
- package/build/registry/toolsets/pipelines.d.ts.map +1 -1
- package/build/registry/toolsets/pipelines.js +208 -5
- package/build/registry/toolsets/pipelines.js.map +1 -1
- package/build/registry/toolsets/release-management.d.ts +8 -0
- package/build/registry/toolsets/release-management.d.ts.map +1 -0
- package/build/registry/toolsets/release-management.js +783 -0
- package/build/registry/toolsets/release-management.js.map +1 -0
- package/build/registry/toolsets/sto.d.ts.map +1 -1
- package/build/registry/toolsets/sto.js +93 -17
- package/build/registry/toolsets/sto.js.map +1 -1
- package/build/registry/types.d.ts +52 -4
- package/build/registry/types.d.ts.map +1 -1
- package/build/resources/harness-schema.d.ts.map +1 -1
- package/build/resources/harness-schema.js +2 -1
- package/build/resources/harness-schema.js.map +1 -1
- package/build/tools/entity-schema/live.d.ts +6 -5
- package/build/tools/entity-schema/live.d.ts.map +1 -1
- package/build/tools/entity-schema/live.js +114 -10
- package/build/tools/entity-schema/live.js.map +1 -1
- package/build/tools/entity-schema/types.d.ts +7 -1
- package/build/tools/entity-schema/types.d.ts.map +1 -1
- package/build/tools/harness-create.d.ts.map +1 -1
- package/build/tools/harness-create.js +5 -1
- package/build/tools/harness-create.js.map +1 -1
- package/build/tools/harness-delete.d.ts.map +1 -1
- package/build/tools/harness-delete.js +5 -1
- package/build/tools/harness-delete.js.map +1 -1
- package/build/tools/harness-execute.d.ts.map +1 -1
- package/build/tools/harness-execute.js +15 -9
- package/build/tools/harness-execute.js.map +1 -1
- package/build/tools/harness-get.d.ts.map +1 -1
- package/build/tools/harness-get.js +5 -1
- package/build/tools/harness-get.js.map +1 -1
- package/build/tools/harness-list.d.ts.map +1 -1
- package/build/tools/harness-list.js +18 -2
- package/build/tools/harness-list.js.map +1 -1
- package/build/tools/harness-schema.d.ts +2 -1
- package/build/tools/harness-schema.d.ts.map +1 -1
- package/build/tools/harness-schema.js +10 -8
- package/build/tools/harness-schema.js.map +1 -1
- package/build/tools/harness-update.d.ts.map +1 -1
- package/build/tools/harness-update.js +5 -1
- package/build/tools/harness-update.js.map +1 -1
- package/build/tools/index.js +1 -1
- package/build/tools/index.js.map +1 -1
- package/build/utils/url-parser.d.ts +2 -0
- package/build/utils/url-parser.d.ts.map +1 -1
- package/build/utils/url-parser.js +55 -0
- package/build/utils/url-parser.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -43,6 +43,17 @@ export const pageExtract = (raw) => {
|
|
|
43
43
|
total: r.data?.totalElements ?? r.data?.totalItems ?? 0,
|
|
44
44
|
};
|
|
45
45
|
};
|
|
46
|
+
/**
|
|
47
|
+
* Spring Data page at the response root (no NG `{ data }` envelope):
|
|
48
|
+
* `{ content, totalElements }`. Used by Release Management (RMG) list APIs.
|
|
49
|
+
*/
|
|
50
|
+
export const springPageExtract = (raw) => {
|
|
51
|
+
const r = raw;
|
|
52
|
+
return {
|
|
53
|
+
items: Array.isArray(r.content) ? r.content : [],
|
|
54
|
+
total: typeof r.totalElements === "number" ? r.totalElements : 0,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
46
57
|
/** Extract `data` from NG API and wrap primitive values in an object for structuredContent compatibility. */
|
|
47
58
|
export const countExtract = (raw) => {
|
|
48
59
|
const r = raw;
|
|
@@ -125,8 +136,8 @@ export const stoExemptionsExtract = (raw, input) => {
|
|
|
125
136
|
};
|
|
126
137
|
};
|
|
127
138
|
/**
|
|
128
|
-
* STO
|
|
129
|
-
* (`GET /sto/api/v2/
|
|
139
|
+
* STO Remediation DiffOccurrences
|
|
140
|
+
* (`GET /sto/api/v2/remediation-agent/diff-occurrences`).
|
|
130
141
|
*
|
|
131
142
|
* API shape:
|
|
132
143
|
* { validationScanId, existingOccurrences: [...], newOccurrences: [...],
|
|
@@ -136,7 +147,7 @@ export const stoExemptionsExtract = (raw, input) => {
|
|
|
136
147
|
* tell still-present vs newly introduced occurrences without two list calls.
|
|
137
148
|
* Fingerprint is not on the wire (Diff matching is server-side only).
|
|
138
149
|
*/
|
|
139
|
-
export const
|
|
150
|
+
export const stoRemediationDiffExtract = (raw) => {
|
|
140
151
|
if (raw === null || raw === undefined || typeof raw !== "object")
|
|
141
152
|
return raw;
|
|
142
153
|
const r = raw;
|
|
@@ -779,18 +790,53 @@ export const chaosK8sInfraListExtract = (raw) => {
|
|
|
779
790
|
total: r.totalNoOfInfrastructures ?? (Array.isArray(r.infras) ? r.infras.length : 0),
|
|
780
791
|
};
|
|
781
792
|
};
|
|
782
|
-
//
|
|
783
|
-
|
|
793
|
+
// Pick the tool-specific sub-object out of toolConfig; loadTestManager also
|
|
794
|
+
// accepts flat toolConfig at the root for forward-compat, so fall back to that.
|
|
795
|
+
const pickToolBlock = (toolType, toolConfig) => {
|
|
796
|
+
if (!toolConfig)
|
|
797
|
+
return undefined;
|
|
798
|
+
const key = typeof toolType === "string" ? toolType.toLowerCase() : "";
|
|
799
|
+
const nested = key
|
|
800
|
+
? toolConfig[key]
|
|
801
|
+
: undefined;
|
|
802
|
+
return nested ?? toolConfig;
|
|
803
|
+
};
|
|
804
|
+
const readTunable = (tc, name) => {
|
|
805
|
+
if (!tc)
|
|
806
|
+
return undefined;
|
|
807
|
+
const tunables = tc.tunables;
|
|
808
|
+
return tunables?.[name];
|
|
809
|
+
};
|
|
810
|
+
const readScriptField = (tc, name) => {
|
|
811
|
+
if (!tc)
|
|
812
|
+
return undefined;
|
|
813
|
+
const script = tc.script;
|
|
814
|
+
return script?.[name];
|
|
815
|
+
};
|
|
816
|
+
// K6 rpsLimit has two historical storage locations: tunables.rpsLimit (current
|
|
817
|
+
// authoring surface) and options.rpsLimit (legacy/UI-authored path — see
|
|
818
|
+
// loadTestManager k6.go LoadOptions.RPSLimit). Mirror the backend's own
|
|
819
|
+
// dispatch-time fallback precedence (loadtest_handlers.go) so read-side scalars
|
|
820
|
+
// stay truthful regardless of which shape a given record was persisted with.
|
|
821
|
+
const readK6RpsLimit = (tc) => {
|
|
822
|
+
const fromTunables = readTunable(tc, "rpsLimit");
|
|
823
|
+
if (fromTunables != null && fromTunables !== 0)
|
|
824
|
+
return fromTunables;
|
|
825
|
+
const options = tc?.options;
|
|
826
|
+
const fromOptions = options?.rpsLimit;
|
|
827
|
+
if (fromOptions != null && fromOptions !== 0)
|
|
828
|
+
return fromOptions;
|
|
829
|
+
return undefined;
|
|
830
|
+
};
|
|
784
831
|
/**
|
|
785
|
-
* Project a single load test (
|
|
832
|
+
* Project a single load test (LoadTestResponse) to a stable shape.
|
|
786
833
|
*
|
|
787
|
-
*
|
|
788
|
-
*
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
834
|
+
* Since the variables migration, all tunables and custom env vars live under
|
|
835
|
+
* toolConfig.<tool>.tunables / toolConfig.<tool>.variables (see LocustSpec /
|
|
836
|
+
* K6Spec / JMeterSpec in loadTestManager/internal/domain). We pass toolConfig
|
|
837
|
+
* through as-is for fidelity AND surface derived convenience scalars mirroring
|
|
838
|
+
* the create-side LLM surface so round-trips are intuitive.
|
|
792
839
|
*
|
|
793
|
-
* Drops the large base64 scriptContent and backend user-detail envelopes.
|
|
794
840
|
* Mirrors `identity` into `loadtestId` so the deep-link resolver fills
|
|
795
841
|
* {loadtestId} instead of falling back to the name.
|
|
796
842
|
*/
|
|
@@ -798,35 +844,64 @@ export const chaosLoadTestExtract = (raw) => {
|
|
|
798
844
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
799
845
|
return raw;
|
|
800
846
|
const t = raw;
|
|
801
|
-
const
|
|
802
|
-
const
|
|
847
|
+
const toolConfig = t.toolConfig;
|
|
848
|
+
const toolBlock = pickToolBlock(t.toolType, toolConfig);
|
|
849
|
+
const variables = toolBlock?.variables;
|
|
850
|
+
const envVars = toolBlock?.envVars;
|
|
803
851
|
return {
|
|
804
852
|
loadtestId: t.identity,
|
|
853
|
+
uniqueId: t.uniqueId,
|
|
854
|
+
parentUniqueId: t.parentUniqueId,
|
|
805
855
|
identity: t.identity,
|
|
806
856
|
name: t.name,
|
|
807
857
|
description: t.description,
|
|
808
858
|
tags: t.tags,
|
|
859
|
+
serviceReferences: t.serviceReferences,
|
|
809
860
|
environmentIdentifier: t.environmentIdentifier,
|
|
810
861
|
infraIdentifier: t.infraIdentifier,
|
|
862
|
+
infraType: t.infraType,
|
|
811
863
|
targetType: t.targetType,
|
|
812
864
|
toolType: t.toolType,
|
|
813
865
|
scriptSource: t.scriptSource,
|
|
814
|
-
|
|
815
|
-
|
|
866
|
+
importType: t.importType,
|
|
867
|
+
templateReference: t.templateReference,
|
|
868
|
+
templateUpdateAvailable: t.templateUpdateAvailable,
|
|
869
|
+
latestRevisionIdentifier: t.latestRevisionIdentifier,
|
|
870
|
+
maxDurationSec: t.maxDurationSec,
|
|
871
|
+
cleanupPolicy: t.cleanupPolicy,
|
|
872
|
+
resources: t.resources,
|
|
873
|
+
// Canonical tool config — passed through as-is for fidelity.
|
|
874
|
+
toolConfig,
|
|
816
875
|
variables,
|
|
817
|
-
|
|
818
|
-
//
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
876
|
+
envVars,
|
|
877
|
+
// Denormalised display strings the backend emits for table renders.
|
|
878
|
+
targetUsersDisplay: t.targetUsers,
|
|
879
|
+
durationSecondsDisplay: t.durationSeconds,
|
|
880
|
+
// Derived convenience scalars (typed tunables under toolConfig.<tool>.tunables).
|
|
881
|
+
target_url: readTunable(toolBlock, "targetUrl"),
|
|
882
|
+
users: readTunable(toolBlock, "targetUsers"),
|
|
883
|
+
duration_sec: readTunable(toolBlock, "durationSeconds"),
|
|
884
|
+
ramp_up_sec: readTunable(toolBlock, "rampUpTimeSec"),
|
|
885
|
+
worker_count: readTunable(toolBlock, "workerCount"),
|
|
886
|
+
spawn_rate: readTunable(toolBlock, "spawnRate"),
|
|
887
|
+
host_url: readTunable(toolBlock, "hostUrl"),
|
|
888
|
+
iterations: readTunable(toolBlock, "iterations"),
|
|
889
|
+
rps_limit: readK6RpsLimit(toolBlock),
|
|
890
|
+
// Derived convenience scalars from toolConfig.<tool>.script (image mode).
|
|
891
|
+
script_image: readScriptField(toolBlock, "image"),
|
|
892
|
+
script_entrypoint: readScriptField(toolBlock, "entrypoint"),
|
|
893
|
+
load_args: readScriptField(toolBlock, "loadArgs"),
|
|
894
|
+
image_pull_secret: readScriptField(toolBlock, "imagePullSecret"),
|
|
895
|
+
recentRuns: t.recentRuns,
|
|
896
|
+
isSampleTest: t.isSampleTest,
|
|
897
|
+
isApiGenerated: t.isApiGenerated,
|
|
898
|
+
isAIUsed: t.isAIUsed,
|
|
827
899
|
lastExecuted: t.lastExecuted,
|
|
828
900
|
createdAt: t.createdAt,
|
|
901
|
+
createdBy: t.createdBy,
|
|
829
902
|
updatedAt: t.updatedAt,
|
|
903
|
+
updatedBy: t.updatedBy,
|
|
904
|
+
yaml: t.yaml,
|
|
830
905
|
};
|
|
831
906
|
};
|
|
832
907
|
/**
|
|
@@ -838,6 +913,16 @@ export const chaosLoadTestListExtract = (raw) => {
|
|
|
838
913
|
const items = (r.items ?? []).map(chaosLoadTestExtract);
|
|
839
914
|
return { items, total: r.pagination?.totalItems ?? items.length };
|
|
840
915
|
};
|
|
916
|
+
/**
|
|
917
|
+
* Chaos Service (v3) list response: { data: [...], correlationID, pagination: { index, limit, totalPages, totalItems } }.
|
|
918
|
+
* Distinct from chaos_loadtest's { items, pagination } envelope — the v3 chaos-services API
|
|
919
|
+
* wraps the array under `data` per shared PaginationResponse contract.
|
|
920
|
+
*/
|
|
921
|
+
export const chaosServiceListExtract = (raw) => {
|
|
922
|
+
const r = raw;
|
|
923
|
+
const items = r.data ?? [];
|
|
924
|
+
return { items, total: r.pagination?.totalItems ?? items.length };
|
|
925
|
+
};
|
|
841
926
|
/**
|
|
842
927
|
* Extract chaos hub list response: { items: [...], pagination: { totalItems } }
|
|
843
928
|
*/
|
|
@@ -906,6 +991,20 @@ export function flattenTrafficType(item) {
|
|
|
906
991
|
}
|
|
907
992
|
}
|
|
908
993
|
}
|
|
994
|
+
/**
|
|
995
|
+
* Public v4 paginated lists (`EnvironmentListResponse`, `TrafficTypeListResponse` / `RolloutStatusListResponse`):
|
|
996
|
+
* `{ data, limit, offset, totalCount }`. Promote `data`→`items` and `totalCount`→`total`
|
|
997
|
+
* so harness_list compact/output schema see a full total, not the current page length.
|
|
998
|
+
*/
|
|
999
|
+
export const fmeV4PaginatedListExtract = (raw) => {
|
|
1000
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw))
|
|
1001
|
+
return raw;
|
|
1002
|
+
const r = raw;
|
|
1003
|
+
if (!Array.isArray(r.data))
|
|
1004
|
+
return raw;
|
|
1005
|
+
const total = typeof r.totalCount === "number" ? r.totalCount : r.data.length;
|
|
1006
|
+
return { ...r, items: r.data, total };
|
|
1007
|
+
};
|
|
909
1008
|
/** Extract FME feature flag list — passthrough with trafficType.id flattened on each item. */
|
|
910
1009
|
export const fmeListExtract = (raw) => {
|
|
911
1010
|
if (raw && typeof raw === "object") {
|
|
@@ -928,4 +1027,305 @@ export const fmeGetExtract = (raw) => {
|
|
|
928
1027
|
}
|
|
929
1028
|
return raw;
|
|
930
1029
|
};
|
|
1030
|
+
// ── Release Management (RMG) ──────────────────────────────────────────────
|
|
1031
|
+
const RMG_API_PREFIX = "/api";
|
|
1032
|
+
export const RMG_DEFAULT_DAYS_BACK = 30;
|
|
1033
|
+
export const RMG_MAX_DAYS_BACK = 365;
|
|
1034
|
+
/** Days of look-ahead included in the window so scheduled releases stay visible. */
|
|
1035
|
+
export const RMG_DAYS_FORWARD = 7;
|
|
1036
|
+
const RMG_DAY_MS = 86_400_000;
|
|
1037
|
+
export const RMG_DEFAULT_TASK_LIMIT = 50;
|
|
1038
|
+
export const RMG_MAX_TASK_LIMIT = 100;
|
|
1039
|
+
function rmgClampInt(value, min, max, fallback) {
|
|
1040
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
1041
|
+
if (!Number.isFinite(n))
|
|
1042
|
+
return fallback;
|
|
1043
|
+
return Math.min(max, Math.max(min, Math.trunc(n)));
|
|
1044
|
+
}
|
|
1045
|
+
function rmgAsRecord(value) {
|
|
1046
|
+
return value !== null && typeof value === "object" ? value : {};
|
|
1047
|
+
}
|
|
1048
|
+
/** First key holding an array — RMG list payloads vary by gateway version. */
|
|
1049
|
+
function rmgFirstArrayAt(source, keys) {
|
|
1050
|
+
for (const key of keys) {
|
|
1051
|
+
const value = source[key];
|
|
1052
|
+
if (Array.isArray(value))
|
|
1053
|
+
return value;
|
|
1054
|
+
}
|
|
1055
|
+
return undefined;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Copy HARNESS_ORG / HARNESS_PROJECT into input when scopeOptional resources
|
|
1059
|
+
* omit explicit org_id/project_id (same pattern as release list preflight).
|
|
1060
|
+
*/
|
|
1061
|
+
export async function releaseFillScopeFromConfig({ input, registry }) {
|
|
1062
|
+
if (!input.org_id && registry.orgId)
|
|
1063
|
+
input.org_id = registry.orgId;
|
|
1064
|
+
if (!input.project_id && registry.projectId)
|
|
1065
|
+
input.project_id = registry.projectId;
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Resolve the effective scope and time window before the body/query are built.
|
|
1069
|
+
* The registry only merges HARNESS_ORG/HARNESS_PROJECT into `input` when the
|
|
1070
|
+
* caller passes `resource_scope`, but the body always needs them.
|
|
1071
|
+
*/
|
|
1072
|
+
export async function releaseListPreflight(ctx) {
|
|
1073
|
+
await releaseFillScopeFromConfig(ctx);
|
|
1074
|
+
const { input } = ctx;
|
|
1075
|
+
const now = Date.now();
|
|
1076
|
+
const daysBack = rmgClampInt(input.days_back, 1, RMG_MAX_DAYS_BACK, RMG_DEFAULT_DAYS_BACK);
|
|
1077
|
+
if (input.start_ts === undefined || input.start_ts === "") {
|
|
1078
|
+
input.start_ts = now - daysBack * RMG_DAY_MS;
|
|
1079
|
+
}
|
|
1080
|
+
if (input.end_ts === undefined || input.end_ts === "") {
|
|
1081
|
+
input.end_ts = now + RMG_DAYS_FORWARD * RMG_DAY_MS;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
/** POST /api/release/list — scope travels in the body as `scopes`, not as query params. */
|
|
1085
|
+
export function releaseListBody(input) {
|
|
1086
|
+
const scope = {};
|
|
1087
|
+
if (typeof input.org_id === "string" && input.org_id)
|
|
1088
|
+
scope.orgIdentifier = input.org_id;
|
|
1089
|
+
if (typeof input.project_id === "string" && input.project_id) {
|
|
1090
|
+
scope.projectIdentifier = input.project_id;
|
|
1091
|
+
}
|
|
1092
|
+
return { scopes: Object.keys(scope).length > 0 ? [scope] : [] };
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Normalize the list payload and apply the optional status filter client-side
|
|
1096
|
+
* (the endpoint takes no status param). Status matching is case-insensitive
|
|
1097
|
+
* because RMG returns both `Running` and `RUNNING` depending on the field.
|
|
1098
|
+
*/
|
|
1099
|
+
export function releaseListExtract(raw, input) {
|
|
1100
|
+
const root = rmgAsRecord(raw);
|
|
1101
|
+
const payload = Array.isArray(raw)
|
|
1102
|
+
? { content: raw }
|
|
1103
|
+
: rmgFirstArrayAt(root, ["content", "releases", "items"])
|
|
1104
|
+
? root
|
|
1105
|
+
: rmgAsRecord(root.data);
|
|
1106
|
+
let items = rmgFirstArrayAt(payload, ["content", "releases", "items"]) ?? [];
|
|
1107
|
+
const pageItemCount = items.length;
|
|
1108
|
+
const requestedStatus = typeof input?.status === "string" ? input.status.trim() : "";
|
|
1109
|
+
if (requestedStatus) {
|
|
1110
|
+
const wanted = requestedStatus.toLowerCase();
|
|
1111
|
+
items = items.filter((rel) => {
|
|
1112
|
+
const status = rel.status ?? rel.releaseStatus;
|
|
1113
|
+
return typeof status === "string" && status.toLowerCase() === wanted;
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
const total = ["totalElements", "totalItems", "totalCount", "total"]
|
|
1117
|
+
.map((key) => payload[key])
|
|
1118
|
+
.find((value) => typeof value === "number");
|
|
1119
|
+
return {
|
|
1120
|
+
items,
|
|
1121
|
+
total: requestedStatus ? items.length : (total ?? items.length),
|
|
1122
|
+
...(requestedStatus
|
|
1123
|
+
? {
|
|
1124
|
+
status_filter: requestedStatus,
|
|
1125
|
+
_hint: "status is filtered client-side on this page only; total is the filtered count for this page, " +
|
|
1126
|
+
`not the account (${pageItemCount} unfiltered items on this page). ` +
|
|
1127
|
+
"Increment page (keep size and other filters) if matches may exist on later pages.",
|
|
1128
|
+
}
|
|
1129
|
+
: {}),
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
/** Flatten GET /api/release/{id} → { release: releaseInfo, ... }. */
|
|
1133
|
+
export function releaseGetExtract(raw) {
|
|
1134
|
+
const r = raw;
|
|
1135
|
+
if (r.releaseInfo && typeof r.releaseInfo === "object") {
|
|
1136
|
+
return { release: r.releaseInfo };
|
|
1137
|
+
}
|
|
1138
|
+
return raw;
|
|
1139
|
+
}
|
|
1140
|
+
function rmgSplitCsvFilter(value) {
|
|
1141
|
+
if (typeof value !== "string" || !value.trim())
|
|
1142
|
+
return undefined;
|
|
1143
|
+
const parts = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1144
|
+
return parts.length > 0 ? parts : undefined;
|
|
1145
|
+
}
|
|
1146
|
+
/** Normalize sort/status/type filters before query param mapping (GET list). */
|
|
1147
|
+
export function normalizeReleaseActivityExecutionInput(input) {
|
|
1148
|
+
const sortField = typeof input.sort_field === "string" && input.sort_field.length > 0
|
|
1149
|
+
? input.sort_field
|
|
1150
|
+
: "start_ts";
|
|
1151
|
+
const sortDirection = input.sort_direction === "asc" ? "asc" : "desc";
|
|
1152
|
+
input.sort = [sortField, sortDirection];
|
|
1153
|
+
const statusParts = rmgSplitCsvFilter(input.status);
|
|
1154
|
+
if (statusParts)
|
|
1155
|
+
input.status = statusParts;
|
|
1156
|
+
const typeParts = rmgSplitCsvFilter(input.activity_type);
|
|
1157
|
+
if (typeParts)
|
|
1158
|
+
input.activity_type = typeParts;
|
|
1159
|
+
}
|
|
1160
|
+
export function normalizeReleaseTaskLimit(input) {
|
|
1161
|
+
if (input.limit === undefined && input.size !== undefined) {
|
|
1162
|
+
input.limit = input.size;
|
|
1163
|
+
}
|
|
1164
|
+
input.limit = rmgClampInt(input.limit, 1, RMG_MAX_TASK_LIMIT, RMG_DEFAULT_TASK_LIMIT);
|
|
1165
|
+
}
|
|
1166
|
+
/** GET /api/release/{id}/tasks → standard list envelope with cursor pagination. */
|
|
1167
|
+
export function releaseTaskListExtract(raw, input) {
|
|
1168
|
+
const r = raw;
|
|
1169
|
+
const items = Array.isArray(r.tasks) ? r.tasks : [];
|
|
1170
|
+
const limit = rmgClampInt(input?.limit ?? input?.size, 1, RMG_MAX_TASK_LIMIT, RMG_DEFAULT_TASK_LIMIT);
|
|
1171
|
+
return {
|
|
1172
|
+
items,
|
|
1173
|
+
total: items.length,
|
|
1174
|
+
limit_applied: limit,
|
|
1175
|
+
status_filter: typeof input?.status === "string" && input.status ? input.status : "all",
|
|
1176
|
+
pagination: {
|
|
1177
|
+
cursor: typeof input?.cursor === "string" ? input.cursor : undefined,
|
|
1178
|
+
next_cursor: r.nextRequest?.cursor,
|
|
1179
|
+
last: r.last,
|
|
1180
|
+
},
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
/** GET /api/release/{id}/execution/activities — Spring page at root. */
|
|
1184
|
+
export function releaseActivityExecutionListExtract(raw) {
|
|
1185
|
+
const r = raw;
|
|
1186
|
+
const items = Array.isArray(r.content) ? r.content : [];
|
|
1187
|
+
return {
|
|
1188
|
+
items,
|
|
1189
|
+
total: typeof r.totalElements === "number" ? r.totalElements : items.length,
|
|
1190
|
+
pagination: {
|
|
1191
|
+
page: r.number,
|
|
1192
|
+
size: r.size,
|
|
1193
|
+
total_pages: r.totalPages,
|
|
1194
|
+
total_elements: r.totalElements,
|
|
1195
|
+
number_of_elements: r.numberOfElements,
|
|
1196
|
+
first: r.first,
|
|
1197
|
+
last: r.last,
|
|
1198
|
+
},
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function requireReleaseAndPhase(input) {
|
|
1202
|
+
const releaseId = input.release_id;
|
|
1203
|
+
const phaseId = input.phase_identifier;
|
|
1204
|
+
if (typeof releaseId !== "string" || !releaseId) {
|
|
1205
|
+
throw new Error("release_id is required");
|
|
1206
|
+
}
|
|
1207
|
+
if (typeof phaseId !== "string" || !phaseId) {
|
|
1208
|
+
throw new Error("phase_identifier is required — pass via params on harness_get (from harness_list release_execution_phase)");
|
|
1209
|
+
}
|
|
1210
|
+
return { releaseId, phaseId };
|
|
1211
|
+
}
|
|
1212
|
+
export function releaseExecutionPhaseOutputPath(input) {
|
|
1213
|
+
const { releaseId, phaseId } = requireReleaseAndPhase(input);
|
|
1214
|
+
const enc = encodeURIComponent;
|
|
1215
|
+
return `${RMG_API_PREFIX}/orchestration/execution/release/${enc(releaseId)}/phase/${enc(phaseId)}/output`;
|
|
1216
|
+
}
|
|
1217
|
+
export function releaseExecutionPhaseInputPath(input) {
|
|
1218
|
+
const { releaseId, phaseId } = requireReleaseAndPhase(input);
|
|
1219
|
+
const enc = encodeURIComponent;
|
|
1220
|
+
return `${RMG_API_PREFIX}/orchestration/execution/release/${enc(releaseId)}/phase/${enc(phaseId)}/input`;
|
|
1221
|
+
}
|
|
1222
|
+
export function releaseExecutionActivityOutputPath(input) {
|
|
1223
|
+
const { releaseId, phaseId } = requireReleaseAndPhase(input);
|
|
1224
|
+
const activityId = input.activity_identifier;
|
|
1225
|
+
if (typeof activityId !== "string" || !activityId) {
|
|
1226
|
+
throw new Error("activity_identifier is required — pass via params on harness_get (from harness_list release_execution_activity)");
|
|
1227
|
+
}
|
|
1228
|
+
const enc = encodeURIComponent;
|
|
1229
|
+
return `${RMG_API_PREFIX}/orchestration/execution/release/${enc(releaseId)}/phase/${enc(phaseId)}/activity/${enc(activityId)}/output`;
|
|
1230
|
+
}
|
|
1231
|
+
function releasePhaseIoGetExtract(raw, input, field) {
|
|
1232
|
+
const r = raw;
|
|
1233
|
+
const items = Array.isArray(r[field]) ? r[field] : [];
|
|
1234
|
+
return {
|
|
1235
|
+
[field]: items,
|
|
1236
|
+
phase_identifier: input?.phase_identifier,
|
|
1237
|
+
[`total_${field}`]: items.length,
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
export function releasePhaseOutputGetExtract(raw, input) {
|
|
1241
|
+
return releasePhaseIoGetExtract(raw, input, "outputs");
|
|
1242
|
+
}
|
|
1243
|
+
export function releasePhaseInputGetExtract(raw, input) {
|
|
1244
|
+
return releasePhaseIoGetExtract(raw, input, "inputs");
|
|
1245
|
+
}
|
|
1246
|
+
export function releaseActivityOutputGetExtract(raw, input) {
|
|
1247
|
+
const r = raw;
|
|
1248
|
+
const items = Array.isArray(r.outputs) ? r.outputs : [];
|
|
1249
|
+
return {
|
|
1250
|
+
outputs: items,
|
|
1251
|
+
phase_identifier: input?.phase_identifier,
|
|
1252
|
+
activity_identifier: input?.activity_identifier,
|
|
1253
|
+
total_outputs: items.length,
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
export function releaseActivityInputGetExtract(raw) {
|
|
1257
|
+
const r = raw;
|
|
1258
|
+
const items = Array.isArray(r.inputs) ? r.inputs : [];
|
|
1259
|
+
return {
|
|
1260
|
+
inputs: items,
|
|
1261
|
+
total_inputs: items.length,
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
export function releaseInputGetExtract(raw) {
|
|
1265
|
+
const r = raw;
|
|
1266
|
+
return {
|
|
1267
|
+
release_id: r.release_id,
|
|
1268
|
+
process_execution_id: r.process_execution_id,
|
|
1269
|
+
yaml: r.yaml,
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
/** GET /api/orchestration/execution/{id}/phases → standard list envelope. */
|
|
1273
|
+
export function releasePhaseListExtract(raw) {
|
|
1274
|
+
const r = raw;
|
|
1275
|
+
const items = Array.isArray(r.phases) ? r.phases : [];
|
|
1276
|
+
return {
|
|
1277
|
+
items,
|
|
1278
|
+
total: items.length,
|
|
1279
|
+
...(r.release_id ? { release_id: r.release_id } : {}),
|
|
1280
|
+
...(typeof r.total_running_phases === "number" ? { total_running_phases: r.total_running_phases } : {}),
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
/** Project RMG process/activity YAML entity responses to a stable agent shape. */
|
|
1284
|
+
export function rmgYamlEntityExtract(raw) {
|
|
1285
|
+
if (!isRecord(raw))
|
|
1286
|
+
return raw;
|
|
1287
|
+
const gitDetails = raw.git_details ?? raw.gitDetails;
|
|
1288
|
+
const out = {};
|
|
1289
|
+
if (typeof raw.identifier === "string")
|
|
1290
|
+
out.identifier = raw.identifier;
|
|
1291
|
+
if (typeof raw.name === "string")
|
|
1292
|
+
out.name = raw.name;
|
|
1293
|
+
if (typeof raw.yaml === "string")
|
|
1294
|
+
out.yaml = raw.yaml;
|
|
1295
|
+
if (typeof raw.orgIdentifier === "string")
|
|
1296
|
+
out.orgIdentifier = raw.orgIdentifier;
|
|
1297
|
+
if (typeof raw.projectIdentifier === "string")
|
|
1298
|
+
out.projectIdentifier = raw.projectIdentifier;
|
|
1299
|
+
if (gitDetails !== undefined)
|
|
1300
|
+
out.git_details = gitDetails;
|
|
1301
|
+
if (Object.keys(out).length > 0)
|
|
1302
|
+
return out;
|
|
1303
|
+
return raw;
|
|
1304
|
+
}
|
|
1305
|
+
/** Normalize RMG delete responses to a stable confirmation shape. */
|
|
1306
|
+
export function rmgYamlEntityDeleteExtract(raw) {
|
|
1307
|
+
if (raw === null || raw === undefined)
|
|
1308
|
+
return { deleted: true };
|
|
1309
|
+
if (!isRecord(raw))
|
|
1310
|
+
return { deleted: true };
|
|
1311
|
+
const out = { deleted: true };
|
|
1312
|
+
if (typeof raw.identifier === "string")
|
|
1313
|
+
out.identifier = raw.identifier;
|
|
1314
|
+
if (raw.status !== undefined)
|
|
1315
|
+
out.status = raw.status;
|
|
1316
|
+
return out;
|
|
1317
|
+
}
|
|
1318
|
+
export function yamlWriteBody(input) {
|
|
1319
|
+
const b = input.body;
|
|
1320
|
+
if (!b || typeof b !== "object") {
|
|
1321
|
+
throw new Error("body is required and must be an object with yaml (and optional git_details)");
|
|
1322
|
+
}
|
|
1323
|
+
if (typeof b.yaml !== "string" || b.yaml.length === 0) {
|
|
1324
|
+
throw new Error("body.yaml is required (non-empty YAML string)");
|
|
1325
|
+
}
|
|
1326
|
+
const out = { yaml: b.yaml };
|
|
1327
|
+
if (b.git_details !== undefined)
|
|
1328
|
+
out.git_details = b.git_details;
|
|
1329
|
+
return out;
|
|
1330
|
+
}
|
|
931
1331
|
//# sourceMappingURL=extractors.js.map
|