@piagent/platform 1.48.1 → 1.48.3

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.
Files changed (116) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +2 -0
  3. package/README.vi.md +2 -0
  4. package/docs/command-reference-vietnamese.md +4 -3
  5. package/docs/distribution-standard.md +6 -6
  6. package/docs/harness-conformance.md +4 -0
  7. package/docs/languages.json +2 -2
  8. package/docs/operator-manual-vietnamese.md +7 -7
  9. package/docs/publishing-for-teams.md +2 -0
  10. package/docs/release-install-policy.md +2 -2
  11. package/docs/team-onboarding.md +2 -2
  12. package/docs-site/architecture.html +1 -1
  13. package/docs-site/assets/search-en.json +1 -1
  14. package/docs-site/assets/search-vi.json +1 -1
  15. package/docs-site/benchmark.html +1 -1
  16. package/docs-site/commands.html +1 -1
  17. package/docs-site/content/en/update.html +8 -0
  18. package/docs-site/content/update.html +8 -0
  19. package/docs-site/context-engine.html +1 -1
  20. package/docs-site/ecosystem.html +1 -1
  21. package/docs-site/en/architecture.html +1 -1
  22. package/docs-site/en/benchmark.html +1 -1
  23. package/docs-site/en/commands.html +1 -1
  24. package/docs-site/en/context-engine.html +1 -1
  25. package/docs-site/en/ecosystem.html +1 -1
  26. package/docs-site/en/index.html +15 -15
  27. package/docs-site/en/mcp-approval.html +1 -1
  28. package/docs-site/en/mcp-auth.html +1 -1
  29. package/docs-site/en/mcp-servers.html +1 -1
  30. package/docs-site/en/mcp.html +1 -1
  31. package/docs-site/en/permissions.html +1 -1
  32. package/docs-site/en/profiles.html +1 -1
  33. package/docs-site/en/quickstart.html +1 -1
  34. package/docs-site/en/runtime.html +1 -1
  35. package/docs-site/en/scope.html +1 -1
  36. package/docs-site/en/security.html +1 -1
  37. package/docs-site/en/team.html +1 -1
  38. package/docs-site/en/update.html +11 -3
  39. package/docs-site/en/whats-new.html +52 -27
  40. package/docs-site/en/windows.html +1 -1
  41. package/docs-site/en/workflows.html +1 -1
  42. package/docs-site/index.html +15 -15
  43. package/docs-site/mcp-approval.html +1 -1
  44. package/docs-site/mcp-auth.html +1 -1
  45. package/docs-site/mcp-servers.html +1 -1
  46. package/docs-site/mcp.html +1 -1
  47. package/docs-site/permissions.html +1 -1
  48. package/docs-site/profiles.html +1 -1
  49. package/docs-site/quickstart.html +1 -1
  50. package/docs-site/releases.json +77 -0
  51. package/docs-site/runtime.html +1 -1
  52. package/docs-site/scope.html +1 -1
  53. package/docs-site/security.html +1 -1
  54. package/docs-site/team.html +1 -1
  55. package/docs-site/update.html +11 -3
  56. package/docs-site/whats-new.html +52 -27
  57. package/docs-site/windows.html +1 -1
  58. package/docs-site/workflows.html +1 -1
  59. package/evals/private-holdout-v1/public-exposure.v2.json +2 -2
  60. package/package.json +1 -1
  61. package/packages/piagent-core/extensions/piagent-guard.ts +4 -1
  62. package/packages/piagent-core/extensions/workspace-inspection.ts +4 -1
  63. package/packages/piagent-core/managed/check-waiver.mjs +35 -0
  64. package/packages/piagent-core/managed/command-tools.mjs +2 -2
  65. package/packages/piagent-core/managed/dist/workspace/manifest.json +1 -1
  66. package/packages/piagent-core/managed/dist/workspace/worker.mjs +7 -1
  67. package/packages/piagent-core/managed/patch-snapshot.mjs +28 -13
  68. package/packages/piagent-core/managed/review-snapshot-request.mjs +1 -1
  69. package/packages/piagent-core/managed/review-snapshot-worker.mjs +52 -11
  70. package/packages/piagent-core/managed/session.mjs +9 -9
  71. package/packages/piagent-core/managed/workflow.mjs +8 -7
  72. package/packages/piagent-core/package.json +1 -1
  73. package/packages/piagent-core/runtime/update/terminal-reload.mjs +122 -0
  74. package/packages/piagent-core/runtime/update/terminal-update-offer.mjs +1 -1
  75. package/packages/piagent-webui/dist/client/assets/{ActivityPanel-DxQ3_dyT.js → ActivityPanel-Bv-jc1s3.js} +1 -1
  76. package/packages/piagent-webui/dist/client/assets/App-DqN7B1JR.js +5 -0
  77. package/packages/piagent-webui/dist/client/assets/AttachmentImage-eZKqLYZ2.js +1 -0
  78. package/packages/piagent-webui/dist/client/assets/GatewayApp-B3--WjSd.js +63 -0
  79. package/packages/piagent-webui/dist/client/assets/{InspectionApp-pD-BqBXm.js → InspectionApp-BKQiA0Ce.js} +1 -1
  80. package/packages/piagent-webui/dist/client/assets/{LineReview-C_0ZpgCH.js → LineReview-CB3mQe7m.js} +1 -1
  81. package/packages/piagent-webui/dist/client/assets/MarkdownMessage-zw5RxDmZ.js +29 -0
  82. package/packages/piagent-webui/dist/client/assets/{SessionAgentWorkspace-3tM7Q6HH.js → SessionAgentWorkspace-ZAdRbxVA.js} +1 -1
  83. package/packages/piagent-webui/dist/client/assets/SessionInspectorDrawer-B2e4-1FG.js +2 -0
  84. package/packages/piagent-webui/dist/client/assets/SettingsNavigation-C3MC0X4P.js +3 -0
  85. package/packages/piagent-webui/dist/client/assets/SettingsPage-D4os5vHj.js +1 -0
  86. package/packages/piagent-webui/dist/client/assets/{TerminalPanel-CtZyb0tj.js → TerminalPanel-CVYUiDkn.js} +2 -2
  87. package/packages/piagent-webui/dist/client/assets/{TerminalView-yaIg6RCs.js → TerminalView-C3upxbKw.js} +1 -1
  88. package/packages/piagent-webui/dist/client/assets/{WorkspaceCodeEditor-BS_ZrjPN.js → WorkspaceCodeEditor-E0Zopcke.js} +1 -1
  89. package/packages/piagent-webui/dist/client/assets/WorkspaceExplorer-DldLoJyf.js +5 -0
  90. package/packages/piagent-webui/dist/client/assets/WorkspaceFilePreview-CvIBYige.js +1 -0
  91. package/packages/piagent-webui/dist/client/assets/{WorkspaceQuickOpen-CJmMBmK8.js → WorkspaceQuickOpen-Bi-kTEEU.js} +1 -1
  92. package/packages/piagent-webui/dist/client/assets/index-DcrpSyBK.js +37 -0
  93. package/packages/piagent-webui/dist/client/assets/{tab-close-ITV4Cf4X.js → tab-close-BwkkhMH7.js} +1 -1
  94. package/packages/piagent-webui/dist/client/assets/transcript-view-model-acWtHGyE.js +3 -0
  95. package/packages/piagent-webui/dist/client/assets/{ui-preferences-0waeSO-S.js → ui-preferences-OfS30-ZV.js} +1 -1
  96. package/packages/piagent-webui/dist/client/assets/{vendor-CSDKB7mU.js → vendor-DNZbaWhT.js} +62 -26
  97. package/packages/piagent-webui/dist/client/assets/{workspace-api-D8sJkiZB.js → workspace-api-CFBR73lU.js} +1 -1
  98. package/packages/piagent-webui/dist/client/assets/workspace-navigation-DW8zhH6U.js +1 -0
  99. package/packages/piagent-webui/dist/client/index.html +3 -3
  100. package/packages/piagent-webui/shared/process-copy.ts +2 -1
  101. package/schemas/piagent-webui/workspace-media-v1.schema.json +6 -0
  102. package/scripts/company-terminal.mjs +21 -1
  103. package/scripts/piagent-cli.mjs +44 -21
  104. package/scripts/piagent-studio.mjs +22 -2
  105. package/scripts/terminal-reload.mjs +15 -0
  106. package/scripts/update-global.mjs +10 -0
  107. package/packages/piagent-webui/dist/client/assets/App-fZeIRoaD.js +0 -5
  108. package/packages/piagent-webui/dist/client/assets/GatewayApp-CpC4lgYK.js +0 -99
  109. package/packages/piagent-webui/dist/client/assets/MarkdownMessage-DGt5B-6D.js +0 -29
  110. package/packages/piagent-webui/dist/client/assets/SessionInspectorDrawer-BJ94aQ6y.js +0 -2
  111. package/packages/piagent-webui/dist/client/assets/SettingsNavigation-BFfqMcuL.js +0 -3
  112. package/packages/piagent-webui/dist/client/assets/SettingsPage-CxpZ7cdM.js +0 -1
  113. package/packages/piagent-webui/dist/client/assets/WorkspaceExplorer-CkFBpcM7.js +0 -5
  114. package/packages/piagent-webui/dist/client/assets/index-CNdhIouM.js +0 -37
  115. package/packages/piagent-webui/dist/client/assets/transcript-view-model-CpEMY1xb.js +0 -3
  116. package/packages/piagent-webui/dist/client/assets/workspace-navigation-DkVobhwg.js +0 -1
