@xn-intenton-z2a/agentic-lib 7.1.76 → 7.1.77

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.1.76",
3
+ "version": "7.1.77",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -9,6 +9,67 @@ import * as core from "@actions/core";
9
9
  import { existsSync, readFileSync, writeFileSync } from "fs";
10
10
  import { runCopilotTask, readOptionalFile, scanDirectory, filterIssues } from "../copilot.js";
11
11
 
12
+ /**
13
+ * Look up the "Talk to the repository" discussion URL via GraphQL.
14
+ * Returns { url, nodeId } or { url: "", nodeId: "" } on failure.
15
+ */
16
+ async function findTalkDiscussion(octokit, repo) {
17
+ try {
18
+ const query = `query($owner: String!, $name: String!) {
19
+ repository(owner: $owner, name: $name) {
20
+ discussions(first: 10, orderBy: { field: CREATED_AT, direction: DESC }) {
21
+ nodes {
22
+ id
23
+ number
24
+ title
25
+ url
26
+ }
27
+ }
28
+ }
29
+ }`;
30
+ const result = await octokit.graphql(query, { owner: repo.owner, name: repo.repo });
31
+ const disc = result.repository.discussions.nodes.find(
32
+ (d) => d.title.toLowerCase().includes("talk to the repository"),
33
+ );
34
+ if (disc) {
35
+ return { url: disc.url, nodeId: disc.id };
36
+ }
37
+ } catch (err) {
38
+ core.warning(`Could not look up Talk discussion: ${err.message}`);
39
+ }
40
+ return { url: "", nodeId: "" };
41
+ }
42
+
43
+ /**
44
+ * Construct the GitHub Pages website URL for a repository.
45
+ */
46
+ function getWebsiteUrl(repo) {
47
+ return `https://${repo.owner}.github.io/${repo.repo}/`;
48
+ }
49
+
50
+ /**
51
+ * Dispatch the discussions bot with a message and discussion URL.
52
+ */
53
+ async function dispatchBot(octokit, repo, message, discussionUrl) {
54
+ if (process.env.GITHUB_REPOSITORY === "xn-intenton-z2a/agentic-lib") {
55
+ core.info("Skipping bot dispatch — running in SDK repo");
56
+ return;
57
+ }
58
+ const inputs = { message };
59
+ if (discussionUrl) inputs["discussion-url"] = discussionUrl;
60
+ try {
61
+ await octokit.rest.actions.createWorkflowDispatch({
62
+ ...repo,
63
+ workflow_id: "agentic-lib-bot.yml",
64
+ ref: "main",
65
+ inputs,
66
+ });
67
+ core.info(`Dispatched bot: ${message.substring(0, 100)}`);
68
+ } catch (err) {
69
+ core.warning(`Could not dispatch bot: ${err.message}`);
70
+ }
71
+ }
72
+
12
73
  async function gatherContext(octokit, repo, config, t) {
13
74
  const mission = readOptionalFile(config.paths.mission.path);
14
75
  const intentionLogFull = readOptionalFile(config.intentionBot.intentionFilepath);
@@ -37,7 +98,13 @@ async function gatherContext(octokit, repo, config, t) {
37
98
 
38
99
  // Extract discussion URL from recent activity for supervisor reporting
39
100
  const discussionUrlMatch = recentActivity.match(/https:\/\/github\.com\/[^/]+\/[^/]+\/discussions\/\d+/);
40
- const activeDiscussionUrl = discussionUrlMatch ? discussionUrlMatch[0] : "";
101
+ let activeDiscussionUrl = discussionUrlMatch ? discussionUrlMatch[0] : "";
102
+
103
+ // Fallback: look up the "Talk to the repository" discussion if not found in activity log
104
+ if (!activeDiscussionUrl) {
105
+ const talk = await findTalkDiscussion(octokit, repo);
106
+ activeDiscussionUrl = talk.url;
107
+ }
41
108
 
42
109
  const featuresPath = config.paths.features.path;
43
110
  const featureNames = existsSync(featuresPath)
@@ -345,12 +412,17 @@ function parseReasoning(content) {
345
412
  return match ? match[1].trim() : "";
346
413
  }
347
414
 
348
- async function executeDispatch(octokit, repo, actionName, params) {
415
+ async function executeDispatch(octokit, repo, actionName, params, ctx) {
349
416
  const workflowFile = actionName.replace("dispatch:", "") + ".yml";
350
417
  const inputs = {};
351
418
  if (params["pr-number"]) inputs["pr-number"] = params["pr-number"];
352
419
  if (params["issue-number"]) inputs["issue-number"] = params["issue-number"];
353
420
 
421
+ // Pass discussion-url when dispatching the bot
422
+ if (workflowFile === "agentic-lib-bot.yml" && ctx?.activeDiscussionUrl) {
423
+ if (!inputs["discussion-url"]) inputs["discussion-url"] = ctx.activeDiscussionUrl;
424
+ }
425
+
354
426
  // Guard: never dispatch workflows from the SDK repo itself (agentic-lib)
355
427
  if (process.env.GITHUB_REPOSITORY === "xn-intenton-z2a/agentic-lib") {
356
428
  core.info(`Skipping dispatch of ${workflowFile} — running in SDK repo`);
@@ -434,9 +506,9 @@ async function executeCloseIssue(octokit, repo, params) {
434
506
  return "skipped:close-issue-missing-number";
435
507
  }
436
508
 
437
- async function executeRespondDiscussions(octokit, repo, params) {
509
+ async function executeRespondDiscussions(octokit, repo, params, ctx) {
438
510
  const message = params.message || "";
439
- const url = params["discussion-url"] || "";
511
+ const url = params["discussion-url"] || ctx?.activeDiscussionUrl || "";
440
512
  if (message) {
441
513
  if (process.env.GITHUB_REPOSITORY === "xn-intenton-z2a/agentic-lib") {
442
514
  core.info("Skipping bot dispatch — running in SDK repo");
@@ -456,7 +528,7 @@ async function executeRespondDiscussions(octokit, repo, params) {
456
528
  return "skipped:respond-no-message";
457
529
  }
458
530
 
459
- async function executeMissionComplete(octokit, repo, params) {
531
+ async function executeMissionComplete(octokit, repo, params, ctx) {
460
532
  const reason = params.reason || "All acceptance criteria satisfied";
461
533
  const signal = [
462
534
  "# Mission Complete",
@@ -480,11 +552,16 @@ async function executeMissionComplete(octokit, repo, params) {
480
552
  } catch (err) {
481
553
  core.warning(`Could not set schedule to off: ${err.message}`);
482
554
  }
555
+
556
+ // Announce mission complete via bot
557
+ const websiteUrl = getWebsiteUrl(repo);
558
+ const discussionUrl = ctx?.activeDiscussionUrl || "";
559
+ await dispatchBot(octokit, repo, `Mission complete! ${reason}\n\nWebsite: ${websiteUrl}`, discussionUrl);
483
560
  }
484
561
  return `mission-complete:${reason.substring(0, 100)}`;
485
562
  }
486
563
 
487
- async function executeMissionFailed(octokit, repo, params) {
564
+ async function executeMissionFailed(octokit, repo, params, ctx) {
488
565
  const reason = params.reason || "Mission could not be completed";
489
566
  const signal = [
490
567
  "# Mission Failed",
@@ -508,6 +585,11 @@ async function executeMissionFailed(octokit, repo, params) {
508
585
  } catch (err) {
509
586
  core.warning(`Could not set schedule to off: ${err.message}`);
510
587
  }
588
+
589
+ // Announce mission failed via bot
590
+ const websiteUrl = getWebsiteUrl(repo);
591
+ const discussionUrl = ctx?.activeDiscussionUrl || "";
592
+ await dispatchBot(octokit, repo, `Mission failed. ${reason}\n\nWebsite: ${websiteUrl}`, discussionUrl);
511
593
  }
512
594
  return `mission-failed:${reason.substring(0, 100)}`;
513
595
  }
@@ -540,12 +622,12 @@ async function executeSetSchedule(octokit, repo, frequency) {
540
622
  return `set-schedule:${frequency}`;
541
623
  }
542
624
 
543
- async function executeAction(octokit, repo, action, params) {
544
- if (action.startsWith("dispatch:")) return executeDispatch(octokit, repo, action, params);
625
+ async function executeAction(octokit, repo, action, params, ctx) {
626
+ if (action.startsWith("dispatch:")) return executeDispatch(octokit, repo, action, params, ctx);
545
627
  if (action.startsWith("set-schedule:")) return executeSetSchedule(octokit, repo, action.replace("set-schedule:", ""));
546
628
  if (action === "nop") return "nop";
547
629
  const handler = ACTION_HANDLERS[action];
548
- if (handler) return handler(octokit, repo, params);
630
+ if (handler) return handler(octokit, repo, params, ctx);
549
631
  core.warning(`Unknown action: ${action}`);
550
632
  return `unknown:${action}`;
551
633
  }
@@ -561,6 +643,22 @@ export async function supervise(context) {
561
643
  const t = config.tuning || {};
562
644
 
563
645
  const ctx = await gatherContext(octokit, repo, config, t);
646
+ const websiteUrl = getWebsiteUrl(repo);
647
+
648
+ // --- Deterministic lifecycle posts (before LLM) ---
649
+
650
+ // Step 2: Auto-announce on first run after init
651
+ // Detect first supervisor run: initTimestamp exists but no supervisor entries in activity
652
+ if (ctx.initTimestamp && !ctx.missionComplete && !ctx.missionFailed) {
653
+ const hasPriorSupervisor = ctx.recentActivity.includes("supervisor");
654
+ if (!hasPriorSupervisor && ctx.mission && ctx.activeDiscussionUrl) {
655
+ core.info("First supervisor run after init — announcing mission");
656
+ const announcement = `New mission started!\n\n**Mission:** ${ctx.mission.substring(0, 300)}\n\n**Website:** ${websiteUrl}`;
657
+ await dispatchBot(octokit, repo, announcement, ctx.activeDiscussionUrl);
658
+ }
659
+ }
660
+
661
+ // --- LLM decision ---
564
662
  const agentInstructions = instructions || "You are the supervisor. Decide what actions to take.";
565
663
  const prompt = buildPrompt(ctx, agentInstructions);
566
664
 
@@ -582,7 +680,7 @@ export async function supervise(context) {
582
680
  const results = [];
583
681
  for (const { action, params } of actions) {
584
682
  try {
585
- const result = await executeAction(octokit, repo, action, params);
683
+ const result = await executeAction(octokit, repo, action, params, ctx);
586
684
  results.push(result);
587
685
  core.info(`Action result: ${result}`);
588
686
  } catch (err) {
@@ -591,6 +689,24 @@ export async function supervise(context) {
591
689
  }
592
690
  }
593
691
 
692
+ // --- Deterministic lifecycle posts (after LLM) ---
693
+
694
+ // Step 3: Auto-respond when a message referral is present
695
+ // If the workflow was triggered with a message (from bot's request-supervisor),
696
+ // and the LLM didn't include a respond:discussions action, post back automatically
697
+ const workflowMessage = context.discussionUrl ? "" : (process.env.INPUT_MESSAGE || "");
698
+ if (workflowMessage && ctx.activeDiscussionUrl) {
699
+ const hasDiscussionResponse = results.some((r) => r.startsWith("respond-discussions:"));
700
+ if (!hasDiscussionResponse) {
701
+ core.info("Message referral detected — auto-responding to discussion");
702
+ const response = reasoning
703
+ ? `Supervisor update: ${reasoning.substring(0, 400)}`
704
+ : `Supervisor processed your request. Actions taken: ${results.join(", ")}`;
705
+ await dispatchBot(octokit, repo, response, ctx.activeDiscussionUrl);
706
+ results.push(`auto-respond:${ctx.activeDiscussionUrl}`);
707
+ }
708
+ }
709
+
594
710
  // Build changes list from executed actions
595
711
  const changes = results
596
712
  .filter((r) => r.startsWith("created-issue:") || r.startsWith("mission-complete:") || r.startsWith("mission-failed:"))
@@ -170,20 +170,12 @@ export async function transform(context) {
170
170
 
171
171
  core.info(`Transformation step completed (${tokensUsed} tokens)`);
172
172
 
173
- // Detect mission-complete: if the LLM made no changes and indicates mission satisfaction
173
+ // Detect mission-complete hint: if the LLM indicates mission satisfaction, log it
174
+ // but do NOT write MISSION_COMPLETE.md — the supervisor is the single authority
175
+ // for mission lifecycle declarations (it also handles bot announcements)
174
176
  const lowerResult = resultContent.toLowerCase();
175
177
  if (lowerResult.includes("mission is satisfied") || lowerResult.includes("mission is complete") || lowerResult.includes("no changes needed")) {
176
- core.info("Mission appears complete — writing MISSION_COMPLETE.md signal");
177
- const signal = [
178
- "# Mission Complete",
179
- "",
180
- `- **Timestamp:** ${new Date().toISOString()}`,
181
- `- **Detected by:** transform`,
182
- `- **Reason:** ${resultContent.substring(0, 200)}`,
183
- "",
184
- "This file was created automatically. To restart transformations, delete this file or run `npx @xn-intenton-z2a/agentic-lib init --reseed`.",
185
- ].join("\n");
186
- writeFileSync("MISSION_COMPLETE.md", signal);
178
+ core.info("Transform indicates mission may be complete — supervisor will verify on next cycle");
187
179
  }
188
180
 
189
181
  const promptBudget = [
@@ -16,7 +16,7 @@
16
16
  "author": "",
17
17
  "license": "MIT",
18
18
  "dependencies": {
19
- "@xn-intenton-z2a/agentic-lib": "^7.1.76"
19
+ "@xn-intenton-z2a/agentic-lib": "^7.1.77"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@vitest/coverage-v8": "^4.0.18",