arc-1 0.6.7 → 0.6.8

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.
@@ -0,0 +1,117 @@
1
+ /**
2
+ * ADT Refactoring API — Change Package Assignment.
3
+ *
4
+ * Moves ABAP objects between packages via the ADT refactoring endpoint.
5
+ * Two-step flow: preview (validate + discover transport) then execute.
6
+ *
7
+ * Endpoint: POST /sap/bc/adt/refactorings
8
+ * - Preview: ?step=preview&rel=http://www.sap.com/adt/relations/refactoring/changepackage
9
+ * - Execute: ?step=execute
10
+ *
11
+ * Preview uses "wrapped" XML (outer changePackageRefactoring element).
12
+ * Execute uses "unwrapped" XML (just genericRefactoring element).
13
+ */
14
+ import { checkOperation, OperationType } from './safety.js';
15
+ const NS_CHANGEPACKAGE = 'http://www.sap.com/adt/refactoring/changepackagerefactoring';
16
+ const NS_GENERIC = 'http://www.sap.com/adt/refactoring/genericrefactoring';
17
+ const NS_ADTCORE = 'http://www.sap.com/adt/core';
18
+ /** Escape XML special characters */
19
+ function escapeXml(s) {
20
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
21
+ }
22
+ /** Build the inner genericRefactoring XML fragment (shared by preview and execute) */
23
+ function buildGenericRefactoringInner(params) {
24
+ const desc = escapeXml(params.description ?? 'ABAP Object');
25
+ const transport = params.transport ?? '';
26
+ return [
27
+ `<generic:title>Change Package</generic:title>`,
28
+ `<generic:adtObjectUri>${escapeXml(params.objectUri)}</generic:adtObjectUri>`,
29
+ `<generic:affectedObjects>`,
30
+ `<generic:affectedObject`,
31
+ ` adtcore:description="${desc}"`,
32
+ ` adtcore:name="${escapeXml(params.objectName)}"`,
33
+ ` adtcore:packageName="${escapeXml(params.oldPackage)}"`,
34
+ ` adtcore:type="${escapeXml(params.objectType)}"`,
35
+ ` adtcore:uri="${escapeXml(params.objectUri)}">`,
36
+ `<generic:userContent/>`,
37
+ `<generic:changePackageDelta>`,
38
+ `<generic:newPackage>${escapeXml(params.newPackage)}</generic:newPackage>`,
39
+ `</generic:changePackageDelta>`,
40
+ `</generic:affectedObject>`,
41
+ `</generic:affectedObjects>`,
42
+ `<generic:transport>${escapeXml(transport)}</generic:transport>`,
43
+ `<generic:ignoreSyntaxErrorsAllowed>false</generic:ignoreSyntaxErrorsAllowed>`,
44
+ `<generic:ignoreSyntaxErrors>false</generic:ignoreSyntaxErrors>`,
45
+ `<generic:userContent/>`,
46
+ ].join('');
47
+ }
48
+ /**
49
+ * Build "wrapped" preview XML.
50
+ * Root: <changepackage:changePackageRefactoring> with inner <generic:genericRefactoring>.
51
+ */
52
+ export function buildPreviewXml(params) {
53
+ return [
54
+ `<?xml version="1.0" encoding="UTF-8"?>`,
55
+ `<changepackage:changePackageRefactoring`,
56
+ ` xmlns:adtcore="${NS_ADTCORE}"`,
57
+ ` xmlns:generic="${NS_GENERIC}"`,
58
+ ` xmlns:changepackage="${NS_CHANGEPACKAGE}">`,
59
+ `<changepackage:oldPackage>${escapeXml(params.oldPackage)}</changepackage:oldPackage>`,
60
+ `<changepackage:newPackage>${escapeXml(params.newPackage)}</changepackage:newPackage>`,
61
+ `<generic:genericRefactoring>`,
62
+ buildGenericRefactoringInner(params),
63
+ `</generic:genericRefactoring>`,
64
+ `<changepackage:userContent/>`,
65
+ `</changepackage:changePackageRefactoring>`,
66
+ ].join('');
67
+ }
68
+ /**
69
+ * Build "unwrapped" execute XML.
70
+ * Root: <generic:genericRefactoring> (no changePackageRefactoring wrapper).
71
+ */
72
+ export function buildExecuteXml(params) {
73
+ return [
74
+ `<?xml version="1.0" encoding="UTF-8"?>`,
75
+ `<generic:genericRefactoring`,
76
+ ` xmlns:generic="${NS_GENERIC}"`,
77
+ ` xmlns:adtcore="${NS_ADTCORE}">`,
78
+ buildGenericRefactoringInner(params),
79
+ `</generic:genericRefactoring>`,
80
+ ].join('');
81
+ }
82
+ /** Extract transport value from preview response XML */
83
+ export function parsePreviewResponse(xml) {
84
+ const match = xml.match(/<generic:transport>([^<]*)<\/generic:transport>/);
85
+ if (!match) {
86
+ // Try without namespace prefix (SAP may strip them)
87
+ const fallback = xml.match(/<transport>([^<]*)<\/transport>/);
88
+ const value = fallback?.[1]?.trim();
89
+ return { transport: value || undefined };
90
+ }
91
+ const value = match[1]?.trim();
92
+ return { transport: value || undefined };
93
+ }
94
+ const PREVIEW_URL = '/sap/bc/adt/refactorings?step=preview&rel=http://www.sap.com/adt/relations/refactoring/changepackage';
95
+ const EXECUTE_URL = '/sap/bc/adt/refactorings?step=execute';
96
+ /**
97
+ * Move an ABAP object to a different package via the ADT refactoring API.
98
+ *
99
+ * Two-step flow:
100
+ * 1. Preview: validates the operation, returns server-assigned transport (if any)
101
+ * 2. Execute: performs the actual TADIR change
102
+ */
103
+ export async function changePackage(http, safety, params) {
104
+ checkOperation(safety, OperationType.Update, 'ChangePackage');
105
+ // Step 1: Preview
106
+ const previewXml = buildPreviewXml(params);
107
+ const previewResp = await http.post(PREVIEW_URL, previewXml, 'application/*', { Accept: 'application/*' });
108
+ const preview = parsePreviewResponse(previewResp.body);
109
+ // Merge transport: explicit param > preview response > empty
110
+ const effectiveTransport = params.transport || preview.transport || '';
111
+ const executeParams = { ...params, transport: effectiveTransport };
112
+ // Step 2: Execute
113
+ const executeXml = buildExecuteXml(executeParams);
114
+ await http.post(EXECUTE_URL, executeXml, 'application/*', { Accept: 'application/*' });
115
+ return { transport: effectiveTransport || undefined };
116
+ }
117
+ //# sourceMappingURL=refactoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refactoring.js","sourceRoot":"","sources":["../../src/adt/refactoring.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/handlers/intent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA+ElD,OAAO,KAAK,EAAkB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAc9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,2BAA2B;AAC3B,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY9C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CASnF;AAeD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAe1F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CASzD;AA2KD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,YAAY,EAC3B,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,UAAU,CAAC,CAsLrB;AAizBD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAyB1E;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM,CA6NR;AAuCD,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD;AAqnDD,0CAA0C;AAC1C,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAE9E;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,IAAI,gBAAgB,GAAG,SAAS,CAEhE;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAEnE;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE1D"}
1
+ {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/handlers/intent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gDAAgD,CAAC;AAC/E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAkFlD,OAAO,KAAK,EAAkB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAc9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKvD,2BAA2B;AAC3B,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY9C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CASnF;AAeD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAe1F;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CASzD;AA2KD;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,CAAC,EAAE,QAAQ,EACnB,OAAO,CAAC,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,YAAY,EAC3B,eAAe,CAAC,EAAE,OAAO,GACxB,OAAO,CAAC,UAAU,CAAC,CAsLrB;AAo0BD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAyB1E;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM,CA6NR;AAwCD,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD;AA+wDD,0CAA0C;AAC1C,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAE9E;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,IAAI,gBAAgB,GAAG,SAAS,CAEhE;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAEnE;AAED,iDAAiD;AACjD,wBAAgB,kBAAkB,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAE1D"}
@@ -11,12 +11,13 @@
11
11
  */
12
12
  import { findDefinition, findReferences, findWhereUsed, getCompletion, } from '../adt/codeintel.js';
13
13
  import { createObject, deleteObject, lockObject, safeUpdateObject, safeUpdateSource, unlockObject, updateObject, } from '../adt/crud.js';
14
- import { buildDataElementXml, buildDomainXml, buildMessageClassXml, buildPackageXml, buildServiceBindingXml, } from '../adt/ddic-xml.js';
14
+ import { buildDataElementXml, buildDomainXml, buildMessageClassXml, buildPackageXml, buildServiceBindingXml, decodeKtdText, rewriteKtdText, } from '../adt/ddic-xml.js';
15
15
  import { activate, activateBatch, applyFixProposal, getFixProposals, publishServiceBinding, runAtcCheck, runUnitTests, syntaxCheck, unpublishServiceBinding, } from '../adt/devtools.js';
16
16
  import { getDump, getTraceDbAccesses, getTraceHitlist, getTraceStatements, listDumps, listTraces, } from '../adt/diagnostics.js';
17
17
  import { AdtApiError, AdtNetworkError, AdtSafetyError, classifySapDomainError, isNotFoundError, } from '../adt/errors.js';
18
18
  import { classifyTextSearchError, mapSapReleaseToAbaplintVersion, probeFeatures } from '../adt/features.js';
19
19
  import { addTileToGroup, createCatalog, createGroup, createTile, deleteCatalog, listCatalogs, listGroups, listTiles, } from '../adt/flp.js';
20
+ import { changePackage } from '../adt/refactoring.js';
20
21
  import { checkOperation, checkPackage, isOperationAllowed, OperationType } from '../adt/safety.js';
21
22
  import { createTransport, deleteTransport, getTransport, getTransportInfo, listTransports, reassignTransport, releaseTransport, releaseTransportRecursive, } from '../adt/transport.js';
22
23
  import { getAppInfo } from '../adt/ui5-repository.js';
@@ -591,6 +592,21 @@ async function handleSAPRead(client, args, cachingLayer) {
591
592
  const { source, cacheHit } = await cachedGet('SRVB', name, () => client.getSrvb(name));
592
593
  return cachedTextResult(source, cacheHit);
593
594
  }
595
+ case 'SKTD': {
596
+ try {
597
+ // ADT returns a <sktd:docu> XML envelope with the Markdown body base64-encoded
598
+ // inside <sktd:text>. Cache the raw envelope (update flow re-uses it) and
599
+ // return the decoded Markdown to the LLM.
600
+ const { source, cacheHit } = await cachedGet('SKTD', name, () => client.getKtd(name));
601
+ return cachedTextResult(decodeKtdText(source), cacheHit);
602
+ }
603
+ catch (err) {
604
+ if (isNotFoundError(err)) {
605
+ return textResult(`No Knowledge Transfer Document (SKTD) found for "${name}". KTD docs are optional Markdown documentation attached to ABAP objects — either one was never created for "${name}", or the name is wrong.`);
606
+ }
607
+ throw err;
608
+ }
609
+ }
594
610
  case 'TABL': {
595
611
  const { source, cacheHit } = await cachedGet('TABL', name, () => client.getTable(name));
596
612
  return cachedTextResult(source, cacheHit);
@@ -747,7 +763,7 @@ async function handleSAPRead(client, args, cachingLayer) {
747
763
  }
748
764
  }
749
765
  default:
750
- return errorResult(`Unknown SAPRead type: "${type}". Supported types: PROG, CLAS, INTF, FUNC, FUGR, INCL, DDLS, DCLS, DDLX, BDEF, SRVD, SRVB, TABL, VIEW, STRU, DOMA, DTEL, TRAN, TABLE_CONTENTS, DEVC, SOBJ, SYSTEM, COMPONENTS, MESSAGES, TEXT_ELEMENTS, VARIANTS, BSP, BSP_DEPLOY, API_STATE, INACTIVE_OBJECTS. ` +
766
+ return errorResult(`Unknown SAPRead type: "${type}". Supported types: PROG, CLAS, INTF, FUNC, FUGR, INCL, DDLS, DCLS, DDLX, BDEF, SRVD, SRVB, SKTD, TABL, VIEW, STRU, DOMA, DTEL, TRAN, TABLE_CONTENTS, DEVC, SOBJ, SYSTEM, COMPONENTS, MESSAGES, TEXT_ELEMENTS, VARIANTS, BSP, BSP_DEPLOY, API_STATE, INACTIVE_OBJECTS. ` +
751
767
  'Tip: Type aliases are auto-normalized (e.g., DDLS/DF → DDLS, DCLS/DL → DCLS, CLAS/OC → CLAS, PROG/P → PROG). ' +
752
768
  'Do not pass a URI — use the "type" and "name" parameters instead.');
753
769
  }
@@ -904,12 +920,13 @@ const DATAELEMENT_V2_CONTENT_TYPE = 'application/vnd.sap.adt.dataelements.v2+xml
904
920
  const SERVICEBINDING_V2_CONTENT_TYPE = 'application/vnd.sap.adt.businessservices.servicebinding.v2+xml; charset=utf-8';
905
921
  const BDEF_CONTENT_TYPE = 'application/vnd.sap.adt.blues.v1+xml';
906
922
  const MESSAGECLASS_CONTENT_TYPE = 'application/vnd.sap.adt.mc.messageclass+xml';
923
+ const SKTD_V2_CONTENT_TYPE = 'application/vnd.sap.adt.sktdv2+xml';
907
924
  function isMetadataWriteType(type) {
908
925
  return type === 'DOMA' || type === 'DTEL' || type === 'MSAG' || type === 'SRVB';
909
926
  }
910
927
  /** Types that require a specific vendor content type for creation (not application/*) */
911
928
  function needsVendorContentType(type) {
912
- return type === 'DOMA' || type === 'DTEL' || type === 'BDEF' || type === 'MSAG';
929
+ return type === 'DOMA' || type === 'DTEL' || type === 'BDEF' || type === 'MSAG' || type === 'SKTD';
913
930
  }
914
931
  /** Content type used for create POST */
915
932
  function createContentTypeForType(type) {
@@ -946,6 +963,8 @@ function vendorContentTypeForType(type) {
946
963
  return BDEF_CONTENT_TYPE;
947
964
  case 'MSAG':
948
965
  return MESSAGECLASS_CONTENT_TYPE;
966
+ case 'SKTD':
967
+ return SKTD_V2_CONTENT_TYPE;
949
968
  default:
950
969
  // Wildcard lets the SAP server resolve the correct handler.
951
970
  // Sending 'application/xml' causes 415 on DDL-based endpoints
@@ -1435,6 +1454,7 @@ const SLASH_TYPE_MAP = {
1435
1454
  'DEVC/K': 'DEVC',
1436
1455
  'TRAN/O': 'TRAN',
1437
1456
  'VIEW/V': 'VIEW',
1457
+ 'SKTD/TYP': 'SKTD',
1438
1458
  };
1439
1459
  /** Normalize ADT type codes and aliases to ARC-1 canonical short types. */
1440
1460
  export function normalizeObjectType(type) {
@@ -1545,13 +1565,17 @@ function objectBasePath(type) {
1545
1565
  return '/sap/bc/adt/packages/';
1546
1566
  case 'TRAN':
1547
1567
  return '/sap/bc/adt/vit/wb/object_type/trant/object_name/';
1568
+ case 'SKTD':
1569
+ return '/sap/bc/adt/documentation/ktd/documents/';
1548
1570
  default:
1549
1571
  return '/sap/bc/adt/programs/programs/';
1550
1572
  }
1551
1573
  }
1552
1574
  /** Map object type + name to the ADT object URL used by CRUD/DevTools/etc. Name is URI-encoded. */
1553
1575
  function objectUrlForType(type, name) {
1554
- return `${objectBasePath(type)}${encodeURIComponent(name)}`;
1576
+ // KTD endpoints require lowercase object names in the URL path (confirmed via Eclipse ADT trace).
1577
+ const effectiveName = type === 'SKTD' ? name.toLowerCase() : name;
1578
+ return `${objectBasePath(type)}${encodeURIComponent(effectiveName)}`;
1555
1579
  }
1556
1580
  /** Infer SAP object type from naming conventions. Returns empty string if type cannot be determined. */
1557
1581
  function inferObjectType(name) {
@@ -1569,7 +1593,8 @@ function inferObjectType(name) {
1569
1593
  * Used for API release state where the full URI is encoded as a single path segment by the caller.
1570
1594
  */
1571
1595
  function objectUrlForTypeRaw(type, name) {
1572
- return `${objectBasePath(type)}${name}`;
1596
+ const effectiveName = type === 'SKTD' ? name.toLowerCase() : name;
1597
+ return `${objectBasePath(type)}${effectiveName}`;
1573
1598
  }
1574
1599
  /** Get the source URL for an object (appends /source/main) */
1575
1600
  function sourceUrlForType(type, name) {
@@ -1602,6 +1627,19 @@ async function handleSAPWrite(client, args, config, cachingLayer) {
1602
1627
  switch (action) {
1603
1628
  case 'update': {
1604
1629
  const existingPackage = await enforcePackageForExistingObject();
1630
+ if (type === 'SKTD') {
1631
+ // KTD update requires the full <sktd:docu> XML envelope with the Markdown
1632
+ // body base64-encoded inside <sktd:text>, PUT with
1633
+ // `application/vnd.sap.adt.sktdv2+xml`. PUTting raw text/plain silently
1634
+ // no-ops (or 415s on strict systems). Fetch the current envelope,
1635
+ // replace only the <sktd:text> body, and PUT it back — preserves
1636
+ // responsible/masterLanguage/packageRef/refObject metadata.
1637
+ const currentEnvelope = await client.getKtd(name);
1638
+ const body = rewriteKtdText(currentEnvelope, source);
1639
+ await safeUpdateObject(client.http, client.safety, objectUrl, body, SKTD_V2_CONTENT_TYPE, transport);
1640
+ cachingLayer?.invalidate(type, name);
1641
+ return textResult(`Successfully updated ${type} ${name}.`);
1642
+ }
1605
1643
  if (isMetadataWriteType(type)) {
1606
1644
  // Metadata updates are full-XML-replace — we must fetch existing metadata
1607
1645
  // and merge with provided fields so omitted fields keep their current values.
@@ -1675,6 +1713,45 @@ async function handleSAPWrite(client, args, config, cachingLayer) {
1675
1713
  if (!affResult.valid) {
1676
1714
  return errorResult(`AFF metadata validation failed for ${type} ${name}:\n- ${(affResult.errors ?? []).join('\n- ')}\n\nFix the metadata and retry.`);
1677
1715
  }
1716
+ if (type === 'SKTD') {
1717
+ // A KTD is not a standalone object — it documents a parent object (e.g., a DDLS view or a CLAS).
1718
+ // The create POST goes to the collection URL with a sktd:docu XML body that references the parent.
1719
+ const refType = String(args.refObjectType ?? '');
1720
+ if (!refType) {
1721
+ return errorResult('"refObjectType" is required for SKTD create — the ADT type+subtype of the parent object being documented (e.g., "DDLS/DF", "CLAS/OC", "PROG/P", "INTF/OI", "BDEF/BDO", "SRVD/SRV").');
1722
+ }
1723
+ const refName = String(args.refObjectName ?? name);
1724
+ // SAP rule: a KTD's own name must equal the parent object's name (one KTD per object).
1725
+ // Creating a KTD named differently from its parent fails server-side with a cryptic
1726
+ // "Check of condition failed" — fail fast with a clear message instead.
1727
+ if (refName.toUpperCase() !== name.toUpperCase()) {
1728
+ return errorResult(`SKTD name "${name}" must match refObjectName "${refName}" — a Knowledge Transfer Document inherits the name of the ABAP object it documents (one KTD per object). To document "${refName}", call SAPWrite(action="create", type="SKTD", name="${refName}", refObjectType="${refType}", ...).`);
1729
+ }
1730
+ const refDescription = String(args.refObjectDescription ?? '');
1731
+ // Build the parent URI. ADT URIs use lowercase names by convention (matches the Eclipse trace).
1732
+ const refParentType = refType.split('/')[0] ?? '';
1733
+ const refUri = `${objectBasePath(refParentType)}${encodeURIComponent(refName.toLowerCase())}`;
1734
+ const ktdBody = `<?xml version="1.0" encoding="UTF-8"?>
1735
+ <sktd:docu xmlns:sktd="http://www.sap.com/wbobj/texts/sktd" xmlns:adtcore="http://www.sap.com/adt/core" adtcore:language="EN" adtcore:name="${escapeXml(name)}" adtcore:type="SKTD/TYP" adtcore:masterLanguage="EN">
1736
+ <adtcore:packageRef adtcore:name="${escapeXml(pkg)}"/>
1737
+ <sktd:refObject adtcore:description="${escapeXml(refDescription)}" adtcore:name="${escapeXml(refName)}" adtcore:type="${escapeXml(refType)}" adtcore:uri="${escapeXml(refUri)}"/>
1738
+ </sktd:docu>`;
1739
+ const ktdCreateUrl = '/sap/bc/adt/documentation/ktd/documents';
1740
+ const ktdResult = await createObject(client.http, client.safety, ktdCreateUrl, ktdBody, SKTD_V2_CONTENT_TYPE, effectiveTransport);
1741
+ // If initial Markdown was provided, follow up with an update PUT to write it.
1742
+ // Same envelope contract as the update path: fetch-then-rewrite ensures we
1743
+ // PUT back exactly the shape SAP gave us (with all the server-assigned
1744
+ // metadata), only swapping <sktd:text>.
1745
+ if (source) {
1746
+ const currentEnvelope = await client.getKtd(name);
1747
+ const body = rewriteKtdText(currentEnvelope, source);
1748
+ await safeUpdateObject(client.http, client.safety, objectUrl, body, SKTD_V2_CONTENT_TYPE, effectiveTransport);
1749
+ cachingLayer?.invalidate(type, name);
1750
+ return textResult(`Created SKTD ${name} in package ${pkg} and wrote Markdown content.\nNext step: SAPActivate(type="SKTD", name="${name}").\n${ktdResult}`);
1751
+ }
1752
+ cachingLayer?.invalidate(type, name);
1753
+ return textResult(`Created SKTD ${name} in package ${pkg} (no Markdown content written — pass "source" to write the body).\nNext step: SAPActivate(type="SKTD", name="${name}").\n${ktdResult}`);
1754
+ }
1678
1755
  // Build type-specific creation XML body.
1679
1756
  // SAP ADT requires the root element to match the object type —
1680
1757
  // a generic objectReferences body returns 400 "System expected the element ...".
@@ -1785,7 +1862,7 @@ async function handleSAPWrite(client, args, config, cachingLayer) {
1785
1862
  }
1786
1863
  case 'delete': {
1787
1864
  await enforcePackageForExistingObject();
1788
- // Lock, delete, unlock pattern — auto-propagate lock corrNr if no explicit transport
1865
+ // Lock, delete, unlock pattern (works for all types including SKTD) — auto-propagate lock corrNr if no explicit transport
1789
1866
  await client.http.withStatefulSession(async (session) => {
1790
1867
  const lock = await lockObject(session, client.safety, objectUrl);
1791
1868
  const effectiveTransport = transport ?? (lock.corrNr || undefined);
@@ -2713,6 +2790,72 @@ async function handleSAPManage(client, config, args, cachingLayer, isPerUserClie
2713
2790
  });
2714
2791
  return textResult(`Deleted package ${name}.`);
2715
2792
  }
2793
+ case 'change_package': {
2794
+ const objectName = String(args.objectName ?? '').trim();
2795
+ const objectType = String(args.objectType ?? '').trim();
2796
+ const oldPackage = String(args.oldPackage ?? '').trim();
2797
+ const newPackage = String(args.newPackage ?? '').trim();
2798
+ const transport = String(args.transport ?? '').trim();
2799
+ let objectUri = String(args.objectUri ?? '').trim();
2800
+ if (!objectName)
2801
+ return errorResult('"objectName" is required for change_package action.');
2802
+ if (!objectType)
2803
+ return errorResult('"objectType" is required for change_package action.');
2804
+ if (!oldPackage)
2805
+ return errorResult('"oldPackage" is required for change_package action.');
2806
+ if (!newPackage)
2807
+ return errorResult('"newPackage" is required for change_package action.');
2808
+ checkOperation(client.safety, OperationType.Update, 'ChangePackage');
2809
+ checkPackage(client.safety, oldPackage);
2810
+ checkPackage(client.safety, newPackage);
2811
+ // Resolve object URI via search if not provided
2812
+ if (!objectUri) {
2813
+ const searchResp = await client.http.get(`/sap/bc/adt/repository/informationsystem/search?operation=quickSearch&query=${encodeURIComponent(objectName)}&maxResults=10`);
2814
+ const uriMatch = searchResp.body.match(new RegExp(`adtcore:uri="([^"]*)"[^>]*adtcore:type="${objectType.replace('/', '\\/')}"`, 'i'));
2815
+ if (!uriMatch?.[1]) {
2816
+ return errorResult(`Could not find object "${objectName}" with type "${objectType}" via ADT search. ` +
2817
+ `Verify the object exists and the type is correct (e.g., CLAS/OC, DDLS/DF, PROG/P).`);
2818
+ }
2819
+ objectUri = uriMatch[1];
2820
+ }
2821
+ // Transport pre-flight for non-local target packages
2822
+ let effectiveTransport = transport || undefined;
2823
+ if (!effectiveTransport && newPackage.toUpperCase() !== '$TMP') {
2824
+ try {
2825
+ const transportInfo = await getTransportInfo(client.http, client.safety, objectUri, newPackage, 'I');
2826
+ if (transportInfo.lockedTransport) {
2827
+ effectiveTransport = transportInfo.lockedTransport;
2828
+ }
2829
+ else if (!transportInfo.isLocal && transportInfo.recording) {
2830
+ const existingList = transportInfo.existingTransports.length > 0
2831
+ ? `\n\nExisting transports for this package:\n${transportInfo.existingTransports
2832
+ .slice(0, 10)
2833
+ .map((t) => ` - ${t.id}: ${t.description} (${t.owner})`)
2834
+ .join('\n')}`
2835
+ : '';
2836
+ return errorResult(`Package "${newPackage}" requires a transport number for change_package, but none was provided.\n\n` +
2837
+ `To fix this, either:\n` +
2838
+ `1. Use SAPTransport(action="list") to find an existing modifiable transport\n` +
2839
+ `2. Use SAPTransport(action="create", description="...") to create a new one\n` +
2840
+ `3. Then retry SAPManage(action="change_package", ..., transport="<transport_id>")` +
2841
+ existingList);
2842
+ }
2843
+ }
2844
+ catch {
2845
+ // Graceful fallback: let SAP enforce transport requirements if the pre-check fails.
2846
+ }
2847
+ }
2848
+ const result = await changePackage(client.http, client.safety, {
2849
+ objectUri,
2850
+ objectType,
2851
+ objectName,
2852
+ oldPackage,
2853
+ newPackage,
2854
+ transport: effectiveTransport,
2855
+ });
2856
+ const transportNote = result.transport ? ` (transport: ${result.transport})` : '';
2857
+ return textResult(`Moved ${objectName} from package ${oldPackage} to ${newPackage}${transportNote}.`);
2858
+ }
2716
2859
  case 'flp_list_catalogs': {
2717
2860
  const catalogs = await listCatalogs(client.http, client.safety);
2718
2861
  const customCount = catalogs.filter((c) => /^(Z|Y)/i.test(c.domainId)).length;