pi-orchestrator-config 4.6.2 → 4.6.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.
@@ -27,16 +27,10 @@ This agent does NOT run tests. When tests are required (e.g., before creating a
27
27
  1. Ask orchestrator: "Have all tests passed?"
28
28
  2. If NO/UNKNOWN: "Please delegate to test-runner, then call me again"
29
29
 
30
- ## Project Settings
30
+ ## Attribution
31
31
 
32
- {{SETTINGS:comment_signature}}
33
-
34
- - If `comment_signature` is `true`: append a signature to every GitHub body you write —
35
- PR/issue **create**, **edit --body**, and **comment**.
36
- Format: `\n\n---\n*Assisted-by: PI (<model>)*` using `$PI_MODEL` for model.
37
- If `$PI_COMMENT_SIGNATURE` is set, use: `\n\n---\n*$PI_COMMENT_SIGNATURE*`.
38
- Skip if the body already contains `Assisted-by`.
39
- Runtime enforcement also injects this on `gh pr|issue create|comment|edit` `--body` / heredoc.
32
+ Runtime owns attribution for `gh pr` and `gh issue` create, edit, and comment bodies passed with `--body`.
33
+ Never manually add a signature, including raw `$PI_MODEL`, or use a manual fallback.
40
34
 
41
35
  ## Core Operations
42
36
 
@@ -1041,6 +1041,7 @@ export function registerAsyncAgents(
1041
1041
  // Resolve base branch for reviewers so they diff against the correct target
1042
1042
  const spawnEnv: Record<string, string | undefined> = {
1043
1043
  ...process.env,
1044
+ PI_MODEL: effectiveModel || undefined,
1044
1045
  PI_SUBAGENT_CHILD: "1",
1045
1046
  PI_AGENT_NAME: agentName,
1046
1047
  PI_PRIMARY_MODEL: process.env.PI_PRIMARY_MODEL || process.env.PI_MODEL || "",
@@ -806,17 +806,38 @@ function commentSignatureFooter(signature: string): string {
806
806
  return `\n\n---\n*${signature}*`;
807
807
  }
808
808
 
809
+ const ghSignatureModel = /^[\w:./+@-]+(?: [\w:./+@-]+)*$/;
810
+ const ghSignatureLine = /(^|\n|\\n)(?:(?:\n|\\n)---(?:\n|\\n))?\*Assisted-by: PI \(([^\r\n]*?)\)\*(?=\r?\n|\\n|$)/g;
811
+
809
812
  function bodyAlreadySigned(text: string): boolean {
810
- return /\*Assisted-by:/.test(text) || /(?:^|\n|\\n)Assisted-by:\s/.test(text);
813
+ const lines = text.matchAll(ghSignatureLine);
814
+ for (const line of lines) {
815
+ if (ghSignatureModel.test(line[2])) return true;
816
+ }
817
+ return false;
811
818
  }
812
819
 
813
- /** Unresolved model placeholders are stale template footers, not signatures. */
814
- function replaceUnresolvedModelFooters(payload: string): string {
815
- const unresolvedFooter = /(?:\n|\\n){2}---(?:\n|\\n)\*Assisted-by: PI \((?:\$PI_MODEL|\$\{PI_MODEL(?::-unknown)?\})\)\*/g;
816
- const replaced = payload.replace(unresolvedFooter, "");
817
- if (replaced !== payload)
818
- enfLog.debug("injectGhBodySignature replaced unresolved PI_MODEL footer");
819
- return replaced;
820
+ /** Keep the first standalone valid footer, but use the current operation's model. */
821
+ function normalizeGhBodyFooters(payload: string, signature: string): string {
822
+ let signed = false;
823
+ return payload.replace(ghSignatureLine, (block, _prefix: string, model: string) => {
824
+ if (model.includes("PI_MODEL")) {
825
+ enfLog.debug("injectGhBodySignature removed unresolved PI_MODEL footer");
826
+ return "";
827
+ }
828
+ if (ghSignatureModel.test(model)) {
829
+ if (signed) {
830
+ enfLog.debug("injectGhBodySignature removed duplicate valid footer", model);
831
+ return "";
832
+ }
833
+ signed = true;
834
+ if (`Assisted-by: PI (${model})` !== signature) {
835
+ enfLog.debug("injectGhBodySignature replaced stale footer", model);
836
+ return block.replace(`*Assisted-by: PI (${model})*`, `*${signature}*`);
837
+ }
838
+ }
839
+ return block;
840
+ });
820
841
  }
821
842
 
822
843
  /** Index of the matching closer for a quote at `openIdx`, honoring POSIX escapes. */
@@ -829,6 +850,17 @@ function matchingQuoteIndex(s: string, openIdx: number): number | null {
829
850
  return close < 0 ? null : close;
830
851
  }
831
852
  for (let i = openIdx + 1; i < s.length; i++) {
853
+ if (s.startsWith("<<", i)) {
854
+ const opener = /^<<(-?)[ \t]*(['"]?)([\w-]+)\2[^\n]*\n/.exec(s.slice(i));
855
+ if (opener) {
856
+ const closer = new RegExp(String.raw`\n${opener[1] ? "\\t*" : ""}${opener[3]}\r?(?=\n|$)`).exec(s.slice(i + opener[0].length - 1));
857
+ if (closer) {
858
+ enfLog.debug("matchingQuoteIndex skip heredoc", opener[3]);
859
+ i += opener[0].length - 1 + closer.index + closer[0].length - 1;
860
+ continue;
861
+ }
862
+ }
863
+ }
832
864
  if (s[i] === "\\") {
833
865
  i++;
834
866
  continue;
@@ -873,7 +905,7 @@ function lastHeredocInSpan(
873
905
  spanStart: number,
874
906
  spanEnd: number,
875
907
  ): RegExpExecArray | null {
876
- const heredocRe = /<<(?:-)?\s*(['"]?)(\w+)\1[^\n]*\n([\s\S]*?)\n([ \t]*)\2\s*(?=\n|$)/g;
908
+ const heredocRe = /<<-?[ \t]*(['"]?)([\w-]+)\1[^\n]*\n([\s\S]*?)\n([ \t]*)\2\r?(?=\n|$)/g;
877
909
  let last: RegExpExecArray | null = null;
878
910
  let m: RegExpExecArray | null;
879
911
  while ((m = heredocRe.exec(command)) !== null) {
@@ -905,9 +937,9 @@ export function injectGhBodySignature(command: string, signature: string): strin
905
937
  }
906
938
 
907
939
  const payload = command.slice(span.open + 1, span.close);
908
- const normalizedPayload = replaceUnresolvedModelFooters(payload);
940
+ const normalizedPayload = normalizeGhBodyFooters(payload, signature);
909
941
  if (normalizedPayload !== payload) {
910
- // Re-parse positions after removal so command-substitution heredocs still
942
+ // Re-parse positions after cleanup so command-substitution heredocs still
911
943
  // receive their footer before the closing delimiter.
912
944
  const normalizedCommand = command.slice(0, span.open + 1) + normalizedPayload + command.slice(span.close);
913
945
  return injectGhBodySignature(normalizedCommand, signature);
@@ -925,7 +957,9 @@ export function injectGhBodySignature(command: string, signature: string): strin
925
957
  const closeIdx = last.index + last[0].lastIndexOf(closeToken);
926
958
  if (closeIdx >= last.index) {
927
959
  enfLog.debug("injectGhBodySignature heredoc in --body", delim);
928
- return command.slice(0, closeIdx) + footer + command.slice(closeIdx);
960
+ const crlf = command[closeIdx - 1] === "\r";
961
+ const insertAt = crlf ? closeIdx - 1 : closeIdx;
962
+ return command.slice(0, insertAt) + (crlf ? footer.replaceAll("\n", "\r\n") : footer) + command.slice(insertAt);
929
963
  }
930
964
  }
931
965
 
@@ -389,7 +389,7 @@ export function registerEnforcement(pi: ExtensionAPI, inContainer?: boolean): vo
389
389
  cachedTrailerSelection = null;
390
390
  // Set comment signature env var for CLI tools to read
391
391
  if (getSetting(ctx.cwd, "comment_signature")) {
392
- const modelId = (process.env.PI_PRIMARY_MODEL || process.env.PI_MODEL || (ctx as any).model?.id || "unknown").replace(/[^a-zA-Z0-9._:@/ -]/g, "").trim() || "unknown";
392
+ const modelId = ((ctx as any).model?.id || process.env.PI_MODEL || process.env.PI_PRIMARY_MODEL || "unknown").replace(/[^a-zA-Z0-9._:@/ -]/g, "").trim() || "unknown";
393
393
  process.env.PI_COMMENT_SIGNATURE = `Assisted-by: PI (${modelId})`;
394
394
  } else {
395
395
  delete process.env.PI_COMMENT_SIGNATURE;
@@ -535,12 +535,12 @@ export function registerEnforcement(pi: ExtensionAPI, inContainer?: boolean): vo
535
535
  // comment_signature: inject Assisted-by footer into gh pr/issue create|comment|edit bodies
536
536
  if (getSetting(ctx.cwd, "comment_signature")) {
537
537
  const modelId = (
538
- process.env.PI_PRIMARY_MODEL ||
539
- process.env.PI_MODEL ||
540
538
  (ctx as any).model?.id ||
539
+ process.env.PI_MODEL ||
540
+ process.env.PI_PRIMARY_MODEL ||
541
541
  "unknown"
542
542
  ).replace(/[^a-zA-Z0-9._:@/ -]/g, "").trim() || "unknown";
543
- const signature = process.env.PI_COMMENT_SIGNATURE || `Assisted-by: PI (${modelId})`;
543
+ const signature = `Assisted-by: PI (${modelId})`;
544
544
  const injected = injectGhBodySignature(event.input.command, signature);
545
545
  if (injected !== event.input.command) {
546
546
  log.info("comment_signature injected into gh body command", signature);
@@ -485,7 +485,7 @@ export async function runSingleAgent(
485
485
  cwd: cwd,
486
486
  shell: false,
487
487
  stdio: ["ignore", "pipe", "pipe"],
488
- env: { ...process.env, PI_SUBAGENT_CHILD: "1", PI_AGENT_NAME: agentName, PI_PRIMARY_MODEL: process.env.PI_PRIMARY_MODEL || process.env.PI_MODEL || "", __PI_CONFIG_SESSION_ID: (globalThis as any).__piConfigSessionId || "", __PI_PARENT_SESSION_ID: (globalThis as any).__piConfigSessionId || "" },
488
+ env: { ...process.env, PI_MODEL: effectiveModel || undefined, PI_SUBAGENT_CHILD: "1", PI_AGENT_NAME: agentName, PI_PRIMARY_MODEL: process.env.PI_PRIMARY_MODEL || process.env.PI_MODEL || "", __PI_CONFIG_SESSION_ID: (globalThis as any).__piConfigSessionId || "", __PI_PARENT_SESSION_ID: (globalThis as any).__piConfigSessionId || "" },
489
489
  });
490
490
  let buf = "";
491
491
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pidiff-ui",
3
3
  "private": true,
4
- "version": "4.6.2",
4
+ "version": "4.6.3",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-orchestrator-config",
3
- "version": "4.6.2",
3
+ "version": "4.6.3",
4
4
  "description": "Orchestrator pattern for pi: specialist subagents, enforcement, code review loop, workflow commands",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -59,11 +59,14 @@
59
59
  "skills/",
60
60
  "settings-keys.json"
61
61
  ],
62
+ "peerDependencies": {
63
+ "@earendil-works/pi-agent-core": "*",
64
+ "@earendil-works/pi-ai": "*",
65
+ "@earendil-works/pi-coding-agent": "*",
66
+ "@earendil-works/pi-tui": "*",
67
+ "typebox": "*"
68
+ },
62
69
  "dependencies": {
63
- "@earendil-works/pi-agent-core": ">=0.87.0",
64
- "@earendil-works/pi-ai": ">=0.87.0",
65
- "@earendil-works/pi-coding-agent": ">=0.87.0",
66
- "@earendil-works/pi-tui": ">=0.87.0",
67
70
  "@huggingface/transformers": "^4.2.0",
68
71
  "acpx": ">=0.12.0 <1",
69
72
  "chokidar": "^5.0.0",