@xn-intenton-z2a/agentic-lib 7.4.7 → 7.4.9

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 (47) hide show
  1. package/{src → .github}/agents/agent-apply-fix.md +14 -0
  2. package/{src → .github}/agents/agent-director.md +14 -0
  3. package/{src → .github}/agents/agent-discovery.md +12 -0
  4. package/{src → .github}/agents/agent-discussion-bot.md +13 -0
  5. package/{src → .github}/agents/agent-issue-resolution.md +16 -0
  6. package/{src → .github}/agents/agent-iterate.md +12 -0
  7. package/{src → .github}/agents/agent-maintain-features.md +12 -0
  8. package/{src → .github}/agents/agent-maintain-library.md +11 -0
  9. package/{src → .github}/agents/agent-ready-issue.md +4 -0
  10. package/{src → .github}/agents/agent-review-issue.md +12 -0
  11. package/{src → .github}/agents/agent-supervisor.md +13 -0
  12. package/.github/workflows/agentic-lib-bot.yml +1 -1
  13. package/.github/workflows/agentic-lib-test.yml +4 -2
  14. package/.github/workflows/agentic-lib-workflow.yml +79 -35
  15. package/README.md +5 -7
  16. package/agentic-lib.toml +16 -38
  17. package/bin/agentic-lib.js +59 -61
  18. package/package.json +3 -4
  19. package/src/actions/agentic-step/action.yml +2 -2
  20. package/src/actions/agentic-step/copilot.js +0 -5
  21. package/src/actions/agentic-step/index.js +8 -1
  22. package/src/actions/agentic-step/logging.js +14 -2
  23. package/src/actions/agentic-step/tasks/direct.js +86 -65
  24. package/src/actions/agentic-step/tasks/discussions.js +198 -264
  25. package/src/actions/agentic-step/tasks/enhance-issue.js +84 -33
  26. package/src/actions/agentic-step/tasks/fix-code.js +111 -57
  27. package/src/actions/agentic-step/tasks/maintain-features.js +69 -52
  28. package/src/actions/agentic-step/tasks/maintain-library.js +57 -19
  29. package/src/actions/agentic-step/tasks/resolve-issue.js +43 -18
  30. package/src/actions/agentic-step/tasks/review-issue.js +117 -117
  31. package/src/actions/agentic-step/tasks/supervise.js +140 -151
  32. package/src/actions/agentic-step/tasks/transform.js +106 -258
  33. package/src/copilot/agents.js +2 -2
  34. package/src/copilot/config.js +4 -20
  35. package/src/copilot/{hybrid-session.js → copilot-session.js} +39 -7
  36. package/src/copilot/github-tools.js +514 -0
  37. package/src/copilot/guards.js +1 -1
  38. package/src/copilot/session.js +0 -141
  39. package/src/copilot/tools.js +4 -0
  40. package/src/iterate.js +1 -1
  41. package/src/scripts/accept-release.sh +4 -4
  42. package/src/scripts/push-to-logs.sh +1 -1
  43. package/src/seeds/zero-SCREENSHOT_INDEX.png +0 -0
  44. package/src/seeds/zero-package.json +1 -1
  45. package/src/agents/agentic-lib.yml +0 -66
  46. package/src/copilot/context.js +0 -457
  47. package/src/mcp/server.js +0 -830
package/agentic-lib.toml CHANGED
@@ -52,14 +52,8 @@ model = "gpt-5-mini"
52
52
  # reasoning-effort = "low" # low | medium | high | none (none = disable entirely)
53
53
  infinite-sessions = false # set to true for long sessions with compaction
54
54
  # transformation-budget = 4 # max code-changing cycles per run (0 = unlimited)
55
- # max-feature-files = 3
56
- # max-source-files = 3
57
- # max-source-chars = 1000
58
- # max-test-chars = 500
59
55
  # max-issues = 5
60
- # issue-body-limit = 200
61
56
  # stale-days = 14
62
- # max-summary-chars = 500
63
57
  # max-discussion-comments = 5
64
58
 
65
59
  # ─── Profile Definitions ────────────────────────────────────────────
@@ -68,19 +62,13 @@ infinite-sessions = false # set to true for long sessions with compaction
68
62
  # [tuning] or [limits] to deviate from the active profile.
69
63
 
70
64
  [profiles.min]
