@tanstack/intent 0.0.5 → 0.0.7

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,300 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { execSync } from "node:child_process";
4
-
5
- //#region src/feedback.ts
6
- const META_FEEDBACK_REPO = "TanStack/intent";
7
- const SECRET_PATTERNS = [
8
- /(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,}/,
9
- /(?:sk|pk)[-_](?:live|test)[-_][A-Za-z0-9]{24,}/,
10
- /AKIA[0-9A-Z]{16}/,
11
- /-----BEGIN (?:RSA |EC )?PRIVATE KEY-----/,
12
- /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/,
13
- /(?:Bearer|token)\s+[A-Za-z0-9_\-.~+/]{20,}/i,
14
- /[A-Za-z0-9]{32,}(?=.*(?:key|secret|token|password))/i
15
- ];
16
- function containsSecrets(text) {
17
- return SECRET_PATTERNS.some((pattern) => pattern.test(text));
18
- }
19
- function hasGhCli() {
20
- try {
21
- execSync("gh --version", { stdio: "ignore" });
22
- return true;
23
- } catch {
24
- return false;
25
- }
26
- }
27
- function getHomeConfigDir() {
28
- return process.env.XDG_CONFIG_HOME ?? join(process.env.HOME ?? process.env.USERPROFILE ?? "", ".config");
29
- }
30
- function resolveFrequency(root) {
31
- const userConfigPath = join(getHomeConfigDir(), "intent", "config.json");
32
- try {
33
- const userCfg = JSON.parse(readFileSync(userConfigPath, "utf8"));
34
- if (userCfg.feedback?.frequency) return userCfg.feedback.frequency;
35
- } catch {}
36
- const projectConfigPath = join(root, "intent.config.json");
37
- try {
38
- const projCfg = JSON.parse(readFileSync(projectConfigPath, "utf8"));
39
- if (projCfg.feedback?.frequency) return projCfg.feedback.frequency;
40
- } catch {}
41
- return "every-5";
42
- }
43
- const REQUIRED_FIELDS = [
44
- "skill",
45
- "package",
46
- "skillVersion",
47
- "task",
48
- "whatWorked",
49
- "whatFailed",
50
- "missing",
51
- "selfCorrections",
52
- "userRating"
53
- ];
54
- function validatePayload(payload) {
55
- const errors = [];
56
- if (!payload || typeof payload !== "object") return {
57
- valid: false,
58
- errors: ["Payload must be a JSON object"]
59
- };
60
- const obj = payload;
61
- for (const field of REQUIRED_FIELDS) if (typeof obj[field] !== "string" || obj[field].trim() === "") errors.push(`Missing or empty required field: ${field}`);
62
- if (obj.userRating && ![
63
- "good",
64
- "mixed",
65
- "bad"
66
- ].includes(obj.userRating)) errors.push("userRating must be one of: good, mixed, bad");
67
- if (containsSecrets(Object.values(obj).filter((v) => typeof v === "string").join("\n"))) errors.push("Payload appears to contain secrets or tokens — submission rejected");
68
- return {
69
- valid: errors.length === 0,
70
- errors
71
- };
72
- }
73
- const META_REQUIRED_FIELDS = [
74
- "metaSkill",
75
- "library",
76
- "agentUsed",
77
- "artifactQuality",
78
- "whatWorked",
79
- "whatFailed",
80
- "suggestions",
81
- "userRating"
82
- ];
83
- const VALID_META_SKILLS = [
84
- "domain-discovery",
85
- "tree-generator",
86
- "generate-skill",
87
- "skill-staleness-check"
88
- ];
89
- const VALID_AGENTS = [
90
- "oz",
91
- "claude-code",
92
- "cursor",
93
- "copilot",
94
- "codex",
95
- "other"
96
- ];
97
- const VALID_QUALITY_RATINGS = [
98
- "good",
99
- "mixed",
100
- "bad"
101
- ];
102
- function validateMetaPayload(payload) {
103
- const errors = [];
104
- if (!payload || typeof payload !== "object") return {
105
- valid: false,
106
- errors: ["Payload must be a JSON object"]
107
- };
108
- const obj = payload;
109
- for (const field of META_REQUIRED_FIELDS) if (typeof obj[field] !== "string" || obj[field].trim() === "") errors.push(`Missing or empty required field: ${field}`);
110
- if (obj.metaSkill && !VALID_META_SKILLS.includes(obj.metaSkill)) errors.push(`metaSkill must be one of: ${VALID_META_SKILLS.join(", ")}`);
111
- if (obj.agentUsed && !VALID_AGENTS.includes(obj.agentUsed)) errors.push(`agentUsed must be one of: ${VALID_AGENTS.join(", ")}`);
112
- if (obj.artifactQuality && !VALID_QUALITY_RATINGS.includes(obj.artifactQuality)) errors.push("artifactQuality must be one of: good, mixed, bad");
113
- if (obj.userRating && !VALID_QUALITY_RATINGS.includes(obj.userRating)) errors.push("userRating must be one of: good, mixed, bad");
114
- if (containsSecrets(Object.values(obj).filter((v) => typeof v === "string").join("\n"))) errors.push("Payload appears to contain secrets or tokens — submission rejected");
115
- return {
116
- valid: errors.length === 0,
117
- errors
118
- };
119
- }
120
- function metaToMarkdown(payload) {
121
- const lines = [
122
- `# Meta-Skill Feedback: ${payload.metaSkill}`,
123
- "",
124
- `**Library:** ${payload.library}`,
125
- `**Agent:** ${payload.agentUsed}`,
126
- `**Artifact quality:** ${payload.artifactQuality}`,
127
- `**Rating:** ${payload.userRating}`
128
- ];
129
- if (payload.interviewQuality) lines.push(`**Interview quality:** ${payload.interviewQuality}`);
130
- if (payload.failureModeQuality) lines.push(`**Failure mode quality:** ${payload.failureModeQuality}`);
131
- lines.push("", "## What Worked", payload.whatWorked, "", "## What Failed", payload.whatFailed, "", "## Suggestions", payload.suggestions);
132
- return lines.join("\n") + "\n";
133
- }
134
- function toMarkdown(payload) {
135
- const lines = [
136
- `# Skill Feedback: ${payload.skill}`,
137
- "",
138
- `**Package:** ${payload.package}`,
139
- `**Skill version:** ${payload.skillVersion}`,
140
- `**Rating:** ${payload.userRating}`,
141
- "",
142
- "## Task",
143
- payload.task,
144
- "",
145
- "## What Worked",
146
- payload.whatWorked,
147
- "",
148
- "## What Failed",
149
- payload.whatFailed,
150
- "",
151
- "## Missing",
152
- payload.missing,
153
- "",
154
- "## Self-Corrections",
155
- payload.selfCorrections
156
- ];
157
- if (payload.userComments) lines.push("", "## User Comments", payload.userComments);
158
- return lines.join("\n") + "\n";
159
- }
160
- function submitFeedback(payload, repo, opts) {
161
- const md = toMarkdown(payload);
162
- if (opts.ghAvailable) try {
163
- execSync(`gh issue create --repo ${repo} --title "${`Skill Feedback: ${payload.skill} (${payload.userRating})`.replace(/"/g, "\\\"")}" --body -`, {
164
- input: md,
165
- stdio: [
166
- "pipe",
167
- "pipe",
168
- "pipe"
169
- ]
170
- });
171
- return {
172
- method: "gh",
173
- detail: `Submitted issue to ${repo}`
174
- };
175
- } catch {}
176
- if (opts.outputPath) {
177
- writeFileSync(opts.outputPath, md, "utf8");
178
- return {
179
- method: "file",
180
- detail: `Saved to ${opts.outputPath}`
181
- };
182
- }
183
- return {
184
- method: "stdout",
185
- detail: md
186
- };
187
- }
188
- function submitMetaFeedback(payload, opts) {
189
- const md = metaToMarkdown(payload);
190
- if (opts.ghAvailable) try {
191
- execSync(`gh issue create --repo ${META_FEEDBACK_REPO} --title "${`Meta-Skill Feedback: ${payload.metaSkill} (${payload.userRating})`.replace(/"/g, "\\\"")}" --label "feedback:${payload.metaSkill}" --body -`, {
192
- input: md,
193
- stdio: [
194
- "pipe",
195
- "pipe",
196
- "pipe"
197
- ]
198
- });
199
- return {
200
- method: "gh",
201
- detail: `Submitted issue to ${META_FEEDBACK_REPO}`
202
- };
203
- } catch {}
204
- if (opts.outputPath) {
205
- writeFileSync(opts.outputPath, md, "utf8");
206
- return {
207
- method: "file",
208
- detail: `Saved to ${opts.outputPath}`
209
- };
210
- }
211
- return {
212
- method: "stdout",
213
- detail: md
214
- };
215
- }
216
- function runFeedback(args) {
217
- const isMeta = args.includes("--meta");
218
- const submitFlag = args.includes("--submit");
219
- const fileIdx = args.indexOf("--file");
220
- const filePath = fileIdx !== -1 ? args[fileIdx + 1] : void 0;
221
- if (!submitFlag || !filePath) {
222
- if (isMeta) console.error("Usage: intent feedback --meta --submit --file <path>");
223
- else console.error("Usage: intent feedback --submit --file <path>");
224
- process.exit(1);
225
- }
226
- if (!existsSync(filePath)) {
227
- console.error(`File not found: ${filePath}`);
228
- process.exit(1);
229
- }
230
- let raw;
231
- try {
232
- raw = JSON.parse(readFileSync(filePath, "utf8"));
233
- } catch {
234
- console.error("Invalid JSON in feedback file");
235
- process.exit(1);
236
- }
237
- const ghAvailable = hasGhCli();
238
- if (resolveFrequency(process.cwd()) === "never") {
239
- console.log("Feedback is disabled (frequency: never)");
240
- return;
241
- }
242
- const dateSuffix = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
243
- if (isMeta) {
244
- const validation$1 = validateMetaPayload(raw);
245
- if (!validation$1.valid) {
246
- console.error("Meta-feedback validation failed:");
247
- for (const err of validation$1.errors) console.error(` - ${err}`);
248
- process.exit(1);
249
- }
250
- const payload$1 = raw;
251
- const fallbackPath$1 = `intent-meta-feedback-${dateSuffix}.md`;
252
- const result$1 = submitMetaFeedback(payload$1, {
253
- ghAvailable,
254
- outputPath: ghAvailable ? void 0 : fallbackPath$1
255
- });
256
- switch (result$1.method) {
257
- case "gh":
258
- console.log(`✓ ${result$1.detail}`);
259
- break;
260
- case "file":
261
- console.log(`✓ ${result$1.detail}`);
262
- console.log(`Open a GitHub Discussion at https://github.com/${META_FEEDBACK_REPO}/discussions/new?category=Feedback`);
263
- break;
264
- case "stdout":
265
- console.log("--- Meta-feedback markdown (copy/paste to discussion) ---");
266
- console.log(result$1.detail);
267
- break;
268
- }
269
- return;
270
- }
271
- const validation = validatePayload(raw);
272
- if (!validation.valid) {
273
- console.error("Feedback validation failed:");
274
- for (const err of validation.errors) console.error(` - ${err}`);
275
- process.exit(1);
276
- }
277
- const payload = raw;
278
- const repo = payload.package.replace(/^@/, "").replace(/\//, "/");
279
- const fallbackPath = `intent-feedback-${dateSuffix}.md`;
280
- const result = submitFeedback(payload, repo, {
281
- ghAvailable,
282
- outputPath: ghAvailable ? void 0 : fallbackPath
283
- });
284
- switch (result.method) {
285
- case "gh":
286
- console.log(`✓ ${result.detail}`);
287
- break;
288
- case "file":
289
- console.log(`✓ ${result.detail}`);
290
- console.log("You can manually open an issue with this content.");
291
- break;
292
- case "stdout":
293
- console.log("--- Feedback markdown (copy/paste to issue) ---");
294
- console.log(result.detail);
295
- break;
296
- }
297
- }
298
-
299
- //#endregion
300
- export { runFeedback as a, toMarkdown as c, resolveFrequency as i, validateMetaPayload as l, hasGhCli as n, submitFeedback as o, metaToMarkdown as r, submitMetaFeedback as s, containsSecrets as t, validatePayload as u };
@@ -1,3 +0,0 @@
1
- import { a as runFeedback, c as toMarkdown, i as resolveFrequency, l as validateMetaPayload, n as hasGhCli, o as submitFeedback, r as metaToMarkdown, s as submitMetaFeedback, t as containsSecrets, u as validatePayload } from "./feedback-DKreHfB1.mjs";
2
-
3
- export { runFeedback };
@@ -1,3 +0,0 @@
1
- import { a as runInit, i as readProjectConfig, n as hasIntentBlock, o as writeProjectConfig, r as injectIntentBlock, t as detectAgentConfigs } from "./init-DNxmjQfU.mjs";
2
-
3
- export { detectAgentConfigs, runInit };
@@ -1,70 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
-
4
- //#region src/init.ts
5
- const AGENT_CONFIG_FILES = [
6
- "AGENTS.md",
7
- "CLAUDE.md",
8
- ".cursorrules",
9
- ".github/copilot-instructions.md"
10
- ];
11
- const INTENT_BLOCK_MARKER = "## Intent Skills";
12
- const INTENT_BLOCK = `## Intent Skills
13
-
14
- This project uses TanStack Intent. Run \`npx intent list\` to discover
15
- available AI coding skills. Before working with a library that has skills,
16
- read the relevant SKILL.md file at the path shown in the list output.
17
- `;
18
- const DEFAULT_CONFIG = { feedback: { frequency: "every-5" } };
19
- function detectAgentConfigs(root) {
20
- return AGENT_CONFIG_FILES.map((f) => join(root, f)).filter((f) => existsSync(f));
21
- }
22
- function hasIntentBlock(filePath) {
23
- try {
24
- return readFileSync(filePath, "utf8").includes(INTENT_BLOCK_MARKER);
25
- } catch {
26
- return false;
27
- }
28
- }
29
- function injectIntentBlock(filePath) {
30
- if (hasIntentBlock(filePath)) return false;
31
- let content;
32
- try {
33
- content = readFileSync(filePath, "utf8");
34
- } catch {
35
- content = "";
36
- }
37
- const separator = content.length > 0 && !content.endsWith("\n\n") ? "\n\n" : "";
38
- writeFileSync(filePath, content + separator + INTENT_BLOCK);
39
- return true;
40
- }
41
- function writeProjectConfig(root) {
42
- const configPath = join(root, "intent.config.json");
43
- if (!existsSync(configPath)) writeFileSync(configPath, JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n");
44
- return configPath;
45
- }
46
- function readProjectConfig(root) {
47
- const configPath = join(root, "intent.config.json");
48
- try {
49
- return JSON.parse(readFileSync(configPath, "utf8"));
50
- } catch {
51
- return null;
52
- }
53
- }
54
- function runInit(root) {
55
- const detected = detectAgentConfigs(root);
56
- const injected = [];
57
- const skipped = [];
58
- const created = [];
59
- for (const filePath of detected) if (injectIntentBlock(filePath)) injected.push(filePath);
60
- else skipped.push(filePath);
61
- return {
62
- injected,
63
- skipped,
64
- created,
65
- configPath: writeProjectConfig(root)
66
- };
67
- }
68
-
69
- //#endregion
70
- export { runInit as a, readProjectConfig as i, hasIntentBlock as n, writeProjectConfig as o, injectIntentBlock as r, detectAgentConfigs as t };
@@ -1,4 +0,0 @@
1
- import "./utils-DjkEPBxu.mjs";
2
- import { t as scanForIntents } from "./scanner-CpsJAHXT.mjs";
3
-
4
- export { scanForIntents };
@@ -1,4 +0,0 @@
1
- import "./utils-DjkEPBxu.mjs";
2
- import { t as checkStaleness } from "./staleness-CnomT9Hm.mjs";
3
-
4
- export { checkStaleness };