@lazyingart/agintiflow 0.20.190 → 0.20.191

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": "@lazyingart/agintiflow",
3
- "version": "0.20.190",
3
+ "version": "0.20.191",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
@@ -10,6 +10,17 @@ This note records the working publication route for AgInTiFlow so future release
10
10
 
11
11
  Latest verified release:
12
12
 
13
+ - Version: `0.20.190`
14
+ - Commit: `f192f8e`
15
+ - GitHub Actions run: `https://github.com/lazyingart/AgInTiFlow/actions/runs/26736284533`
16
+ - Workflow result: success
17
+ - npm registry check: `npm view @lazyingart/agintiflow version dist-tags.latest --registry=https://registry.npmjs.org` returned `0.20.190`.
18
+ - Installed verification: `npm install -g @lazyingart/agintiflow@0.20.190` then `aginti --version` returned `0.20.190`.
19
+ - Webapp verification: `aginti webapp restart --port 3210` then `curl -fsS http://127.0.0.1:3210/health` returned `version":"0.20.190"` from the global npm package path.
20
+ - Feature verification: `aginti --provider mock --routing manual --model mock-agent --no-shell --allow-file-tools --scs off "hello"` returned a direct greeting and did not create `hello.py`.
21
+
22
+ Previous verified release:
23
+
13
24
  - Version: `0.20.189`
14
25
  - Commit: `0095284`
15
26
  - GitHub Actions run: `https://github.com/lazyingart/AgInTiFlow/actions/runs/26734901522`