71
- # ~10% of gpt-4.1 context (128K). Fast, cheap — CI testing, quick validation.
65
+ # Fast, cheap — CI testing, quick validation.
72
66
  reasoning-effort = "low" # low | medium | high | none
73
67
  infinite-sessions = false # enable session compaction for long runs
74
68
  transformation-budget = 16 # max code-changing cycles per run
75
- max-feature-files = 3 # max feature files included in prompts
76
- max-source-files = 3 # max source files included in prompts
77
- max-source-chars = 4000 # max chars of each source file's content included in prompts
78
- max-test-chars = 2000 # max chars of each test file's content included in prompts
79
- max-issues = 5 # max open issues included in prompts
80
- issue-body-limit = 1000 # max chars of each issue's body text included in prompts
81
- stale-days = 14 # days since last activity before an issue is considered stale and excluded
82
- max-summary-chars = 2000 # max chars of each document's summary included in prompts
83
- max-discussion-comments = 3 # max recent discussion comments (newest first) included in prompts
69
+ max-issues = 5 # max open issues fetched from GitHub
70
+ stale-days = 14 # days since last activity before an issue is considered stale
71
+ max-discussion-comments = 3 # max recent discussion comments fetched
84
72
  max-feature-issues = 1 # max concurrent feature development issues
85
73
  max-maintenance-issues = 1 # max concurrent maintenance issues
86
74
  max-attempts-per-branch = 2 # max transform attempts before abandoning a branch
@@ -89,19 +77,13 @@ features-limit = 2 # max feature files in features/ director
89
77
  library-limit = 8 # max library entries in library/ directory
90
78
 
91
79
  [profiles.recommended]
92
- # ~30% of claude-sonnet-4 context (216K). Balanced — good results, default for consumer repos.
80
+ # Balanced — good results, default for consumer repos.
93
81
  reasoning-effort = "medium" # low | medium | high | none
94
82
  infinite-sessions = true # enable session compaction for long runs
95
83
  transformation-budget = 32 # max code-changing cycles per run
96
- max-feature-files = 10 # max feature files included in prompts
97
- max-source-files = 10 # max source files included in prompts
98
- max-source-chars = 8000 # max chars of each source file's content included in prompts
99
- max-test-chars = 5000 # max chars of each test file's content included in prompts
100
- max-issues = 15 # max open issues included in prompts
101
- issue-body-limit = 2000 # max chars of each issue's body text included in prompts
102
- stale-days = 30 # days since last activity before an issue is considered stale and excluded
103
- max-summary-chars = 5000 # max chars of each document's summary included in prompts
104
- max-discussion-comments = 10 # max recent discussion comments (newest first) included in prompts
84
+ max-issues = 15 # max open issues fetched from GitHub
85
+ stale-days = 30 # days since last activity before an issue is considered stale
86
+ max-discussion-comments = 10 # max recent discussion comments fetched
105
87
  max-feature-issues = 2 # max concurrent feature development issues
106
88
  max-maintenance-issues = 1 # max concurrent maintenance issues
107
89
  max-attempts-per-branch = 3 # max transform attempts before abandoning a branch
@@ -110,19 +92,13 @@ features-limit = 4 # max feature files in features/ director
110
92
  library-limit = 32 # max library entries in library/ directory
111
93
 
112
94
  [profiles.max]
113
- # ~90% of gpt-5-mini context (264K). Thorough — maximum context for complex missions.
95
+ # Thorough — maximum context for complex missions.
114
96
  reasoning-effort = "high" # low | medium | high | none
115
97
  infinite-sessions = true # enable session compaction for long runs
116
98
  transformation-budget = 128 # max code-changing cycles per run
117
- max-feature-files = 20 # max feature files included in prompts
118
- max-source-files = 25 # max source files included in prompts
119
- max-source-chars = 12000 # max chars of each source file's content included in prompts
120
- max-test-chars = 8000 # max chars of each test file's content included in prompts
121
- max-issues = 30 # max open issues included in prompts
122
- issue-body-limit = 3000 # max chars of each issue's body text included in prompts
123
- stale-days = 90 # days since last activity before an issue is considered stale and excluded
124
- max-summary-chars = 8000 # max chars of each document's summary included in prompts
125
- max-discussion-comments = 20 # max recent discussion comments (newest first) included in prompts
99
+ max-issues = 30 # max open issues fetched from GitHub
100
+ stale-days = 90 # days since last activity before an issue is considered stale
101
+ max-discussion-comments = 20 # max recent discussion comments fetched
126
102
  max-feature-issues = 4 # max concurrent feature development issues
