@alessandroraffa/tangyr 4.0.0 → 4.1.0

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/dist/index.js CHANGED
@@ -16497,7 +16497,10 @@ function resolveCopilotProfile(scope, projectRoot, mappings) {
16497
16497
  hooks: r(slotMap, "hooks"),
16498
16498
  hook_scripts: r(slotMap, "hook_scripts"),
16499
16499
  mcp_shared_file: r(slotMap, "mcp_shared_file"),
16500
- instructions
16500
+ instructions,
16501
+ // Project-only, like instructions: `.github/instructions` is a repository
16502
+ // surface and has no user-level equivalent Copilot documents.
16503
+ rules: r(slotMap, "rules")
16501
16504
  };
16502
16505
  }
16503
16506
  function resolveCodexProfile(scope, projectRoot, mappings) {
@@ -28327,6 +28330,36 @@ ${frontmatterYaml}${body}`;
28327
28330
  }
28328
28331
  return { agentsAppendix: "", dotRulesFiles };
28329
28332
  }
28333
+ function compileCopilotRules(sourceRulesDir) {
28334
+ if (!fs39.existsSync(sourceRulesDir)) {
28335
+ return [];
28336
+ }
28337
+ const files = [];
28338
+ for (const ruleFile of ts(path38.join(sourceRulesDir, "*.md")).sort()) {
28339
+ const name = path38.basename(ruleFile, ".md");
28340
+ const { data } = parseMarkdownFrontmatter(ruleFile);
28341
+ const { body } = parseRule(ruleFile);
28342
+ const declared = data.paths;
28343
+ const applyTo = Array.isArray(declared) ? declared.filter((p) => typeof p === "string").join(", ") : typeof declared === "string" && declared.trim() !== "" ? declared.trim() : "**";
28344
+ const frontmatter = [
28345
+ "---",
28346
+ `applyTo: ${JSON.stringify(applyTo)}`,
28347
+ "x-tangyr:",
28348
+ ` source: rules/${path38.basename(ruleFile)}`,
28349
+ ` hash: ${computeSourceHash(ruleFile)}`,
28350
+ " target: copilot",
28351
+ "---"
28352
+ ].join("\n");
28353
+ files.push({
28354
+ name: `${name}.instructions.md`,
28355
+ content: `${frontmatter}
28356
+
28357
+ ${body.trim()}
28358
+ `
28359
+ });
28360
+ }
28361
+ return files;
28362
+ }
28330
28363
 
28331
28364
  // src/adapters/codex.ts
28332
28365
  var skippedComponents = ["settings", "lsp", "output-styles"];
@@ -29002,12 +29035,7 @@ function promptFrontmatter(data, defaultName) {
29002
29035
  }
29003
29036
 
29004
29037
  // src/adapters/copilot.ts
29005
- var skippedComponents2 = [
29006
- "rules",
29007
- "settings",
29008
- "lsp",
29009
- "output-styles"
29010
- ];
29038
+ var skippedComponents2 = ["settings", "lsp", "output-styles"];
29011
29039
  var legacyCopilotAgentsPath = "~/.copilot/agents";
29012
29040
  function syncCopilot(config, sourceRoot, mappings, extensions, options, lossReport, logger, manifest, scopePath) {
29013
29041
  const scope = options.scope ?? "global";
@@ -29018,6 +29046,7 @@ function syncCopilot(config, sourceRoot, mappings, extensions, options, lossRepo
29018
29046
  }).copilot;
29019
29047
  const paths = {
29020
29048
  agents: profile.agents,
29049
+ rules: profile.rules,
29021
29050
  skills: profile.skills,
29022
29051
  prompts: profile.prompts,
29023
29052
  hooks: profile.hooks,
@@ -29051,6 +29080,36 @@ function syncCopilot(config, sourceRoot, mappings, extensions, options, lossRepo
29051
29080
  )
29052
29081
  );
29053
29082
  }
29083
+ if (!shouldSkipComponent3(options, "rules") && !paths.rules) {
29084
+ addLoss(lossReport, "copilot", "rules", {
29085
+ source: "rules",
29086
+ fields: [
29087
+ {
29088
+ field: "rules",
29089
+ action: "rule-path-scoping",
29090
+ severity: resolveLossSeverity(
29091
+ "agent-field",
29092
+ "rules",
29093
+ "rule-path-scoping"
29094
+ ),
29095
+ detail: "Rules: no user-level rules surface for Copilot; `.github/instructions` is a repository path and has no global equivalent"
29096
+ }
29097
+ ]
29098
+ });
29099
+ }
29100
+ if (!shouldSkipComponent3(options, "rules") && paths.rules) {
29101
+ outcomes.push(
29102
+ ...syncRules2(
29103
+ config,
29104
+ sourceRoot,
29105
+ paths.rules,
29106
+ options,
29107
+ logger,
29108
+ manifest,
29109
+ scopePath
29110
+ )
29111
+ );
29112
+ }
29054
29113
  if (!shouldSkipComponent3(options, "agents")) {
29055
29114
  outcomes.push(...cleanupLegacyAgents(paths, options, logger));
29056
29115
  outcomes.push(
@@ -29456,6 +29515,36 @@ function syncMcp3(config, sourceRoot, paths, options, lossReport, logger) {
29456
29515
  logger
29457
29516
  );
29458
29517
  }
29518
+ function syncRules2(config, sourceRoot, rulesSlot, options, logger, manifest, scopePath) {
29519
+ const sourceRulesDir = path41.resolve(sourceRoot, config.source.rules);
29520
+ if (!fs41.existsSync(sourceRulesDir)) {
29521
+ return [skippedMissingSource3("rules", sourceRulesDir)];
29522
+ }
29523
+ const destinationRoot = resolveTargetPath(rulesSlot);
29524
+ return compileCopilotRules(sourceRulesDir).map((file) => {
29525
+ const destination = path41.join(destinationRoot, file.name);
29526
+ if (options.dryRun) {
29527
+ logger.info(`[dry-run] rules: compile -> ${destination}`);
29528
+ return {
29529
+ component: "rules",
29530
+ status: "dry-run",
29531
+ path: destination
29532
+ };
29533
+ }
29534
+ return writeCompiledArtifact2(
29535
+ "rules",
29536
+ destination,
29537
+ file.content,
29538
+ void 0,
29539
+ config,
29540
+ sourceRoot,
29541
+ options,
29542
+ logger,
29543
+ manifest,
29544
+ scopePath
29545
+ );
29546
+ });
29547
+ }
29459
29548
  function writeCompiledArtifact2(component, destination, content, expectedHash, config, sourceRoot, options, logger, manifest, scopePath) {
29460
29549
  if (!options.force && isCompiledCurrent2(destination, content, expectedHash)) {
29461
29550
  return { component, status: "skipped-current", path: destination };
@@ -29614,7 +29703,7 @@ function syncCursor(config, sourceRoot, mappings, extensions, options, lossRepor
29614
29703
  }
29615
29704
  if (!shouldSkipComponent4(options, "rules")) {
29616
29705
  outcomes.push(
29617
- ...syncRules2(
29706
+ ...syncRules3(
29618
29707
  config,
29619
29708
  sourceRoot,
29620
29709
  paths,
@@ -29870,7 +29959,7 @@ function syncAgents3(config, sourceRoot, paths, mappings, extensions, options, l
29870
29959
  );
29871
29960
  });
29872
29961
  }
29873
- function syncRules2(config, sourceRoot, paths, mappings, options, lossReport, logger, manifest, scopePath) {
29962
+ function syncRules3(config, sourceRoot, paths, mappings, options, lossReport, logger, manifest, scopePath) {
29874
29963
  const sourceRulesDir = path42.join(sourceRoot, config.source.rules);
29875
29964
  if (!fs42.existsSync(sourceRulesDir)) {
29876
29965
  return [skippedMissingSource4("rules", sourceRulesDir)];
@@ -30202,7 +30291,7 @@ function syncCline(config, sourceRoot, mappings, extensions, options, lossReport
30202
30291
  }
30203
30292
  if (!shouldSkipComponent5(options, "rules")) {
30204
30293
  outcomes.push(
30205
- ...syncRules3(
30294
+ ...syncRules4(
30206
30295
  config,
30207
30296
  sourceRoot,
30208
30297
  paths,
@@ -30337,7 +30426,7 @@ function syncAgents4(config, sourceRoot, mappings, extensions, options, lossRepo
30337
30426
  };
30338
30427
  });
30339
30428
  }
30340
- function syncRules3(config, sourceRoot, paths, mappings, options, lossReport, logger, manifest, scopePath) {
30429
+ function syncRules4(config, sourceRoot, paths, mappings, options, lossReport, logger, manifest, scopePath) {
30341
30430
  const sourceRulesDir = path43.join(sourceRoot, config.source.rules);
30342
30431
  if (!fs43.existsSync(sourceRulesDir)) {
30343
30432
  return [skippedMissingSource5("rules", sourceRulesDir)];
@@ -32354,6 +32443,9 @@ function syncOutcomeToManifestKey(tool, outcome, mappings, scope = "global", pro
32354
32443
  const hooksRoot = resolveTargetPath(copilot.hooks);
32355
32444
  const mcpFile2 = resolveTargetPath(copilot.mcp_shared_file);
32356
32445
  const instructionsMirror = copilot.instructions !== null ? resolveTargetPath(copilot.instructions) : null;
32446
+ if (copilot.rules !== null && outcome.path.startsWith(`${resolveTargetPath(copilot.rules)}${path45.sep}`)) {
32447
+ return `copilot/rules/${path45.relative(resolveTargetPath(copilot.rules), outcome.path)}`;
32448
+ }
32357
32449
  if (outcome.path.startsWith(`${skillsRoot2}${path45.sep}`)) {
32358
32450
  return `copilot/skills/${path45.relative(skillsRoot2, outcome.path)}`;
32359
32451
  }
@@ -52,6 +52,9 @@ targets:
52
52
  hook_scripts: ~/.agents/hooks
53
53
  mcp_shared_file: ~/.copilot/mcp-config.json
54
54
  instructions: null
55
+ # Null, like instructions: `.github/instructions` is a repository surface
56
+ # and Copilot documents no user-level equivalent for it.
57
+ rules: null
55
58
  project:
56
59
  agents: .github/agents
57
60
  skills: .github/skills
@@ -61,6 +64,18 @@ targets:
61
64
  mcp_shared_file: .vscode/mcp.json
62
65
  instructions: .github/copilot-instructions.md
63
66
  agents_md: AGENTS.md
67
+ # Copilot's own rules surface, and the only one that keeps a rule's path
68
+ # scope. It reads `.github/instructions/*.instructions.md`, whose
69
+ # frontmatter `applyTo` takes a glob, so a rule declaring `paths` survives
70
+ # as a rule rather than as prose folded into the instructions file
71
+ # (https://docs.github.com/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot,
72
+ # https://code.visualstudio.com/docs/agent-customization/custom-instructions).
73
+ # Until this entry existed Copilot received no rules at all: it recorded a
74
+ # `rule-path-scoping` loss whose text — "no verified global user-level
75
+ # rules surface" — was written for the global scope and had gone stale
76
+ # here, where `.github/` is Copilot's alone and nothing contends for it.
77
+ # Measured 2026-09-11 and reported independently: 0 of 3 rules delivered.
78
+ rules: .github/instructions
64
79
 
65
80
  codex:
66
81
  global:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alessandroraffa/tangyr",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "CLI for the Tangyr discipline — install and manage operating kits for AI coding tools",
5
5
  "license": "MIT",
6
6
  "engines": {