@lesliechan721/aw 0.1.0-beta.10 → 0.1.0-beta.12

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 (227) hide show
  1. package/dist/authoring/assets/aw-config.d.mts +1 -50
  2. package/dist/authoring/assets/aw-config.mjs +58 -928
  3. package/dist/authoring/assets/aw-config.mjs.map +1 -1
  4. package/dist/authoring/scripts/init-plugin.mjs +28 -33
  5. package/dist/authoring/scripts/init-plugin.mjs.map +1 -1
  6. package/dist/authoring/scripts/lib/plugin-version-check.d.mts +1 -0
  7. package/dist/authoring/scripts/lib/plugin-version-check.mjs +229 -8
  8. package/dist/authoring/scripts/lib/plugin-version-check.mjs.map +1 -1
  9. package/dist/authoring/scripts/validate-plugin.mjs +159 -48
  10. package/dist/authoring/scripts/validate-plugin.mjs.map +1 -1
  11. package/dist/scripts/bundle-plugins.js +18 -4
  12. package/dist/scripts/bundle-plugins.js.map +1 -1
  13. package/dist/scripts/test-plugin-scripts.d.ts +2 -0
  14. package/dist/scripts/test-plugin-scripts.js +21 -5
  15. package/dist/scripts/test-plugin-scripts.js.map +1 -1
  16. package/dist/src/commands/aw-capabilities.d.ts +1 -1
  17. package/dist/src/commands/aw-capabilities.js +1 -1
  18. package/dist/src/commands/aw-capabilities.js.map +1 -1
  19. package/dist/src/commands/catalog-dev-source.d.ts +6 -3
  20. package/dist/src/commands/catalog-dev-source.js +96 -35
  21. package/dist/src/commands/catalog-dev-source.js.map +1 -1
  22. package/dist/src/commands/catalog-publication-inspection.d.ts +1 -1
  23. package/dist/src/commands/catalog-publication-inspection.js +54 -8
  24. package/dist/src/commands/catalog-publication-inspection.js.map +1 -1
  25. package/dist/src/commands/catalog-publication-journal.js +1 -1
  26. package/dist/src/commands/catalog-publication-journal.js.map +1 -1
  27. package/dist/src/commands/catalog-source.d.ts +19 -4
  28. package/dist/src/commands/catalog-source.js +121 -12
  29. package/dist/src/commands/catalog-source.js.map +1 -1
  30. package/dist/src/commands/catalog-store.d.ts +26 -7
  31. package/dist/src/commands/catalog-store.js +361 -42
  32. package/dist/src/commands/catalog-store.js.map +1 -1
  33. package/dist/src/commands/console.js +28 -17
  34. package/dist/src/commands/console.js.map +1 -1
  35. package/dist/src/commands/operation-plan.d.ts +2 -1
  36. package/dist/src/commands/operation-plan.js +24 -0
  37. package/dist/src/commands/operation-plan.js.map +1 -1
  38. package/dist/src/commands/operation-planner.d.ts +2 -2
  39. package/dist/src/commands/operation-planner.js +22 -20
  40. package/dist/src/commands/operation-planner.js.map +1 -1
  41. package/dist/src/commands/options.d.ts +2 -2
  42. package/dist/src/commands/options.js +18 -4
  43. package/dist/src/commands/options.js.map +1 -1
  44. package/dist/src/commands/plugin-capabilities.js +2 -2
  45. package/dist/src/commands/plugin-capabilities.js.map +1 -1
  46. package/dist/src/commands/rebuild-command.d.ts +19 -0
  47. package/dist/src/commands/rebuild-command.js +828 -283
  48. package/dist/src/commands/rebuild-command.js.map +1 -1
  49. package/dist/src/commands/rebuild-integration.d.ts +25 -47
  50. package/dist/src/commands/rebuild-integration.js +1176 -1016
  51. package/dist/src/commands/rebuild-integration.js.map +1 -1
  52. package/dist/src/commands/rebuild-operations.d.ts +50 -12
  53. package/dist/src/commands/rebuild-operations.js +207 -101
  54. package/dist/src/commands/rebuild-operations.js.map +1 -1
  55. package/dist/src/commands/status-v6.d.ts +21 -2
  56. package/dist/src/commands/status-v6.js +163 -31
  57. package/dist/src/commands/status-v6.js.map +1 -1
  58. package/dist/src/commands/sync-command.d.ts +17 -0
  59. package/dist/src/commands/sync-command.js +45 -37
  60. package/dist/src/commands/sync-command.js.map +1 -1
  61. package/dist/src/commands/write-commands.d.ts +5 -0
  62. package/dist/src/commands/write-commands.js +50 -3
  63. package/dist/src/commands/write-commands.js.map +1 -1
  64. package/dist/src/generators/local-plugin.js +14 -4
  65. package/dist/src/generators/local-plugin.js.map +1 -1
  66. package/dist/src/index.js +260 -91
  67. package/dist/src/index.js.map +1 -1
  68. package/dist/src/output/command-receipt.js +1 -3
  69. package/dist/src/output/command-receipt.js.map +1 -1
  70. package/dist/src/output/rebuild-progress.js +1 -3
  71. package/dist/src/output/rebuild-progress.js.map +1 -1
  72. package/dist/src/portable/materializer.js +10 -8
  73. package/dist/src/portable/materializer.js.map +1 -1
  74. package/dist/src/tui/catalog-generation.js +41 -1
  75. package/dist/src/tui/catalog-generation.js.map +1 -1
  76. package/dist/src/tui/catalog-sources/session.d.ts +1 -0
  77. package/dist/src/tui/catalog-sources/session.js +16 -3
  78. package/dist/src/tui/catalog-sources/session.js.map +1 -1
  79. package/dist/src/tui/catalog-sources/types.d.ts +3 -2
  80. package/dist/src/tui/components.d.ts +4 -0
  81. package/dist/src/tui/components.js +36 -24
  82. package/dist/src/tui/components.js.map +1 -1
  83. package/dist/src/tui/console-app-v4.d.ts +13 -4
  84. package/dist/src/tui/console-app-v4.js +2065 -857
  85. package/dist/src/tui/console-app-v4.js.map +1 -1
  86. package/dist/src/tui/controller-runtime.js +731 -62
  87. package/dist/src/tui/controller-runtime.js.map +1 -1
  88. package/dist/src/tui/controller.d.ts +156 -10
  89. package/dist/src/tui/controller.js +1187 -163
  90. package/dist/src/tui/controller.js.map +1 -1
  91. package/dist/src/tui/diagnostic-projection.d.ts +22 -0
  92. package/dist/src/tui/diagnostic-projection.js +437 -0
  93. package/dist/src/tui/diagnostic-projection.js.map +1 -0
  94. package/dist/src/tui/diagnostics.d.ts +1 -1
  95. package/dist/src/tui/diagnostics.js +7 -2
  96. package/dist/src/tui/diagnostics.js.map +1 -1
  97. package/dist/src/tui/glossary.d.ts +23 -0
  98. package/dist/src/tui/glossary.js +42 -0
  99. package/dist/src/tui/glossary.js.map +1 -0
  100. package/dist/src/tui/index.d.ts +4 -1
  101. package/dist/src/tui/index.js +4 -1
  102. package/dist/src/tui/index.js.map +1 -1
  103. package/dist/src/tui/keys.d.ts +44 -0
  104. package/dist/src/tui/keys.js +43 -15
  105. package/dist/src/tui/keys.js.map +1 -1
  106. package/dist/src/tui/lifecycle-action-view.d.ts +6 -0
  107. package/dist/src/tui/lifecycle-action-view.js +34 -0
  108. package/dist/src/tui/lifecycle-action-view.js.map +1 -0
  109. package/dist/src/tui/model.d.ts +12 -2
  110. package/dist/src/tui/model.js +128 -52
  111. package/dist/src/tui/model.js.map +1 -1
  112. package/dist/src/tui/operation-diagnostic-screens.d.ts +21 -0
  113. package/dist/src/tui/operation-diagnostic-screens.js +101 -0
  114. package/dist/src/tui/operation-diagnostic-screens.js.map +1 -0
  115. package/dist/src/tui/operation-history.d.ts +80 -0
  116. package/dist/src/tui/operation-history.js +130 -0
  117. package/dist/src/tui/operation-history.js.map +1 -0
  118. package/dist/src/tui/operation-review-planner.js +366 -99
  119. package/dist/src/tui/operation-review-planner.js.map +1 -1
  120. package/dist/src/tui/router.d.ts +82 -17
  121. package/dist/src/tui/router.js +186 -38
  122. package/dist/src/tui/router.js.map +1 -1
  123. package/dist/src/tui/screen-registry.d.ts +546 -0
  124. package/dist/src/tui/screen-registry.js +179 -0
  125. package/dist/src/tui/screen-registry.js.map +1 -0
  126. package/dist/src/tui/session-console-app.d.ts +6 -0
  127. package/dist/src/tui/session-console-app.js +13 -0
  128. package/dist/src/tui/session-console-app.js.map +1 -0
  129. package/dist/src/tui/session-host.d.ts +44 -0
  130. package/dist/src/tui/session-host.js +197 -0
  131. package/dist/src/tui/session-host.js.map +1 -0
  132. package/dist/src/types.d.ts +64 -3
  133. package/dist/src/types.js +1 -1
  134. package/dist/src/types.js.map +1 -1
  135. package/dist/src/utils/agent-version.js +1 -1
  136. package/dist/src/utils/agent-version.js.map +1 -1
  137. package/dist/src/utils/artifact-plan.d.ts +2 -2
  138. package/dist/src/utils/artifact-plan.js +8 -6
  139. package/dist/src/utils/artifact-plan.js.map +1 -1
  140. package/dist/src/utils/artifact-renderer.d.ts +2 -1
  141. package/dist/src/utils/artifact-renderer.js +139 -120
  142. package/dist/src/utils/artifact-renderer.js.map +1 -1
  143. package/dist/src/utils/artifact-request.d.ts +5 -0
  144. package/dist/src/utils/artifact-request.js +40 -0
  145. package/dist/src/utils/artifact-request.js.map +1 -1
  146. package/dist/src/utils/bundle-layout.js +4 -4
  147. package/dist/src/utils/bundle-layout.js.map +1 -1
  148. package/dist/src/utils/catalog-capability-projection.d.ts +8 -0
  149. package/dist/src/utils/catalog-capability-projection.js +14 -0
  150. package/dist/src/utils/catalog-capability-projection.js.map +1 -0
  151. package/dist/src/utils/catalog-generation-resolver.d.ts +14 -2
  152. package/dist/src/utils/catalog-generation-resolver.js +49 -27
  153. package/dist/src/utils/catalog-generation-resolver.js.map +1 -1
  154. package/dist/src/utils/catalog-generation-service.d.ts +8 -1
  155. package/dist/src/utils/catalog-generation-service.js +81 -47
  156. package/dist/src/utils/catalog-generation-service.js.map +1 -1
  157. package/dist/src/utils/catalog-generation-store.d.ts +1 -0
  158. package/dist/src/utils/catalog-generation-store.js +60 -5
  159. package/dist/src/utils/catalog-generation-store.js.map +1 -1
  160. package/dist/src/utils/catalog-operation-context.js +1 -0
  161. package/dist/src/utils/catalog-operation-context.js.map +1 -1
  162. package/dist/src/utils/catalog-public-error.js +4 -0
  163. package/dist/src/utils/catalog-public-error.js.map +1 -1
  164. package/dist/src/utils/catalog-source-impact.d.ts +3 -2
  165. package/dist/src/utils/catalog-source-impact.js +142 -20
  166. package/dist/src/utils/catalog-source-impact.js.map +1 -1
  167. package/dist/src/utils/catalog-source-references.js +95 -9
  168. package/dist/src/utils/catalog-source-references.js.map +1 -1
  169. package/dist/src/utils/catalog-sources.d.ts +1 -1
  170. package/dist/src/utils/catalog-sources.js +19 -3
  171. package/dist/src/utils/catalog-sources.js.map +1 -1
  172. package/dist/src/utils/codex-manager.js +8 -0
  173. package/dist/src/utils/codex-manager.js.map +1 -1
  174. package/dist/src/utils/codex-native-observation.d.ts +34 -1
  175. package/dist/src/utils/codex-native-observation.js +132 -0
  176. package/dist/src/utils/codex-native-observation.js.map +1 -1
  177. package/dist/src/utils/codex-reconciler.d.ts +0 -2
  178. package/dist/src/utils/codex-reconciler.js.map +1 -1
  179. package/dist/src/utils/codex-shared-native.d.ts +2 -26
  180. package/dist/src/utils/codex-shared-native.js +8 -82
  181. package/dist/src/utils/codex-shared-native.js.map +1 -1
  182. package/dist/src/utils/git-catalog-provider.d.ts +3 -0
  183. package/dist/src/utils/git-catalog-provider.js +40 -1
  184. package/dist/src/utils/git-catalog-provider.js.map +1 -1
  185. package/dist/src/utils/local-marketplace.d.ts +1 -0
  186. package/dist/src/utils/local-marketplace.js +69 -73
  187. package/dist/src/utils/local-marketplace.js.map +1 -1
  188. package/dist/src/utils/multi-source-catalog.js +1 -0
  189. package/dist/src/utils/multi-source-catalog.js.map +1 -1
  190. package/dist/src/utils/native-cli.d.ts +9 -4
  191. package/dist/src/utils/native-cli.js +280 -34
  192. package/dist/src/utils/native-cli.js.map +1 -1
  193. package/dist/src/utils/path-catalog-provider.js +2 -0
  194. package/dist/src/utils/path-catalog-provider.js.map +1 -1
  195. package/dist/src/utils/plugin-config-impact.d.ts +33 -0
  196. package/dist/src/utils/plugin-config-impact.js +298 -0
  197. package/dist/src/utils/plugin-config-impact.js.map +1 -0
  198. package/dist/src/utils/plugin-config-write.d.ts +36 -14
  199. package/dist/src/utils/plugin-config-write.js +709 -225
  200. package/dist/src/utils/plugin-config-write.js.map +1 -1
  201. package/dist/src/utils/plugin-config.d.ts +58 -4
  202. package/dist/src/utils/plugin-config.js +328 -60
  203. package/dist/src/utils/plugin-config.js.map +1 -1
  204. package/dist/src/utils/plugin-scripts.d.ts +20 -12
  205. package/dist/src/utils/plugin-scripts.js +389 -114
  206. package/dist/src/utils/plugin-scripts.js.map +1 -1
  207. package/dist/src/utils/process-tree.d.ts +2 -2
  208. package/dist/src/utils/process-tree.js +1 -1
  209. package/dist/src/utils/process-tree.js.map +1 -1
  210. package/dist/src/utils/project-boundary.d.ts +11 -1
  211. package/dist/src/utils/project-boundary.js +33 -11
  212. package/dist/src/utils/project-boundary.js.map +1 -1
  213. package/dist/src/utils/safe-operation-diagnostic.d.ts +15 -0
  214. package/dist/src/utils/safe-operation-diagnostic.js +33 -0
  215. package/dist/src/utils/safe-operation-diagnostic.js.map +1 -0
  216. package/dist/src/utils/sensitive-content.d.ts +4 -0
  217. package/dist/src/utils/sensitive-content.js +36 -0
  218. package/dist/src/utils/sensitive-content.js.map +1 -0
  219. package/dist/src/utils/windows-claude-shim.d.ts +9 -0
  220. package/dist/src/utils/windows-claude-shim.js +141 -0
  221. package/dist/src/utils/windows-claude-shim.js.map +1 -0
  222. package/dist/vitest.config.js +91 -10
  223. package/dist/vitest.config.js.map +1 -1
  224. package/package.json +9 -9
  225. package/dist/authoring/templates/aw-config-runtime.d.mts +0 -2
  226. package/dist/authoring/templates/aw-config-runtime.mjs +0 -407
  227. package/dist/authoring/templates/aw-config-runtime.mjs.map +0 -1