127
103
  max-maintenance-issues = 2 # max concurrent maintenance issues
128
104
  max-attempts-per-branch = 5 # max transform attempts before abandoning a branch
@@ -133,9 +109,11 @@ library-limit = 64 # max library entries in library/ directo
133
109
  [mission-complete]
134
110
  # Thresholds for deterministic mission-complete declaration.
135
111
  # All conditions must be met simultaneously.
136
- min-resolved-issues = 3 # minimum closed-as-RESOLVED issues since init
137
- min-dedicated-tests = 1 # minimum test files that import from src/lib/
112
+ min-resolved-issues = 2 # minimum closed-as-RESOLVED issues since init
113
+ min-dedicated-tests = 0 # minimum test files that import from src/lib/
138
114
  max-source-todos = 0 # max TODO comments allowed in ./src (0 = none)
139
115
 
140
116
  [bot]
141
117
  log-file = "test/intentïon.md" #@dist "intentïon.md"
118
+ log-branch = "agentic-lib-logs"
119
+ screenshot-file = "SCREENSHOT_INDEX.png"
@@ -37,7 +37,7 @@ const TASK_AGENT_MAP = {
37
37
  "maintain-library": "agent-maintain-library",
38
38
  };
39
39
  const INIT_COMMANDS = ["init", "update", "reset"];
40
- const ALL_COMMANDS = [...INIT_COMMANDS, ...TASK_COMMANDS, "version", "mcp", "iterate"];
40
+ const ALL_COMMANDS = [...INIT_COMMANDS, ...TASK_COMMANDS, "version", "iterate"];
41
41
 
42
42
  const HELP = `
43
43
  @xn-intenton-z2a/agentic-lib — Agentic Coding Systems SDK
@@ -61,9 +61,6 @@ Iterator:
61
61
  iterate --here Discover the project and generate a MISSION.md, then iterate
62
62
  iterate --list-missions List available built-in mission seeds
63
63
 
64
- MCP Server:
65
- mcp Start MCP server (for Claude Code, Cursor, etc.)
66
-
67
64
  Options:
68
65
  --purge Full reset — clear features, activity log, source code
69
66
  --reseed Clear features + activity log (keep source code)
@@ -135,13 +132,6 @@ const discussionUrl = discussionIdx >= 0 ? flags[discussionIdx + 1] : "";
135
132
 
136
133
  // ─── Task Commands ───────────────────────────────────────────────────
137
134
 
138
- if (command === "mcp") {
139
- const { startServer } = await import("../src/mcp/server.js");
140
- await startServer();
141
- // Server runs until stdin closes — don't exit
142
- await new Promise(() => {}); // block forever
143
- }
144
-
145
135
  if (command === "iterate") {
146
136
  process.exit(await runIterate());
147
137
  }
@@ -215,10 +205,10 @@ async function runIterate() {
215
205
  console.log("");
216
206
 
217
207
  const discoveryPrompt = loadAgentPrompt("agent-discovery");
218
- const { runHybridSession } = await import("../src/copilot/hybrid-session.js");
208
+ const { runCopilotSession } = await import("../src/copilot/copilot-session.js");
219
209
  const effectiveModel = model || config.model || "gpt-5-mini";
220
210
 
221
- const discoveryResult = await runHybridSession({
211
+ const discoveryResult = await runCopilotSession({
222
212
  workspacePath: target,
223
213
  model: effectiveModel,
224
214
  tuning: config.tuning || {},
@@ -298,8 +288,8 @@ async function runIterate() {
298
288
  );
299
289
  }
300
290
 
301
- const { runHybridSession } = await import("../src/copilot/hybrid-session.js");
302
- const { gatherLocalContext, gatherGitHubContext, buildUserPrompt } = await import("../src/copilot/context.js");
291
+ const { runCopilotSession } = await import("../src/copilot/copilot-session.js");
292
+ const { readOptionalFile } = await import("../src/copilot/session.js");
303
293
 
304
294
  // Load agent prompt: --agent flag > default agent-iterate
305
295
  const agentName = agentFlag || "agent-iterate";
@@ -322,32 +312,26 @@ async function runIterate() {
322
312
  if (discussionUrl) console.log(`Discussion: ${discussionUrl}`);
323
313
  console.log("");
324
314
 
325
- // Gather context for the agent
326
- const localContext = gatherLocalContext(target, config);
327
-
328
- // Optionally gather GitHub context
329
- let githubContext;
330
- if (issueNumber || prNumber || discussionUrl) {
331
- console.log("Fetching GitHub context...");
332
- githubContext = gatherGitHubContext({
333
- issueNumber: issueNumber || undefined,
334
- prNumber: prNumber || undefined,
335
- discussionUrl: discussionUrl || undefined,
336
- workspacePath: target,
337
- });
338
- }
339
-
340
- // Build context-aware user prompt
341
- const { prompt: userPrompt } = buildUserPrompt(agentName, localContext, githubContext, {
342
- tuning: config.tuning,
343
- config,
344
- });
315
+ // Build lean prompt the model explores via tools (read_file, list_files, run_command)
316
+ const missionPath = resolve(target, config.paths?.mission?.path || "MISSION.md");
317
+ const missionContent = readOptionalFile(missionPath, 2000) || "(no mission defined)";
318
+ const userPrompt = [
319
+ "## Mission",
320
+ missionContent,
321
+ "",
322
+ "## Your Task",
323
+ "Use list_files to explore the repository, read_file to examine source code and tests,",
324
+ "and run_command to run the test suite. Write code to advance the mission.",
325
+ ...(issueNumber ? [``, `Focus on issue #${issueNumber}.`] : []),
326
+ ...(prNumber ? [``, `Focus on PR #${prNumber}.`] : []),
327
+ ...(discussionUrl ? [``, `Discussion context: ${discussionUrl}`] : []),
328
+ ].join("\n");
345
329
 