@@ -1 +1 @@
1
- import{o as e}from"./bootstrap-CedkNtRG.js";async function t(t,n,r,i){let a=new URLSearchParams({path:r}),o=await fetch(`/api/v1/sessions/${encodeURIComponent(t)}/inspection/workspace/${n}?${a}`,{credentials:`same-origin`,headers:{Accept:`application/json`},signal:i});if(o.status===401&&e(),!o.ok)throw Error(`workspace-read-failed`);return await o.json()}var n=(e,n,r)=>t(e,`tree`,n,r),r=(e,n,r)=>t(e,`file`,n,r),i=(e,n,r)=>t(e,`media`,n,r);async function a(t,n,r){let i=await fetch(`/api/v1/sessions/${encodeURIComponent(t)}/inspection/workspace/paths?${new URLSearchParams({query:n})}`,{credentials:`same-origin`,headers:{Accept:`application/json`},signal:r});if(i.status===401&&e(),!i.ok)throw Error(`workspace-read-failed`);return await i.json()}async function o(t,n,r){let i=await fetch(`/api/v1/sessions/${encodeURIComponent(t)}/inspection/workspace/search?${new URLSearchParams({query:n})}`,{credentials:`same-origin`,headers:{Accept:`application/json`},signal:r});if(i.status===401&&e(),!i.ok)throw Error(`workspace-read-failed`);return await i.json()}export{o as a,n as i,i as n,a as r,r as t};
1
+ import{o as e}from"./bootstrap-CedkNtRG.js";async function t(t,n,r,i){let a=new URLSearchParams({path:r}),o=await fetch(`/api/v1/sessions/${encodeURIComponent(t)}/inspection/workspace/${n}?${a}`,{credentials:`same-origin`,headers:{Accept:`application/json`},signal:i});if(o.status===401&&e(),!o.ok)throw Error(`workspace-read-failed`);return await o.json()}var n=(e,n,r)=>t(e,`tree`,n,r),r=(e,n,r)=>t(e,`file`,n,r),i=(e,n,r)=>t(e,`media`,n,r);async function a(t,n,r){let i=await fetch(`/api/v1/sessions/${encodeURIComponent(t)}/inspection/workspace/paths?${new URLSearchParams({query:n})}`,{credentials:`same-origin`,headers:{Accept:`application/json`},signal:r});if(i.status===401&&e(),!i.ok)throw Error(`workspace-read-failed`);return await i.json()}async function o(t,n,r){let i=await fetch(`/api/v1/sessions/${encodeURIComponent(t)}/inspection/workspace/search?${new URLSearchParams({query:n})}`,{credentials:`same-origin`,headers:{Accept:`application/json`},signal:r});if(i.status===401&&e(),!i.ok)throw Error(`workspace-read-failed`);return await i.json()}async function s(e,t){let n=t.split(`/`).at(-1)??`file`,a=await i(e,t).catch(()=>null),o=a?.data&&a.mime?`data:${a.mime};base64,${a.data}`:null,s=!1;if(!o){let n=await r(e,t).catch(()=>null);if(typeof n?.content!=`string`)return!1;o=URL.createObjectURL(new Blob([n.content],{type:`text/plain`})),s=!0}let c=document.createElement(`a`);return c.href=o,c.download=n,document.body.append(c),c.click(),c.remove(),s&&setTimeout(()=>URL.revokeObjectURL(o),1e4),!0}export{s as a,n as i,i as n,o,a as r,r as t};
@@ -0,0 +1 @@
1
+ import{r as e}from"./rolldown-runtime-hePW80VL.js";import{An as t,Rn as n,Ut as r,zt as i}from"./vendor-DNZbaWhT.js";import{i as a,n as o}from"./ui-preferences-OfS30-ZV.js";import{h as s}from"./api-BQS4Dtrr.js";var c=e(n(),1);function l(e,t=1){let n=/^(.+?)(?::(\d+)(?::\d+)?)?$/.exec(e.replace(/^@/,``)),r=n?.[1];return!r||r.length>4096||/^[~/]/.test(r)||/[\\\x00-\x1f\x7f:]/.test(r)||r.split(`/`).some(e=>!e||e===`.`||e===`..`)?null:{path:r,line:Math.max(1,Math.min(1e6,Number(n?.[2])||t||1))}}function u(e){let t=e.trim();if(!t||t.length>4096||/^(?:https?|mailto|data|javascript):/i.test(t)||t.startsWith(`#`))return null;if(/^file:/i.test(t))try{t=new URL(t).pathname}catch{return null}try{t=decodeURIComponent(t)}catch{}let n=/#L(\d+)(?:-L?\d+)?$/.exec(t),r=n?Number(n[1]):void 0;if(n&&(t=t.slice(0,n.index)),t=t.replace(/^\.\//,``),t.startsWith(`/`)){let e=/^(\/.+?)(?::(\d+)(?::\d+)?)?$/.exec(t),n=e?.[1]??``;return!n||/[\x00-\x1f\x7f]/.test(n)||n.split(`/`).slice(1).some(e=>!e||e===`.`||e===`..`)?null:{path:n,line:Math.max(1,Math.min(1e6,r??(Number(e?.[2])||1))),absolute:!0}}let i=l(t,r);return i?{...i,absolute:!1}:null}var d=t(),f=`piagent-workspace-open`;async function p(e,t){let n=(await s(e)).roots.find(e=>e.source===`project`&&t.startsWith(`${e.path.replace(/\/+$/,``)}/`));return n?t.slice(n.path.replace(/\/+$/,``).length+1):null}async function m(e,t){return t.absolute?p(e,t.path):t.path}var h=(0,c.createContext)(null);function g(){return(0,c.useContext)(h)}var _=(0,c.createContext)(null);function v({sessionRef:e,onOpen:t,children:n}){let r=n=>{t(),window.dispatchEvent(new CustomEvent(f,{detail:{sessionRef:e,...n}}))};return(0,d.jsx)(_.Provider,{value:e?t=>{if(!(`absolute`in t)||!t.absolute){r({path:t.path,line:t.line});return}p(e,t.path).then(e=>{e&&r({path:e,line:t.line})},()=>void 0)}:null,children:(0,d.jsx)(h.Provider,{value:e??null,children:n})})}function y({path:e,line:t,children:n}){let i=(0,c.useContext)(_),{locale:s}=a(),u=l(e,t);return!i||!u?n?(0,d.jsx)(d.Fragment,{children:n}):null:(0,d.jsx)(r,{size:`small`,onClick:()=>i(u),sx:{textTransform:`none`,verticalAlign:`baseline`},children:n??o(s,`Mở trong editor`,`Open in editor`)})}function b({link:e,children:t}){let n=(0,c.useContext)(_),{locale:r}=a();return n?(0,d.jsx)(i,{component:`button`,type:`button`,underline:`hover`,onClick:()=>n(e),title:o(r,`Mở ${e.path}`,`Open ${e.path}`),sx:{font:`inherit`,verticalAlign:`baseline`,textAlign:`left`},children:t}):(0,d.jsx)(d.Fragment,{children:t})}function x({children:e}){return(0,d.jsx)(d.Fragment,{children:c.Children.map(e,e=>typeof e==`string`?e.split(/((?<![\w@])@[\w./-]+\.[\w]+(?::\d+)?)/g).map((e,t)=>e.startsWith(`@`)&&l(e)?(0,d.jsx)(y,{path:e,children:e},t):e):e)})}export{v as a,u as c,x as i,l,y as n,m as o,b as r,g as s,f as t};
@@ -7,10 +7,10 @@
7
7
  <meta name="csp-nonce" content="__PIAGENT_CSP_NONCE__" />
8
8
  <meta name="piagent-webui-mode" content="__PIAGENT_WEBUI_MODE__" />
9
9
  <title>Piagent WebUI</title>
10
- <script type="module" crossorigin src="/assets/index-CNdhIouM.js"></script>
10
+ <script type="module" crossorigin src="/assets/index-DcrpSyBK.js"></script>
11
11
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-hePW80VL.js">
12
- <link rel="modulepreload" crossorigin href="/assets/vendor-CSDKB7mU.js">
13
- <link rel="modulepreload" crossorigin href="/assets/ui-preferences-0waeSO-S.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/vendor-DNZbaWhT.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/ui-preferences-OfS30-ZV.js">
14
14
  <link rel="stylesheet" crossorigin href="/assets/index-CjM70M7D.css">
15
15
  </head>
16
16
  <body>
@@ -15,7 +15,8 @@ const SEVERITY: Record<string, [string, string]> = { blocking: ["blocking", "blo
15
15
  const KIND: Record<string, [string, string]> = { wrong_premise: ["sai giả định", "wrong premise"], conflicts_with_request: ["conflict với yêu cầu", "conflicts with the request"],
16
16
  ambiguous: ["chưa rõ ràng", "ambiguous"], out_of_scope: ["out of scope", "out of scope"] };
17
17
  const UNAVAILABLE: Record<string, [string, string]> = { too_large: ["patch quá lớn", "the patch is too large"], not_git: ["thư mục không phải git", "not a git repository"],
18
- limit: ["subagent đã hết lượt gọi", "the subagent ran out of calls"], failed: ["subagent lỗi", "the subagent failed"] };
18
+ limit: ["subagent đã hết lượt gọi", "the subagent ran out of calls"], failed: ["subagent lỗi", "the subagent failed"],
19
+ runtime_changed: ["Piagent vừa được cập nhật, hãy mở lại cuộc trò chuyện", "Piagent was just updated; reopen the conversation"] };
19
20
 
20
21
  // How a code-changing turn ended against the Harness workflow, in a few words.
21
22
  export function outcomeText(process: ProcessCopyInput, locale: CopyLocale): string {
@@ -40,6 +40,12 @@
40
40
  "image/bmp",
41
41
  "image/x-icon",
42
42
  "image/avif",
43
+ "image/svg+xml",
44
+ "application/pdf",
45
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
46
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
47
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
48
+ "application/zip",
43
49
  null
44
50
  ]
45
51
  },
@@ -9,6 +9,7 @@ import { execFile } from 'node:child_process';
9
9
  import { pathToFileURL } from 'node:url';
10
10
 
11
11
  import { registerTerminalUpdateOffer } from '../packages/piagent-core/runtime/update/terminal-update-offer.mjs';
12
+ import { watchTerminalReload } from '../packages/piagent-core/runtime/update/terminal-reload.mjs';
12
13
  import { registerStyleCommand } from '../packages/piagent-core/runtime/terminal/terminal-style.mjs';
13
14
  import { parseFailure } from '../packages/piagent-core/runtime/managed-failure.mjs';
14
15
  import { checkpointsOf } from '../packages/piagent-core/managed/checkpoints.mjs';
@@ -258,6 +259,16 @@ export function companyMode(Base, { summary, whatsNew, components }) {
258
259
  const say = (mode, name, tone = 'warning') => mode.showExtensionNotify(companyCommandText(name, summary()), tone);
259
260
  return class CompanyInteractiveMode extends Base {
260
261
  async handleShareCommand() { say(this, 'share'); }
262
+ // Pi's own shutdown without its process.exit: the Terminal is restored and
263
+ // the session closed, then piagent-studio.mjs hands over to the new release.
264
+ async stopForRestart() {
265
+ if (this.isShuttingDown) return;
266
+ this.isShuttingDown = true;
267
+ this.themeController?.disableAutoSync?.();
268
+ await this.ui.terminal.drainInput(1000);
269
+ this.stop();
270
+ await this.runtimeHost.dispose();
271
+ }
261
272
  async handleBugCommand() { say(this, 'bug'); }
262
273
  suggestBugReport() {}
263
274
  crashReportInstructions() { return 'Lần sau mở lại: piagent studio, rồi /resume. Gửi admin của team giờ xảy ra lỗi.'; }
@@ -285,7 +296,7 @@ export function companyMode(Base, { summary, whatsNew, components }) {
285
296
  };
286
297
  }
287
298
 
288
- export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindingChanged = () => false }) {
299
+ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindingChanged = () => false, restartInPlace = null }) {
289
300
  const require = createRequire(path.join(sdkRoot, 'package.json'));
290
301
  let tui;
291
302
  const components = async () => (tui ??= await import(pathToFileURL(require.resolve('@earendil-works/pi-tui')).href));
@@ -302,6 +313,15 @@ export function companyTerminalExtension({ managed, packageRoot, sdkRoot, bindin
302
313
  registerTerminalUpdateOffer(pi, { installed, packageRoot, restart: 'piagent studio',
303
314
  afterUpdate: () => bindingChanged() ? 'Bản mới đổi trình khởi chạy công ty: Agent Watch tự cập nhật cấu hình (cần Agent Watch đang chạy); piagent studio chờ việc này khi mở lại.' : null });
304
315
 
316
+ // `piagent reload` and a finished update: the company code is loaded once
317
+ // per process, so this Terminal starts again in place on the same
318
+ // conversation (piagent-studio.mjs), when idle. A Terminal opened by an
319
+ // older launcher cannot be started again for the member: it says so.
320
+ watchTerminalReload(pi, { apply: async (ctx, request) => {
321
+ if (!restartInPlace) { ctx.ui.notify(`Có Piagent ${request.version ?? 'mới'}: thoát rồi mở lại \`piagent studio\`, rồi /resume, để dùng bản mới.`, 'warning'); return; }
322
+ setTimeout(() => { void restartInPlace(); }, 0);
323
+ } });
324
+
305
325
  // The member's pick of look (/style); /settings is not offered here.
306
326
  registerStyleCommand(pi, { remember: true });
307
327
 
@@ -29,7 +29,8 @@ const scriptByCommand = {
29
29
  "piagent-dashboard": "scripts/piagent-dashboard.mjs",
30
30
  "piagent-pi-host": "scripts/pi-host.mjs",
31
31
  "piagent-skills": "scripts/skill-sources.mjs",
32
- "piagent-restore-pi": "scripts/personal-pi-restore.mjs"
32
+ "piagent-restore-pi": "scripts/personal-pi-restore.mjs",
33
+ "piagent-reload": "scripts/terminal-reload.mjs"
33
34
  };
34
35
 
35
36
  const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
@@ -93,6 +94,7 @@ if (invokedAs === "piagent") {
93
94
  console.log(" dashboard Open and manage the local session hub");
94
95
  console.log(" studio Open the managed company agent imported by Agent Watch");
95
96
  console.log(" pi Same as `piagent`: Pi on the release Piagent is qualified on, in Piagent's home");
97
+ console.log(" reload Move every open Piagent Terminal to the installed release, without closing them");
96
98
  console.log(" restore-pi Take an older Piagent install out of your own pi (~/.pi/agent)");
97
99
  console.log(" pi-host Show or install the Pi host Piagent runs");
98
100
  console.log(" skills Add, list or remove skill sources such as mattpocock/skills");
@@ -196,18 +198,48 @@ const runner = target.endsWith(".mjs") ? process.execPath : "bash";
196
198
  const runnerArgs = target.endsWith(".mjs")
197
199
  ? ["--disable-warning=ExperimentalWarning", "--import", pathToFileURL(path.join(sourceRoot, "scripts", "register-typescript-loader.mjs")).href, target]
198
200
  : [target];
199
- const child = spawn(runner, [...runnerArgs, ...forwardedArgs], {
200
- cwd: process.cwd(),
201
- env: script === "scripts/piagent-studio.mjs" ? { PATH: "/usr/bin:/bin", HOME: os.homedir(), TERM: process.env.TERM || "xterm-256color", LANG: "en_US.UTF-8" }
202
- : { ...process.env, PI_CODING_AGENT_DIR: piagentHome(), ...(terminal ? { PIAGENT_ACTIVE: "1" } : {}) },
203
- stdio: "inherit"
204
- });
201
+ // The company Terminal can start again in place on a new release (`piagent
202
+ // reload`, or after `piagent-update`): it writes the arguments that reopen its
203
+ // conversation to this file and exits with RESTART_CODE; the files of the
204
+ // installed release are run again with them, in the same terminal window.
205
+ const RESTART_CODE = 75;
206
+ const restartFile = script === "scripts/piagent-studio.mjs" ? path.join(os.homedir(), ".pi", "piagent-restart", `${process.pid}.json`) : null;
207
+ function takeRestart() {
208
+ if (!restartFile) return null;
209
+ try {
210
+ const value = JSON.parse(fs.readFileSync(restartFile, "utf8"));
211
+ fs.rmSync(restartFile, { force: true });
212
+ return Array.isArray(value?.args) && value.args.every((arg) => typeof arg === "string") ? value.args : null;
213
+ } catch { return null; }
214
+ }
205
215
 
206
- child.once("error", (error) => {
207
- const code = error && typeof error === "object" && "code" in error ? ` (${error.code})` : "";
208
- console.error(`Pi Agent command could not start ${runner}${code}. Ensure it is installed and available on PATH.`);
209
- process.exit(1);
210
- });
216
+ let child;
217
+ function launch(args) {
218
+ child = spawn(runner, [...runnerArgs, ...args], {
219
+ cwd: process.cwd(),
220
+ env: script === "scripts/piagent-studio.mjs" ? { PATH: "/usr/bin:/bin", HOME: os.homedir(), TERM: process.env.TERM || "xterm-256color", LANG: "en_US.UTF-8", PIAGENT_RESTART_FILE: restartFile }
221
+ : { ...process.env, PI_CODING_AGENT_DIR: piagentHome(), ...(terminal ? { PIAGENT_ACTIVE: "1" } : {}) },
222
+ stdio: "inherit"
223
+ });
224
+
225
+ child.once("error", (error) => {
226
+ const code = error && typeof error === "object" && "code" in error ? ` (${error.code})` : "";
227
+ console.error(`Pi Agent command could not start ${runner}${code}. Ensure it is installed and available on PATH.`);
228
+ process.exit(1);
229
+ });
230
+
231
+ child.once("exit", (code, signal) => {
232
+ if (signal) {
233
+ process.removeAllListeners(signal);
234
+ process.kill(process.pid, signal);
235
+ return;
236
+ }
237
+ const again = code === RESTART_CODE ? takeRestart() : null;
238
+ if (again) { launch(again); return; }
239
+ process.exit(code ?? 1);
240
+ });
241
+ }
242
+ launch(forwardedArgs);
211
243
 
212
244
  // A command stopped from outside (a script, an editor, a timeout) stops its
213
245
  // child too, rather than leaving a company run going in the background. A
@@ -215,12 +247,3 @@ child.once("error", (error) => {
215
247
  // stays until the child has finished.
216
248
  for (const signal of ["SIGTERM", "SIGHUP"]) process.on(signal, () => { try { child.kill(signal); } catch { /* already gone */ } });
217
249
  process.on("SIGINT", () => {});
218
-
219
- child.once("exit", (code, signal) => {
220
- if (signal) {
221
- process.removeAllListeners(signal);
222
- process.kill(process.pid, signal);
223
- return;
224
- }
225
- process.exit(code ?? 1);
226
- });
@@ -30,6 +30,11 @@ const home = os.homedir();
30
30
  // Read before the environment is cleared: a Herdr pane's socket for the
31
31
  // Terminal's reporter, and the PATH that finds the Windows browser from WSL.
32
32
  const herdr = herdrEnvironment(), ambientPath = process.env.PATH;
33
+ // The launcher (piagent-cli.mjs) names a file for a restart in place: the
34
+ // Terminal writes the arguments that reopen this conversation there and exits
35
+ // with RESTART_CODE, and the launcher starts the installed release with them.
36
+ const RESTART_CODE = 75, restartFile = /\/\.pi\/piagent-restart\/\d+\.json$/.test(process.env.PIAGENT_RESTART_FILE ?? '') ? process.env.PIAGENT_RESTART_FILE : null;
37
+ let relaunch = null;
33
38
  // Joining Agent Watch takes a few seconds; keys typed before the Terminal draws are lost, so say so.
34
39
  if (!['--check', '--prompt', '--serve', '--doctor', '--web', '--rpc'].some((f) => flags.has(f)) && process.stderr.isTTY) process.stderr.write('Piagent công ty: đang kết nối Agent Watch, chờ ô nhập hiện ra rồi gõ…\n');
35
40
  // Do this before importing the SDK: it must not discover personal keys, Node
@@ -148,7 +153,8 @@ try {
148
153
  const { companyTerminalExtension, companyToolRenderers, companyInteractiveMode, harnessSummary } = await import('./company-terminal.mjs');
149
154
  const toolRenderers = await companyToolRenderers(config.sdk_root);
150
155
  const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
151
- const terminal = companyTerminalExtension({ managed: () => current, packageRoot, sdkRoot: config.sdk_root,
156
+ const restart = { request: null };
157
+ const terminal = companyTerminalExtension({ managed: () => current, packageRoot, sdkRoot: config.sdk_root, restartInPlace: restartFile ? () => restart.request?.() : null,
152
158
  bindingChanged: () => { try { return digest(config.entrypoint) !== config.entrypoint_sha256; } catch { return true; } } });
153
159
  // Herdr shows the Terminal's state and reopens it after a restart; scripted runs have no pane to show.
154
160
  const reportToHerdr = herdr && !['--check', '--prompt', '--rpc'].some((f) => flags.has(f));
@@ -216,7 +222,15 @@ try {
216
222
  : write(typeof chunk === 'string' && chunk.includes('To resume this session:') ? `Mở lại cuộc trò chuyện này: piagent studio --project ${project}, rồi /resume\n` : chunk, ...rest);
217
223
  // /share, /bug, /login, /model, /thinking, /settings and /changelog: company-terminal.mjs.
218
224
  const CompanyMode = await companyInteractiveMode(api, { sdkRoot: config.sdk_root, packageRoot, summary: () => harnessSummary(current) });
219
- await new CompanyMode(host, { verbose: false }).run();
225
+ const mode = new CompanyMode(host, { verbose: false });
226
+ const restarting = new Promise((resolve) => { restart.request = async () => {
227
+ if (relaunch) return;
228
+ const file = current?.session.sessionManager.getSessionFile?.(), saved = file && fs.existsSync(file) ? file : null;
229
+ const kept = []; for (let i = 0; i < args.length; i++) { if (args[i] === '--session') { i++; continue; } kept.push(args[i]); }
230
+ relaunch = [...kept, ...(saved ? ['--session', saved] : [])];
231
+ await mode.stopForRestart(); resolve();
232
+ }; });
233
+ await Promise.race([mode.run(), restarting]);
220
234
  }
221
235
  }
222
236
  } catch (error) {
@@ -229,3 +243,9 @@ try {
229
243
  : process.platform === 'linux' ? 'Trong Agent Watch cho Windows, chọn lại Kết nối Piagent trong WSL.' : 'Mở Agent Watch → Studio, nhập lại cấu hình cho Piagent, hoặc kiểm tra quyền Keychain.');
230
244
  process.stderr.write(`Agent Watch: ${code}. ${hint}\n`); process.exitCode = 1;
231
245
  } finally { await gateway?.close(); if (current) await current.dispose(); else await broker?.dispose(); hold?.release(); }
246
+ if (relaunch && restartFile) {
247
+ fs.mkdirSync(path.dirname(restartFile), { recursive: true, mode: 0o700 });
248
+ fs.writeFileSync(restartFile, JSON.stringify({ args: relaunch }), { mode: 0o600 });
249
+ process.stderr.write('Piagent công ty: đang mở lại với bản mới, giữ nguyên cuộc trò chuyện…\n');
250
+ process.exit(RESTART_CODE);
251
+ }
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ // `piagent reload`: every open Piagent Terminal on this machine (`piagent`
3
+ // and `piagent studio`) loads the installed release when it is idle; a task
4
+ // running in one finishes first. The conversation stays open. piagent-update
5
+ // asks the same once it installed a release.
6
+ import fs from "node:fs";
7
+ import { requestTerminalReload } from "../packages/piagent-core/runtime/update/terminal-reload.mjs";
8
+
9
+ if (process.argv.slice(2).some((arg) => ["--help", "-h"].includes(arg))) {
10
+ console.log("Usage: piagent reload\n\nEvery open Piagent Terminal (piagent, piagent studio) loads the installed release when it is idle.\nA task running in one finishes first; the conversation stays open.");
11
+ process.exit(0);
12
+ }
13
+ const manifest = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
14
+ requestTerminalReload({ version: manifest.version, piHost: manifest.peerDependencies?.["@earendil-works/pi-coding-agent"] ?? null });
15
+ console.log(`Piagent ${manifest.version}: các Terminal đang mở (piagent, piagent studio) sẽ nạp bản này khi rảnh; Terminal đang chạy task thì nạp khi task xong. Cuộc trò chuyện giữ nguyên.`);
@@ -552,6 +552,16 @@ function main() {
552
552
  : `\nPASS: updated to v${targetHelper}.`);
553
553
  // A dashboard started before the update still serves the earlier release.
554
554
  if (!options.dryRun && helperNeedsChange) console.log("Open the dashboard with `piagent dashboard`: one still running an earlier release is restarted on the new one.");
555
+ // Open Terminals move to the new release when they are idle (a run in
556
+ // progress finishes first): the same request as `piagent reload`.
557
+ if (!options.dryRun && (helperNeedsChange || packageNeedsChange)) {
558
+ import("../packages/piagent-core/runtime/update/terminal-reload.mjs")
559
+ .then(({ requestTerminalReload }) => {
560
+ requestTerminalReload({ version: targetHelper, piHost: targetHost });
561
+ console.log("Open Terminals (piagent, piagent studio) load the new release when idle; a running task finishes first.");
562
+ })
563
+ .catch(() => console.log("Open Terminals keep the earlier release until reopened (`piagent reload` asks them again)."));
564
+ }
555
565
  }
556
566
 
557
567
  main();