@@ -0,0 +1,88 @@
1
+ # LazyEdit Publish Skill Installation
2
+
3
+ Date: 2026-06-03
4
+
5
+ ## Installed Skill
6
+
7
+ Skill id:
8
+
9
+ - `lazyedit-publish-workflow`
10
+
11
+ Source skill:
12
+
13
+ - `/home/lachlan/.codex/skills/lazyedit-publish-workflow/SKILL.md`
14
+
15
+ AgInTiFlow project-local copy:
16
+
17
+ - `/home/lachlan/ProjectsLFS/Agent/AgInTiFlow/.aginti/skills/lazyedit-publish-workflow/SKILL.md`
18
+
19
+ Global AgInTiFlow custom copy:
20
+
21
+ - Skill Mesh storage under `/home/lachlan/.agintiflow/skillmesh/skills/lazyedit-publish-workflow/`
22
+ - Installed as a local-reviewed enabled Skill Mesh skill.
23
+
24
+ ## Why Both Copies Exist
25
+
26
+ The project-local `.aginti/skills/` copy documents the skill in the AgInTiFlow repository and lets local development sessions load it as `source=project-local`.
27
+
28
+ The Skill Mesh copy makes the same skill available from other working directories such as LALACHAN, RARACHAN, LazyEdit, or Agent without requiring the user to start AgInTiFlow from the AgInTiFlow repo.
29
+
30
+ ## Verification
31
+
32
+ Project-local loader:
33
+
34
+ ```bash
35
+ node -e "import { listSkills, selectSkillsForGoal } from './src/skill-library.js'; const skill=listSkills({projectRoot:process.cwd(), includeBody:true}).find(s=>s.id==='lazyedit-publish-workflow'); if(!skill) throw new Error('missing'); console.log(skill.source);"
36
+ ```
37
+
38
+ Expected result:
39
+
40
+ ```text
41
+ project-local
42
+ ```
43
+
44
+ Global Skill Mesh install:
45
+
46
+ ```bash
47
+ node bin/aginti-cli.js skillmesh export lazyedit-publish-workflow --out /tmp/lazyedit-publish-workflow.skillpack.json
48
+ node bin/aginti-cli.js skillmesh import /tmp/lazyedit-publish-workflow.skillpack.json --enable
49
+ node bin/aginti-cli.js skillmesh status
50
+ ```
51
+
52
+ Expected result includes:
53
+
54
+ ```text
55
+ enabled lazyedit-publish-workflow: LazyEdit Publish Workflow
56
+ ```
57
+
58
+ Cross-directory discovery:
59
+
60
+ ```bash
61
+ cd /home/lachlan/ProjectsLFS/Agent
62
+ aginti skills lazyedit
63
+
64
+ cd /home/lachlan/ProjectsLFS/LALACHAN
65
+ node /home/lachlan/ProjectsLFS/Agent/AgInTiFlow/bin/aginti-cli.js skills lazyedit
66
+ ```
67
+
68
+ Expected result:
69
+
70
+ ```text
71
+ lazyedit-publish-workflow ... source=skillmesh
72
+ ```
73
+
74
+ Selection check:
75
+
76
+ ```bash
77
+ node -e "import { selectSkillsForGoal } from '/home/lachlan/ProjectsLFS/Agent/AgInTiFlow/src/skill-library.js'; const selected=selectSkillsForGoal('publish latest LALACHAN generated video through LazyEdit to Shipinhao YouTube Instagram with corrected subtitles', {projectRoot:'/home/lachlan/ProjectsLFS/LALACHAN', includeBody:true}).map(s=>s.id); console.log(selected); if(!selected.includes('lazyedit-publish-workflow')) throw new Error('not selected');"
78
+ ```
79
+
80
+ Expected result:
81
+
82
+ - `lazyedit-publish-workflow` appears in the selected skill list.
83
+
84
+ ## Operational Notes
85
+
86
+ The skill is prompt guidance, not a privileged tool. LazyEdit publishing still runs through normal AgInTiFlow permission policy and shell/tmux safeguards.
87
+
88
+ The subtitle correction rule is preserved: generated video scripts/stories are reference context for correcting ASR recognition errors, not verbatim targets. The agent should compare ASR output against the script, infer intended wording, preserve timing/line structure, and avoid blindly copying script text when the audio differs.
@@ -0,0 +1,62 @@
1
+ # Paper Revision Skill Installation
2
+
3
+ Date: 2026-06-03
4
+
5
+ Source repository:
6
+
7
+ - `/home/lachlan/ProjectsLFS/paper-revision-skill`
8
+ - `https://github.com/lachlanchen/paper-revision-skill`
9
+
10
+ Purpose:
11
+
12
+ - Add plan-gated academic manuscript revision as a reusable skill.
13
+ - Keep manuscript-specific revision policy in the skill, not in AgInTiFlow core.
14
+ - Let Codex, AgInTiFlow, Claude, Gemini, and Copilot consume the same workflow guidance with tool-specific entry files.
15
+
16
+ AgInTiFlow integration:
17
+
18
+ - The repository's root `SKILL.md` is Codex-style and uses `name:` plus `description:`.
19
+ - AgInTiFlow SkillMesh now accepts that dialect by normalizing `name:` to native `id:` and deriving `label:` when missing.
20
+ - Install the root `SKILL.md` as a reviewed local SkillMesh skill and enable it.
21
+
22
+ Suggested install command from the AgInTiFlow repository:
23
+
24
+ ```bash
25
+ node --input-type=module - <<'NODE'
26
+ import fs from "node:fs/promises";
27
+ import {
28
+ buildSkillPackFromMarkdown,
29
+ enableSkillMeshSkill,
30
+ installSkillPack,
31
+ } from "./src/skillmesh.js";
32
+
33
+ const content = await fs.readFile("/home/lachlan/ProjectsLFS/paper-revision-skill/SKILL.md", "utf8");
34
+ const pack = await buildSkillPackFromMarkdown(content, { valueScore: 95 });
35
+ await installSkillPack(pack, { enabled: true });
36
+ await enableSkillMeshSkill("paper-revision-skill", true);
37
+ console.log(JSON.stringify({ ok: true, installedSkills: pack.skills.map((skill) => skill.id), packHash: pack.packHash }, null, 2));
38
+ NODE
39
+ ```
40
+
41
+ Validation:
42
+
43
+ ```bash
44
+ node scripts/smoke-skillmesh.js
45
+ node --input-type=module - <<'NODE'
46
+ import { selectSkillsForGoal } from "./src/skill-library.js";
47
+ const selected = selectSkillsForGoal(
48
+ "Use the paper revision workflow to answer reviewer comments before editing LaTeX.",
49
+ { limit: 8, includeBody: false }
50
+ );
51
+ console.log(JSON.stringify(selected.map((skill) => ({ id: skill.id, source: skill.source })), null, 2));
52
+ if (!selected.some((skill) => skill.id === "paper-revision-skill")) {
53
+ throw new Error("paper-revision-skill was not selected");
54
+ }
55
+ NODE
56
+ ```
57
+
58
+ Boundary:
59
+
60
+ - Do not move manuscript-revision details into AgInTiFlow core.
61
+ - Improve AgInTiFlow core only when the issue is general skill compatibility, skill discovery, SkillMesh validation, evidence tracking, PDF/build tooling, or tool invocation reliability.
62
+ - Keep the skill's plan-first, edit-second, PDF-verified revision workflow in the skill repository.
@@ -64,6 +64,28 @@ assert(!listSkills({ includeBody: false }).some((skill) => skill.id === "mesh-an
64
64
  await setSkillMeshMode("share");
65
65
  const config = await loadSkillMeshConfig();
66
66
  assert(config.mode === "share", "share mode should persist");
67
+
68
+ const codexStyleMarkdown = [
69
+ "---",
70
+ "name: paper-revision-skill",
71
+ "description: Plan-gated academic manuscript revision workflow for LaTeX papers, reviewer responses, proof corrections, redlines, PDF-backed audits, and submission packaging.",
72
+ "---",
73
+ "",
74
+ "Plan first, edit second, verify from compiled PDFs, and keep revision evidence under references/.",
75
+ "",
76
+ ].join("\n");
77
+ const codexPack = await buildSkillPackFromMarkdown(codexStyleMarkdown, { valueScore: 90 });
78
+ assert(codexPack.skills[0].id === "paper-revision-skill", "Codex-style name should become SkillMesh id");
79
+ assert(codexPack.skills[0].content.includes("id: paper-revision-skill"), "Codex-style skill should be normalized with id");
80
+ assert(codexPack.skills[0].content.includes("label: Paper Revision Skill"), "Codex-style skill should receive a label");
81
+ await installSkillPack(codexPack, { enabled: true });
82
+ assert(
83
+ selectSkillsForGoal("use the paper revision workflow to answer reviewer comments before editing latex", { limit: 8 }).some(
84
+ (skill) => skill.id === "paper-revision-skill"
85
+ ),
86
+ "Codex-style imported skill should be selectable"
87
+ );
88
+
67
89
  const serviceUnit = buildSkillMeshServiceUnit({
68
90
  dataDir: path.join(tempRoot, "relay-service"),
69
91
  runScript: path.join(tempRoot, "relay-service", "aginti-skill-relay.run.sh"),
@@ -120,6 +142,7 @@ console.log(
120
142
  "metadata-sync",
121
143
  "soft-unreachable-node",
122
144
  "systemd-service-unit",
145
+ "codex-style-skill-import",
123
146
  ],
124
147
  },
125
148
  null,
@@ -100,15 +100,19 @@ function normalizeExternalTools(value) {
100
100
  export function loadSkillFile(filePath) {
101
101
  const text = fs.readFileSync(filePath, "utf8");
102
102
  const { meta, body } = parseFrontmatter(text, filePath);
103
- for (const field of ["id", "label", "description"]) {
104
- if (typeof meta[field] !== "string" || !meta[field].trim()) {
105
- throw new Error(`${filePath}: ${field} must be a non-empty string`);
106
- }
103
+ const id = String(meta.id || meta.name || "").trim();
104
+ if (!id) {
105
+ throw new Error(`${filePath}: id or name must be a non-empty string`);
106
+ }
107
+ const label = String(meta.label || titleCaseSkillId(id)).trim();
108
+ const description = String(meta.description || "").trim();
109
+ if (!description) {
110
+ throw new Error(`${filePath}: description must be a non-empty string`);
107
111
  }
108
112
  return {
109
- id: meta.id.trim(),
110
- label: meta.label.trim(),
111
- description: meta.description.trim(),
113
+ id,
114
+ label,
115
+ description,
112
116
  triggers: normalizeList(meta.triggers),
113
117
  tools: normalizeList(meta.tools),
114
118
  body,
package/src/skillmesh.js CHANGED
@@ -321,6 +321,60 @@ function canonicalSkillContent(content = "") {
321
321
  return String(content || "").replace(/\r\n/g, "\n").trim();
322
322
  }
323
323
 
324
+ function titleCaseSkillId(id = "") {
325
+ return String(id || "")
326
+ .split(/[-_\s/]+/)
327
+ .filter(Boolean)
328
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
329
+ .join(" ");
330
+ }
331
+
332
+ function parseSkillMarkdownContent(content = "", context = "SKILL.md") {
333
+ const text = String(content || "");
334
+ if (!text.trim()) throw new Error(`${context}: empty skill`);
335
+ if (Buffer.byteLength(text, "utf8") > MAX_SKILL_BYTES) throw new Error(`${context}: skill is too large`);
336
+ if (redactSensitiveText(text) !== text) throw new Error(`${context}: contains token-like secret text`);
337
+ const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
338
+ if (!match) throw new Error(`${context}: missing YAML frontmatter`);
339
+ const frontmatter = match[1].replace(/\r\n/g, "\n");
340
+ const fields = {};
341
+ const passthrough = [];
342
+ for (const line of frontmatter.split(/\n/)) {
343
+ const scalar = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
344
+ if (scalar) {
345
+ const key = scalar[1];
346
+ const value = scalar[2].trim().replace(/^['"]|['"]$/g, "");
347
+ if (value) fields[key] = value;
348
+ if (["id", "name", "label", "description"].includes(key)) continue;
349
+ }
350
+ passthrough.push(line);
351
+ }
352
+ const id = fields.id || fields.name || "";
353
+ if (!id) throw new Error(`${context}: id or name is required`);
354
+ if (!safeSkillId(id)) throw new Error(`${context}: invalid skill id ${id}`);
355
+ const description = fields.description || "";
356
+ if (!description) throw new Error(`${context}: description is required`);
357
+ const label = fields.label || titleCaseSkillId(id);
358
+ return {
359
+ fields: { ...fields, id, label, description },
360
+ body: text.slice(match[0].length).trim(),
361
+ passthrough: passthrough.join("\n").trim(),
362
+ };
363
+ }
364
+
365
+ function normalizeSkillMarkdownForSkillMesh(content = "", context = "SKILL.md") {
366
+ const parsed = parseSkillMarkdownContent(content, context);
367
+ const frontmatter = [
368
+ "---",
369
+ `id: ${parsed.fields.id}`,
370
+ `label: ${parsed.fields.label}`,
371
+ `description: ${parsed.fields.description}`,
372
+ parsed.passthrough,
373
+ "---",
374
+ ].filter((line) => line !== "");
375
+ return `${frontmatter.join("\n")}\n\n${parsed.body}`.trim();
376
+ }
377
+
324
378
  function canonicalPackForSignature(pack) {
325
379
  const copy = { ...pack };
326
380
  delete copy.signature;
@@ -382,25 +436,7 @@ function verifyPackSignature(pack) {
382
436
  }
383
437
 
384
438
  function validateSkillMarkdownContent(content = "", context = "SKILL.md") {
385
- const text = String(content || "");
386
- if (!text.trim()) throw new Error(`${context}: empty skill`);
387
- if (Buffer.byteLength(text, "utf8") > MAX_SKILL_BYTES) throw new Error(`${context}: skill is too large`);
388
- if (redactSensitiveText(text) !== text) throw new Error(`${context}: contains token-like secret text`);
389
- const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
390
- if (!match) throw new Error(`${context}: missing YAML frontmatter`);
391
- const frontmatter = match[1];
392
- const fields = {};
393
- for (const line of frontmatter.split(/\r?\n/)) {
394
- const scalar = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
395
- if (!scalar) continue;
396
- const value = scalar[2].trim().replace(/^['"]|['"]$/g, "");
397
- if (value) fields[scalar[1]] = value;
398
- }
399
- for (const field of ["id", "label", "description"]) {
400
- if (!fields[field]) throw new Error(`${context}: ${field} is required`);
401
- }
402
- if (!safeSkillId(fields.id)) throw new Error(`${context}: invalid skill id ${fields.id}`);
403
- return fields;
439
+ return parseSkillMarkdownContent(content, context).fields;
404
440
  }
405
441
 
406
442
  function builtInSkillIds() {
@@ -420,7 +456,7 @@ export async function buildSkillPack(skillId, { home = agintiflowHome(), author
420
456
  export async function buildSkillPackFromMarkdown(content, { home = agintiflowHome(), author = "local-user", valueScore = 80 } = {}) {
421
457
  const fields = validateSkillMarkdownContent(content, "SKILL.md");
422
458
  const id = fields.id;
423
- const normalized = canonicalSkillContent(content);
459
+ const normalized = normalizeSkillMarkdownForSkillMesh(content, "SKILL.md");
424
460
  const entry = {
425
461
  id,
426
462
  path: `skills/${id}/SKILL.md`,