@@ -3,16 +3,24 @@ import { randomUUID } from 'node:crypto';
3
3
  import path from 'node:path';
4
4
  import fs from 'fs-extra';
5
5
  import { redactString } from '../output/redact.js';
6
- import { observeProcessTree, terminateProcessTree } from './process-tree.js';
6
+ import { createWindowsJobInvocation, observeProcessTree, terminateProcessTree, } from './process-tree.js';
7
7
  import { resolveAwHome } from './paths.js';
8
8
  import { resolveEffectivePluginConfig } from './plugin-config.js';
9
9
  import { assertTestWritablePath } from './test-path-fence.js';
10
+ import { attachSafeOperationError } from './safe-operation-diagnostic.js';
11
+ import { collectSensitiveTokenRepresentations, containsBlockedSensitiveToken, } from './sensitive-content.js';
10
12
  export { calculateFileDigest } from './bundle-integrity.js';
11
- export const PLUGIN_SCRIPT_TIMEOUT_DEFAULT_MS = 30_000;
13
+ export const PLUGIN_SCRIPT_TIMEOUT_DEFAULT_MS = 300_000;
12
14
  export const PLUGIN_SCRIPT_TIMEOUT_MIN_MS = 1_000;
13
- export const PLUGIN_SCRIPT_TIMEOUT_MAX_MS = 300_000;
15
+ export const PLUGIN_SCRIPT_TIMEOUT_MAX_MS = 1_800_000;
14
16
  const OUTPUT_LIMIT = 64 * 1024;
