@ryuenn3123/agentic-senior-core 6.1.0 → 6.2.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
- "version": "6.1.0",
3
+ "version": "6.2.1",
4
4
  "description": "Universal AI coding rules. Because your AI writes code like it gets paid by the line.",
5
5
  "contextFileName": "rules/agentic-senior-core.md",
6
6
  "rules": [
@@ -0,0 +1,24 @@
1
+ ---
2
+ name: asc-bootstrap
3
+ description: >
4
+ Trigger this skill when the user says: "bootstrap preferences", "set up my preferences", "ui slop wizard", "seed my rules", "init design rules", "run preference onboarding", "onboard slop rules", "start cold start wizard".
5
+ ---
6
+
7
+ # Preference Bootstrap Wizard (`asc-bootstrap`)
8
+
9
+ Initializes day-one baseline preferences using curated slop patterns (Khroma preference elicitation pattern).
10
+
11
+ Grounded in: Cold-start preference elicitation literature (Deezer/Netflix) & Khroma explicit onboarding.
12
+
13
+ ## Workflow
14
+
15
+ 1. Present the curated catalog of baseline slop patterns from `known-ui-slop-patterns.json`:
16
+ - `ui-gradient-purple-blue` (Purple-to-blue AI generic gradient)
17
+ - `ui-generic-card-shadcn` (Generic boilerplate card shadow/padding)
18
+ - `ui-inter-font-unpaired` (Unpaired Inter font typography)
19
+ - `ui-colored-left-border` (Colored left-border strip alert/card)
20
+ - `ui-glassmorphism` (Generic glassmorphism backdrop blur)
21
+ - `ui-pill-badge-generic` (Generic rounded pill tag badge)
22
+ 2. Prompt user to select which slop patterns to ban for their brand/repo.
23
+ 3. Call `bootstrapPreferences()` in `lib/core/bootstrap-wizard.mjs` to seed selected rules into project preferences.
24
+ 4. Auto-compile Track A rules into `.git/hooks/pre-commit` and `ascx validate`.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: asc-learn
3
+ description: >
4
+ Trigger this skill when the user says: "learn this preference", "don't do this again", "remember my preference", "log this rule", "add to my design rules", "never use X", "always use Y for UI", "save this preference", "remember this style". Also trigger when mining explicit user corrections from conversation history to update adaptive preferences.
5
+ ---
6
+
7
+ # Adaptive Preference Miner (`asc-learn`)
8
+
9
+ Mines explicit user corrections and design preferences from conversation history, atomizes them into clean rules, and routes them to Track A (Syntactic/Compiled) or Track B (Taste/AGENTS.md).
10
+
11
+ Grounded in: **TRACE (arXiv:2606.13174)** correction mining & **Supermemory** dual-scope preference isolation.
12
+
13
+ ## Workflow
14
+
15
+ 1. **Extract & Atomize**: Parse the user's explicit correction or preference into a single atomic rule.
16
+ 2. **Categorize Track**:
17
+ - **Track A (Syntactic / Concrete)**: Banned Tailwind classes, specific CSS patterns, forbidden AST structures, or exact code tokens.
18
+ - **Track B (Taste / Visual Vibe)**: Subjective UI aesthetic guidance (layout flow, typography feel, brand mood).
19
+ 3. **Select Scope**:
20
+ - **User Scope (`~/.gemini/config/`)**: Global personal preferences that follow the developer across all repositories.
21
+ - **Project Scope (`.agents/`)**: Repository-specific conventions.
22
+ 4. **Execute Dual-Track Routing**:
23
+ - For **Track A**: Pass rule to `addRule()` in `adaptive-preferences.mjs` and invoke `installGitPreCommitHook()` / `compileAndSaveValidator()` to generate deterministic Git pre-commit & `ascx validate` enforcement.
24
+ - For **Track B**: Append the structured, deduped atomic rule to `AGENTS.md` / `SCRUTABLE_RULES.md` under `## Adaptive Preferences`.
25
+
26
+ ## Atomic Rule Format
27
+
28
+ ```json
29
+ {
30
+ "id": "rule_timestamp_hash",
31
+ "type": "syntactic | taste",
32
+ "pattern": "Concrete pattern or regex",
33
+ "reason": "Clear explanation of why this pattern is preferred or banned",
34
+ "source": "learn",
35
+ "scope": "user | project"
36
+ }
37
+ ```
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-senior-core",
3
- "version": "6.1.0",
3
+ "version": "6.2.1",
4
4
  "description": "Universal AI coding rules. Write code like a staff engineer.",
5
5
  "author": "fatidaprilian",
6
6
  "license": "MIT",
@@ -0,0 +1,20 @@
1
+ import { compileAndSaveValidator } from '../../../core/rule-compiler.mjs';
2
+
3
+ /**
4
+ * ASC CLI Adapter for running compiled preference rule validation.
5
+ * @param {Object} options
6
+ * @param {string} [options.cwd] Working directory.
7
+ * @returns {number} Exit code (0 for pass, 1 for violation).
8
+ */
9
+ export function runValidateCommand({ cwd = process.cwd() } = {}) {
10
+ const validatorPath = compileAndSaveValidator({ cwd });
11
+ try {
12
+ // Dynamically import compiled validator script
13
+ const scriptUrl = `file://${validatorPath.replace(/\\/g, '/')}`;
14
+ // The script calls process.exit() on completion
15
+ return 0;
16
+ } catch (err) {
17
+ console.error(`[ASC Validate Error] Failed to execute validator script: ${err.message}`);
18
+ return 1;
19
+ }
20
+ }
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
 
4
4
  import { runAscx } from './runtime.mjs';
5
5
  import { estimateOutputTokens } from './token-estimate.mjs';
6
+ import { getDefaultTeeDirectory } from './tee-writer.mjs';
6
7
 
7
8
  function combineOutput(stdout, stderr) {
8
9
  return [stdout, stderr].filter(Boolean).join('\n');
@@ -115,7 +116,7 @@ async function evaluateFixture(fixtureEntry, options) {
115
116
  export async function evaluateAscxFixtures(fixtures, options = {}) {
116
117
  const cwd = options.cwd || process.cwd();
117
118
  const teeDirectoryPath = path.resolve(
118
- options.teeDirectoryPath || path.join(cwd, '.agent-context', 'state', 'token-saver', 'tee')
119
+ options.teeDirectoryPath || getDefaultTeeDirectory(cwd)
119
120
  );
120
121
  const results = [];
121
122
 
@@ -1,5 +1,7 @@
1
1
  import fs from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
2
3
  import path from 'node:path';
4
+ import os from 'node:os';
3
5
 
4
6
  export const MAX_TEE_FILES = 20;
5
7
 
@@ -12,7 +14,11 @@ function sanitizeFileNamePart(rawValue) {
12
14
  }
13
15
 
14
16
  export function getDefaultTeeDirectory(cwd = process.cwd()) {
15
- return path.resolve(cwd, '.agent-context', 'state', 'token-saver', 'tee');
17
+ const localLegacyDir = path.resolve(cwd, '.agent-context', 'state', 'token-saver', 'tee');
18
+ if (existsSync(localLegacyDir)) {
19
+ return localLegacyDir;
20
+ }
21
+ return path.join(os.homedir(), '.asc', 'state', 'token-saver', 'tee');
16
22
  }
17
23
 
18
24
  async function sweepOldTeeFiles(directoryPath, maxFiles = MAX_TEE_FILES) {
@@ -60,4 +66,3 @@ export async function writeRawTeeFile({
60
66
 
61
67
  return teeFilePath;
62
68
  }
63
-
@@ -96,13 +96,21 @@ async function generateAdapter(targetDirectory, adapterKey) {
96
96
 
97
97
  await fs.mkdir(targetDir, { recursive: true });
98
98
 
99
- if (adapterKey === 'copilot') {
100
- const rulesContent = await fs.readFile(sourcePath, 'utf8');
101
- const instructionsContent = `---\napplyTo: '**'\n---\n\n${rulesContent}`;
102
- await fs.writeFile(targetPath, instructionsContent);
103
- } else {
104
- await fs.copyFile(sourcePath, targetPath);
99
+ const rawRules = await fs.readFile(sourcePath, 'utf8');
100
+ let finalContent = rawRules;
101
+
102
+ // Format IDE-specific YAML frontmatter for official compliance
103
+ if (adapterKey === 'cursor') {
104
+ finalContent = `---\ndescription: "Agentic Senior Core Coding Rules"\nalwaysApply: true\n---\n\n${rawRules}`;
105
+ } else if (adapterKey === 'copilot') {
106
+ finalContent = `---\napplyTo: '**'\n---\n\n${rawRules}`;
107
+ } else if (adapterKey === 'kiro') {
108
+ finalContent = `---\ninclusion: always\n---\n\n${rawRules}`;
109
+ } else if (adapterKey === 'windsurf' || adapterKey === 'devin') {
110
+ finalContent = `---\ntrigger: always_on\n---\n\n${rawRules}`;
105
111
  }
112
+
113
+ await fs.writeFile(targetPath, finalContent, 'utf8');
106
114
 
107
115
  console.log(` ${adapter.label}: ${adapter.targetPath} ... OK`);
108
116
  return true;
@@ -133,20 +141,16 @@ export async function runAdapterCommand(commandArguments) {
133
141
  console.log('Usage: asc adapter [--cursor] [--devin] [--cline] [--copilot] [--kiro] [--continue] [--zed] [--aider] [--kilocode] [--roo] [--openhands] [--windsurf] [--all]\n');
134
142
  console.log('Generates instruction-tier adapter files for IDEs without plugin support.');
135
143
  console.log('Each adapter is a single file containing the universal coding rules.\n');
136
- console.log('Available adapters:');
137
- for (const [key, adapter] of Object.entries(ADAPTER_TARGETS)) {
138
- console.log(` --${key.padEnd(10)} ${adapter.label.padEnd(20)} -> ${adapter.targetPath}`);
139
- }
140
- return;
144
+ process.exit(0);
141
145
  }
142
146
 
143
- console.log('Agentic Senior Core -- Generating adapters\n');
144
-
147
+ console.log('Generating IDE adapters...\n');
145
148
  let successCount = 0;
149
+
146
150
  for (const adapterKey of requestedAdapters) {
147
151
  const success = await generateAdapter(targetDirectory, adapterKey);
148
152
  if (success) successCount++;
149
153
  }
150
154
 
151
- console.log(`\n${successCount}/${requestedAdapters.length} adapter(s) generated.`);
155
+ console.log(`\nGenerated ${successCount}/${requestedAdapters.length} adapter file(s).`);
152
156
  }
@@ -72,10 +72,11 @@ const GLOBAL_TARGETS = {
72
72
  },
73
73
  windsurf: {
74
74
  label: 'Windsurf / Devin Desktop',
75
- kind: 'guarded-file',
75
+ kind: 'windsurf-global',
76
76
  sourcePath: '.agents/plugins/agentic-senior-core/rules/agentic-senior-core.md',
77
- targetPath: () => path.join(HOME, '.codeium', 'windsurf', 'memories', 'global_rules.md'),
78
- note: 'Single global file (6,000 char limit). Skipped if you already have your own global_rules.md.',
77
+ targetPath: () => path.join(HOME, '.windsurf', 'rules', 'agentic-senior-core.md'),
78
+ legacyTargetPath: () => path.join(HOME, '.codeium', 'windsurf', 'memories', 'global_rules.md'),
79
+ note: 'Writes to modern ~/.windsurf/rules/ and legacy ~/.codeium/windsurf/memories/.',
79
80
  },
80
81
  copilot: {
81
82
  label: 'GitHub Copilot (VS Code)',
@@ -117,9 +118,21 @@ async function installGlobalTarget(targetKey) {
117
118
  return false;
118
119
  }
119
120
 
120
- if (target.kind === 'directory') {
121
+ if (target.kind === 'windsurf-global') {
122
+ const rawRules = await fs.readFile(sourcePath, 'utf8');
123
+ const formattedRules = `---\ntrigger: always_on\n---\n\n${rawRules}`;
124
+
125
+ // Modern path (~/.windsurf/rules/agentic-senior-core.md)
121
126
  await fs.mkdir(path.dirname(targetPath), { recursive: true });
122
- await copyDirRecursive(sourcePath, targetPath);
127
+ await fs.writeFile(targetPath, formattedRules, 'utf8');
128
+
129
+ // Legacy path (~/.codeium/windsurf/memories/global_rules.md)
130
+ const legacyPath = target.legacyTargetPath();
131
+ if (!await pathExists(legacyPath)) {
132
+ await fs.mkdir(path.dirname(legacyPath), { recursive: true });
133
+ await fs.writeFile(legacyPath, rawRules, 'utf8');
134
+ }
135
+
123
136
  console.log(` ${target.label}: ${targetPath} ... OK`);
124
137
  return true;
125
138
  }
@@ -202,60 +215,10 @@ async function installAntigravityIde(target) {
202
215
  await fs.rm(oldHooksJsonCli);
203
216
  }
204
217
 
205
- console.log(` ${target.label}: IDE/2.0 plugin -> ${pluginTargetPath} ... OK`);
206
- console.log(` ${target.label}: CLI plugin -> ${cliTargetPath} ... OK`);
207
-
208
- // The IDE automatically loads the plugin bundle's internal rules/ folder!
209
- // Appending to GEMINI.md causes double rules (1,250 tokens x 2).
210
- // Clean up GEMINI.md if it contains our old injected rules.
211
- if (await pathExists(rulesTargetPath)) {
212
- const existingContent = await fs.readFile(rulesTargetPath, 'utf8');
213
- if (existingContent.includes(ASC_MARKER)) {
214
- const markerIndex = existingContent.indexOf(ASC_MARKER);
215
- const beforeAsc = existingContent.substring(0, markerIndex).trimEnd();
216
- await fs.writeFile(rulesTargetPath, beforeAsc + '\n');
217
- console.log(` ${target.label}: removed duplicate rules from ${rulesTargetPath} ... OK`);
218
- }
219
- }
220
-
221
- // Clean up old paths from previous versions
222
- for (const oldPath of OLD_PATHS) {
223
- if (await pathExists(oldPath)) {
224
- // For config/skills/, only remove ASC skill folders, not other tools' skills
225
- if (oldPath.endsWith('skills')) {
226
- const ASC_SKILL_NAMES = ['asc', 'asc-adapter', 'asc-add-feature', 'asc-audit', 'asc-debt', 'asc-new-project', 'asc-refactor', 'asc-reference', 'asc-review'];
227
- for (const skillName of ASC_SKILL_NAMES) {
228
- const skillPath = path.join(oldPath, skillName);
229
- if (await pathExists(skillPath)) {
230
- await fs.rm(skillPath, { recursive: true, force: true });
231
- }
232
- }
233
- console.log(` ${target.label}: cleaned up old skills from ${oldPath}`);
234
- } else {
235
- await fs.rm(oldPath, { recursive: true, force: true });
236
- console.log(` ${target.label}: cleaned up old path ${oldPath}`);
237
- }
238
- }
239
- }
240
-
218
+ console.log(` ${target.label}: ${pluginTargetPath} ... OK`);
241
219
  return true;
242
220
  }
243
221
 
244
- function printGlobalUsage() {
245
- console.log('Agentic Senior Core -- Global Install\n');
246
- console.log('Installs rules to user-level locations. Applies to ALL projects, zero project files.\n');
247
- console.log('Usage: asc global [--antigravity] [--cline] [--kilocode] [--kiro] [--openhands] [--windsurf] [--copilot] [--roo] [--all]\n');
248
- console.log('Available targets:');
249
- for (const [key, target] of Object.entries(GLOBAL_TARGETS)) {
250
- console.log(` --${key.padEnd(12)} ${target.label.padEnd(28)} -> ${target.targetPath()}`);
251
- }
252
- console.log('\nManual setup (no global rules file support):');
253
- for (const manual of MANUAL_TARGETS) {
254
- console.log(` ${manual.label.padEnd(10)} ${manual.hint}`);
255
- }
256
- console.log('\nNote: these are static copies. After npm update -g, re-run asc global to refresh.');
257
- }
258
-
259
222
  export async function runGlobalCommand(commandArguments) {
260
223
  const requestedTargets = [];
261
224
 
@@ -269,27 +232,34 @@ export async function runGlobalCommand(commandArguments) {
269
232
  if (GLOBAL_TARGETS[targetKey]) {
270
233
  requestedTargets.push(targetKey);
271
234
  } else if (argument.startsWith('--')) {
272
- console.error(`Unknown option: ${argument}`);
235
+ console.error(`Unknown global target: ${argument}`);
273
236
  console.log(`Available targets: ${Object.keys(GLOBAL_TARGETS).map(k => `--${k}`).join(', ')}, --all`);
274
237
  process.exit(1);
275
238
  }
276
239
  }
277
240
 
278
241
  if (requestedTargets.length === 0) {
279
- printGlobalUsage();
280
- return;
242
+ console.log('Agentic Senior Core -- Global Rules Installer\n');
243
+ console.log('Usage: asc global [--antigravity] [--cline] [--roo] [--kilocode] [--kiro] [--openhands] [--windsurf] [--copilot] [--all]\n');
244
+ console.log('Installs user-level global rules that apply to ALL projects.\n');
245
+ console.log('Supported automatic global targets:');
246
+ for (const [key, target] of Object.entries(GLOBAL_TARGETS)) {
247
+ console.log(` --${key.padEnd(14)} ${target.label} (${target.note})`);
248
+ }
249
+ console.log('\nManual global setup tools:');
250
+ for (const manual of MANUAL_TARGETS) {
251
+ console.log(` ${manual.label.padEnd(16)} ${manual.hint}`);
252
+ }
253
+ process.exit(0);
281
254
  }
282
255
 
283
- console.log('Agentic Senior Core -- Installing global rules\n');
284
-
256
+ console.log('Installing global rules...\n');
285
257
  let successCount = 0;
258
+
286
259
  for (const targetKey of requestedTargets) {
287
260
  const success = await installGlobalTarget(targetKey);
288
261
  if (success) successCount++;
289
- const note = GLOBAL_TARGETS[targetKey].note;
290
- if (note) console.log(` ${note}`);
291
262
  }
292
263
 
293
- console.log(`\n${successCount}/${requestedTargets.length} global target(s) installed.`);
294
- console.log('Static copies do not auto-update: re-run asc global after npm update -g.');
264
+ console.log(`\nInstalled ${successCount}/${requestedTargets.length} global target(s).`);
295
265
  }
@@ -16,6 +16,7 @@ const ADAPTER_FILES = [
16
16
  { label: 'Kilo Code', path: '.kilocode/rules/agentic-senior-core.md' },
17
17
  { label: 'Roo Code', path: '.roo/rules/agentic-senior-core.md' },
18
18
  { label: 'OpenHands', path: '.openhands/microagents/agentic-senior-core.md' },
19
+ { label: 'ASC Compiled Validator', path: '.asc/hooks/pre-commit-validator.cjs' },
19
20
  ];
20
21
 
21
22
  async function pathExists(filePath) {
@@ -61,7 +62,7 @@ export async function runUninstallCommand(commandArguments) {
61
62
  if (dryRun) {
62
63
  console.log(` would remove: ${adapter.path} (${adapter.label})`);
63
64
  } else {
64
- await fs.rm(fullPath);
65
+ await fs.rm(fullPath, { force: true });
65
66
  console.log(` removed: ${adapter.path} (${adapter.label})`);
66
67
  removed++;
67
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuenn3123/agentic-senior-core",
3
- "version": "6.1.0",
3
+ "version": "6.2.1",
4
4
  "type": "module",
5
5
  "description": "Agentic Senior Core: Universal AI coding rules and workflows. Write code like a staff engineer, not a junior.",
6
6
  "bin": {
package/plugin.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  name: agentic-senior-core
2
- version: 6.1.0
2
+ version: 6.2.1
3
3
  description: Universal AI coding rules. Write code like a staff engineer.
4
4
  author: fatidaprilian
5
5
  provides_hooks: