@xn-intenton-z2a/agentic-lib 7.1.66 → 7.1.68

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/agentic-lib.toml CHANGED
@@ -70,7 +70,7 @@ infinite-sessions = false # set to true for long sessions with compaction
70
70
  # Fast & cheap — CI testing, quick validation, budget-conscious iteration.
71
71
  reasoning-effort = "low" # low | medium | high | none
72
72
  infinite-sessions = false # enable session compaction for long runs
73
- transformation-budget = 4 # max code-changing cycles per run
73
+ transformation-budget = 16 # max code-changing cycles per run
74
74
  max-feature-files = 3 # max feature files included in prompts
75
75
  max-source-files = 3 # max source files included in prompts
76
76
  max-source-chars = 1000 # max chars of each source file's content included in prompts
@@ -91,7 +91,7 @@ library-limit = 8 # max library entries in library/ directo
91
91
  # Balanced — good results without excessive cost. Default for consumer repos.
92
92
  reasoning-effort = "medium" # low | medium | high | none
93
93
  infinite-sessions = true # enable session compaction for long runs
94
- transformation-budget = 8 # max code-changing cycles per run
94
+ transformation-budget = 32 # max code-changing cycles per run
95
95
  max-feature-files = 10 # max feature files included in prompts
96
96
  max-source-files = 10 # max source files included in prompts
97
97
  max-source-chars = 5000 # max chars of each source file's content included in prompts
@@ -112,7 +112,7 @@ library-limit = 32 # max library entries in library/ directo
112
112
  # Thorough — maximum context, highest quality. For complex missions.
113
113
  reasoning-effort = "high" # low | medium | high | none
114
114
  infinite-sessions = true # enable session compaction for long runs
115
- transformation-budget = 32 # max code-changing cycles per run
115
+ transformation-budget = 128 # max code-changing cycles per run
116
116
  max-feature-files = 50 # max feature files included in prompts
117
117
  max-source-files = 50 # max source files included in prompts
118
118
  max-source-chars = 20000 # max chars of each source file's content included in prompts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xn-intenton-z2a/agentic-lib",
3
- "version": "7.1.66",
3
+ "version": "7.1.68",
4
4
  "description": "Agentic-lib Agentic Coding Systems SDK powering automated GitHub workflows.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -35,7 +35,7 @@ import { parse as parseToml } from "smol-toml";
35
35
  */
36
36
 
37
37
  // Keys whose paths are writable by agents
38
- const WRITABLE_KEYS = ["source", "tests", "features", "dependencies", "docs", "readme", "examples"];
38
+ const WRITABLE_KEYS = ["source", "tests", "features", "dependencies", "docs", "readme", "examples", "web"];
39
39
 
40
40
  // Default paths — every key that task handlers might access
