Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

View file

@ -0,0 +1,65 @@
# SpecStory Artifacts Directory
This directory is automatically created and maintained by the SpecStory extension to preserve your Cursor composer and chat history.
## What's Here?
- `.specstory/history`: Contains markdown files of your AI coding sessions
- Each file represents a separate chat or composer session
- Files are automatically updated as you work
- `.specstory/cursor_rules_backups`: Contains backups of the `.cursor/rules/derived-cursor-rules.mdc` file
- Backups are automatically created each time the `.cursor/rules/derived-cursor-rules.mdc` file is updated
- You can enable/disable the Cursor Rules feature in the SpecStory settings, it is disabled by default
## Valuable Uses
- Capture: Keep your context window up-to-date when starting new Chat/Composer sessions via @ references
- Search: For previous prompts and code snippets
- Learn: Meta-analyze your patterns and learn from your past experiences
- Derive: Keep Cursor on course with your past decisions by automatically deriving Cursor rules from your AI interactions
## Version Control
We recommend keeping this directory under version control to maintain a history of your AI interactions. However, if you prefer not to version these files, you can exclude them by adding this to your `.gitignore`:
```
.specstory
```
We recommend not keeping the `.specstory/cursor_rules_backups` directory under version control if you are already using git to version the `.cursor/rules` directory, and committing regularly. You can exclude it by adding this to your `.gitignore`:
```
.specstory/cursor_rules_backups
```
## Searching Your Codebase
When searching your codebase in Cursor, search results may include your previous AI coding interactions. To focus solely on your actual code files, you can exclude the AI interaction history from search results.
To exclude AI interaction history:
1. Open the "Find in Files" search in Cursor (Cmd/Ctrl + Shift + F)
2. Navigate to the "files to exclude" section
3. Add the following pattern:
```
.specstory/*
```
This will ensure your searches only return results from your working codebase files.
## Notes
- Auto-save only works when Cursor/sqlite flushes data to disk. This results in a small delay after the AI response is complete before SpecStory can save the history.
- Auto-save does not yet work on remote WSL workspaces.
## Settings
You can control auto-saving behavior in Cursor:
1. Open Cursor → Settings → VS Code Settings (Cmd/Ctrl + ,)
2. Search for "SpecStory"
3. Find "Auto Save" setting to enable/disable
Auto-save occurs when changes are detected in Cursor's sqlite database, or every 2 minutes as a safety net.

78
Frontend-Learner/node_modules/copy-paste/README.md generated vendored Normal file
View file

