@f5xc-salesdemos/xcsh 19.44.1 → 19.44.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/xcsh",
4
- "version": "19.44.1",
4
+ "version": "19.44.2",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5xc-salesdemos/xcsh",
7
7
  "author": "Can Boluk",
@@ -54,13 +54,13 @@
54
54
  "dependencies": {
55
55
  "@agentclientprotocol/sdk": "0.16.1",
56
56
  "@mozilla/readability": "^0.6",
57
- "@f5xc-salesdemos/xcsh-stats": "19.44.1",
58
- "@f5xc-salesdemos/pi-agent-core": "19.44.1",
59
- "@f5xc-salesdemos/pi-ai": "19.44.1",
60
- "@f5xc-salesdemos/pi-natives": "19.44.1",
61
- "@f5xc-salesdemos/pi-resource-management": "19.44.1",
62
- "@f5xc-salesdemos/pi-tui": "19.44.1",
63
- "@f5xc-salesdemos/pi-utils": "19.44.1",
57
+ "@f5xc-salesdemos/xcsh-stats": "19.44.2",
58
+ "@f5xc-salesdemos/pi-agent-core": "19.44.2",
59
+ "@f5xc-salesdemos/pi-ai": "19.44.2",
60
+ "@f5xc-salesdemos/pi-natives": "19.44.2",
61
+ "@f5xc-salesdemos/pi-resource-management": "19.44.2",
62
+ "@f5xc-salesdemos/pi-tui": "19.44.2",
63
+ "@f5xc-salesdemos/pi-utils": "19.44.2",
64
64
  "@sinclair/typebox": "^0.34",
65
65
  "@xterm/headless": "^6.0",
66
66
  "ajv": "^8.20",
@@ -130,7 +130,8 @@ if(sel.includes('>>')){
130
130
  if(!el)return JSON.stringify({found:false,error:'no match for '+sel});
131
131
  el.scrollIntoView({block:'center',inline:'center'});
132
132
  const r=el.getBoundingClientRect();
133
- return JSON.stringify({found:true,x:Math.round(r.x+r.width/2),y:Math.round(r.y+r.height/2),tag:el.tagName,txt:(el.textContent||'').trim().slice(0,30)});
133
+ const inGrid=!!el.closest&&!!el.closest('ngx-datatable,datatable-body-cell,datatable-body-row,[class*=datatable]');
134
+ return JSON.stringify({found:true,x:Math.round(r.x+r.width/2),y:Math.round(r.y+r.height/2),tag:el.tagName,txt:(el.textContent||'').trim().slice(0,30),inGrid:inGrid,val:(el.value!==undefined&&el.value!==null?String(el.value):'')});
134
135
  })()`;
135
136
  }
136
137
 
@@ -179,8 +180,20 @@ if(!el)return JSON.stringify({filled:false,error:'selector not found: '+sel});
179
180
  el.scrollIntoView({block:'center',inline:'center'});el.focus();
180
181
  let p=Object.getPrototypeOf(el),d;while(p){d=Object.getOwnPropertyDescriptor(p,'value');if(d&&d.set)break;p=Object.getPrototypeOf(p);}
181
182
  const v=${val};d&&d.set?d.set.call(el,v):el.value=v;
182
- for(const ev of['input','change','blur','focusout'])el.dispatchEvent(new Event(ev,{bubbles:true}));
183
- return JSON.stringify({filled:true,val:el.value});
183
+ // Commit to Angular's form model: input+change first. ngx-datatable inline-edit
184
+ // cells differ in how they persist: http-lb "Domains" (vsui-input) commits on
185
+ // BLUR, while ip-prefix-set "IPv4 Prefix" reverts on a bare blur and only persists
186
+ // on an Enter keydown. So for inputs inside a datatable we dispatch Enter BEFORE
187
+ // blur (Enter commits the row; the subsequent blur then re-renders from a model
188
+ // that already holds the value, instead of reverting). Plain textboxes get only
189
+ // blur/focusout — no synthetic Enter, which would risk a premature form submit.
190
+ el.dispatchEvent(new Event('input',{bubbles:true}));
191
+ el.dispatchEvent(new Event('change',{bubbles:true}));
192
+ const inGrid=!!el.closest&&!!el.closest('ngx-datatable,datatable-body-cell,datatable-body-row,[class*=datatable]');
193
+ if(inGrid){for(const t of['keydown','keypress','keyup'])el.dispatchEvent(new KeyboardEvent(t,{bubbles:true,key:'Enter',code:'Enter',keyCode:13,which:13}));}
194
+ el.dispatchEvent(new Event('blur',{bubbles:true}));
195
+ el.dispatchEvent(new Event('focusout',{bubbles:true}));
196
+ return JSON.stringify({filled:true,val:el.value,inGrid:inGrid});
184
197
  })()`;
185
198
  }
186
199
 
@@ -214,6 +227,34 @@ export class ExtensionPageActions implements PageActions {
214
227
  }
215
228
 
