@askexenow/exe-os 0.9.69 → 0.9.70

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 (75) hide show
  1. package/deploy/stack-manifests/v0.9.json +96 -16
  2. package/dist/bin/agentic-ontology-backfill.js +6 -0
  3. package/dist/bin/agentic-reflection-backfill.js +6 -0
  4. package/dist/bin/agentic-semantic-label.js +6 -0
  5. package/dist/bin/backfill-conversations.js +6 -0
  6. package/dist/bin/backfill-responses.js +6 -0
  7. package/dist/bin/backfill-vectors.js +6 -0
  8. package/dist/bin/bulk-sync-postgres.js +6 -0
  9. package/dist/bin/cleanup-stale-review-tasks.js +6 -0
  10. package/dist/bin/cli.js +1257 -178
  11. package/dist/bin/exe-agent.js +6 -0
  12. package/dist/bin/exe-assign.js +6 -0
  13. package/dist/bin/exe-boot.js +6 -0
  14. package/dist/bin/exe-call.js +6 -0
  15. package/dist/bin/exe-cloud.js +6 -0
  16. package/dist/bin/exe-dispatch.js +6 -0
  17. package/dist/bin/exe-doctor.js +6 -0
  18. package/dist/bin/exe-export-behaviors.js +6 -0
  19. package/dist/bin/exe-forget.js +6 -0
  20. package/dist/bin/exe-gateway.js +151 -110
  21. package/dist/bin/exe-heartbeat.js +6 -0
  22. package/dist/bin/exe-kill.js +6 -0
  23. package/dist/bin/exe-launch-agent.js +6 -0
  24. package/dist/bin/exe-new-employee.js +6 -0
  25. package/dist/bin/exe-pending-messages.js +6 -0
  26. package/dist/bin/exe-pending-notifications.js +6 -0
  27. package/dist/bin/exe-pending-reviews.js +6 -0
  28. package/dist/bin/exe-rename.js +13 -4
  29. package/dist/bin/exe-review.js +6 -0
  30. package/dist/bin/exe-search.js +6 -0
  31. package/dist/bin/exe-session-cleanup.js +6 -0
  32. package/dist/bin/exe-start-codex.js +6 -0
  33. package/dist/bin/exe-start-opencode.js +6 -0
  34. package/dist/bin/exe-status.js +6 -0
  35. package/dist/bin/exe-team.js +6 -0
  36. package/dist/bin/git-sweep.js +6 -0
  37. package/dist/bin/graph-backfill.js +150 -110
  38. package/dist/bin/graph-export.js +6 -0
  39. package/dist/bin/intercom-check.js +6 -0
  40. package/dist/bin/registry-proxy.js +207 -0
  41. package/dist/bin/scan-tasks.js +6 -0
  42. package/dist/bin/setup.js +6 -0
  43. package/dist/bin/shard-migrate.js +6 -0
  44. package/dist/bin/stack-update.js +128 -0
  45. package/dist/gateway/index.js +151 -110
  46. package/dist/hooks/bug-report-worker.js +6 -0
  47. package/dist/hooks/codex-stop-task-finalizer.js +6 -0
  48. package/dist/hooks/commit-complete.js +6 -0
  49. package/dist/hooks/error-recall.js +6 -0
  50. package/dist/hooks/ingest.js +6 -0
  51. package/dist/hooks/instructions-loaded.js +6 -0
  52. package/dist/hooks/notification.js +6 -0
  53. package/dist/hooks/post-compact.js +6 -0
  54. package/dist/hooks/post-tool-combined.js +6 -0
  55. package/dist/hooks/pre-compact.js +6 -0
  56. package/dist/hooks/pre-tool-use.js +6 -0
  57. package/dist/hooks/prompt-submit.js +6 -0
  58. package/dist/hooks/session-end.js +6 -0
  59. package/dist/hooks/session-start.js +6 -0
  60. package/dist/hooks/stop.js +6 -0
  61. package/dist/hooks/subagent-stop.js +6 -0
  62. package/dist/hooks/summary-worker.js +6 -0
  63. package/dist/index.js +151 -110
  64. package/dist/lib/employee-templates.js +6 -0
  65. package/dist/lib/exe-daemon.js +382 -234
  66. package/dist/lib/hybrid-search.js +6 -0
  67. package/dist/lib/registry-proxy.js +162 -0
  68. package/dist/lib/schedules.js +6 -0
  69. package/dist/lib/store.js +6 -0
  70. package/dist/mcp/server.js +318 -222
  71. package/dist/runtime/index.js +6 -0
  72. package/dist/tui/App.js +6 -0
  73. package/package.json +3 -2
  74. package/stack.release.json +6 -4
  75. package/stack.release.schema.json +89 -18