41
41
  const PATH_DEFAULTS = {
@@ -50,6 +50,7 @@ const PATH_DEFAULTS = {
50
50
  library: "library/",
51
51
  librarySources: "SOURCES.md",
52
52
  contributing: "CONTRIBUTING.md",
53
+ web: "src/web/",
53
54
  };
54
55
 
55
56
  // Default limits for path-specific constraints
@@ -63,7 +64,7 @@ const LIMIT_DEFAULTS = {
63
64
  const FALLBACK_TUNING = {
64
65
  reasoningEffort: "medium",
65
66
  infiniteSessions: true,
66
- transformationBudget: 8,
67
+ transformationBudget: 32,
67
68
  featuresScan: 10,
68
69
  sourceScan: 10,
69
70
  sourceContent: 5000,
@@ -92,7 +93,7 @@ function parseTuningProfile(profileSection) {
92
93
  return {
93
94
  reasoningEffort: profileSection["reasoning-effort"] || "medium",
94
95
  infiniteSessions: profileSection["infinite-sessions"] ?? true,
95
- transformationBudget: profileSection["transformation-budget"] || 8,
96
+ transformationBudget: profileSection["transformation-budget"] || 32,
96
97
  featuresScan: profileSection["max-feature-files"] || 10,
97
98
  sourceScan: profileSection["max-source-files"] || 10,
98
99
  sourceContent: profileSection["max-source-chars"] || 5000,
@@ -101,7 +101,7 @@ async function run() {
101
101
 
102
102
  // Compute limits status for enriched logging
103
103
  const limitsStatus = [
104
- { name: "transformation-budget", valueNum: 0, capacityNum: config.transformationBudget || 0, value: `0/${config.transformationBudget || 0}`, remaining: `${config.transformationBudget || 0} remaining`, status: "" },
104
+ { name: "transformation-budget", valueNum: 0, capacityNum: config.transformationBudget || 0, value: `0/${config.transformationBudget || 0}`, remaining: `${config.transformationBudget || 0}`, status: "" },
105
105
  { name: "max-feature-issues", valueNum: 0, capacityNum: config.featureDevelopmentIssuesWipLimit, value: `?/${config.featureDevelopmentIssuesWipLimit}`, remaining: "?", status: "" },
106
106
  { name: "max-maintenance-issues", valueNum: 0, capacityNum: config.maintenanceIssuesWipLimit, value: `?/${config.maintenanceIssuesWipLimit}`, remaining: "?", status: "" },
107
107
  { name: "max-attempts-per-issue", valueNum: 0, capacityNum: config.attemptsPerIssue, value: `?/${config.attemptsPerIssue}`, remaining: "?", status: task === "resolve-issue" ? "" : "n/a" },
@@ -122,7 +122,7 @@ async function run() {
122
122
  const profileName = config.tuning?.profileName || "unknown";
123
123
 
124
124
  // Transformation cost: 1 for code-changing tasks, 0 otherwise
125
- const COST_TASKS = ["transform", "fix-code"];
125
+ const COST_TASKS = ["transform", "fix-code", "maintain-features", "maintain-library"];
126
126
  const isNop = result.outcome === "nop" || result.outcome === "error";
127
127
  const transformationCost = COST_TASKS.includes(task) && !isNop ? 1 : 0;
128
128
 
@@ -151,6 +151,7 @@ async function run() {
151
151
  promptBudget: result.promptBudget,
152
152
  closingNotes,
153
153
  transformationCost,
154
+ narrative: result.narrative,
154
155
  });
155
156
  }
156
157
 
@@ -34,6 +34,7 @@ import * as core from "@actions/core";
34
34
  * @param {Array} [options.promptBudget] - Prompt budget entries { section, size, files, notes }
35
35
  * @param {string} [options.closingNotes] - Auto-generated limit concern notes
36
36
  * @param {number} [options.transformationCost] - Transformation cost for this entry (0 or 1)
37
+ * @param {string} [options.narrative] - LLM-generated narrative description of the change
37
38
  */
38
39
  export function logActivity({
39
40
  filepath,
@@ -57,6 +58,7 @@ export function logActivity({
57
58
  promptBudget,
58
59
  closingNotes,
59
60
  transformationCost,
61
+ narrative,
60
62
  }) {
61
63
  const dir = dirname(filepath);
62
64
  if (!existsSync(dir)) {
@@ -110,6 +112,10 @@ export function logActivity({
110
112
  parts.push("", "### Closing Notes");
111
113
  parts.push(closingNotes);
112
114
  }
115
+ if (narrative) {
116
+ parts.push("", "### Narrative");
117
+ parts.push(narrative);
118
+ }
113
119
  if (details) {
114
120
  parts.push("");
115
121
  parts.push(details);
@@ -98,7 +98,7 @@ async function resolveConflicts({ config, pr, prNumber, instructions, model, wri
98
98
  ].join("\n");
99
99
 
100
100
  const t = config.tuning || {};
101
- const { tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
101
+ const { tokensUsed, inputTokens, outputTokens, cost, content: resultContent } = await runCopilotTask({
102
102
  model,
103
103
  systemMessage: `You are resolving git merge conflicts on PR #${prNumber}. Write resolved versions of each conflicted file, removing all conflict markers. Preserve the PR's feature intent while incorporating main's updates.`,
104
104
  prompt,
@@ -116,6 +116,7 @@ async function resolveConflicts({ config, pr, prNumber, instructions, model, wri
116
116
  cost,
117
117
  model,
118
118
  details: `Resolved ${conflicts.length} conflicted file(s) on PR #${prNumber}`,
119
+ narrative: (resultContent || "").substring(0, 2000),
119
120
  };
120
121
  }
121
122
 
@@ -186,7 +187,7 @@ export async function fixCode(context) {
186
187
  ].join("\n");
187
188
 
188
189
  const t = config.tuning || {};
189
- const { tokensUsed, inputTokens, outputTokens, cost } = await runCopilotTask({
190
+ const { tokensUsed, inputTokens, outputTokens, cost, content: resultContent } = await runCopilotTask({
190
191
  model,
191
192
  systemMessage: `You are an autonomous coding agent fixing failing tests on PR #${prNumber}. Make minimal, targeted changes to fix the test failures.`,
192
193
  prompt,
@@ -204,5 +205,6 @@ export async function fixCode(context) {
204
205
  cost,
205
206
  model,
206
207
  details: `Applied fix for ${failedChecks.length} failing check(s) on PR #${prNumber}`,
208
+ narrative: (resultContent || "").substring(0, 2000),
207
209
  };
208
210
  }
@@ -99,5 +99,6 @@ export async function resolveIssue(context) {
99
99
  model,
100
100
  commitUrl: null,
101
101
  details: `Generated code for issue #${issueNumber}: ${resultContent.substring(0, 200)}`,
102
+ narrative: (resultContent || "").substring(0, 2000),
102
103
  };
103
104
  }
@@ -46,6 +46,13 @@ async function reviewSingleIssue({ octokit, repo, config, targetIssueNumber, ins
46
46
  sortByMtime: true,
47
47
  clean: true,
48
48
  });
49
+ const webFiles = scanDirectory(config.paths.web?.path || "src/web/", [".html", ".css", ".js"], {
50
+ fileLimit: t.sourceScan || 20,
51
+ contentLimit: t.sourceContent || 5000,
52
+ recursive: true,
53
+ sortByMtime: true,
54
+ clean: true,
55
+ });
49
56
  const docsFiles = scanDirectory(config.paths.documentation?.path || "docs/", [".md"], {
50
57
  fileLimit: t.featuresScan || 10,
51
58
  contentLimit: t.documentSummary || 2000,
@@ -66,6 +73,14 @@ async function reviewSingleIssue({ octokit, repo, config, targetIssueNumber, ins
66
73
  `## Current Tests (${testFiles.length} files)`,
67
74
  ...testFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
68
75
  "",
76
+ ...(webFiles.length > 0
77
+ ? [
78
+ `## Website Files (${webFiles.length} files)`,
79
+ "The website in `src/web/` uses the JS library.",
80
+ ...webFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
81
+ "",
82
+ ]
83
+ : []),
69
84
  ...(docsFiles.length > 0
70
85
  ? [`## Documentation (${docsFiles.length} files)`, ...docsFiles.map((f) => `- ${f.name}`), ""]
71
86
  : []),
@@ -41,6 +41,13 @@ export async function transform(context) {
41
41
  clean: true,
42
42
  outline: true,
43
43
  });
44
+ const webFiles = scanDirectory(config.paths.web?.path || "src/web/", [".html", ".css", ".js"], {
45
+ fileLimit: t.sourceScan || 10,
46
+ contentLimit: t.sourceContent || 5000,
47
+ recursive: true,
48
+ sortByMtime: true,
49
+ clean: true,
50
+ });
44
51
 
45
52
  const { data: rawIssues } = await octokit.rest.issues.listForRepo({
46
53
  ...repo,
@@ -79,6 +86,7 @@ export async function transform(context) {
79
86
  mission,
80
87
  features,
81
88
  sourceFiles,
89
+ webFiles,
82
90
  openIssues,
83
91
  tuning: t,
84
92
  });
@@ -107,6 +115,16 @@ export async function transform(context) {
107
115
  `## Current Source Files (${sourceFiles.length})`,
108
116
  ...sourceFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
109
117
  "",
118
+ ...(webFiles.length > 0
119
+ ? [
120
+ `## Website Files (${webFiles.length})`,
121
+ "The website in `src/web/` uses the JS library.",
122
+ "When transforming source code, also update the website to use the library's new/changed features.",
123
+ "The `lib-meta.js` file (generated by `npm run build:web` from `package.json`) provides `name`, `version`, and `description` exports to the browser.",
124
+ ...webFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
125
+ "",
126
+ ]
127
+ : []),
110
128
  `## Open Issues (${openIssues.length})`,
111
129
  ...openIssues.slice(0, t.issuesScan || 20).map((i) => summariseIssue(i, t.issueBodyLimit || 500)),
112
130
  "",
@@ -183,6 +201,7 @@ export async function transform(context) {
183
201
  cost,
184
202
  model,
185
203
  details: resultContent.substring(0, 500),
204
+ narrative: (resultContent || "").substring(0, 2000),
186
205
  promptBudget,
187
206
  contextNotes: `Transformed with ${sourceFiles.length} source files (mtime-sorted, cleaned), ${features.length} features, ${openIssues.length} issues (${rawIssues.length - openIssues.length} stale filtered).`,
188
207
  };
@@ -201,6 +220,7 @@ async function transformTdd({
201
220
  mission,
202
221
  features,
203
222
  sourceFiles,
223
+ webFiles,
204
224
  openIssues,
205
225
  tuning: t,
206
226
  }) {
@@ -228,6 +248,14 @@ async function transformTdd({
228
248
  `## Current Source Files (${sourceFiles.length})`,
229
249
  ...sourceFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
230
250
  "",
251
+ ...(webFiles.length > 0
252
+ ? [
253
+ `## Website Files (${webFiles.length})`,
254
+ "The website in `src/web/` uses the JS library.",
255
+ ...webFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
256
+ "",
257
+ ]
258
+ : []),
231
259
  `## Open Issues (${openIssues.length})`,
232
260
  ...openIssues.slice(0, t.issuesScan || 20).map((i) => summariseIssue(i, t.issueBodyLimit || 500)),
233
261
  "",
@@ -272,6 +300,14 @@ async function transformTdd({
272
300
  `## Current Source Files (${sourceFiles.length})`,
273
301
  ...sourceFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
274
302
  "",
303
+ ...(webFiles.length > 0
304
+ ? [
305
+ `## Website Files (${webFiles.length})`,
306
+ "The website in `src/web/` uses the JS library. Update it to reflect any new features.",
307
+ ...webFiles.map((f) => `### ${f.name}\n\`\`\`\n${f.content}\n\`\`\``),
308
+ "",
309
+ ]
310
+ : []),
275
311
  formatPathsSection(writablePaths, readOnlyPaths, _config),
276
312
  "",
277
313
  "## Output Artifacts",
@@ -12,6 +12,9 @@ You may complete the implementation of a feature and/or bring the code output in
12
12
  or other documentation. Do as much as you can all at once so that the build runs (even with nothing
13
13
  to build) and the tests pass and the main at least doesn't output an error.
14
14
 
15
+ The repository has a website in `src/web/` that uses the JS library. If a fix affects library
16
+ exports or behaviour, also update the website files to stay in sync.
17
+
15
18
  ## Merge Conflict Resolution
16
19
 
17
20
  When resolving merge conflicts (files containing <<<<<<< / ======= / >>>>>>> markers):
@@ -57,11 +57,11 @@ Users can ask for new features or mission changes through this discussion thread
57
57
 
58
58
  - **Feature requests** — When a user says "add feature X" or "I want Y", acknowledge the request and pass it to the supervisor to create a GitHub issue. The pipeline will pick it up and implement it.
59
59
  - **Re-seed requests** — When a user says "change the mission to Z" or "re-seed with plot-code-lib", explain that this requires running `npx @xn-intenton-z2a/agentic-lib init --purge --mission <name>`. List the available missions if asked: hamming-distance, fizz-buzz, roman-numerals, string-utils, dense-encoding, cron-engine, owl-ontology, plot-code-lib, time-series-lab, lunar-lander, empty. Note that re-seeding resets all source code, issues, and discussions.
60
- - **Website feedback** — The project has a website published via GitHub Pages. If a user comments on the website, pass feedback to the supervisor to create an issue for the pipeline to address.
60
+ - **Website feedback** — The project has a website that uses the JS library, published via GitHub Pages. If a user comments on the website, pass feedback to the supervisor to create an issue for the pipeline to address.
61
61
 
62
62
  ## Website Awareness
63
63
 
64
- The repository publishes a website via GitHub Pages that showcases the library. The URL follows the pattern `https://<owner>.github.io/<repo>/`. When discussing the project, mention the website as a way for users to see the library in action.
64
+ The repository publishes a website via GitHub Pages that uses the JS library. The URL follows the pattern `https://<owner>.github.io/<repo>/`. The website imports the library and displays its output. When discussing the project, mention the website as a way to see the library in action.
65
65
 
66
66
  ## Conversation Style
67
67
 
@@ -22,16 +22,29 @@ When implementing features, also produce evidence artifacts under `docs/`:
22
22
  Design the library API with hooks that make evidence capture easy: return structured result objects,
23
23
  support `outputFile` options where appropriate, and emit results that observers can record.
24
24
 
25
- ## Website Showcase
25
+ ## Website
26
26
 
27
- Maintain a website in `src/web/` that visually demonstrates the library's capabilities. The website is
28
- published to GitHub Pages automatically (from `docs/` via `npm run build:web`).
27
+ The repository has a website in `src/web/` that uses the JS library. It is published to GitHub Pages
28
+ automatically (from `docs/` via `npm run build:web`).
29
29
 
30
- - `src/web/index.html` is the main page — evolve it to showcase the library interactively
30
+ ### How the library connects to the website
31
+
32
+ - `src/lib/main.js` is the JS library — it exports functions, `name`, `version`, `description`, and `getIdentity()`
33
+ - `npm run build:web` copies `src/web/*` to `docs/` and generates `docs/lib-meta.js` from `package.json`
34
+ - `src/web/index.html` imports `lib-meta.js` via `<script type="module">` to display the library's identity
35
+ - The website should import and call library functions — not just describe them
36
+
37
+ ### What to do with the website
38
+
39
+ - **Use the library**: Import the library (or its browser-compatible parts) and call its functions on the page
40
+ - **Show real results**: Display actual output from library functions, not placeholder text
41
+ - When you add or change library functions, update the website to reflect them
42
+
43
+ ### Guidelines
44
+
45
+ - `src/web/index.html` is the main page — update it as the library grows
31
46
  - You may add CSS, JS, images, or additional HTML pages in `src/web/`
32
- - The website should demonstrate what the library does in a way a visitor can see and interact with
33
47
  - Keep it self-contained (no external CDN dependencies unless essential)
34
48
  - Link back to the repository for source code and mission details
35
- - When the library produces visual output (plots, graphs, data), embed or render it on the website
36
- - When the library is computational (algorithms, utilities), create an interactive demo or show example results
37
- - The website tests in `tests/unit/web.test.js` verify the HTML exists and is structurally valid — you may extend them
49
+ - The website tests in `tests/unit/web.test.js` verify structure and library wiring extend them as needed
50
+ - The website is not the mission — it supports the library. Don't over-invest in the website at the expense of the library
@@ -27,3 +27,4 @@ Features must be achievable in a single software repository not part of a corpor
27
27
  The feature spec should be a multiline markdown with a few level 1 headings.
28
28
  The feature must be compatible with the mission statement in MISSION.md and ideally realise part of the value in the mission.
29
29
  The feature must be something that can be realised in a single source file (as below), ideally just as a library, CLI tool or possibly an HTTP API in combination with infrastructure as code deployment.
30
+ The repository also has a website in `src/web/` that uses the JS library. When proposing features, consider both the library API and how the feature could be shown on the website.
@@ -1,5 +1,6 @@
1
- Does the combination source file, test file, README file and dependencies file show a solution
1
+ Does the combination source file, test file, website files, README file and dependencies file show a solution
2
2
  with a reasonable likelihood of including a high-impact resolution to the following issue? Evaluate whether the solution delivers substantial user value, addresses core functionality needs, and directly enhances the product's primary purpose rather than implementing superficial improvements or excessive validation.
3
+ Note: The repository has a website in `src/web/` that uses the JS library. When reviewing, check that website files are updated alongside library changes.
3
4
 
4
5
  When reviewing, also check that evidence artifacts exist under `docs/` for implemented features.
5
6
  If a feature works but has no evidence (no example outputs, test results, or walkthroughs in `docs/`),
@@ -38,7 +38,7 @@ When open issues with the `automated` label lack the `ready` label and are more
38
38
  ### Mission Initialised (init completed)
39
39
  When recent workflow runs show an init completion, the repository has a fresh or updated mission.
40
40
  Dispatch the discussions bot to announce the new mission to the community.
41
- Include the website URL in the announcement — the site is at `https://<owner>.github.io/<repo>/`.
41
+ Include the website URL in the announcement — the site is at `https://<owner>.github.io/<repo>/` and runs the library.
42
42
 
43
43
  ### Mission Accomplished (bounded missions)
44
44
  When ALL of the following conditions are met, the mission is accomplished:
@@ -48,7 +48,7 @@ When ALL of the following conditions are met, the mission is accomplished:
48
48
  4. Evidence artifacts exist under `docs/` (example outputs, test results, or walkthroughs)
49
49
 
50
50
  When all conditions are met:
51
- 1. `dispatch:agentic-lib-bot` — announce mission accomplished in the discussions thread. Include the website URL (`https://<owner>.github.io/<repo>/`) so users can see the finished product.
51
+ 1. `dispatch:agentic-lib-bot` — announce mission accomplished in the discussions thread. Include the website URL (`https://<owner>.github.io/<repo>/`) where users can see the finished product.
52
52
  2. `set-schedule:off` — stop the workflow. The mission is done.
53
53
  3. Log `mission-accomplished` in the activity log.
54
54
 
@@ -25,6 +25,9 @@ paths:
25
25
  targetSourcePath:
26
26
  path: "src/lib/"
27
27
  permissions: ["write"]
28
+ targetWebPath:
29
+ path: "src/web/"
30
+ permissions: ["write"]
28
31
  dependenciesFilepath:
29
32
  path: "package.json"
30
33
  permissions: ["write"]
@@ -4,21 +4,59 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>repository0</title>
7
+ <meta property="og:title" content="repository0">
8
+ <meta property="og:description" content="An autonomous repository powered by agentic-lib">
9
+ <meta property="og:type" content="website">
7
10
  <style>
8
11
  body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; color: #333; }
9
12
  h1 { border-bottom: 2px solid #eee; padding-bottom: 0.5rem; }
10
13
  a { color: #0366d6; }
11
- .status { background: #f6f8fa; padding: 1rem; border-radius: 6px; margin: 1rem 0; }
14
+ .identity { background: #f6f8fa; padding: 1rem; border-radius: 6px; margin: 1rem 0; font-family: monospace; }
15
+ .identity dt { font-weight: bold; color: #666; }
16
+ .identity dd { margin: 0 0 0.5rem 0; font-size: 1.1rem; }
17
+ .social { display: flex; gap: 1rem; margin: 1rem 0; flex-wrap: wrap; }
18
+ .social a { display: inline-block; padding: 0.4rem 0.8rem; border: 1px solid #ddd; border-radius: 4px; text-decoration: none; font-size: 0.9rem; }
19
+ .social a:hover { background: #f6f8fa; }
20
+ #demo-output { background: #1e1e1e; color: #d4d4d4; padding: 1rem; border-radius: 6px; font-family: monospace; white-space: pre-wrap; min-height: 2rem; }
12
21
  </style>
13
22
  </head>
14
23
  <body>
15
- <h1>repository0</h1>
16
- <div class="status">
17
- <p>This website is maintained by the autonomous pipeline. It showcases the library built from the project's mission.</p>
24
+ <h1 id="lib-name">repository0</h1>
25
+ <div class="identity">
26
+ <dl>
27
+ <dt>Version</dt>
28
+ <dd id="lib-version">loading...</dd>
29
+ <dt>Description</dt>
30
+ <dd id="lib-description">loading...</dd>
31
+ </dl>
32
+ </div>
33
+ <h2>Output</h2>
34
+ <div id="demo-output">Loading library...</div>
35
+ <h2>Links</h2>
36
+ <div class="social">
37
+ <a id="share-github" href="https://github.com/xn-intenton-z2a/repository0" target="_blank" rel="noopener">GitHub</a>
38
+ <a id="share-twitter" href="#" target="_blank" rel="noopener">X/Twitter</a>
39
+ <a id="share-linkedin" href="#" target="_blank" rel="noopener">LinkedIn</a>
18
40
  </div>
19
41
  <h2>About</h2>
20
- <p>See <a href="https://github.com/xn-intenton-z2a/repository0">the repository</a> for source code and mission details.</p>
21
- <h2>Demo</h2>
22
- <p><em>The pipeline will evolve this section to demonstrate the library's capabilities.</em></p>
42
+ <p>This website uses the library. See <a href="https://github.com/xn-intenton-z2a/repository0">the repository</a> for source code and mission details.</p>
43
+ <script type="module">
44
+ try {
45
+ const { name, version, description } = await import('./lib-meta.js');
46
+ document.getElementById('lib-name').textContent = name;
47
+ document.getElementById('lib-version').textContent = version;
48
+ document.getElementById('lib-description').textContent = description || '(no description)';
49
+ document.getElementById('demo-output').textContent = JSON.stringify({ name, version, description }, null, 2);
50
+ document.title = name + ' v' + version;
51
+ const pageUrl = encodeURIComponent(window.location.href);
52
+ const text = encodeURIComponent('Check out ' + name + ' v' + version + ' — ' + description);
53
+ document.getElementById('share-twitter').href = 'https://x.com/intent/tweet?url=' + pageUrl + '&text=' + text;
54
+ document.getElementById('share-linkedin').href = 'https://www.linkedin.com/sharing/share-offsite/?url=' + pageUrl;
55
+ } catch (e) {
56
+ document.getElementById('lib-version').textContent = '(build required)';
57
+ document.getElementById('lib-description').textContent = 'Run npm run build:web to generate library metadata';
58
+ document.getElementById('demo-output').textContent = 'Library not yet built. Run: npm run build:web';
59
+ }
60
+ </script>
23
61
  </body>
24
62
  </html>
@@ -3,10 +3,30 @@
3
3
  // Copyright (C) 2025-2026 Polycode Limited
4
4
  // src/lib/main.js
5
5
 
6
+ import { createRequire } from "module";
6
7
  import { fileURLToPath } from "url";
7
8
 
9
+ const require = createRequire(import.meta.url);
10
+ const pkg = require("../../package.json");
11
+
12
+ export const name = pkg.name;
13
+ export const version = pkg.version;
14
+ export const description = pkg.description;
15
+
16
+ export function getIdentity() {
17
+ return { name, version, description };
18
+ }
19
+
8
20
  export function main(args) {
9
- console.log(`Run with: ${JSON.stringify(args)}`);
21
+ if (args?.includes("--version")) {
22
+ console.log(version);
23
+ return;
24
+ }
25
+ if (args?.includes("--identity")) {
26
+ console.log(JSON.stringify(getIdentity(), null, 2));
27
+ return;
28
+ }
29
+ console.log(`${name}@${version}`);
10
30
  }
11
31
 
12
32
  if (process.argv[1] === fileURLToPath(import.meta.url)) {
@@ -1,7 +1,7 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  // Copyright (C) 2025-2026 Polycode Limited
3
- import { describe, test } from "vitest";
4
- import { main } from "../../src/lib/main.js";
3
+ import { describe, test, expect } from "vitest";
4
+ import { main, getIdentity, name, version, description } from "../../src/lib/main.js";
5
5
 
6
6
  describe("Main Output", () => {
7
7
  test("should terminate without error", () => {
@@ -9,3 +9,18 @@ describe("Main Output", () => {
9
9
  main();
10
10
  });
11
11
  });
12
+
13
+ describe("Library Identity", () => {
14
+ test("exports name, version, and description", () => {
15
+ expect(typeof name).toBe("string");
16
+ expect(typeof version).toBe("string");
17
+ expect(typeof description).toBe("string");
18
+ expect(name.length).toBeGreaterThan(0);
19
+ expect(version).toMatch(/^\d+\.\d+\.\d+/);
20
+ });
21
+
22
+ test("getIdentity returns correct structure", () => {
23
+ const identity = getIdentity();
24
+ expect(identity).toEqual({ name, version, description });
25
+ });
26
+ });
@@ -6,17 +6,17 @@
6
6
  "main": "src/lib/main.js",
7
7
  "scripts": {
8
8
  "build": "npm run build:web",
9
- "build:web": "mkdir -p docs && touch docs/.nojekyll && cp -r src/web/* docs/ 2>/dev/null || echo 'No web files to build'",
9
+ "build:web": "mkdir -p docs && touch docs/.nojekyll && cp -r src/web/* docs/ 2>/dev/null || true && node --input-type=commonjs -p \"var p=require('./package.json');['name','version','description'].map(function(k){return 'export const '+k+' = '+JSON.stringify(p[k])+';'}).join('\\n')\" > docs/lib-meta.js",
10
10
  "test": "vitest --run tests/unit/*.test.js",
11
11
  "test:unit": "vitest --run --coverage tests/unit/*.test.js",
12
- "start": "node src/lib/main.js",
13
- "start:web": "npx serve docs"
12
+ "start": "npm run build:web && npx serve docs",
13
+ "start:cli": "node src/lib/main.js"
14
14
  },
15
15
  "keywords": [],
16
16
  "author": "",
17
17
  "license": "MIT",
18
18
  "dependencies": {
19
- "@xn-intenton-z2a/agentic-lib": "^7.1.66"
19
+ "@xn-intenton-z2a/agentic-lib": "^7.1.68"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@vitest/coverage-v8": "^4.0.18",
@@ -14,4 +14,20 @@ describe("Website", () => {
14
14
  expect(html).toContain("<html");
15
15
  expect(html).toContain("</html>");
16
16
  });
17
+
18
+ test("index.html imports the library via lib-meta.js", () => {
19
+ const html = readFileSync("src/web/index.html", "utf8");
20
+ expect(html).toContain("lib-meta.js");
21
+ });
22
+
23
+ test("index.html displays library identity elements", () => {
24
+ const html = readFileSync("src/web/index.html", "utf8");
25
+ expect(html).toContain("lib-name");
26
+ expect(html).toContain("lib-version");
27
+ });
28
+
29
+ test("index.html has social share links", () => {
30
+ const html = readFileSync("src/web/index.html", "utf8");
31
+ expect(html).toMatch(/share.*(twitter|x\.com|linkedin)/is);
32
+ });
17
33
  });