216
229
  async fill(selector: string, value: string, _context?: string): Promise<void> {
230
+ // Probe the element: location, current value, and whether it's an
231
+ // ngx-datatable inline-edit cell. Most console inputs commit reliably via
232
+ // the native-setter path (buildFillScript) — that's what the verified
233
+ // resources use. But ngx-datatable inline cells (e.g. ip-prefix-set's
234
+ // "IPv4 Prefix") do NOT pick up a synthetic value-setter: the cell stays
235
+ // ng-untouched and the reactive form reports the field empty at save. Those
236
+ // cells only commit through REAL keystrokes (each keydown runs inside
237
+ // Angular's NgZone), so for grid inputs we focus the cell and type via CDP.
238
+ const probe = await evalJson(this.#ext, buildResolverScript(selector));
239
+ if (!probe?.found) {
240
+ throw new Error(`fill("${selector}"): ${probe?.error ?? "selector not found"}`);
241
+ }
242
+ if (probe.inGrid) {
243
+ await this.#ext.clickXy(probe.x as number, probe.y as number);
244
+ await new Promise(r => setTimeout(r, 200));
245
+ // Clear any pre-existing text (Backspace ×N) so re-fills are clean —
246
+ // fresh Add-Item rows are empty, so this is a no-op for create.
247
+ const curLen = typeof probe.val === "string" ? probe.val.length : 0;
248
+ for (let i = 0; i < curLen; i++) await this.#ext.keyPress("Backspace").catch(() => {});
249
+ await this.#ext.typeText(value);
250
+ await new Promise(r => setTimeout(r, 200));
251
+ // Enter commits the inline row to the model; Angular marks it ng-valid.
252
+ await this.#ext.keyPress("Enter").catch(() => {});
253
+ await new Promise(r => setTimeout(r, 300));
254
+ const after = await evalJson(this.#ext, buildResolverScript(selector));
255
+ if (typeof after?.val === "string" && after.val.includes(value)) return;
256
+ // Real typing didn't stick — fall through to the native-setter backstop.
257
+ }
217
258
  const result = await evalJson(this.#ext, buildFillScript(selector, value));
218
259
  if (!result?.filled) {
219
260
  throw new Error(`fill("${selector}"): ${result?.error ?? "could not set value"}`);
@@ -18,10 +18,16 @@
18
18
  * `.toString()` — the same pattern used by dom-context/dt-context.
19
19
  */
20
20
 
21
+ /** Minimal KeyboardEvent constructor shape — typed loosely because this module
22
+ * is type-checked under the webworker lib (no DOM `KeyboardEvent` global) but is
23
+ * injected into and runs in the page, where `view.KeyboardEvent` exists. */
24
+ type KeyboardEventCtor = new (type: string, init?: { bubbles?: boolean; key?: string; code?: string }) => unknown;
25
+
21
26
  interface CommittableElement {
22
27
  value: string;
23
- ownerDocument?: { defaultView?: { Event?: typeof Event } | null } | null;
28
+ ownerDocument?: { defaultView?: { Event?: typeof Event; KeyboardEvent?: KeyboardEventCtor } | null } | null;
24
29
  dispatchEvent(event: unknown): unknown;
30
+ closest?(selector: string): unknown;
25
31
  }
26
32
 
27
33
  export function commitInputValue(el: CommittableElement, value: string): void {
@@ -46,6 +52,22 @@ export function commitInputValue(el: CommittableElement, value: string): void {
46
52
  // console's vsui-input commits to the model on blur, not on keystroke).
47
53
  el.dispatchEvent(new EventCtor("input", { bubbles: true }));
48
54
  el.dispatchEvent(new EventCtor("change", { bubbles: true }));
55
+ // ngx-datatable inline-edit cells that persist on Enter (ip-prefix-set
56
+ // "IPv4 Prefix") revert on a bare blur. For inputs inside a datatable,
57
+ // dispatch Enter BEFORE blur so the row commits first; http-lb "Domains"
58
+ // (commits on blur) is unaffected because blur still fires afterwards.
59
+ // Only the page provides KeyboardEvent (this module type-checks under the
60
+ // webworker lib, which has no DOM KeyboardEvent global) — if absent, skip
61
+ // the best-effort Enter and let the blur below carry the commit.
62
+ const KeyCtor = view?.KeyboardEvent;
63
+ const inGrid =
64
+ typeof el.closest === "function" &&
65
+ !!el.closest("ngx-datatable,datatable-body-cell,datatable-body-row,[class*=datatable]");
66
+ if (inGrid && KeyCtor) {
67
+ for (const t of ["keydown", "keypress", "keyup"] as const) {
68
+ el.dispatchEvent(new KeyCtor(t, { bubbles: true, key: "Enter", code: "Enter" }));
69
+ }
70
+ }
49
71
  el.dispatchEvent(new EventCtor("blur", { bubbles: false }));
50
72
  el.dispatchEvent(new EventCtor("focusout", { bubbles: true }));
51
73
  }
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.44.1",
21
- "commit": "04edd68d368b93a173bf04dd234c4f6ba7733907",
22
- "shortCommit": "04edd68",
20
+ "version": "19.44.2",
21
+ "commit": "6e93a54c64e7bdd78d54b56b0c0237025aa420c7",
22
+ "shortCommit": "6e93a54",
23
23
  "branch": "main",
24
- "tag": "v19.44.1",
25
- "commitDate": "2026-06-24T19:09:09Z",
26
- "buildDate": "2026-06-24T19:32:57.402Z",
24
+ "tag": "v19.44.2",
25
+ "commitDate": "2026-06-25T00:16:19Z",
26
+ "buildDate": "2026-06-25T00:38:03.351Z",
27
27
  "dirty": true,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
30
30
  "repoSlug": "f5xc-salesdemos/xcsh",
31
- "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/04edd68d368b93a173bf04dd234c4f6ba7733907",
32
- "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.44.1"
31
+ "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/6e93a54c64e7bdd78d54b56b0c0237025aa420c7",
32
+ "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.44.2"
33
33
  };