@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.
- package/.agents/plugins/agentic-senior-core/plugin.json +1 -1
- package/.agents/plugins/agentic-senior-core/skills/asc-bootstrap/SKILL.md +24 -0
- package/.agents/plugins/agentic-senior-core/skills/asc-learn/SKILL.md +37 -0
- package/gemini-extension.json +1 -1
- package/lib/cli/ascx/adapters/validate.mjs +20 -0
- package/lib/cli/ascx/fixture-evaluator.mjs +2 -1
- package/lib/cli/ascx/tee-writer.mjs +7 -2
- package/lib/cli/commands/adapter.mjs +18 -14
- package/lib/cli/commands/global.mjs +35 -65
- package/lib/cli/commands/uninstall.mjs +2 -1
- package/package.json +1 -1
- package/plugin.yaml +1 -1
|
@@ -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
|
+
```
|
package/gemini-extension.json
CHANGED
|
@@ -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 ||
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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('
|
|
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(`\
|
|
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: '
|
|
75
|
+
kind: 'windsurf-global',
|
|
76
76
|
sourcePath: '.agents/plugins/agentic-senior-core/rules/agentic-senior-core.md',
|
|
77
|
-
targetPath: () => path.join(HOME, '.
|
|
78
|
-
|
|
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 === '
|
|
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
|
|
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}:
|
|
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
|
|
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
|
-
|
|
280
|
-
|
|
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('
|
|
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(`\
|
|
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
package/plugin.yaml
CHANGED