15
- const TOKEN_BOUNDARY_LOOKAHEAD = 2;
17
+ const WINDOWS_JOB_CLOSE_TIMEOUT_MS = 4_500;
18
+ class PluginProcessInputError extends Error {
19
+ constructor(cause) {
20
+ super('Plugin process input could not be sent.', { cause });
21
+ this.name = 'PluginProcessInputError';
22
+ }
23
+ }
16
24
  export async function resolveBundledPluginFilePath(options) {
17
25
  const bundleRoot = await fs.realpath(options.bundleRoot);
18
26
  const relativePath = options.pluginRelativePath.startsWith('./') ? options.pluginRelativePath.slice(2) : options.pluginRelativePath;
@@ -83,32 +91,47 @@ export function collectSensitivePluginConfigValues(manifest, values) {
83
91
  });
84
92
  });
85
93
  }
94
+ export function assertNoSensitiveConfigValues(value, sensitiveValues, message) {
95
+ const strings = [];
96
+ const visit = (entry) => {
97
+ if (typeof entry === 'string') {
98
+ strings.push(entry);
99
+ return;
100
+ }
101
+ if (Array.isArray(entry)) {
102
+ entry.forEach(visit);
103
+ return;
104
+ }
105
+ if (entry !== null && typeof entry === 'object') {
106
+ Object.entries(entry).forEach(([key, child]) => {
107
+ strings.push(key);
108
+ visit(child);
109
+ });
110
+ }
111
+ };
112
+ visit(value);
113
+ if (strings.some((entry) => containsBlockedSensitiveToken(entry, sensitiveValues))) {
114
+ throw new Error(message);
115
+ }
116
+ }
117
+ export function assertNoSensitiveConfigInFiles(files, sensitiveValues, message) {
118
+ assertNoSensitiveConfigValues(Object.entries(files).map(([relativePath, content]) => ({
119
+ relativePath,
120
+ content: content.toString('utf8'),
121
+ })), sensitiveValues, message);
122
+ }
86
123
  function findSensitiveTokenMatches(value, sensitiveValue, startLimit) {
87
124
  if (sensitiveValue === '')
88
125
  return [];
89
- if (sensitiveValue.length >= 8 && !/^(?:true|false|-?\d+(?:\.\d+)?)$/u.test(sensitiveValue)) {
90
- const matches = [];
91
- for (let start = value.indexOf(sensitiveValue); start >= 0 && start < startLimit; start = value.indexOf(sensitiveValue, start + 1)) {
92
- matches.push({ start, end: start + sensitiveValue.length });
93
- }
94
- return matches;
95
- }
96
- const escaped = sensitiveValue.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
97
- const numeric = /^-?\d+(?:\.\d+)?$/u.test(sensitiveValue);
98
- const boundary = numeric ? '\\p{L}\\p{N}_.+-' : '\\p{L}\\p{N}_';
99
- const pattern = new RegExp(`(?<![${boundary}])${escaped}(?![${boundary}])`, 'uy');
100
126
  const matches = [];
101
127
  for (let start = value.indexOf(sensitiveValue); start >= 0 && start < startLimit; start = value.indexOf(sensitiveValue, start + 1)) {
102
- pattern.lastIndex = start;
103
- if (pattern.test(value))
104
- matches.push({ start, end: start + sensitiveValue.length });
128
+ matches.push({ start, end: start + sensitiveValue.length });
105
129
  }
106
130
  return matches;
107
131
  }