@ -0,0 +1,78 @@
# node-copy-paste
A command line utility that allows read/write (i.e copy/paste) access to the system clipboard. It does this by wrapping [`pbcopy/pbpaste`](https://developer.apple.com/library/mac/#documentation/Darwin/Reference/Manpages/man1/pbcopy.1.html) (for OSX), [`xclip`](http://www.cyberciti.biz/faq/xclip-linux-insert-files-command-output-intoclipboard/) (for Linux, FreeBSD, and OpenBSD), and [`clip`](http://www.labnol.org/software/tutorials/copy-dos-command-line-output-clipboard-clip-exe/2506/) (for Windows). Currently works with node.js v0.8+.
## The API
When `require("copy-paste")` is executed, an object with the following properties is returned:
- `copy(text[, callback])`: asynchronously replaces the current contents of the clip board with `text`. Takes either a string, array, object, or readable stream. Returns the same value passed in. Optional callback will fire when the copy operation is complete.
- `copy.json(obj[, callback])`: asynchronously replaces the current contents of the clip board with the JSON string of `obj`. Returns the same value passed in. Optional callback will fire when the copy operation is complete.
- `paste([callback])`: if no callback is provided, `paste` synchronously returns the current contents of the system clip board. Otherwise, the contents of the system clip board are passed to the callback as the second parameter. The first one being a potential error.
- `require("copy-paste").global()`: adds `copy` and `paste` to the global namespace. Returns an object with `copy` and `paste` as properties.
Example usage:
```js
const { copy, paste } = require("copy-paste");
copy("some text", (err, text) => {
// "some text" is in your clipboard
});
paste((err, text) => {
// complete...
});
const text = paste(); // Synchronous paste
copy({ hello: "world" }) // Asynchronous copy
```
### Promise-based API
For modern JavaScript applications, you can use the promise-based interface by requiring the `promises` submodule:
```javascript
const clipboard = require('copy-paste/promises');
```
The promise-based API provides the following methods:
- `copy(text)`: Returns a promise that resolves with the copied text when the operation is complete
- `copy.json(obj)`: Returns a promise that resolves with the copied JSON string when the operation is complete
- `paste()`: Returns a promise that resolves with the clipboard contents when the operation is complete
Example usage with async/await:
```javascript
const { copy, paste } = require('copy-paste/promises');
// Copy text
await copy('Hello World');
// Copy JSON
await copy.json({ hello: 'world' });
// Paste text
const text = await paste();
```
## Getting node-copy-paste
The easiest way to get node-copy-paste is with [npm](http://npmjs.org/):
npm install copy-paste
Alternatively you can clone this git repository:
git clone git://github.com/xavi-/node-copy-paste.git
## Future plans
I'm hoping to add various fallbacks for instances when `xclip` or `clip` is not avaiable (see [experimental-fallbacks](https://github.com/xavi-/node-copy-paste/tree/experimental-fallbacks/platform) branch). Also this library needs to be more thoroughly tested on windows.
## Developed by
* Xavi Ramirez
## License
This project is released under [The MIT License](http://www.opensource.org/licenses/mit-license.php).

127
Frontend-Learner/node_modules/copy-paste/index.js generated vendored Normal file
View file

@ -0,0 +1,127 @@
const child_process = require("node:child_process");
const spawn = child_process.spawn;
const execSync = child_process.execSync;
const util = require("node:util");
let config;
switch (process.platform) {
case "darwin":
config = require("./platform/darwin");
break;
case "win32":
config = require("./platform/win32");
break;
case "linux":
if (process.env.WAYLAND_DISPLAY) {
config = require("./platform/linux-wayland");
} else {
config = require("./platform/linux");
}
break;
case "freebsd":
config = require("./platform/linux");
break;
case "openbsd":
config = require("./platform/linux");
break;
case "android":
config = require("./platform/android");
break;
default:
throw new Error(`Unknown platform: "${process.platform}"`);
}
const noop = () => {};
exports.copy = (text, callback) => {
const opts = { env: { ...process.env, ...config.copy.env } };
const child = spawn(config.copy.command, config.copy.args, opts);
let done = callback
? (...args) => {
callback(...args);
done = noop;
}
: (err) => {
if (err) throw err;
done = noop;
};
const err = [];
child.stdin.on("error", (err) => done(err));
child
.on("exit", () => done(null, text))
.on("error", (err) => done(err))
.stderr.on("data", (chunk) => err.push(chunk))
.on("end", () => {
if (err.length === 0) return;
done(new Error(config.decode(err)));
});
if (!child.pid) return text;
if (text?.pipe) text.pipe(child.stdin);
else {
let output;
const type = Object.prototype.toString.call(text);
if (type === "[object String]") output = text;
else if (type === "[object Object]") output = util.inspect(text, { depth: null });
else if (type === "[object Array]") output = util.inspect(text, { depth: null });
else if (type === "[object Null]") output = "null";
else if (type === "[object Undefined]") output = "undefined";
else output = text.toString();
child.stdin.end(config.encode(output));
}
return text;
};
exports.copy.json = (obj, callback) => exports.copy(JSON.stringify(obj, null, "\t"), callback);
const pasteCommand = [config.paste.command].concat(config.paste.args).join(" ");
exports.paste = (callback) => {
const opts = { env: { ...process.env, ...config.paste.env }, maxBuffer: 1024 * 1024 * 10 };
if (execSync && !callback) return config.decode(execSync(pasteCommand, opts));
if (!callback) throw new Error("Synchronous version of paste is not supported on this platform.");
const child = spawn(config.paste.command, config.paste.args, opts);
let done =
callback &&
((...args) => {
callback(...args);
done = noop;
});
const data = [];
const err = [];
child.on("error", (err) => done(err));
child.stdout
.on("data", (chunk) => data.push(chunk))
.on("end", () => done(null, config.decode(data)));
child.stderr
.on("data", (chunk) => err.push(chunk))
.on("end", () => {
if (err.length === 0) return;
done(new Error(config.decode(err)));
});
};
exports.paste.json = (callback) =>
!callback
? JSON.parse(exports.paste())
: exports.paste((err, text) => callback(err, text && JSON.parse(text)));
exports.global = () => {
global.copy = exports.copy;
global.paste = exports.paste;
return exports;
};

29
Frontend-Learner/node_modules/copy-paste/package.json generated vendored Normal file
View file

@ -0,0 +1,29 @@
{
"name": "copy-paste",
"version": "2.2.0",
"description": "A command line utility that allows read/write (i.e copy/paste) access to the system clipboard.",
"keywords": [
"copy",
"paste",
"copy and paste",
"clipboard"
],
"maintainers": [
{
"name": "Xavi",
"email": "xavi.rmz@gmail.com",
"web": "http://xavi.co"
}
],
"main": "./index.js",
"repository": {
"type": "git",
"url": "https://github.com/xavi-/node-copy-paste"
},
"dependencies": {
"iconv-lite": "^0.4.8"
},
"scripts": {
"test": "node --test test/*js"
}
}

View file

@ -0,0 +1,9 @@
exports.copy = { command: "termux-clipboard-set", args: [] };
exports.paste = { command: "termux-clipboard-get", args: [] };
exports.paste.full_command = exports.paste.command;
exports.encode = (str) => Buffer.from(str, "utf8");
exports.decode = (chunks) => {
const data = Array.isArray(chunks) ? chunks : [chunks];
return Buffer.concat(data).toString("utf8");
};

View file

@ -0,0 +1,9 @@
exports.copy = { command: "pbcopy", args: [], env: { LANG: "en_US.UTF-8" } };
exports.paste = { command: "pbpaste", args: [] };
exports.paste.full_command = exports.paste.command;
exports.encode = (str) => Buffer.from(str, "utf8");
exports.decode = (chunks) => {
const data = Array.isArray(chunks) ? chunks : [chunks];
return Buffer.concat(data).toString("utf8");
};

View file

@ -0,0 +1,52 @@
Function Base64Encode(sText)
Dim oXML, oNode
Set oXML = CreateObject("Msxml2.DOMDocument.3.0")
Set oNode = oXML.CreateElement("base64")
oNode.dataType = "bin.base64"
oNode.nodeTypedValue =Stream_StringToBinary(sText)
Base64Encode = oNode.text
Set oNode = Nothing
Set oXML = Nothing
End Function
'Stream_StringToBinary Function
'2003 Antonin Foller, http://www.motobit.com
'Text - string parameter To convert To binary data
Function Stream_StringToBinary(Text)
Const adTypeText = 2
Const adTypeBinary = 1
'Create Stream object
Dim BinaryStream 'As New Stream
Set BinaryStream = CreateObject("ADODB.Stream")
'Specify stream type - we want To save text/string data.
BinaryStream.Type = adTypeText
'Specify charset For the source text (unicode) data.
BinaryStream.CharSet = "utf-8"
'Open the stream And write text/string data To the object
BinaryStream.Open
BinaryStream.WriteText Text
'Change stream type To binary
BinaryStream.Position = 0
BinaryStream.Type = adTypeBinary
'Ignore first two bytes - sign of
BinaryStream.Position = 0
'Open the stream And get binary data from the object
Stream_StringToBinary = BinaryStream.Read
Set BinaryStream = Nothing
End Function
Dim objHTML
Set objHTML = CreateObject("htmlfile")
text = objHTML.ParentWindow.ClipboardData.GetData("Text")
Wscript.Echo Base64Encode(text)

View file

@ -0,0 +1,12 @@
exports.copy = process.env.WSL_DISTRO_NAME
? { command: "clip.exe", args: [] }
: { command: "wl-copy", args: [] };
exports.paste = { command: "wl-paste", args: [] };
exports.paste.full_command = [exports.paste.command].concat(exports.paste.args).join(" ");
exports.encode = (str) => Buffer.from(str, "utf8");
exports.decode = (chunks) => {
const data = Array.isArray(chunks) ? chunks : [chunks];
return Buffer.concat(data).toString("utf8");
};

View file

@ -0,0 +1,23 @@
exports.copy = process.env.WSL_DISTRO_NAME
? { command: "clip.exe", args: [] }
: { command: "xclip", args: ["-selection", "clipboard"] };
exports.paste = process.env.WSL_DISTRO_NAME
? {
command: "powershell.exe",
args: ["-noprofile", "-command", "Get-Clipboard"],
}
: { command: "xclip", args: ["-selection", "clipboard", "-o"] };
exports.paste.full_command = [exports.paste.command].concat(exports.paste.args).join(" ");
exports.encode = (str) => Buffer.from(str, "utf8");
exports.decode = (chunks) => {
const data = Array.isArray(chunks) ? chunks : [chunks];
let output = Buffer.concat(data).toString("utf8");
// Check if running under WSL and strip the last two characters added by powershell.exe
if (process.env.WSL_DISTRO_NAME) output = output.slice(0, -2);
return output;
};

View file

@ -0,0 +1,21 @@
const iconv = require("iconv-lite");
const path = require("node:path");
const vbsPath = path.join(__dirname, ".\\fallbacks\\paste.vbs");
const paste = { command: "cscript", args: ["/Nologo", vbsPath] };
paste.full_command = [paste.command, paste.args[0], `"${vbsPath}"`].join(" ");
exports.copy = { command: "clip", args: [] };
exports.paste = paste;
exports.encode = (str) => iconv.encode(str, "utf16le");
exports.decode = (chunks) => {
const data = Array.isArray(chunks) ? chunks : [chunks];
let b64 = iconv.decode(Buffer.concat(data), "cp437");
b64 = b64.substring(0, b64.length - 2); // Chops off extra "\r\n"
// remove bom and decode
return Buffer.from(b64, "base64").subarray(3).toString("utf-8");
};

28
Frontend-Learner/node_modules/copy-paste/promises.js generated vendored Normal file
View file

@ -0,0 +1,28 @@
const clipboard = require("./index.js");
exports.copy = (text) => {
return new Promise((resolve, reject) => {
clipboard.copy(text, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
};
exports.copy.json = (obj) => {
return new Promise((resolve, reject) => {
clipboard.copy.json(obj, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
};
exports.paste = () => {
return new Promise((resolve, reject) => {
clipboard.paste((err, result) => {
if (err) reject(err);
else resolve(result);
});
});
};

View file

@ -0,0 +1,83 @@
const assert = require("node:assert");
const { describe, it } = require("node:test");
const clipboard = require("../index.js");
const clipboardPromises = require("../promises.js");
const tests = [
{
text: "123456789abcdefghijklmnopqrstuvwxyz+-=&_[]<^=>=/{:})-{(`)}",
description: "ascii chars (<128)",
},
{ text: "ÉæÆôöòûùÿÖÜ¢£¥₧ƒ", description: "cp437 chars (<256)" },
{ text: "ĀāĂ㥹ĆćĈĉĊċČčĎ ፰፱፲፳፴፵፶፷፸፹፺፻፼", description: "unicode chars (<2^16)" },
{ text: "±", description: "special chars" },
{ text: "你好,我是中文", description: "chinese chars" },
];
function copyAndPasteAsync(content) {
return new Promise((resolve, reject) => {
clipboard.copy(content, (errorWhenCopy) => {
if (errorWhenCopy) return reject(errorWhenCopy);
clipboard.paste((errorWhenPaste, p) => {
if (errorWhenPaste) return reject(errorWhenPaste);
resolve(p);
});
});
});
}
describe("copy and paste", () => {
for (const { text, description } of tests) {
it(`should work correctly with ${description}`, async () => {
const result = await copyAndPasteAsync(text);
assert.ok(result);
assert.strictEqual(result, text);
});
}
it("should work correctly with JSON", async () => {
const obj = { name: "John", age: 30 };
const expectedText = `{\n\t"name": "John",\n\t"age": 30\n}`;
return new Promise((resolve, reject) => {
clipboard.copy.json(obj, (err, text) => {
if (err) return reject(err);
assert.ok(text);
assert.strictEqual(text, expectedText);
clipboard.paste((err, text) => {
if (err) return reject(err);
assert.ok(text);
assert.strictEqual(text, expectedText);
resolve();
});
});
});
});
});
describe("promise-based copy and paste", () => {
for (const { text, description } of tests) {
it(`should work correctly with ${description}`, async () => {
await clipboardPromises.copy(text);
const result = await clipboardPromises.paste();
assert.ok(result);
assert.strictEqual(result, text);
});
}
it("should work correctly with JSON", async () => {
const obj = { name: "John", age: 30 };
const expectedText = `{\n\t"name": "John",\n\t"age": 30\n}`;
await clipboardPromises.copy.json(obj);
const result = await clipboardPromises.paste();
assert.ok(result);
assert.strictEqual(result, expectedText);
});
});