346
330
  // Derive maxToolCalls from transformation budget
347
331
  const budget = config.transformationBudget || 0;
348
332
  const effectiveMaxToolCalls = budget > 0 ? budget * 20 : undefined;
349
333
 
350
- const result = await runHybridSession({
334
+ const result = await runCopilotSession({
351
335
  workspacePath: target,
352
336
  model: effectiveModel,
353
337
  tuning: config.tuning || {},
@@ -423,31 +407,31 @@ async function runTask(taskName) {
423
407
 
424
408
  try {
425
409
  const { loadAgentPrompt } = await import("../src/copilot/agents.js");
426
- const { runHybridSession } = await import("../src/copilot/hybrid-session.js");
427
- const { gatherLocalContext, gatherGitHubContext, buildUserPrompt } = await import("../src/copilot/context.js");
410
+ const { runCopilotSession } = await import("../src/copilot/copilot-session.js");
411
+ const { readOptionalFile } = await import("../src/copilot/session.js");
428
412
 
429
413
  const agentPrompt = loadAgentPrompt(agentName);
430
- const localContext = gatherLocalContext(target, config);
431
-
432
- let githubContext;
433
- if (issueNumber || prNumber) {
434
- githubContext = gatherGitHubContext({
435
- issueNumber: issueNumber || undefined,
436
- prNumber: prNumber || undefined,
437
- workspacePath: target,
438
- });
439
- }
440
414
 
441
- const { prompt: userPrompt, promptBudget } = buildUserPrompt(agentName, localContext, githubContext, {
442
- tuning: config.tuning,
443
- config,
444
- });
415
+ // Build lean prompt the model explores via tools (read_file, list_files, run_command)
416
+ const missionPath = resolve(target, config.paths?.mission?.path || config.paths?.mission || "MISSION.md");
417
+ const missionContent = readOptionalFile(missionPath, 2000) || "(no mission defined)";
418
+ const userPrompt = [
419
+ "## Mission",
420
+ missionContent,
421
+ "",
422
+ "## Your Task",
423
+ "Use list_files to explore the repository, read_file to examine source code and tests,",
424
+ "and run_command to run the test suite. Write code to advance the mission.",
425
+ ...(issueNumber ? [``, `Focus on issue #${issueNumber}.`] : []),
426
+ ...(prNumber ? [``, `Focus on PR #${prNumber}.`] : []),
427
+ ...(discussionUrl ? [``, `Discussion context: ${discussionUrl}`] : []),
428
+ ].join("\n");
445
429
 
446
430
  // Derive maxToolCalls from transformation budget (budget × 20, or unlimited)
447
431
  const budget = config.transformationBudget || 0;
448
432
  const effectiveMaxToolCalls = budget > 0 ? budget * 20 : undefined;
449
433
 
450
- const result = await runHybridSession({
434
+ const result = await runCopilotSession({
451
435
  workspacePath: target,
452
436
  model: effectiveModel,
453
437
  tuning: config.tuning || {},
@@ -469,12 +453,6 @@ async function runTask(taskName) {
469
453
  console.log(`Tool calls: ${result.toolCalls}`);
470
454
  console.log(`Tokens: ${tokensUsed} (in=${result.tokensIn} out=${result.tokensOut})`);
471
455
  if (result.narrative) console.log(`Narrative: ${result.narrative}`);
472
- if (promptBudget) {
473
- console.log("Prompt budget:");
474
- for (const entry of promptBudget) {
475
- console.log(` ${entry.section}: ${entry.size} chars, ${entry.files} files ${entry.notes}`);
476
- }
477
- }
478
456
  console.log("");
479
457
  return result.success ? 0 : 1;
480
458
  } catch (err) {
@@ -575,11 +553,23 @@ function initActions(agenticDir) {
575
553
  }
576
554
  }
577
555
 
578
- function initDirContents(srcSubdir, dstDir, label) {
556
+ function initAgents(dstDir) {
557
+ console.log("\n--- Agents ---");
558
+ const agentsSrcDir = resolve(pkgRoot, ".github/agents");
559
+ if (!existsSync(agentsSrcDir)) return;
560
+ for (const entry of readdirSync(agentsSrcDir, { withFileTypes: true })) {
561
+ if (!entry.isFile()) continue;
562
+ initCopyFile(resolve(agentsSrcDir, entry.name), resolve(dstDir, entry.name), `agents/${entry.name}`);
563
+ }
564
+ }
565
+
566
+ function initDirContents(srcSubdir, dstDir, label, excludeFiles = []) {
579
567
  console.log(`\n--- ${label} ---`);
580
568
  const dir = resolve(srcDir, srcSubdir);
581
569
  if (!existsSync(dir)) return;
570
+ const excludeSet = new Set(excludeFiles);
582
571
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
572
+ if (excludeSet.has(entry.name)) continue;
583
573
  if (entry.isDirectory()) {
584
574
  initCopyDirRecursive(resolve(dir, entry.name), resolve(dstDir, entry.name), `${srcSubdir}/${entry.name}`);
585
575
  } else {
@@ -768,6 +758,7 @@ function initPurge(seedsDir, missionName, initTimestamp) {
768
758
  "zero-package.json": "package.json",
769
759
  "zero-README.md": "README.md",
770
760
  "zero-.gitignore": ".gitignore",
761
+ "zero-SCREENSHOT_INDEX.png": "SCREENSHOT_INDEX.png",
771
762
  };
772
763
  for (const [seedFile, targetRel] of Object.entries(SEED_MAP)) {
773
764
  const src = resolve(seedsDir, seedFile);
@@ -1269,7 +1260,14 @@ function runInit() {
1269
1260
  initWorkflows();
1270
1261
  initActions(agenticDir);
1271
1262
  initDirContents("copilot", resolve(agenticDir, "copilot"), "Copilot (shared modules)");
1272
- initDirContents("agents", resolve(agenticDir, "agents"), "Agents");
1263
+ initAgents(resolve(target, ".github/agents"));
1264
+ // Remove stale legacy agents directory
1265
+ const legacyAgentsDir = resolve(agenticDir, "agents");
1266
+ if (existsSync(legacyAgentsDir)) {
1267
+ if (!dryRun) rmSync(legacyAgentsDir, { recursive: true });
1268
+ console.log(" REMOVE stale: .github/agentic-lib/agents/ (migrated to .github/agents/)");
1269
+ initChanges++;
1270
+ }
1273
1271
  initDirContents("seeds", resolve(agenticDir, "seeds"), "Seeds");
1274
1272
  initScripts(agenticDir);
1275
1273
  initConfig(seedsDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.4.7",
3
+ "version": "7.4.9",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -79,10 +79,9 @@
79
79
  "src/actions/agentic-step/tasks/",
80
80
  "src/actions/commit-if-changed/",
81
81
  "src/actions/setup-npmrc/",
82
- "src/agents/",
82
+ ".github/agents/",
83
83
  "src/seeds/",
84
- "src/scripts/",
85
- "src/mcp/"
84
+ "src/scripts/"
86
85
  ],
87
86
  "overrides": {
88
87
  "minimatch": ">=10.2.3",
@@ -16,9 +16,9 @@ inputs:
16
16
  maintain-library, enhance-issue, review-issue, discussions, supervise
17
17
  required: true
18
18
  config:
19
- description: "Path to agentic-lib.yml configuration file"
19
+ description: "Path to agentic-lib.toml configuration file"
20
20
  required: false
21
- default: ".github/agentic-lib/agents/agentic-lib.yml"
21
+ default: "agentic-lib.toml"
22
22
  instructions:
23
23
  description: "Path to agent prompt/instructions file (.md)"
24
24
  required: false
@@ -39,7 +39,6 @@ import {
39
39
  scanDirectory as _scanDirectory,
40
40
  buildClientOptions as _buildClientOptions,
41
41
  logTuningParam as _logTuningParam,
42
- runCopilotTask as _runCopilotTask,
43
42
  } from "../../copilot/session.js";
44
43
 
45
44
  export function readOptionalFile(filePath, limit) {
@@ -57,7 +56,3 @@ export function buildClientOptions(githubToken) {
57
56
  export function logTuningParam(param, value, profileName, model, clip) {
58
57
  return _logTuningParam(param, value, profileName, model, clip, actionsLogger);
59
58
  }
60
-
61
- export async function runCopilotTask(options) {
62
- return _runCopilotTask({ ...options, logger: actionsLogger });
63
- }
@@ -9,7 +9,7 @@ import * as core from "@actions/core";
9
9
  import * as github from "@actions/github";
10
10
  import { loadConfig, getWritablePaths } from "./config-loader.js";
11
11
  import { logActivity, generateClosingNotes } from "./logging.js";
12
- import { readFileSync } from "fs";
12
+ import { readFileSync, existsSync } from "fs";
13
13
  import {
14
14
  buildMissionMetrics, buildMissionReadiness,
15
15
  computeTransformationCost, readCumulativeCost, buildLimitsStatus,
@@ -60,6 +60,12 @@ async function run() {
60
60
  const handler = TASKS[task];
61
61
  if (!handler) throw new Error(`Unknown task: ${task}. Available: ${Object.keys(TASKS).join(", ")}`);
62
62
 
63
+ // Resolve log and screenshot paths (fetched from agentic-lib-logs branch by workflow)
64
+ const logFile = config.intentionBot?.intentionFilepath || "intenti\u00F6n.md";
65
+ const screenshotFile = config.intentionBot?.screenshotFile || "SCREENSHOT_INDEX.png";
66
+ const logFilePath = existsSync(logFile) ? logFile : null;
67
+ const screenshotFilePath = existsSync(screenshotFile) ? screenshotFile : null;
68
+
63
69
  const context = {
64
70
  task, config, instructions, issueNumber, writablePaths, testCommand, model,
65
71
  prNumber: core.getInput("pr-number"),
@@ -68,6 +74,7 @@ async function run() {
68
74
  commentCreatedAt: core.getInput("comment-created-at"),
69
75
  octokit: github.getOctokit(process.env.GITHUB_TOKEN),
70
76
  repo: github.context.repo, github: github.context,
77
+ logFilePath, screenshotFilePath,
71
78
  };
72
79
 
73
80
  const startTime = Date.now();
@@ -5,8 +5,9 @@
5
5
  // Appends structured entries to the intentïon.md activity log,
6
6
  // including commit URLs and safety-check outcomes.
7
7
 
8
- import { writeFileSync, readFileSync, appendFileSync, existsSync, mkdirSync } from "fs";
9
- import { dirname } from "path";
8
+ import { writeFileSync, readFileSync, appendFileSync, existsSync, mkdirSync, copyFileSync } from "fs";
9
+ import { dirname, basename } from "path";
10
+ import { join } from "path";
10
11
  import * as core from "@actions/core";
11
12
 
12
13
  /**
@@ -158,6 +159,17 @@ export function logActivity({
158
159
  } else {
159
160
  writeFileSync(filepath, `# intentïon Activity Log\n${entry}`);
160
161
  }
162
+
163
+ // Write ASCII fallback copy (intention.md) for systems that can't handle UTF-8 filenames
164
+ const name = basename(filepath);
165
+ if (name !== "intention.md" && name.includes("intenti")) {
166
+ const fallbackPath = join(dirname(filepath), "intention.md");
167
+ try {
168
+ copyFileSync(filepath, fallbackPath);
169
+ } catch {
170
+ // Best-effort — don't fail the log if the copy fails
171
+ }
172
+ }
161
173
  }
162
174
 
163
175
  /**