@@ -7912,6 +7912,12 @@ var init_platform_procedures = __esm({
7912
7912
  priority: "p0",
7913
7913
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
7914
7914
  },
7915
+ {
7916
+ title: "Code context first for repository orientation",
7917
+ domain: "workflow",
7918
+ priority: "p1",
7919
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
7920
+ },
7915
7921
  {
7916
7922
  title: "Commit discipline \u2014 never leave verified work floating",
7917
7923
  domain: "workflow",
package/dist/bin/setup.js CHANGED
@@ -6411,6 +6411,12 @@ var init_platform_procedures = __esm({
6411
6411
  priority: "p0",
6412
6412
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
6413
6413
  },
6414
+ {
6415
+ title: "Code context first for repository orientation",
6416
+ domain: "workflow",
6417
+ priority: "p1",
6418
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
6419
+ },
6414
6420
  {
6415
6421
  title: "Commit discipline \u2014 never leave verified work floating",
6416
6422
  domain: "workflow",
@@ -3353,6 +3353,12 @@ var init_platform_procedures = __esm({
3353
3353
  priority: "p0",
3354
3354
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
3355
3355
  },
3356
+ {
3357
+ title: "Code context first for repository orientation",
3358
+ domain: "workflow",
3359
+ priority: "p1",
3360
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
3361
+ },
3356
3362
  {
3357
3363
  title: "Commit discipline \u2014 never leave verified work floating",
3358
3364
  domain: "workflow",
@@ -150,6 +150,102 @@ function createStackUpdatePlan(manifest, envRaw, targetVersion) {
150
150
  breakingChanges: release.breakingChanges ?? []
151
151
  };
152
152
  }
153
+ var ASKEXE_GHCR_IMAGE = /^(?:ghcr\.io\/askexe|registry\.askexe\.com\/askexe)\/[a-z0-9._/-]+(?::[^:@$/{]+|@sha256:[a-f0-9]{64})$/i;
154
+ function validatePinnedGhcrImage(image, label) {
155
+ const trimmed = image.trim().replace(/^['"]|['"]$/g, "");
156
+ if (!trimmed) return `${label} is empty`;
157
+ if (trimmed.includes("${")) return null;
158
+ if (!trimmed.startsWith("ghcr.io/askexe/") && !trimmed.startsWith("registry.askexe.com/askexe/")) return `${label} must use ghcr.io/askexe/* or registry.askexe.com/askexe/*, got ${trimmed}`;
159
+ if (/:latest(?:$|[\s#])/.test(trimmed)) return `${label} must not use :latest (${trimmed})`;
160
+ if (!ASKEXE_GHCR_IMAGE.test(trimmed)) return `${label} must be pinned with an explicit tag or sha256 digest from ghcr.io/askexe or registry.askexe.com/askexe, got ${trimmed}`;
161
+ return null;
162
+ }
163
+ function validateComposeImageLiteral(image, label) {
164
+ const trimmed = image.trim().replace(/^['"]|['"]$/g, "");
165
+ if (!trimmed) return `${label} is empty`;
166
+ if (trimmed.startsWith("ghcr.io/askexe/") || trimmed.startsWith("registry.askexe.com/askexe/")) return validatePinnedGhcrImage(trimmed, label);
167
+ if (/^(postgres|pgvector\/pgvector|clickhouse\/clickhouse-server|redis|nginx|postgrest\/postgrest|supabase\/gotrue):[^:]+$/i.test(trimmed)) return null;
168
+ return `${label} uses unsupported non-AskExe image ${trimmed}; customer app images must come from pinned ghcr.io/askexe images`;
169
+ }
170
+ function collectProductionDeployGateIssues(plan, envRaw, composeRaw) {
171
+ const issues = [];
172
+ const env = parseEnv(envRaw);
173
+ for (const [serviceName, service] of Object.entries(plan.release.services)) {
174
+ const manifestIssue = validatePinnedGhcrImage(service.image, `manifest ${plan.targetVersion}.${serviceName}.image`);
175
+ if (manifestIssue) issues.push({ kind: "manifest-image", message: manifestIssue });
176
+ const envImage = env.get(service.env);
177
+ if (envImage) {
178
+ const envIssue = validatePinnedGhcrImage(envImage, `env ${service.env}`);
179
+ if (envIssue) issues.push({ kind: "env-image", message: envIssue });
180
+ }
181
+ }
182
+ const lines = composeRaw.split(/\r?\n/);
183
+ lines.forEach((line, index) => {
184
+ if (/^\s*build\s*:/.test(line)) {
185
+ issues.push({ kind: "compose-build", message: `compose line ${index + 1} contains build:, production deploys must pull images` });
186
+ }
187
+ const imageMatch = line.match(/^\s*image\s*:\s*(.+?)\s*(?:#.*)?$/);
188
+ if (imageMatch) {
189
+ const image = imageMatch[1].trim();
190
+ if (image.includes("${")) {
191
+ const fallback = image.match(/:-([^}]+)}/)?.[1];
192
+ if (fallback) {
193
+ const composeIssue = validateComposeImageLiteral(fallback, `compose image fallback on line ${index + 1}`);
194
+ if (composeIssue) issues.push({ kind: "compose-image", message: composeIssue });
195
+ }
196
+ } else {
197
+ const composeIssue = validateComposeImageLiteral(image, `compose image on line ${index + 1}`);
198
+ if (composeIssue) issues.push({ kind: "compose-image", message: composeIssue });
199
+ }
200
+ }
201
+ });
202
+ return issues;
203
+ }
204
+ function assertDeploymentScopeAllowed(plan, persona = "customer") {
205
+ if (persona === "askexe-control-plane") return;
206
+ const blocked = Object.entries(plan.release.services).filter(([, service]) => service.deploymentScope === "askexe-control-plane").map(([name]) => name);
207
+ if (blocked.length > 0) {
208
+ throw new Error(
209
+ `Customer deployment manifest includes AskExe control-plane service(s): ${blocked.join(", ")}. Customer VPSs may deploy customer services and optional agents only.`
210
+ );
211
+ }
212
+ }
213
+ function assertProductionDeployGate(plan, envRaw, composeRaw, options = {}) {
214
+ const issues = collectProductionDeployGateIssues(plan, envRaw, composeRaw);
215
+ if (issues.length === 0) return;
216
+ if (options.breakGlassReason?.trim()) {
217
+ writeBreakGlassAudit(plan, issues, options);
218
+ return;
219
+ }
220
+ const details = issues.map((issue) => `- [${issue.kind}] ${issue.message}`).join("\n");
221
+ throw new Error(
222
+ `Production deploy gate failed. Exe OS deploys must use pinned ghcr.io/askexe or registry.askexe.com/askexe images and must not build from source on the VPS.
223
+ ${details}
224
+ Emergency override requires --break-glass <reason> and writes an audit file.`
225
+ );
226
+ }
227
+ function writeBreakGlassAudit(plan, issues, options) {
228
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
229
+ const stamp = now().toISOString().replace(/[:.]/g, "-");
230
+ const defaultDir = existsSync("exe/output") ? "exe/output" : path.dirname(options.envFile ?? ".");
231
+ const auditFile = options.breakGlassAuditFile ?? path.join(defaultDir, `stack-update-break-glass-${stamp}.md`);
232
+ mkdirSync(path.dirname(auditFile), { recursive: true });
233
+ const body = [
234
+ `# Stack Update Break-Glass Audit \u2014 ${now().toISOString()}`,
235
+ "",
236
+ `Target version: ${plan.targetVersion}`,
237
+ `Reason: ${options.breakGlassReason?.trim()}`,
238
+ "",
239
+ "## Gate failures overridden",
240
+ ...issues.map((issue) => `- [${issue.kind}] ${issue.message}`),
241
+ "",
242
+ "## Required follow-up",
243
+ "Return this deployment to the standard pinned GHCR image path immediately after the emergency is resolved.",
244
+ ""
245
+ ].join("\n");
246
+ writeFileSync(auditFile, body, { mode: 384 });
247
+ console.warn(`[stack-update] BREAK-GLASS deploy override recorded: ${auditFile}`);
248
+ }
153
249
  function assertBreakingChangesAllowed(plan, allowedIds) {
154
250
  const required = plan.breakingChanges.filter((c) => c.requiresConfirmation !== false);
155
251
  const missing = required.filter((c) => !allowedIds.includes(c.id));
@@ -172,6 +268,15 @@ async function runStackUpdate(options) {
172
268
  const envRaw = readFileSync(options.envFile, "utf8");
173
269
  const plan = createStackUpdatePlan(manifest, envRaw, options.targetVersion);
174
270
  assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
271
+ assertDeploymentScopeAllowed(plan, options.deploymentPersona ?? "customer");
272
+ const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
273
+ const composeRaw = readFileSync(options.composeFile, "utf8");
274
+ assertProductionDeployGate(plan, plannedEnvRaw, composeRaw, {
275
+ breakGlassReason: options.breakGlassReason,
276
+ breakGlassAuditFile: options.breakGlassAuditFile,
277
+ now,
278
+ envFile: options.envFile
279
+ });
175
280
  const lockFile = options.lockFile ?? path.join(path.dirname(options.envFile), ".exe-stack-lock.json");
176
281
  const previousVersion = readCurrentStackVersion(lockFile);
177
282
  if (options.dryRun || plan.changes.length === 0) {
@@ -360,6 +465,7 @@ function parseArgs(args) {
360
465
  dryRun: false,
361
466
  check: false,
362
467
  rollback: false,
468
+ deploymentPersona: process.env.EXE_STACK_DEPLOYMENT_PERSONA === "askexe-control-plane" ? "askexe-control-plane" : "customer",
363
469
  yes: false,
364
470
  allowedBreakingChangeIds: []
365
471
  };
@@ -390,6 +496,18 @@ function parseArgs(args) {
390
496
  else if (arg === "--license-key") opts.licenseKey = next();
391
497
  else if (arg.startsWith("--license-key=")) opts.licenseKey = arg.split("=").slice(1).join("=");
392
498
  else if (arg === "--rollback") opts.rollback = true;
499
+ else if (arg === "--deployment-persona") {
500
+ const value = next();
501
+ if (value !== "customer" && value !== "askexe-control-plane") throw new Error(`Invalid --deployment-persona: ${value}`);
502
+ opts.deploymentPersona = value;
503
+ } else if (arg.startsWith("--deployment-persona=")) {
504
+ const value = arg.split("=").slice(1).join("=");
505
+ if (value !== "customer" && value !== "askexe-control-plane") throw new Error(`Invalid --deployment-persona: ${value}`);
506
+ opts.deploymentPersona = value;
507
+ } else if (arg === "--break-glass") opts.breakGlassReason = next();
508
+ else if (arg.startsWith("--break-glass=")) opts.breakGlassReason = arg.split("=").slice(1).join("=");
509
+ else if (arg === "--break-glass-audit-file") opts.breakGlassAuditFile = next();
510
+ else if (arg.startsWith("--break-glass-audit-file=")) opts.breakGlassAuditFile = arg.split("=").slice(1).join("=");
393
511
  else if (arg === "--dry-run") opts.dryRun = true;
394
512
  else if (arg === "--check") opts.check = true;
395
513
  else if (arg === "--yes" || arg === "-y") opts.yes = true;
@@ -427,6 +545,9 @@ Options:
427
545
  --device-id <id> Device ID to include in deploy audit
428
546
  --license-key <key> License key to include in deploy audit
429
547
  --rollback Restore latest backed-up .env and restart stack
548
+ --deployment-persona <customer|askexe-control-plane> Scope gate (default: customer)
549
+ --break-glass <reason> Emergency override for production deploy gate; writes audit file
550
+ --break-glass-audit-file <path> Audit file path for --break-glass
430
551
  --allow-breaking <ids> Confirm breaking changes, comma-separated
431
552
  -y, --yes Non-interactive confirmation
432
553
  `);
@@ -466,6 +587,13 @@ async function main() {
466
587
  const manifest = await loadStackManifest(opts.manifestRef, void 0, opts.manifestPublicKey, opts.manifestAuthToken);
467
588
  const envRaw = readFileSync2(opts.envFile, "utf8");
468
589
  const plan = createStackUpdatePlan(manifest, envRaw, opts.targetVersion);
590
+ assertDeploymentScopeAllowed(plan, opts.deploymentPersona);
591
+ const plannedEnvRaw = patchEnv(envRaw, Object.fromEntries(plan.changes.map((c) => [c.key, c.after])));
592
+ assertProductionDeployGate(plan, plannedEnvRaw, readFileSync2(opts.composeFile, "utf8"), {
593
+ breakGlassReason: opts.breakGlassReason,
594
+ breakGlassAuditFile: opts.breakGlassAuditFile,
595
+ envFile: opts.envFile
596
+ });
469
597
  console.log(`Exe OS stack target: ${plan.targetVersion}`);
470
598
  console.log(`Manifest: ${opts.manifestRef}`);
471
599
  console.log(`Compose: ${opts.composeFile}`);
@@ -4793,6 +4793,12 @@ var init_platform_procedures = __esm({
4793
4793
  priority: "p0",
4794
4794
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4795
4795
  },
4796
+ {
4797
+ title: "Code context first for repository orientation",
4798
+ domain: "workflow",
4799
+ priority: "p1",
4800
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4801
+ },
4796
4802
  {
4797
4803
  title: "Commit discipline \u2014 never leave verified work floating",
4798
4804
  domain: "workflow",
@@ -6151,13 +6157,25 @@ var init_wiki_client = __esm({
6151
6157
 
6152
6158
  // src/lib/code-chunker.ts
6153
6159
  import ts from "typescript";
6160
+ function languageForFile(filePath) {
6161
+ const base = filePath.split(/[\\/]/).pop()?.toLowerCase() ?? "";
6162
+ if (["dockerfile", "makefile", "rakefile", "gemfile"].includes(base)) return base;
6163
+ const ext = base.includes(".") ? base.split(".").pop() : void 0;
6164
+ return ext ? LANGUAGE_BY_EXTENSION[ext] : void 0;
6165
+ }
6154
6166
  function chunkSourceFile(source, fileName = "file.ts") {
6167
+ const language = languageForFile(fileName);
6168
+ if (language === "typescript" || language === "javascript") {
6169
+ return chunkTypeScriptLike(source, fileName);
6170
+ }
6171
+ return chunkGenericSource(source, fileName, language);
6172
+ }
6173
+ function chunkTypeScriptLike(source, fileName) {
6155
6174
  const sourceFile = ts.createSourceFile(
6156
6175
  fileName,
6157
6176
  source,
6158
6177
  ts.ScriptTarget.Latest,
6159
6178
  true,
6160
- // setParentNodes
6161
6179
  fileName.endsWith(".tsx") || fileName.endsWith(".jsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS
6162
6180
  );
6163
6181
  const chunks = [];
@@ -6179,153 +6197,176 @@ function chunkSourceFile(source, fileName = "file.ts") {
6179
6197
  if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
6180
6198
  return node.name?.getText(sourceFile) ?? "(anonymous)";
6181
6199
  }
6182
- if (ts.isClassDeclaration(node)) {
6183
- return node.name?.getText(sourceFile) ?? "(anonymous class)";
6184
- }
6185
- if (ts.isInterfaceDeclaration(node)) {
6186
- return node.name.getText(sourceFile);
6187
- }
6188
- if (ts.isTypeAliasDeclaration(node)) {
6189
- return node.name.getText(sourceFile);
6190
- }
6191
- if (ts.isEnumDeclaration(node)) {
6192
- return node.name.getText(sourceFile);
6193
- }
6194
- if (ts.isVariableStatement(node)) {
6195
- const decls = node.declarationList.declarations;
6196
- return decls.map((d) => d.name.getText(sourceFile)).join(", ");
6197
- }
6198
- if (ts.isExportAssignment(node)) {
6199
- return "default export";
6200
- }
6200
+ if (ts.isClassDeclaration(node)) return node.name?.getText(sourceFile) ?? "(anonymous class)";
6201
+ if (ts.isInterfaceDeclaration(node)) return node.name.getText(sourceFile);
6202
+ if (ts.isTypeAliasDeclaration(node)) return node.name.getText(sourceFile);
6203
+ if (ts.isEnumDeclaration(node)) return node.name.getText(sourceFile);
6204
+ if (ts.isVariableStatement(node)) return node.declarationList.declarations.map((d) => d.name.getText(sourceFile)).join(", ");
6205
+ if (ts.isExportAssignment(node)) return "default export";
6201
6206
  return "(unknown)";
6202
6207
  }
6203
6208
  function visitTopLevel(node) {
6204
6209
  if (ts.isImportDeclaration(node)) {
6205
- importLines.push({
6206
- start: getLineNumber(node.getStart(sourceFile)),
6207
- end: getLineNumber(node.getEnd())
6208
- });
6210
+ importLines.push({ start: getLineNumber(node.getStart(sourceFile)), end: getLineNumber(node.getEnd()) });
6209
6211
  return;
6210
6212
  }
6211
6213
  if (ts.isFunctionDeclaration(node)) {
6212
- chunks.push({
6213
- kind: "function",
6214
- name: getName(node),
6215
- text: getNodeText(node),
6216
- startLine: getLineNumber(node.getStart(sourceFile)),
6217
- endLine: getLineNumber(node.getEnd()),
6218
- comment: getLeadingComment(node)
6219
- });
6214
+ chunks.push({ kind: "function", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
6220
6215
  return;
6221
6216
  }
6222
6217
  if (ts.isClassDeclaration(node)) {
6223
- chunks.push({
6224
- kind: "class",
6225
- name: getName(node),
6226
- text: getNodeText(node),
6227
- startLine: getLineNumber(node.getStart(sourceFile)),
6228
- endLine: getLineNumber(node.getEnd()),
6229
- comment: getLeadingComment(node)
6230
- });
6218
+ chunks.push({ kind: "class", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
6231
6219
  return;
6232
6220
  }
6233
- if (ts.isInterfaceDeclaration(node)) {
6234
- chunks.push({
6235
- kind: "type",
6236
- name: getName(node),
6237
- text: getNodeText(node),
6238
- startLine: getLineNumber(node.getStart(sourceFile)),
6239
- endLine: getLineNumber(node.getEnd()),
6240
- comment: getLeadingComment(node)
6241
- });
6242
- return;
6243
- }
6244
- if (ts.isTypeAliasDeclaration(node)) {
6245
- chunks.push({
6246
- kind: "type",
6247
- name: getName(node),
6248
- text: getNodeText(node),
6249
- startLine: getLineNumber(node.getStart(sourceFile)),
6250
- endLine: getLineNumber(node.getEnd()),
6251
- comment: getLeadingComment(node)
6252
- });
6253
- return;
6254
- }
6255
- if (ts.isEnumDeclaration(node)) {
6256
- chunks.push({
6257
- kind: "type",
6258
- name: getName(node),
6259
- text: getNodeText(node),
6260
- startLine: getLineNumber(node.getStart(sourceFile)),
6261
- endLine: getLineNumber(node.getEnd()),
6262
- comment: getLeadingComment(node)
6263
- });
6221
+ if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node)) {
6222
+ chunks.push({ kind: "type", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
6264
6223
  return;
6265
6224
  }
6266
6225
  if (ts.isVariableStatement(node)) {
6267
- const decls = node.declarationList.declarations;
6268
- const isFnLike = decls.some(
6269
- (d) => d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer))
6270
- );
6271
- chunks.push({
6272
- kind: isFnLike ? "function" : "variable",
6273
- name: getName(node),
6274
- text: getNodeText(node),
6275
- startLine: getLineNumber(node.getStart(sourceFile)),
6276
- endLine: getLineNumber(node.getEnd()),
6277
- comment: getLeadingComment(node)
6278
- });
6226
+ const isFnLike = node.declarationList.declarations.some((d) => d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer)));
6227
+ chunks.push({ kind: isFnLike ? "function" : "variable", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
6279
6228
  return;
6280
6229
  }
6281
6230
  if (ts.isExportAssignment(node)) {
6282
- chunks.push({
6283
- kind: "export",
6284
- name: "default export",
6285
- text: getNodeText(node),
6286
- startLine: getLineNumber(node.getStart(sourceFile)),
6287
- endLine: getLineNumber(node.getEnd()),
6288
- comment: getLeadingComment(node)
6289
- });
6231
+ chunks.push({ kind: "export", name: "default export", text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
6290
6232
  return;
6291
6233
  }
6292
6234
  if (ts.isExpressionStatement(node)) {
6293
6235
  const text = getNodeText(node);
6294
- if (text.length > 10) {
6295
- chunks.push({
6296
- kind: "other",
6297
- name: text.slice(0, 40).replace(/\n/g, " "),
6298
- text,
6299
- startLine: getLineNumber(node.getStart(sourceFile)),
6300
- endLine: getLineNumber(node.getEnd())
6301
- });
6302
- }
6303
- return;
6236
+ if (text.length > 10) chunks.push({ kind: "other", name: text.slice(0, 40).replace(/\n/g, " "), text, startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()) });
6304
6237
  }
6305
6238
  }
6306
6239
  sourceFile.statements.forEach(visitTopLevel);
6307
6240
  if (importLines.length > 0) {
6308
6241
  const startLine = importLines[0].start;
6309
6242
  const endLine = importLines[importLines.length - 1].end;
6310
- const importText = lines.slice(startLine - 1, endLine).join("\n");
6311
- chunks.unshift({
6312
- kind: "import",
6313
- name: `${importLines.length} imports`,
6314
- text: importText,
6315
- startLine,
6243
+ chunks.unshift({ kind: "import", name: `${importLines.length} imports`, text: lines.slice(startLine - 1, endLine).join("\n"), startLine, endLine });
6244
+ }
6245
+ chunks.sort((a, b) => a.startLine - b.startLine);
6246
+ return chunks.length > 0 ? chunks : chunkByWindows(source, 80);
6247
+ }
6248
+ function chunkGenericSource(source, _fileName, language) {
6249
+ const lines = source.split("\n");
6250
+ if (source.trim().length === 0) return [];
6251
+ if (language && TEXT_LIKE_LANGUAGES.has(language)) return chunkTextLike(lines, language);
6252
+ const chunks = [];
6253
+ const patterns = [
6254
+ { kind: "function", regex: /^\s*(?:async\s+)?def\s+([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
6255
+ { kind: "class", regex: /^\s*class\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
6256
+ { kind: "function", regex: /^\s*(?:pub\s+)?fn\s+([A-Za-z_][\w]*)\s*[<(]/, name: (m) => m[1] },
6257
+ { kind: "class", regex: /^\s*(?:pub\s+)?(?:struct|enum|trait)\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
6258
+ { kind: "function", regex: /^\s*func\s+(?:\([^)]*\)\s*)?([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
6259
+ { kind: "function", regex: /^\s*(?:public|private|protected|static|final|suspend|fun|override|open|internal|export|async|func|function|subroutine)\s+.*?([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
6260
+ { kind: "function", regex: /^\s*function\s+([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
6261
+ { kind: "type", regex: /^\s*(?:interface|type|enum|record|data\s+class|case\s+class|contract|library)\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
6262
+ { kind: "section", regex: /^\s{0,3}#{1,6}\s+(.+)$/, name: (m) => m[1].trim() }
6263
+ ];
6264
+ const starts = [];
6265
+ for (let i = 0; i < lines.length; i++) {
6266
+ const line = lines[i];
6267
+ for (const pattern of patterns) {
6268
+ const match = line.match(pattern.regex);
6269
+ if (match) {
6270
+ starts.push({ line: i + 1, kind: pattern.kind, name: pattern.name(match) });
6271
+ break;
6272
+ }
6273
+ }
6274
+ }
6275
+ if (starts.length === 0) return chunkByWindows(source, 80);
6276
+ for (let i = 0; i < starts.length; i++) {
6277
+ const start = starts[i];
6278
+ const next = starts[i + 1]?.line ?? lines.length + 1;
6279
+ const endLine = Math.max(start.line, next - 1);
6280
+ chunks.push({
6281
+ kind: start.kind,
6282
+ name: start.name,
6283
+ text: lines.slice(start.line - 1, endLine).join("\n"),
6284
+ startLine: start.line,
6316
6285
  endLine
6317
6286
  });
6318
6287
  }
6319
- chunks.sort((a, b) => a.startLine - b.startLine);
6288
+ return chunks;
6289
+ }
6290
+ function chunkTextLike(lines, language) {
6291
+ if (language === "markdown" || language === "mdx") {
6292
+ const starts = lines.map((line, i) => ({ line, i })).filter(({ line }) => /^\s{0,3}#{1,6}\s+/.test(line));
6293
+ if (starts.length > 0) {
6294
+ return starts.map((start, idx) => {
6295
+ const end = starts[idx + 1]?.i ?? lines.length;
6296
+ const title = start.line.replace(/^\s{0,3}#{1,6}\s+/, "").trim();
6297
+ return { kind: "section", name: title, text: lines.slice(start.i, end).join("\n"), startLine: start.i + 1, endLine: end };
6298
+ });
6299
+ }
6300
+ }
6301
+ return chunkByWindows(lines.join("\n"), 80);
6302
+ }
6303
+ function chunkByWindows(source, windowLines) {
6304
+ const lines = source.split("\n");
6305
+ const chunks = [];
6306
+ for (let i = 0; i < lines.length; i += windowLines) {
6307
+ const end = Math.min(lines.length, i + windowLines);
6308
+ const text = lines.slice(i, end).join("\n");
6309
+ if (text.trim()) chunks.push({ kind: "other", name: `lines ${i + 1}-${end}`, text, startLine: i + 1, endLine: end });
6310
+ }
6320
6311
  return chunks;
6321
6312
  }
6322
6313
  function isChunkable(filePath) {
6323
- const ext = filePath.split(".").pop()?.toLowerCase();
6324
- return ext === "ts" || ext === "tsx" || ext === "js" || ext === "jsx";
6314
+ return Boolean(languageForFile(filePath));
6325
6315
  }
6316
+ var LANGUAGE_BY_EXTENSION, TEXT_LIKE_LANGUAGES;
6326
6317
  var init_code_chunker = __esm({
6327
6318
  "src/lib/code-chunker.ts"() {
6328
6319
  "use strict";
6320
+ LANGUAGE_BY_EXTENSION = {
6321
+ c: "c",
6322
+ cc: "cpp",
6323
+ cpp: "cpp",
6324
+ cxx: "cpp",
6325
+ h: "c",
6326
+ hh: "cpp",
6327
+ hpp: "cpp",
6328
+ cs: "csharp",
6329
+ css: "css",
6330
+ scss: "scss",
6331
+ f: "fortran",
6332
+ f90: "fortran",
6333
+ f95: "fortran",
6334
+ go: "go",
6335
+ html: "html",
6336
+ htm: "html",
6337
+ java: "java",
6338
+ js: "javascript",
6339
+ jsx: "javascript",
6340
+ json: "json",
6341
+ kt: "kotlin",
6342
+ kts: "kotlin",
6343
+ lua: "lua",
6344
+ md: "markdown",
6345
+ mdx: "mdx",
6346
+ pas: "pascal",
6347
+ php: "php",
6348
+ py: "python",
6349
+ r: "r",
6350
+ rb: "ruby",
6351
+ rs: "rust",
6352
+ scala: "scala",
6353
+ sc: "scala",
6354
+ sol: "solidity",
6355
+ sql: "sql",
6356
+ svelte: "svelte",
6357
+ swift: "swift",
6358
+ toml: "toml",
6359
+ ts: "typescript",
6360
+ tsx: "typescript",
6361
+ vue: "vue",
6362
+ xml: "xml",
6363
+ yaml: "yaml",
6364
+ yml: "yaml",
6365
+ sh: "shell",
6366
+ bash: "shell",
6367
+ zsh: "shell"
6368
+ };
6369
+ TEXT_LIKE_LANGUAGES = /* @__PURE__ */ new Set(["json", "markdown", "mdx", "toml", "yaml", "xml", "html", "css", "scss", "sql"]);
6329
6370
  }
6330
6371
  });
6331
6372
 
@@ -4535,6 +4535,12 @@ var init_platform_procedures = __esm({
4535
4535
  priority: "p0",
4536
4536
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4537
4537
  },
4538
+ {
4539
+ title: "Code context first for repository orientation",
4540
+ domain: "workflow",
4541
+ priority: "p1",
4542
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4543
+ },
4538
4544
  {
4539
4545
  title: "Commit discipline \u2014 never leave verified work floating",
4540
4546
  domain: "workflow",
@@ -4218,6 +4218,12 @@ var init_platform_procedures = __esm({
4218
4218
  priority: "p0",
4219
4219
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4220
4220
  },
4221
+ {
4222
+ title: "Code context first for repository orientation",
4223
+ domain: "workflow",
4224
+ priority: "p1",
4225
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4226
+ },
4221
4227
  {
4222
4228
  title: "Commit discipline \u2014 never leave verified work floating",
4223
4229
  domain: "workflow",
@@ -7906,6 +7906,12 @@ var init_platform_procedures = __esm({
7906
7906
  priority: "p0",
7907
7907
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
7908
7908
  },
7909
+ {
7910
+ title: "Code context first for repository orientation",
7911
+ domain: "workflow",
7912
+ priority: "p1",
7913
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
7914
+ },
7909
7915
  {
7910
7916
  title: "Commit discipline \u2014 never leave verified work floating",
7911
7917
  domain: "workflow",
@@ -4126,6 +4126,12 @@ var init_platform_procedures = __esm({
4126
4126
  priority: "p0",
4127
4127
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4128
4128
  },
4129
+ {
4130
+ title: "Code context first for repository orientation",
4131
+ domain: "workflow",
4132
+ priority: "p1",
4133
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4134
+ },
4129
4135
  {
4130
4136
  title: "Commit discipline \u2014 never leave verified work floating",
4131
4137
  domain: "workflow",
@@ -4302,6 +4302,12 @@ var init_platform_procedures = __esm({
4302
4302
  priority: "p0",
4303
4303
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4304
4304
  },
4305
+ {
4306
+ title: "Code context first for repository orientation",
4307
+ domain: "workflow",
4308
+ priority: "p1",
4309
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4310
+ },
4305
4311
  {
4306
4312
  title: "Commit discipline \u2014 never leave verified work floating",
4307
4313
  domain: "workflow",
@@ -4127,6 +4127,12 @@ var init_platform_procedures = __esm({
4127
4127
  priority: "p0",
4128
4128
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4129
4129
  },
4130
+ {
4131
+ title: "Code context first for repository orientation",
4132
+ domain: "workflow",
4133
+ priority: "p1",
4134
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4135
+ },
4130
4136
  {
4131
4137
  title: "Commit discipline \u2014 never leave verified work floating",
4132
4138
  domain: "workflow",
@@ -4127,6 +4127,12 @@ var init_platform_procedures = __esm({
4127
4127
  priority: "p0",
4128
4128
  content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
4129
4129
  },
4130
+ {
4131
+ title: "Code context first for repository orientation",
4132
+ domain: "workflow",
4133
+ priority: "p1",
4134
+ content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
4135
+ },
4130
4136
  {
4131
4137
  title: "Commit discipline \u2014 never leave verified work floating",
4132
4138
  domain: "workflow",