@hasna/instructions 0.4.8 → 0.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.
- package/README.md +35 -0
- package/dist/cli/index.js +449 -218
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +417 -186
- package/dist/lib/apply.d.ts +7 -0
- package/dist/lib/apply.d.ts.map +1 -1
- package/dist/lib/global-agent-rules-standard.d.ts +106 -0
- package/dist/lib/global-agent-rules-standard.d.ts.map +1 -1
- package/dist/lib/global-agent-rules-stored-content.test.d.ts +2 -0
- package/dist/lib/global-agent-rules-stored-content.test.d.ts.map +1 -0
- package/dist/lib/session-render-contract.d.ts +10 -0
- package/dist/lib/session-render-contract.d.ts.map +1 -1
- package/dist/lib/session-render-ownership.d.ts +23 -0
- package/dist/lib/session-render-ownership.d.ts.map +1 -0
- package/dist/lib/session-render-ownership.test.d.ts +2 -0
- package/dist/lib/session-render-ownership.test.d.ts.map +1 -0
- package/dist/lib/session-render.d.ts +24 -1
- package/dist/lib/session-render.d.ts.map +1 -1
- package/dist/mcp/index.js +214 -39
- package/package.json +1 -1
package/dist/mcp/index.js
CHANGED
|
@@ -5359,8 +5359,12 @@ var init_redact = __esm(() => {
|
|
|
5359
5359
|
});
|
|
5360
5360
|
|
|
5361
5361
|
// src/lib/session-render-contract.ts
|
|
5362
|
-
var SESSION_RENDER_SCHEMA = "hasna.configs.session-render/v1";
|
|
5363
|
-
var init_session_render_contract = () => {
|
|
5362
|
+
var SESSION_RENDER_SCHEMA = "hasna.configs.session-render/v1", SESSION_RENDER_MANAGED_NAMESPACE = ".hasna", SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR, SESSION_RENDER_MANIFEST_RELATIVE_PATH, SESSION_RENDER_SNAPSHOT_RELATIVE_DIR;
|
|
5363
|
+
var init_session_render_contract = __esm(() => {
|
|
5364
|
+
SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR = `${SESSION_RENDER_MANAGED_NAMESPACE}/instructions`;
|
|
5365
|
+
SESSION_RENDER_MANIFEST_RELATIVE_PATH = `${SESSION_RENDER_MANAGED_NAMESPACE}/session-render-manifest.json`;
|
|
5366
|
+
SESSION_RENDER_SNAPSHOT_RELATIVE_DIR = `${SESSION_RENDER_MANAGED_NAMESPACE}/session-render-snapshots`;
|
|
5367
|
+
});
|
|
5364
5368
|
|
|
5365
5369
|
// src/lib/project-context.ts
|
|
5366
5370
|
import { basename, dirname, isAbsolute, join as join3, parse, relative, resolve } from "path";
|
|
@@ -5645,7 +5649,7 @@ function applyTransform(source, output, context = {}) {
|
|
|
5645
5649
|
var init_transforms = () => {};
|
|
5646
5650
|
|
|
5647
5651
|
// src/lib/session-render.ts
|
|
5648
|
-
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS;
|
|
5652
|
+
var ANTIGRAVITY_RULE_FILE_CHAR_LIMIT = 12000, SESSION_RENDERER_OWNER_ID = "instructions-session-renderer", SESSION_RENDER_PROFILE_ENTRYPOINTS, SESSION_RENDER_OWNED_CONFIG_TARGETS, CODEWITH_FLATTENED_ADAPTER, CODEWITH_NATIVE_ADAPTER, SESSION_TOOL_ADAPTERS, SESSION_RENDER_MANAGED_DIRS, SESSION_RENDER_SHARED_MANAGED_DIRS, SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS;
|
|
5649
5653
|
var init_session_render = __esm(() => {
|
|
5650
5654
|
init_global_agent_rules_standard();
|
|
5651
5655
|
init_project_context();
|
|
@@ -5664,6 +5668,174 @@ var init_session_render = __esm(() => {
|
|
|
5664
5668
|
".gemini/GEMINI.md",
|
|
5665
5669
|
".gemini/ANTIGRAVITY.md"
|
|
5666
5670
|
];
|
|
5671
|
+
CODEWITH_FLATTENED_ADAPTER = {
|
|
5672
|
+
tool: "codewith",
|
|
5673
|
+
mode: "flattened-markdown",
|
|
5674
|
+
indexFile: "CODEWITH.md",
|
|
5675
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
5676
|
+
envVar: "CODEWITH_HOME",
|
|
5677
|
+
nativeImports: false,
|
|
5678
|
+
description: "Codewith CODEWITH.md flattened until native @ imports are implemented in Codewith."
|
|
5679
|
+
};
|
|
5680
|
+
CODEWITH_NATIVE_ADAPTER = {
|
|
5681
|
+
tool: "codewith",
|
|
5682
|
+
mode: "native-imports",
|
|
5683
|
+
indexFile: "CODEWITH.md",
|
|
5684
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
5685
|
+
envVar: "CODEWITH_HOME",
|
|
5686
|
+
nativeImports: true,
|
|
5687
|
+
description: "Codewith CODEWITH.md with gated @ imports into managed fragments."
|
|
5688
|
+
};
|
|
5689
|
+
SESSION_TOOL_ADAPTERS = {
|
|
5690
|
+
claude: {
|
|
5691
|
+
tool: "claude",
|
|
5692
|
+
mode: "native-imports",
|
|
5693
|
+
indexFile: "CLAUDE.md",
|
|
5694
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
5695
|
+
envVar: "CLAUDE_CONFIG_DIR",
|
|
5696
|
+
nativeImports: true,
|
|
5697
|
+
description: "Claude Code CLAUDE.md with @ imports into managed fragments."
|
|
5698
|
+
},
|
|
5699
|
+
codex: {
|
|
5700
|
+
tool: "codex",
|
|
5701
|
+
mode: "flattened-markdown",
|
|
5702
|
+
indexFile: "AGENTS.md",
|
|
5703
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
5704
|
+
envVar: "CODEX_HOME",
|
|
5705
|
+
nativeImports: false,
|
|
5706
|
+
description: "Codex AGENTS.md flattened instruction file."
|
|
5707
|
+
},
|
|
5708
|
+
cursor: {
|
|
5709
|
+
tool: "cursor",
|
|
5710
|
+
mode: "cursor-mdc",
|
|
5711
|
+
managedDir: ".cursor/rules",
|
|
5712
|
+
nativeImports: false,
|
|
5713
|
+
description: "Cursor project rule files in .cursor/rules/*.mdc."
|
|
5714
|
+
},
|
|
5715
|
+
opencode: {
|
|
5716
|
+
tool: "opencode",
|
|
5717
|
+
mode: "opencode-instructions",
|
|
5718
|
+
indexFile: "AGENTS.md",
|
|
5719
|
+
configFile: "opencode.json",
|
|
5720
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
5721
|
+
envVar: "OPENCODE_CONFIG_DIR",
|
|
5722
|
+
nativeImports: false,
|
|
5723
|
+
description: "OpenCode AGENTS.md plus opencode.json instructions pointing at managed fragments."
|
|
5724
|
+
},
|
|
5725
|
+
aicopilot: {
|
|
5726
|
+
tool: "aicopilot",
|
|
5727
|
+
mode: "flattened-markdown",
|
|
5728
|
+
indexFile: "AICOPILOT.md",
|
|
5729
|
+
managedDir: SESSION_RENDER_INSTRUCTIONS_MANAGED_DIR,
|
|
5730
|
+
envVar: "AICOPILOT_CONFIG_DIR",
|
|
5731
|
+
nativeImports: false,
|
|
5732
|
+
description: "AI Copilot AICOPILOT.md flattened instruction file."
|
|
5733
|
+
},
|
|
5734
|
+
qwen: {
|
|
5735
|
+
tool: "qwen",
|
|
5736
|
+
mode: "flattened-markdown",
|
|
5737
|
+
indexFile: "QWEN.md",
|
|
5738
|
+
managedDir: ".qwen/instructions",
|
|
5739
|
+
envVar: "QWEN_HOME",
|
|
5740
|
+
nativeImports: false,
|
|
5741
|
+
description: "Qwen Code QWEN.md hierarchical instructional context file."
|
|
5742
|
+
},
|
|
5743
|
+
antigravity: {
|
|
5744
|
+
tool: "antigravity",
|
|
5745
|
+
mode: "antigravity-rules",
|
|
5746
|
+
managedDir: ".agents/rules",
|
|
5747
|
+
nativeImports: false,
|
|
5748
|
+
description: "Google Antigravity project rules in .agents/rules/*.md."
|
|
5749
|
+
},
|
|
5750
|
+
codewith: CODEWITH_FLATTENED_ADAPTER
|
|
5751
|
+
};
|
|
5752
|
+
SESSION_RENDER_MANAGED_DIRS = [
|
|
5753
|
+
...new Set([
|
|
5754
|
+
CODEWITH_FLATTENED_ADAPTER,
|
|
5755
|
+
CODEWITH_NATIVE_ADAPTER,
|
|
5756
|
+
...Object.values(SESSION_TOOL_ADAPTERS)
|
|
5757
|
+
].map((adapter) => adapter.managedDir))
|
|
5758
|
+
];
|
|
5759
|
+
SESSION_RENDER_SHARED_MANAGED_DIRS = [".cursor/rules"];
|
|
5760
|
+
SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS = [
|
|
5761
|
+
...SESSION_RENDER_MANAGED_DIRS.filter((dir) => !SESSION_RENDER_SHARED_MANAGED_DIRS.includes(dir)),
|
|
5762
|
+
SESSION_RENDER_MANIFEST_RELATIVE_PATH,
|
|
5763
|
+
SESSION_RENDER_SNAPSHOT_RELATIVE_DIR
|
|
5764
|
+
];
|
|
5765
|
+
});
|
|
5766
|
+
|
|
5767
|
+
// src/lib/session-render-ownership.ts
|
|
5768
|
+
import { existsSync as existsSync3, readFileSync, statSync } from "fs";
|
|
5769
|
+
import { dirname as dirname2, join as join4, parse as parse2, relative as relative2, sep } from "path";
|
|
5770
|
+
function toSegments(absolutePath2) {
|
|
5771
|
+
return absolutePath2.replaceAll("\\", "/").split("/").filter(Boolean);
|
|
5772
|
+
}
|
|
5773
|
+
function pathIsSessionRenderManagedDir(absolutePath2) {
|
|
5774
|
+
const segments = toSegments(absolutePath2);
|
|
5775
|
+
return MANAGED_PATH_SEGMENTS.some((managed) => {
|
|
5776
|
+
if (managed.length === 0 || managed.length > segments.length)
|
|
5777
|
+
return false;
|
|
5778
|
+
for (let start = 0;start + managed.length <= segments.length; start += 1) {
|
|
5779
|
+
if (managed.every((segment, offset) => segments[start + offset] === segment))
|
|
5780
|
+
return true;
|
|
5781
|
+
}
|
|
5782
|
+
return false;
|
|
5783
|
+
});
|
|
5784
|
+
}
|
|
5785
|
+
function readManifestRelativePaths(manifestPath) {
|
|
5786
|
+
let stats;
|
|
5787
|
+
try {
|
|
5788
|
+
if (!existsSync3(manifestPath))
|
|
5789
|
+
return null;
|
|
5790
|
+
stats = statSync(manifestPath);
|
|
5791
|
+
} catch {
|
|
5792
|
+
return null;
|
|
5793
|
+
}
|
|
5794
|
+
const cached = manifestCache.get(manifestPath);
|
|
5795
|
+
if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
|
|
5796
|
+
return cached.relativePaths;
|
|
5797
|
+
}
|
|
5798
|
+
let manifest;
|
|
5799
|
+
try {
|
|
5800
|
+
manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
5801
|
+
} catch {
|
|
5802
|
+
return null;
|
|
5803
|
+
}
|
|
5804
|
+
if (manifest?.schema !== SESSION_RENDER_SCHEMA || !Array.isArray(manifest.files))
|
|
5805
|
+
return null;
|
|
5806
|
+
const writerId = manifest.targetOwner?.writer?.id;
|
|
5807
|
+
if (writerId !== undefined && writerId !== SESSION_RENDERER_OWNER_ID)
|
|
5808
|
+
return null;
|
|
5809
|
+
const relativePaths = new Set(manifest.files.map((file) => file?.relativePath).filter((relativePath) => typeof relativePath === "string").map((relativePath) => relativePath.replaceAll("\\", "/")));
|
|
5810
|
+
manifestCache.set(manifestPath, { mtimeMs: stats.mtimeMs, size: stats.size, relativePaths });
|
|
5811
|
+
return relativePaths;
|
|
5812
|
+
}
|
|
5813
|
+
function sessionRenderManifestClaimsPath(absolutePath2) {
|
|
5814
|
+
const root = parse2(absolutePath2).root;
|
|
5815
|
+
let home = dirname2(absolutePath2);
|
|
5816
|
+
for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
|
|
5817
|
+
const manifestPath = join4(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
|
|
5818
|
+
const relativePaths = readManifestRelativePaths(manifestPath);
|
|
5819
|
+
if (relativePaths) {
|
|
5820
|
+
const claimed = relative2(home, absolutePath2).split(sep).join("/");
|
|
5821
|
+
if (relativePaths.has(claimed))
|
|
5822
|
+
return true;
|
|
5823
|
+
}
|
|
5824
|
+
const parent = dirname2(home);
|
|
5825
|
+
if (parent === home || home === root)
|
|
5826
|
+
break;
|
|
5827
|
+
home = parent;
|
|
5828
|
+
}
|
|
5829
|
+
return false;
|
|
5830
|
+
}
|
|
5831
|
+
function sessionRenderOwnsPath(absolutePath2) {
|
|
5832
|
+
return pathIsSessionRenderManagedDir(absolutePath2) || sessionRenderManifestClaimsPath(absolutePath2);
|
|
5833
|
+
}
|
|
5834
|
+
var MANIFEST_ANCESTOR_LIMIT = 24, MANAGED_PATH_SEGMENTS, manifestCache;
|
|
5835
|
+
var init_session_render_ownership = __esm(() => {
|
|
5836
|
+
init_session_render();
|
|
5837
|
+
MANAGED_PATH_SEGMENTS = SESSION_RENDER_EXCLUSIVE_MANAGED_PATHS.map((managedPath) => managedPath.split("/").filter(Boolean));
|
|
5838
|
+
manifestCache = new Map;
|
|
5667
5839
|
});
|
|
5668
5840
|
|
|
5669
5841
|
// src/lib/apply.ts
|
|
@@ -5677,8 +5849,8 @@ __export(exports_apply, {
|
|
|
5677
5849
|
applyConfigs: () => applyConfigs,
|
|
5678
5850
|
applyConfig: () => applyConfig
|
|
5679
5851
|
});
|
|
5680
|
-
import { existsSync as
|
|
5681
|
-
import { basename as basename3, dirname as
|
|
5852
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, realpathSync, writeFileSync } from "fs";
|
|
5853
|
+
import { basename as basename3, dirname as dirname3, join as join5, resolve as resolve2 } from "path";
|
|
5682
5854
|
import { homedir as homedir2 } from "os";
|
|
5683
5855
|
function getConfigHome() {
|
|
5684
5856
|
return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir2();
|
|
@@ -5697,14 +5869,14 @@ function normalizeTargetPath(p) {
|
|
|
5697
5869
|
let current = expanded;
|
|
5698
5870
|
const missingSegments = [];
|
|
5699
5871
|
while (true) {
|
|
5700
|
-
if (
|
|
5872
|
+
if (existsSync4(current)) {
|
|
5701
5873
|
try {
|
|
5702
5874
|
return resolve2(realpathSync(current), ...missingSegments);
|
|
5703
5875
|
} catch {
|
|
5704
5876
|
return expanded;
|
|
5705
5877
|
}
|
|
5706
5878
|
}
|
|
5707
|
-
const parent =
|
|
5879
|
+
const parent = dirname3(current);
|
|
5708
5880
|
const name = basename3(current);
|
|
5709
5881
|
if (parent === current)
|
|
5710
5882
|
return expanded;
|
|
@@ -5726,11 +5898,11 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
|
|
|
5726
5898
|
throw new ConfigApplyError(`Antigravity rule file ${renderedTargetPath} is ${renderedContent.length} characters; split it before applying because Antigravity limits rule files to ${ANTIGRAVITY_RULE_FILE_CHAR_LIMIT} characters.`);
|
|
5727
5899
|
}
|
|
5728
5900
|
const path = expandPath(renderedTargetPath);
|
|
5729
|
-
const previousContent =
|
|
5901
|
+
const previousContent = existsSync4(path) ? readFileSync2(path, "utf-8") : null;
|
|
5730
5902
|
const changed = previousContent !== renderedContent;
|
|
5731
5903
|
if (!opts.dryRun) {
|
|
5732
|
-
const dir =
|
|
5733
|
-
if (!
|
|
5904
|
+
const dir = dirname3(path);
|
|
5905
|
+
if (!existsSync4(dir)) {
|
|
5734
5906
|
mkdirSync2(dir, { recursive: true });
|
|
5735
5907
|
}
|
|
5736
5908
|
if (previousContent !== null && changed) {
|
|
@@ -6033,13 +6205,15 @@ function sessionRendererOwnsTarget(targetPath, opts) {
|
|
|
6033
6205
|
return sessionRendererOwnsCanonicalTarget(canonicalApplyTargetPath(targetPath, opts), opts);
|
|
6034
6206
|
}
|
|
6035
6207
|
function sessionRendererOwnsCanonicalTarget(normalized, opts) {
|
|
6208
|
+
if (opts.allowSessionRendererOwned)
|
|
6209
|
+
return false;
|
|
6036
6210
|
const homes = new Set([
|
|
6037
6211
|
getConfigHome(),
|
|
6038
6212
|
opts.vars?.["HOME_DIR"]
|
|
6039
6213
|
].filter((home) => typeof home === "string" && home.length > 0));
|
|
6040
|
-
if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(
|
|
6214
|
+
if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join5(home, ...relativePath.split("/"))))))
|
|
6041
6215
|
return true;
|
|
6042
|
-
return normalized
|
|
6216
|
+
return sessionRenderOwnsPath(normalized);
|
|
6043
6217
|
}
|
|
6044
6218
|
var init_apply = __esm(() => {
|
|
6045
6219
|
init_types();
|
|
@@ -6047,6 +6221,7 @@ var init_apply = __esm(() => {
|
|
|
6047
6221
|
init_config_agents();
|
|
6048
6222
|
init_machine();
|
|
6049
6223
|
init_session_render();
|
|
6224
|
+
init_session_render_ownership();
|
|
6050
6225
|
init_transforms();
|
|
6051
6226
|
});
|
|
6052
6227
|
|
|
@@ -6066,8 +6241,8 @@ __export(exports_sync, {
|
|
|
6066
6241
|
KNOWN_CONFIGS: () => KNOWN_CONFIGS,
|
|
6067
6242
|
CLAUDE_PROMPT_OUTPUTS: () => CLAUDE_PROMPT_OUTPUTS
|
|
6068
6243
|
});
|
|
6069
|
-
import { existsSync as
|
|
6070
|
-
import { basename as basename4, extname as extname2, join as
|
|
6244
|
+
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync3 } from "fs";
|
|
6245
|
+
import { basename as basename4, extname as extname2, join as join6 } from "path";
|
|
6071
6246
|
function claudeRuleOutputs(fileName) {
|
|
6072
6247
|
const stem = basename4(fileName, extname2(fileName));
|
|
6073
6248
|
return [
|
|
@@ -6099,7 +6274,7 @@ function isGeneratedOutputTarget2(config, owners) {
|
|
|
6099
6274
|
return !!ownerIds && !ownerIds.has(config.id);
|
|
6100
6275
|
}
|
|
6101
6276
|
function hasClaudePromptSource() {
|
|
6102
|
-
return
|
|
6277
|
+
return existsSync5(expandPath("~/.claude/CLAUDE.md"));
|
|
6103
6278
|
}
|
|
6104
6279
|
function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
6105
6280
|
const absoluteTargetPath = expandPath(targetPath);
|
|
@@ -6107,7 +6282,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
|
|
|
6107
6282
|
if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
|
|
6108
6283
|
return false;
|
|
6109
6284
|
const stem = basename4(absoluteTargetPath, ".mdc");
|
|
6110
|
-
return
|
|
6285
|
+
return existsSync5(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync5(expandPath(`~/.claude/rules/${stem}.mdc`));
|
|
6111
6286
|
}
|
|
6112
6287
|
function isKnownGeneratedTargetPath(targetPath) {
|
|
6113
6288
|
const normalizedTargetPath = normalizeTargetPath(targetPath);
|
|
@@ -6124,11 +6299,11 @@ async function syncProject(opts) {
|
|
|
6124
6299
|
const allConfigs = await store.listConfigs();
|
|
6125
6300
|
const machine = detectMachineContext();
|
|
6126
6301
|
for (const pf of PROJECT_CONFIG_FILES) {
|
|
6127
|
-
const abs =
|
|
6128
|
-
if (!
|
|
6302
|
+
const abs = join6(absDir, pf.file);
|
|
6303
|
+
if (!existsSync5(abs))
|
|
6129
6304
|
continue;
|
|
6130
6305
|
try {
|
|
6131
|
-
const rawContent =
|
|
6306
|
+
const rawContent = readFileSync3(abs, "utf-8");
|
|
6132
6307
|
if (rawContent.length > 500000) {
|
|
6133
6308
|
result.skipped.push(pf.file);
|
|
6134
6309
|
continue;
|
|
@@ -6157,15 +6332,15 @@ async function syncProject(opts) {
|
|
|
6157
6332
|
}
|
|
6158
6333
|
}
|
|
6159
6334
|
for (const ruleDir of [
|
|
6160
|
-
{ dir:
|
|
6161
|
-
{ dir:
|
|
6335
|
+
{ dir: join6(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
|
|
6336
|
+
{ dir: join6(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" }
|
|
6162
6337
|
]) {
|
|
6163
|
-
if (!
|
|
6338
|
+
if (!existsSync5(ruleDir.dir))
|
|
6164
6339
|
continue;
|
|
6165
6340
|
const mdFiles = readdirSync(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
|
|
6166
6341
|
for (const f of mdFiles) {
|
|
6167
|
-
const abs =
|
|
6168
|
-
const raw =
|
|
6342
|
+
const abs = join6(ruleDir.dir, f);
|
|
6343
|
+
const raw = readFileSync3(abs, "utf-8");
|
|
6169
6344
|
const redacted = redactContent(raw, "markdown");
|
|
6170
6345
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
6171
6346
|
const content = machineAware.content;
|
|
@@ -6204,20 +6379,20 @@ async function syncKnown(opts = {}) {
|
|
|
6204
6379
|
for (const known of targets) {
|
|
6205
6380
|
if (known.rulesDir) {
|
|
6206
6381
|
const absDir = expandPath(known.rulesDir);
|
|
6207
|
-
if (!
|
|
6382
|
+
if (!existsSync5(absDir)) {
|
|
6208
6383
|
result.skipped.push(known.rulesDir);
|
|
6209
6384
|
continue;
|
|
6210
6385
|
}
|
|
6211
6386
|
const extensions = known.rulesExtensions ?? [".md", ".mdc"];
|
|
6212
6387
|
const ruleFiles = readdirSync(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
|
|
6213
6388
|
for (const f of ruleFiles) {
|
|
6214
|
-
const abs2 =
|
|
6389
|
+
const abs2 = join6(absDir, f);
|
|
6215
6390
|
const targetPath = abs2.replace(home, "~");
|
|
6216
6391
|
if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
|
|
6217
6392
|
result.skipped.push(`${targetPath} (generated output)`);
|
|
6218
6393
|
continue;
|
|
6219
6394
|
}
|
|
6220
|
-
const raw =
|
|
6395
|
+
const raw = readFileSync3(abs2, "utf-8");
|
|
6221
6396
|
const redacted = redactContent(raw, "markdown");
|
|
6222
6397
|
const machineAware = templateizeMachineContent(redacted.content, machine);
|
|
6223
6398
|
const content = machineAware.content;
|
|
@@ -6245,12 +6420,12 @@ async function syncKnown(opts = {}) {
|
|
|
6245
6420
|
continue;
|
|
6246
6421
|
}
|
|
6247
6422
|
const abs = expandPath(known.path);
|
|
6248
|
-
if (!
|
|
6423
|
+
if (!existsSync5(abs)) {
|
|
6249
6424
|
result.skipped.push(known.path);
|
|
6250
6425
|
continue;
|
|
6251
6426
|
}
|
|
6252
6427
|
try {
|
|
6253
|
-
const rawContent =
|
|
6428
|
+
const rawContent = readFileSync3(abs, "utf-8");
|
|
6254
6429
|
if (rawContent.length > 500000) {
|
|
6255
6430
|
result.skipped.push(known.path + " (too large)");
|
|
6256
6431
|
continue;
|
|
@@ -6338,9 +6513,9 @@ async function syncToDisk(opts = {}) {
|
|
|
6338
6513
|
}
|
|
6339
6514
|
function buildDiff(expectedContent, targetPath) {
|
|
6340
6515
|
const path = expandPath(targetPath);
|
|
6341
|
-
if (!
|
|
6516
|
+
if (!existsSync5(path))
|
|
6342
6517
|
return `(file not found on disk: ${path})`;
|
|
6343
|
-
const diskContent =
|
|
6518
|
+
const diskContent = readFileSync3(path, "utf-8");
|
|
6344
6519
|
if (diskContent === expectedContent)
|
|
6345
6520
|
return "(no diff \u2014 identical)";
|
|
6346
6521
|
const stored = expectedContent.split(`
|
|
@@ -6520,8 +6695,8 @@ var init_sync = __esm(() => {
|
|
|
6520
6695
|
});
|
|
6521
6696
|
|
|
6522
6697
|
// src/lib/sync-dir.ts
|
|
6523
|
-
import { existsSync as
|
|
6524
|
-
import { join as
|
|
6698
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
|
|
6699
|
+
import { join as join7, relative as relative3 } from "path";
|
|
6525
6700
|
import { homedir as homedir3 } from "os";
|
|
6526
6701
|
function shouldSkip(p) {
|
|
6527
6702
|
return SKIP.some((s) => p.includes(s));
|
|
@@ -6529,9 +6704,9 @@ function shouldSkip(p) {
|
|
|
6529
6704
|
async function syncFromDir(dir, opts = {}) {
|
|
6530
6705
|
const store = opts.store ?? resolveConfigStore();
|
|
6531
6706
|
const absDir = expandPath(dir);
|
|
6532
|
-
if (!
|
|
6707
|
+
if (!existsSync6(absDir))
|
|
6533
6708
|
return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
|
|
6534
|
-
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) =>
|
|
6709
|
+
const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join7(absDir, f)).filter((f) => statSync2(f).isFile());
|
|
6535
6710
|
const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
|
|
6536
6711
|
const home = homedir3();
|
|
6537
6712
|
const allConfigs = await store.listConfigs();
|
|
@@ -6541,7 +6716,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
6541
6716
|
continue;
|
|
6542
6717
|
}
|
|
6543
6718
|
try {
|
|
6544
|
-
const content =
|
|
6719
|
+
const content = readFileSync4(file, "utf-8");
|
|
6545
6720
|
if (content.length > 500000) {
|
|
6546
6721
|
result.skipped.push(file + " (too large)");
|
|
6547
6722
|
continue;
|
|
@@ -6550,7 +6725,7 @@ async function syncFromDir(dir, opts = {}) {
|
|
|
6550
6725
|
const existing = allConfigs.find((c) => c.target_path === targetPath);
|
|
6551
6726
|
if (!existing) {
|
|
6552
6727
|
if (!opts.dryRun)
|
|
6553
|
-
await store.createConfig({ name:
|
|
6728
|
+
await store.createConfig({ name: relative3(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
|
|
6554
6729
|
result.added++;
|
|
6555
6730
|
} else if (existing.content !== content) {
|
|
6556
6731
|
if (!opts.dryRun)
|
|
@@ -6591,7 +6766,7 @@ async function syncToDir(dir, opts = {}) {
|
|
|
6591
6766
|
}
|
|
6592
6767
|
function walkDir(dir, files = []) {
|
|
6593
6768
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
6594
|
-
const full =
|
|
6769
|
+
const full = join7(dir, entry.name);
|
|
6595
6770
|
if (shouldSkip(full))
|
|
6596
6771
|
continue;
|
|
6597
6772
|
if (entry.isDirectory())
|
|
@@ -6613,7 +6788,7 @@ var init_sync_dir = __esm(() => {
|
|
|
6613
6788
|
var require_package = __commonJS((exports, module) => {
|
|
6614
6789
|
module.exports = {
|
|
6615
6790
|
name: "@hasna/instructions",
|
|
6616
|
-
version: "0.4.
|
|
6791
|
+
version: "0.4.9",
|
|
6617
6792
|
description: "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
|
|
6618
6793
|
type: "module",
|
|
6619
6794
|
main: "dist/index.js",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/instructions",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"description": "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|