108
132
  function collectMergedSensitiveTokenMatches(value, sensitiveValues, startLimit) {
109
- const matches = [...new Set(sensitiveValues)]
110
- .filter((sensitiveValue) => sensitiveValue !== '')
111
- .flatMap((sensitiveValue) => findSensitiveTokenMatches(value, sensitiveValue, startLimit))
133
+ const matches = collectSensitiveTokenRepresentations(sensitiveValues)
134
+ .flatMap((representation) => findSensitiveTokenMatches(value, representation, startLimit))
112
135
  .sort((left, right) => left.start - right.start || right.end - left.end);
113
136
  const merged = [];
114
137
  for (const match of matches) {
@@ -141,113 +164,365 @@ export function truncatePluginScriptOutput(value) {
141
164
  export function summarizePluginScriptOutput(value, sensitiveValues) {
142
165
  return redactString(redactSensitiveTokenWindow(value, sensitiveValues, Math.min(value.length, OUTPUT_LIMIT))).trim();
143
166
  }
167
+ function summarizePreApplyFailureOutput(value, roots, sensitiveValues) {
168
+ const summary = redactString(sanitizePreApplyErrorMessage(value, roots, sensitiveValues, Math.min(value.length, OUTPUT_LIMIT))).trim();
169
+ const lines = summary.split('\n').map((line) => line.trim()).filter(Boolean);
170
+ const includesRuntimeStack = lines.some((line) => line.startsWith('file://')
171
+ || line.startsWith('at ')
172
+ || /^Node\.js v/u.test(line));
173
+ if (!includesRuntimeStack)
174
+ return summary;
175
+ return lines.find((line) => /^(?:[A-Za-z]*Error|Error):/u.test(line)) ?? '';
176
+ }
144
177
  function resolveOutputCaptureLimit(sensitiveValues) {
145
- const maxSensitiveTokenLength = sensitiveValues.reduce((maximum, value) => Math.max(maximum, value.length), 0);
146
- // One Unicode code point can require two UTF-16 code units for the trailing token-boundary check.
147
- return OUTPUT_LIMIT + maxSensitiveTokenLength + TOKEN_BOUNDARY_LOOKAHEAD;
148
- }
149
- export const defaultPluginProcessRunner = {
150
- run(invocation, options) {
151
- return new Promise((resolve, reject) => {
152
- options.signal?.throwIfAborted();
153
- const marker = randomUUID();
154
- const child = spawn(invocation.command, invocation.args, { cwd: invocation.cwd, env: { ...invocation.env, AW_NATIVE_CLI_PROCESS_MARKER: marker }, shell: false, stdio: ['pipe', 'pipe', 'pipe'] });
155
- child.stdin?.end(invocation.stdin ?? '');
156
- let stdout = '';
157
- let stderr = '';
158
- let timedOut = false;
159
- let aborted = false;
160
- let settled = false;
161
- let terminating = false;
162
- const outputCaptureLimit = resolveOutputCaptureLimit(options.sensitiveValues ?? []);
163
- let observation;
164
- if (child.pid !== undefined)
165
- observation = observeProcessTree(child.pid, marker);
166
- const timer = setTimeout(() => { timedOut = true; terminate(); }, options.timeoutMs);
167
- const abort = () => { aborted = true; terminate(); };
168
- const cleanup = () => { clearTimeout(timer); options.signal?.removeEventListener('abort', abort); observation?.dispose(); };
169
- const settle = () => { if (settled)
170
- return; settled = true; cleanup(); if (aborted) {
171
- try {
172
- options.signal?.throwIfAborted();
173
- }
174
- catch (error) {
178
+ const maxSensitiveTokenLength = collectSensitiveTokenRepresentations(sensitiveValues).reduce((maximum, value) => Math.max(maximum, value.length), 0);
179
+ return OUTPUT_LIMIT + maxSensitiveTokenLength;
180
+ }
181
+ function privateRootVariants(root) {
182
+ const normalized = path.resolve(root);
183
+ return [...new Set([
184
+ normalized,
185
+ normalized.replaceAll('\\', '/'),
186
+ ...(normalized.startsWith('/var/') ? [`/private${normalized}`] : []),
187
+ ...(normalized.startsWith('/private/var/') ? [normalized.slice('/private'.length)] : []),
188
+ ])];
189
+ }
190
+ function sanitizePreApplyErrorMessage(value, roots, sensitiveValues, windowEnd = value.length) {
191
+ const matches = [
192
+ ...roots
193
+ .filter(({ root }) => root.trim() !== '')
194
+ .flatMap(({ root, replacement }) => privateRootVariants(root)
195
+ .flatMap((variant) => findSensitiveTokenMatches(value, variant, windowEnd)
196
+ .map((match) => ({ ...match, replacement })))),
197
+ ...collectSensitiveTokenRepresentations(sensitiveValues)
198
+ .flatMap((representation) => findSensitiveTokenMatches(value, representation, windowEnd)
199
+ .map((match) => ({ ...match, replacement: '[REDACTED]' }))),
200
+ ].sort((left, right) => left.start - right.start || right.end - left.end);
201
+ const merged = [];
202
+ for (const match of matches) {
203
+ const previous = merged.at(-1);
204
+ if (previous && match.start < previous.end) {
205
+ previous.end = Math.max(previous.end, match.end);
206
+ }
207
+ else {
208
+ merged.push({ ...match, replacement: match.replacement ?? '[REDACTED]' });
209
+ }
210
+ }
211
+ let output = '';
212
+ let offset = 0;
213
+ for (const match of merged) {
214
+ output += `${value.slice(offset, match.start)}${match.replacement}`;
215
+ offset = Math.min(match.end, windowEnd);
216
+ }
217
+ return output + value.slice(offset, windowEnd);
218
+ }
219
+ export function createDefaultPluginProcessRunner(dependencies = {}) {
220
+ const platform = dependencies.platform ?? process.platform;
221
+ const spawnImpl = dependencies.spawn ?? spawn;
222
+ const observeProcessTreeImpl = dependencies.observeProcessTree ?? observeProcessTree;
223
+ const terminateProcessTreeImpl = dependencies.terminateProcessTree ?? terminateProcessTree;
224
+ const createWindowsJobInvocationImpl = dependencies.createWindowsJobInvocation ??
225
+ (dependencies.spawn ? undefined : createWindowsJobInvocation);
226
+ return {
227
+ run(invocation, options) {
228
+ return new Promise((resolve, reject) => {
229
+ options.signal?.throwIfAborted();
230
+ const marker = randomUUID();
231
+ const windowsJobInvocation = platform === 'win32' && createWindowsJobInvocationImpl
232
+ ? createWindowsJobInvocationImpl(invocation.command, invocation.args)
233
+ : undefined;
234
+ const child = spawnImpl(windowsJobInvocation?.command ?? invocation.command, windowsJobInvocation?.args ?? invocation.args, { cwd: invocation.cwd, env: { ...invocation.env, AW_NATIVE_CLI_PROCESS_MARKER: marker }, shell: false, stdio: ['pipe', 'pipe', 'pipe'], detached: platform !== 'win32' });
235
+ let stdout = '';
236
+ let stderr = '';
237
+ let timedOut = false;
238
+ let aborted = false;
239
+ let settled = false;
240
+ let terminating = false;
241
+ let inputCompleted = child.stdin === null;
242
+ let inputError;
243
+ let childExited = false;
244
+ let cleanupCompleted = false;
245
+ let completedExitCode = null;
246
+ let completedSignal = null;
247
+ let windowsJobCloseTimer;
248
+ const outputCaptureLimit = resolveOutputCaptureLimit(options.sensitiveValues ?? []);
249
+ let observation;
250
+ if (!windowsJobInvocation && child.pid !== undefined)
251
+ observation = observeProcessTreeImpl(child.pid, marker);
252
+ const timer = setTimeout(() => { timedOut = true; terminate(); }, options.timeoutMs);
253
+ const abort = () => { aborted = true; terminate(); };
254
+ const cleanup = () => { clearTimeout(timer); if (windowsJobCloseTimer)
255
+ clearTimeout(windowsJobCloseTimer); options.signal?.removeEventListener('abort', abort); observation?.dispose(); };
256
+ const result = () => ({ exitCode: completedExitCode, signal: completedSignal, stdout, stderr, timedOut });
257
+ const settleImmediately = (error) => {
258
+ if (settled)
259
+ return;
260
+ settled = true;
261
+ cleanup();
175
262
  reject(error);
176
- return;
263
+ };
264
+ const settleIfComplete = () => {
265
+ if (settled || !childExited || !cleanupCompleted || !inputCompleted)
266
+ return;
267
+ settled = true;
268
+ cleanup();
269
+ if (aborted) {
270
+ try {
271
+ options.signal?.throwIfAborted();
272
+ }
273
+ catch (error) {
274
+ reject(error);
275
+ return;
276
+ }
277
+ }
278
+ if (inputError && !(inputError.code === 'EPIPE'
279
+ && completedExitCode === 0
280
+ && completedSignal === null) && !timedOut && completedExitCode === 0 && completedSignal === null) {
281
+ reject(new PluginProcessInputError(inputError));
282
+ return;
283
+ }
284
+ resolve(result());
285
+ };
286
+ function terminate(requireConfirmedCleanup = false, allowUnobservedWindowsProcessOnNormalCompletion = false) {
287
+ if (settled || terminating)
288
+ return;
289
+ terminating = true;
290
+ clearTimeout(timer);
291
+ const direct = (signal) => { if (child.exitCode === null && child.signalCode === null)
292
+ child.kill(signal); };
293
+ if (windowsJobInvocation) {
294
+ try {
295
+ if (child.exitCode === null && child.signalCode === null && child.kill('SIGKILL') === false) {
296
+ throw new Error('Windows Job helper did not accept termination.');
297
+ }
298
+ }
299
+ catch (error) {
300
+ settleImmediately(error);
301
+ return;
302
+ }
303
+ windowsJobCloseTimer = setTimeout(() => settleImmediately(new Error('Windows Job helper exit could not be confirmed.')), WINDOWS_JOB_CLOSE_TIMEOUT_MS);
304
+ windowsJobCloseTimer.unref();
305
+ return;
306
+ }
307
+ const termination = child.pid === undefined
308
+ ? Promise.resolve(direct('SIGKILL'))
309
+ : terminateProcessTreeImpl(child.pid, direct, {}, {
310
+ observation,
311
+ requireConfirmedCleanup,
312
+ ...(allowUnobservedWindowsProcessOnNormalCompletion
313
+ ? { allowUnobservedWindowsProcessOnNormalCompletion: true }
314
+ : {}),
315
+ });
316
+ void Promise.resolve(termination).then(() => { cleanupCompleted = true; settleIfComplete(); }, (error) => settleImmediately(error));
177
317
  }
178
- } resolve({ exitCode: child.exitCode, signal: child.signalCode, stdout, stderr, timedOut }); };
179
- function terminate() {
180
- if (settled || terminating)
181
- return;
182
- terminating = true;
183
- const direct = (signal) => { if (child.exitCode === null && child.signalCode === null)
184
- child.kill(signal); };
185
- const termination = child.pid === undefined ? Promise.resolve(direct('SIGKILL')) : terminateProcessTree(child.pid, direct, {}, { observation });
186
- void Promise.resolve(termination).then(settle, settle);
187
- }
188
- child.stdout?.setEncoding('utf8');
189
- child.stderr?.setEncoding('utf8');
190
- child.stdout?.on('data', (chunk) => { if (stdout.length < outputCaptureLimit)
191
- stdout += chunk.slice(0, outputCaptureLimit - stdout.length); });
192
- child.stderr?.on('data', (chunk) => { if (stderr.length < outputCaptureLimit)
193
- stderr += chunk.slice(0, outputCaptureLimit - stderr.length); });
194
- child.on('error', (error) => { if (!settled && !terminating) {
195
- settled = true;
196
- cleanup();
197
- reject(error);
198
- } });
199
- child.on('close', (exitCode, signal) => { if (!settled && !terminating) {
200
- settled = true;
201
- cleanup();
202
- resolve({ exitCode, signal, stdout, stderr, timedOut });
203
- } });
204
- options.signal?.addEventListener('abort', abort, { once: true });
205
- if (options.signal?.aborted)
206
- abort();
207
- });
208
- },
209
- };
210
- export async function runPostApplyScript(options) {
211
- const declaration = options.plugin.manifest.scripts?.postApply;
318
+ child.stdout?.setEncoding('utf8');
319
+ child.stderr?.setEncoding('utf8');
320
+ child.stdout?.on('data', (chunk) => { if (stdout.length < outputCaptureLimit)
321
+ stdout += chunk.slice(0, outputCaptureLimit - stdout.length); });
322
+ child.stderr?.on('data', (chunk) => { if (stderr.length < outputCaptureLimit)
323
+ stderr += chunk.slice(0, outputCaptureLimit - stderr.length); });
324
+ child.on('error', (error) => { if (!settled && (!terminating || windowsJobInvocation))
325
+ settleImmediately(error); });
326
+ const complete = (exitCode, signal) => {
327
+ if (settled)
328
+ return;
329
+ childExited = true;
330
+ completedExitCode = exitCode;
331
+ completedSignal = signal;
332
+ if (windowsJobInvocation) {
333
+ cleanupCompleted = true;
334
+ settleIfComplete();
335
+ return;
336
+ }
337
+ if (terminating) {
338
+ settleIfComplete();
339
+ return;
340
+ }
341
+ terminate(true, platform === 'win32' && exitCode === 0 && signal === null);
342
+ };
343
+ child.on(platform === 'win32' ? 'close' : 'exit', complete);
344
+ if (child.stdin) {
345
+ const completeInput = (error) => {
346
+ if (error !== undefined && error !== null)
347
+ inputError = error;
348
+ inputCompleted = true;
349
+ settleIfComplete();
350
+ };
351
+ child.stdin.once('error', completeInput);
352
+ child.stdin.once('finish', completeInput);
353
+ try {
354
+ child.stdin.end(invocation.stdin ?? '', completeInput);
355
+ }
356
+ catch (error) {
357
+ completeInput(error);
358
+ }
359
+ }
360
+ options.signal?.addEventListener('abort', abort, { once: true });
361
+ if (options.signal?.aborted)
362
+ abort();
363
+ });
364
+ },
365
+ };
366
+ }
367
+ export const defaultPluginProcessRunner = createDefaultPluginProcessRunner();
368
+ export async function runPreApplyScript(options) {
369
+ const declaration = options.plugin.manifest.scripts?.preApply;
212
370
  if (!declaration)
213
371
  return;
214
- const entryPath = await resolveBundledPluginFilePath({ bundleRoot: options.plugin.rootDir, pluginRelativePath: declaration.path, fieldName: 'postApply script' });
215
- const effective = options.plugin.manifest.config?.fields
216
- ? await resolveEffectivePluginConfig({ sourceId: options.plugin.sourceId, sourceIdentity: options.plugin.sourceIdentity, pluginName: options.plugin.manifest.name, manifest: options.plugin.manifest, targetScope: options.scope, cwd: options.cwd, env: options.context.env })
217
- : { values: {}, issues: [] };
218
- if (effective.issues.length > 0)
219
- throw new Error(`postApply config is invalid for ${options.plugin.manifest.name}.`);
220
- const payload = {
221
- schemaVersion: 1,
222
- plugin: { pluginId: options.plugin.pluginId ?? `${options.plugin.sourceId}/${options.plugin.manifest.name}`, name: options.plugin.manifest.name, version: options.plugin.manifest.version, rootDir: options.plugin.rootDir },
223
- target: { platform: options.platform, scope: options.scope, ...(options.scope === 'project' ? { projectRoot: options.cwd } : {}) },
224
- config: { values: effective.values },
225
- components: options.components ?? (options.artifacts.length === 0
226
- ? [{ kind: 'target', key: `${options.platform}:${options.scope}`, outcome: 'unchanged' }]
227
- : options.artifacts.map((artifact) => ({ kind: artifact.kind, key: artifact.artifactKey ?? artifact.id ?? artifact.path, outcome: artifact.state === 'disabled' ? 'removed' : 'updated' }))),
228
- };
229
- const tempRoot = assertTestWritablePath(path.join(resolveAwHome(options.context.env), 'tmp'), 'postApply temp root');
230
- await fs.ensureDir(tempRoot);
231
- const tempDir = await fs.mkdtemp(path.join(tempRoot, 'plugin-post-apply-'));
372
+ const awHome = resolveAwHome(options.context.env);
373
+ const codexHome = options.context.env.AW_CODEX_HOME || path.join(awHome, 'isolated-codex-home');
374
+ const claudeHome = options.context.env.AW_CLAUDE_HOME || path.join(awHome, 'isolated-claude-home');
375
+ let tempDir;
376
+ let interruptSignal;
377
+ let interruptReason;
378
+ let sensitiveValues = [];
379
+ let runnerCleanupConfirmed = false;
380
+ let removeInterruptListeners;
381
+ const privateRoots = () => [
382
+ ...(tempDir ? [
383
+ { root: path.join(tempDir, 'home'), replacement: '[temporary-home]' },
384
+ { root: path.join(tempDir, 'tmp'), replacement: '[temporary]' },
385
+ { root: tempDir, replacement: '[temporary]' },
386
+ ] : []),
387
+ { root: codexHome, replacement: '[codex-home]' },
388
+ { root: claudeHome, replacement: '[claude-home]' },
389
+ { root: awHome, replacement: '[aw-home]' },
390
+ { root: options.plugin.rootDir, replacement: '[plugin-root]' },
391
+ { root: options.cwd, replacement: '[project-root]' },
392
+ ];
232
393
  try {
394
+ const entryPath = await resolveBundledPluginFilePath({ bundleRoot: options.plugin.rootDir, pluginRelativePath: declaration.path, fieldName: 'preApply script' });
395
+ const effective = options.plugin.manifest.config?.fields
396
+ ? await resolveEffectivePluginConfig({ sourceId: options.plugin.sourceId, sourceIdentity: options.plugin.sourceIdentity, logicalIdentity: options.plugin.catalogLogicalIdentity, pluginName: options.plugin.manifest.name, manifest: options.plugin.manifest, targetScope: options.scope, cwd: options.cwd, env: options.context.env })
397
+ : { values: {}, issues: [] };
398
+ if (effective.issues.length > 0)
399
+ throw new Error(`preApply config is invalid for ${options.plugin.manifest.name}.`);
400
+ const payload = {
401
+ schemaVersion: 1,
402
+ plugin: { pluginId: options.plugin.pluginId ?? `${options.plugin.sourceId}/${options.plugin.manifest.name}`, name: options.plugin.manifest.name, version: options.plugin.manifest.version, rootDir: options.plugin.rootDir },
403
+ target: { platform: options.platform, scope: options.scope, ...(options.scope === 'project' ? { projectRoot: options.cwd } : {}) },
404
+ config: { values: effective.values },
405
+ };
406
+ const tempRoot = assertTestWritablePath(path.join(awHome, 'tmp'), 'preApply temp root');
407
+ await fs.ensureDir(tempRoot);
408
+ tempDir = await fs.mkdtemp(path.join(tempRoot, 'plugin-pre-apply-'));
233
409
  await fs.ensureDir(path.join(tempDir, 'home'));
234
410
  await fs.ensureDir(path.join(tempDir, 'tmp'));
235
- const env = buildPluginScriptSpawnEnv({ commandEnv: options.context.env, contextPath: '', tempDir, plugin: payload.plugin, event: 'postApply', platform: options.platform, scope: options.scope, bundleRoot: options.plugin.rootDir });
411
+ const env = buildPluginScriptSpawnEnv({ commandEnv: options.context.env, contextPath: '', tempDir, plugin: payload.plugin, event: 'preApply', platform: options.platform, scope: options.scope, bundleRoot: options.plugin.rootDir });
236
412
  delete env.AW_PLUGIN_CONTEXT;
237
- const sensitiveValues = collectSensitivePluginConfigValues(options.plugin.manifest, effective.values);
413
+ sensitiveValues = collectSensitivePluginConfigValues(options.plugin.manifest, effective.values);
238
414
  const invocation = buildNodeScriptInvocation({ entryPath, cwd: options.plugin.rootDir, env, stdin: `${JSON.stringify(payload)}\n` });
239
415
  const runOptions = { timeoutMs: resolvePluginScriptTimeoutMs({ cliTimeoutMs: options.scriptTimeoutMs, manifestTimeoutMs: declaration.timeoutMs }) };
240
- const result = options.runner
241
- ? await options.runner.run(invocation, runOptions)
242
- : await defaultPluginProcessRunner.run(invocation, { ...runOptions, sensitiveValues });
243
- const stderr = summarizePluginScriptOutput(result.stderr, sensitiveValues);
416
+ const interruptController = new AbortController();
417
+ const handleInterrupt = (signal) => {
418
+ if (interruptSignal)
419
+ return;
420
+ interruptSignal = signal;
421
+ interruptReason = new Error(`preApply interrupted by ${signal}.`);
422
+ interruptController.abort(interruptReason);
423
+ };
424
+ const handleSigint = () => handleInterrupt('SIGINT');
425
+ const handleSigterm = () => handleInterrupt('SIGTERM');
426
+ process.on('SIGINT', handleSigint);
427
+ process.on('SIGTERM', handleSigterm);
428
+ removeInterruptListeners = () => {
429
+ process.removeListener('SIGINT', handleSigint);
430
+ process.removeListener('SIGTERM', handleSigterm);
431
+ };
432
+ let result;
433
+ try {
434
+ result = options.runner
435
+ ? await options.runner.run(invocation, { ...runOptions, signal: interruptController.signal })
436
+ : await defaultPluginProcessRunner.run(invocation, { ...runOptions, sensitiveValues, signal: interruptController.signal });
437
+ runnerCleanupConfirmed = true;
438
+ }
439
+ catch (error) {
440
+ if (interruptSignal && error === interruptReason) {
441
+ runnerCleanupConfirmed = true;
442
+ }
443
+ else if (interruptSignal) {
444
+ throw new Error(`preApply process cleanup failed after ${interruptSignal}.`);
445
+ }
446
+ else if (error instanceof PluginProcessInputError) {
447
+ throw attachSafeOperationError(new Error('preApply input could not be sent.'), {
448
+ code: 'preApplyInputFailed',
449
+ stage: 'preApply',
450
+ safeMessage: 'The preApply context could not be sent to the process.',
451
+ });
452
+ }
453
+ else {
454
+ const causeCode = error && typeof error === 'object' && 'code' in error
455
+ && typeof error.code === 'string' ? error.code : undefined;
456
+ const safeCauseCode = causeCode === 'ENOENT' || causeCode === 'EACCES' || causeCode === 'EPERM'
457
+ ? causeCode : undefined;
458
+ throw attachSafeOperationError(new Error('preApply could not start.'), {
459
+ code: safeCauseCode === 'ENOENT' ? 'preApplyExecutableMissing' : 'preApplyStartFailed',
460
+ stage: 'preApply',
461
+ safeMessage: causeCode === 'ENOENT'
462
+ ? 'The preApply executable is not available.'
463
+ : 'The preApply process could not start.',
464
+ ...(safeCauseCode ? {
465
+ cause: { code: safeCauseCode, safeMessage: `Process start failed (${safeCauseCode}).` },
466
+ } : {}),
467
+ });
468
+ }
469
+ }
470
+ if (!result)
471
+ return;
472
+ const stdout = summarizePreApplyFailureOutput(result.stdout, privateRoots(), sensitiveValues);
473
+ const stderr = summarizePreApplyFailureOutput(result.stderr, privateRoots(), sensitiveValues);
474
+ const output = [
475
+ ...(stdout ? [`stdout: ${stdout}`] : []),
476
+ ...(stderr ? [`stderr: ${stderr}`] : []),
477
+ ].join('; ');
244
478
  if (result.timedOut)
245
- throw new Error(`postApply timed out. stderr: ${stderr}`);
246
- if (result.exitCode !== 0)
247
- throw new Error(`postApply failed with exit code ${result.exitCode}. stderr: ${stderr}`);
479
+ throw attachSafeOperationError(new Error(`preApply timed out.${output ? ` ${output}` : ''}`), {
480
+ code: 'preApplyTimedOut',
481
+ stage: 'preApply',
482
+ safeMessage: 'The preApply process timed out.',
483
+ exitCode: 124,
484
+ });
485
+ if (result.exitCode !== 0) {
486
+ throw attachSafeOperationError(new Error(`preApply failed with exit code ${result.exitCode}.${output ? ` ${output}` : ''}`), {
487
+ code: 'preApplyExited',
488
+ stage: 'preApply',
489
+ safeMessage: 'The preApply process exited unsuccessfully.',
490
+ ...(result.exitCode === null ? {} : { exitCode: result.exitCode }),
491
+ });
492
+ }
493
+ }
494
+ catch (error) {
495
+ const message = error instanceof Error ? error.message : String(error);
496
+ const failure = new Error(redactString(sanitizePreApplyErrorMessage(message, privateRoots(), sensitiveValues)));
497
+ const diagnostic = error && typeof error === 'object' && 'operationDiagnostic' in error
498
+ ? error.operationDiagnostic
499
+ : undefined;
500
+ throw diagnostic ? Object.assign(failure, { operationDiagnostic: diagnostic }) : failure;
248
501
  }
249
502
  finally {
250
- await fs.remove(tempDir);
503
+ let tempCleanupError;
504
+ try {
505
+ if (tempDir)
506
+ await fs.remove(tempDir);
507
+ }
508
+ catch (error) {
509
+ tempCleanupError = error;
510
+ }
511
+ removeInterruptListeners?.();
512
+ if (interruptSignal) {
513
+ if (tempCleanupError) {
514
+ process.stderr.write(`preApply temporary directory cleanup failed after ${interruptSignal}.\n`);
515
+ process.exit(1);
516
+ }
517
+ if (!runnerCleanupConfirmed) {
518
+ process.stderr.write(`preApply process cleanup failed after ${interruptSignal}.\n`);
519
+ process.exit(1);
520
+ }
521
+ process.exit(interruptSignal === 'SIGINT' ? 130 : 143);
522
+ }
523
+ if (tempCleanupError) {
524
+ throw tempCleanupError;
525
+ }
251
526
  }
252
527
  }
253
528
  //# sourceMappingURL=plugin-scripts.js.map