codiedev 0.9.25 → 0.9.28
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 +32 -4
- package/assets/opencode-plugin.mjs +54 -0
- package/assets/tui-brand-plugin.tsx +63 -0
- package/dist/backup/cache.js +2 -2
- package/dist/backup/run.js +5 -0
- package/dist/captureExclusions.d.ts +30 -0
- package/dist/captureExclusions.js +118 -0
- package/dist/captureLog.js +6 -3
- package/dist/cli.js +38 -0
- package/dist/codie.d.ts +2 -0
- package/dist/codie.js +233 -0
- package/dist/codieLauncher.d.ts +41 -0
- package/dist/codieLauncher.js +352 -0
- package/dist/codieRuntime.d.ts +19 -0
- package/dist/codieRuntime.js +91 -0
- package/dist/codieRuntimeInstall.d.ts +27 -0
- package/dist/codieRuntimeInstall.js +145 -0
- package/dist/commands/capture.d.ts +14 -0
- package/dist/commands/capture.js +148 -0
- package/dist/configDir.d.ts +1 -0
- package/dist/configDir.js +54 -0
- package/dist/connect.js +27 -2
- package/dist/hook.js +77 -43
- package/dist/upgradeNudge.js +6 -5
- package/dist/utils.d.ts +30 -3
- package/dist/utils.js +313 -22
- package/package.json +13 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# codiedev
|
|
2
2
|
|
|
3
|
-
Connect Claude Code or
|
|
3
|
+
Connect Claude Code, Codex, Cursor, or OpenCode to Codiedev for team session capture.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -12,21 +12,49 @@ The CLI will prompt you for an API token (get one at https://codiedev.com/portal
|
|
|
12
12
|
|
|
13
13
|
- **Claude Code** — `SessionEnd` hook in `~/.claude/settings.json`
|
|
14
14
|
- **Codex** — `Stop` hook in `~/.codex/hooks.json`
|
|
15
|
+
- **Cursor** — `sessionEnd` hook in `~/.cursor/hooks.json`
|
|
16
|
+
- **OpenCode / Codie** — plugin in `~/.config/opencode/plugins/codiedev.js`
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
Installed clients are wired automatically. The OpenCode adapter is staged even
|
|
19
|
+
when OpenCode is not installed yet, so adding the Codie harness later does not
|
|
20
|
+
require a second connect step.
|
|
17
21
|
|
|
18
22
|
## What gets captured
|
|
19
23
|
|
|
20
|
-
-
|
|
24
|
+
- Agent sessions from connected devices (capture is enabled by default)
|
|
21
25
|
- Transcript + basic stats (message count, tool calls)
|
|
22
26
|
- Processed into summaries and embeddings server-side for search in `/portal/memories`
|
|
23
27
|
|
|
24
|
-
Each captured memory records its
|
|
28
|
+
Each captured memory records its source (`claude-code`, `codex`, `cursor`, or
|
|
29
|
+
`opencode`) so the portal can label the client without breaking the shared
|
|
30
|
+
session → repository / branch / SHA → merge attribution model.
|
|
31
|
+
|
|
32
|
+
## Keep folders local
|
|
33
|
+
|
|
34
|
+
Folder exclusions are device-specific and include every child folder. The CLI
|
|
35
|
+
writes the rule locally before attempting to sync its read-only status to the
|
|
36
|
+
portal, so an offline or failed status sync never weakens the exclusion.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
codiedev ignore ~/Obsidian
|
|
40
|
+
codiedev ignored ~/Obsidian/People # check whether a path is ignored
|
|
41
|
+
codiedev ignored # list every ignored folder
|
|
42
|
+
codiedev unignore ~/Obsidian
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Run `ignore` once per device or persistent VM/container. A new ephemeral
|
|
46
|
+
container needs its own rule unless `~/.codiedev/config.json` is persisted.
|
|
25
47
|
|
|
26
48
|
## Codex note
|
|
27
49
|
|
|
28
50
|
Codex doesn't currently expose a `SessionEnd` event, so the hook runs on `Stop` (fires after each assistant turn). The backend dedupes by `(company, session_id)` and replaces the stored transcript on re-upload so the latest turn's snapshot wins. Summarization happens once per session; subsequent turn uploads keep the raw transcript fresh but don't re-summarize (to avoid running up LLM cost).
|
|
29
51
|
|
|
52
|
+
## OpenCode note
|
|
53
|
+
|
|
54
|
+
OpenCode exposes session lifecycle events through plugins. Codiedev snapshots
|
|
55
|
+
the SDK message list on `session.idle`, normalizes it into the shared capture
|
|
56
|
+
pipeline, and lets the server close the session after a quiet-period lease.
|
|
57
|
+
|
|
30
58
|
## Config
|
|
31
59
|
|
|
32
60
|
Written to `~/.codiedev/config.json`. Override the backend with `CODIEDEV_URL` if needed.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Metadata-only attribution for the Codiedev OpenCode distribution.
|
|
2
|
+
// This plugin never reads or sends prompts, messages, code, diffs, or tool
|
|
3
|
+
// output. It only attaches stable session/git identifiers and explicit skill
|
|
4
|
+
// names to inference requests handled by the company gateway.
|
|
5
|
+
|
|
6
|
+
const skillUseBySession = new Map();
|
|
7
|
+
|
|
8
|
+
function clean(value, max) {
|
|
9
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
10
|
+
return text ? text.slice(0, max) : "";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function addSkill(sessionID, value) {
|
|
14
|
+
const skill = clean(value, 160).replace(/^\//, "").replace(/\.md$/i, "");
|
|
15
|
+
if (!skill) return;
|
|
16
|
+
const skills = skillUseBySession.get(sessionID) || new Set();
|
|
17
|
+
if (skills.size < 50) skills.add(skill);
|
|
18
|
+
skillUseBySession.set(sessionID, skills);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const CodiedevMetadata = async () => ({
|
|
22
|
+
"command.execute.before": async (input) => {
|
|
23
|
+
// Built-in commands are UI actions. Named custom commands are explicit
|
|
24
|
+
// skill dispatches and become part of the session attribution spine.
|
|
25
|
+
const builtIns = new Set([
|
|
26
|
+
"connect", "help", "models", "new", "share", "unshare", "undo", "redo",
|
|
27
|
+
"compact", "sessions", "timeline", "themes", "editor", "export", "exit",
|
|
28
|
+
]);
|
|
29
|
+
if (!builtIns.has(input.command)) addSkill(input.sessionID, input.command);
|
|
30
|
+
},
|
|
31
|
+
"tool.execute.before": async (input, output) => {
|
|
32
|
+
if (input.tool !== "skill") return;
|
|
33
|
+
addSkill(input.sessionID, output.args?.name || output.args?.skill || output.args?.key);
|
|
34
|
+
},
|
|
35
|
+
"chat.headers": async (input, output) => {
|
|
36
|
+
output.headers["X-Codiedev-Session-Id"] = clean(input.sessionID, 200);
|
|
37
|
+
const repo = clean(process.env.CODIEDEV_REPO_URL, 2048);
|
|
38
|
+
const branch = clean(process.env.CODIEDEV_BRANCH, 200);
|
|
39
|
+
const sha = clean(process.env.CODIEDEV_HEAD_SHA, 40);
|
|
40
|
+
const user = clean(process.env.CODIEDEV_USER, 200);
|
|
41
|
+
const skills = [...(skillUseBySession.get(input.sessionID) || [])].join(",");
|
|
42
|
+
if (repo) output.headers["X-Codiedev-Repo-Url"] = repo;
|
|
43
|
+
if (branch) output.headers["X-Codiedev-Branch"] = branch;
|
|
44
|
+
if (/^[0-9a-f]{7,40}$/i.test(sha)) output.headers["X-Codiedev-Head-Sha"] = sha;
|
|
45
|
+
if (user) output.headers["X-Codiedev-User"] = user;
|
|
46
|
+
if (skills) output.headers["X-Codiedev-Skills-Used"] = skills;
|
|
47
|
+
},
|
|
48
|
+
event: async ({ event }) => {
|
|
49
|
+
if (event?.type === "session.deleted") {
|
|
50
|
+
const sessionID = event.properties?.info?.id || event.properties?.sessionID;
|
|
51
|
+
if (sessionID) skillUseBySession.delete(sessionID);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
// Codiedev branding for the OpenCode home screen: the intertwined c/d brand
|
|
3
|
+
// mark (rectangle crop, sized to the footprint the stock wordmark occupied)
|
|
4
|
+
// over the product name, with a "powered by opencode" credit line beneath.
|
|
5
|
+
// Installed and kept current by `codie`; deleting this file and its tui.json
|
|
6
|
+
// entry restores the stock logo.
|
|
7
|
+
// Mark ported from the retired Grok-fork TUI (assets/logo/logo07.txt), itself
|
|
8
|
+
// derived from vm-demo/public/codiedev-icon.png — keep aligned to that
|
|
9
|
+
// intertwined c/d silhouette when refreshing brand assets.
|
|
10
|
+
import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui"
|
|
11
|
+
import { TextAttributes } from "@opentui/core"
|
|
12
|
+
|
|
13
|
+
const MARK = [
|
|
14
|
+
"⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿",
|
|
15
|
+
"⠀⠀⠀⢀⣀⣀⣀⡀⠀⠀⠀⠀⠀⣀⣀⣀⡀⣿⣿⣿",
|
|
16
|
+
"⠀⣠⣾⣿⣿⣿⣿⣿⣶⠄⢠⣶⣿⣿⣿⣿⣿⣿⣿⣿",
|
|
17
|
+
"⣼⣿⣿⠟⠉⠈⠉⠛⠁⣰⣿⣿⡟⠉⠁⠉⠻⣿⣿⣿",
|
|
18
|
+
"⣿⣿⣿⠀⠀⠀⠀⢀⣼⣿⣿⣿⡀⠀⠀⠀⠀⣿⣿⣿",
|
|
19
|
+
"⠹⣿⣿⣷⣤⣤⣴⣿⣿⡿⢿⣿⣷⣤⣤⣤⣾⣿⣿⠏",
|
|
20
|
+
"⠀⠈⠻⢿⣿⣿⣿⠿⠋⠀⠀⠙⠿⣿⣿⣿⡿⠟⠁",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
const tui: TuiPlugin = async (api) => {
|
|
24
|
+
api.slots.register({
|
|
25
|
+
slots: {
|
|
26
|
+
home_logo(ctx) {
|
|
27
|
+
const theme = ctx.theme.current
|
|
28
|
+
return (
|
|
29
|
+
<box flexDirection="column" alignItems="center" gap={1}>
|
|
30
|
+
<box flexDirection="column">
|
|
31
|
+
{MARK.map((line) => (
|
|
32
|
+
<text fg={theme.primary} selectable={false}>
|
|
33
|
+
{line}
|
|
34
|
+
</text>
|
|
35
|
+
))}
|
|
36
|
+
</box>
|
|
37
|
+
<box flexDirection="column" alignItems="center">
|
|
38
|
+
<box flexDirection="row">
|
|
39
|
+
<text fg={theme.text} attributes={TextAttributes.BOLD} selectable={false}>
|
|
40
|
+
codiedev
|
|
41
|
+
</text>
|
|
42
|
+
<text fg={theme.textMuted} selectable={false}>
|
|
43
|
+
{" "}
|
|
44
|
+
harness
|
|
45
|
+
</text>
|
|
46
|
+
</box>
|
|
47
|
+
<text fg={theme.textMuted} selectable={false}>
|
|
48
|
+
powered by opencode
|
|
49
|
+
</text>
|
|
50
|
+
</box>
|
|
51
|
+
</box>
|
|
52
|
+
)
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const plugin: TuiPluginModule & { id: string } = {
|
|
59
|
+
id: "codiedev.brand",
|
|
60
|
+
tui,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default plugin
|
package/dist/backup/cache.js
CHANGED
|
@@ -38,9 +38,9 @@ exports.loadCache = loadCache;
|
|
|
38
38
|
exports.saveCache = saveCache;
|
|
39
39
|
exports.applyCache = applyCache;
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
|
-
const os = __importStar(require("os"));
|
|
42
41
|
const path = __importStar(require("path"));
|
|
43
|
-
const
|
|
42
|
+
const configDir_1 = require("../configDir");
|
|
43
|
+
const CACHE_PATH = path.join((0, configDir_1.codiedevStateDir)(), "backup-state.json");
|
|
44
44
|
function cacheKey(repoKey, rel) {
|
|
45
45
|
return `${repoKey}::${rel}`;
|
|
46
46
|
}
|
package/dist/backup/run.js
CHANGED
|
@@ -86,6 +86,7 @@ const child_process_1 = require("child_process");
|
|
|
86
86
|
const utils_1 = require("../utils");
|
|
87
87
|
const cache_2 = require("./cache");
|
|
88
88
|
const push = __importStar(require("../commands/push"));
|
|
89
|
+
const captureExclusions_1 = require("../captureExclusions");
|
|
89
90
|
function gitRoot(cwd) {
|
|
90
91
|
try {
|
|
91
92
|
return (0, child_process_1.execFileSync)("git", ["-C", cwd, "rev-parse", "--show-toplevel"], {
|
|
@@ -143,6 +144,8 @@ function runBackup(cwd, hookScriptPath) {
|
|
|
143
144
|
const config = (0, utils_1.readConfig)();
|
|
144
145
|
if (!config)
|
|
145
146
|
return;
|
|
147
|
+
if ((0, captureExclusions_1.isCaptureIgnored)(cwd, config.captureIgnoredPaths))
|
|
148
|
+
return;
|
|
146
149
|
const root = gitRoot(cwd);
|
|
147
150
|
if (!root)
|
|
148
151
|
return;
|
|
@@ -195,6 +198,8 @@ async function runBackupUpload(jobFile, deps = DEFAULT_BACKUP_UPLOAD_DEPS) {
|
|
|
195
198
|
const config = deps.readConfig(); // same machine — read full config from disk
|
|
196
199
|
if (!config)
|
|
197
200
|
return;
|
|
201
|
+
if ((0, captureExclusions_1.isCaptureIgnored)(job.root, config.captureIgnoredPaths))
|
|
202
|
+
return;
|
|
198
203
|
const cache = deps.loadCache();
|
|
199
204
|
let dirty = false;
|
|
200
205
|
for (const f of job.files) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { CodiedevConfig } from "./utils";
|
|
2
|
+
export interface NormalizeCapturePathDeps {
|
|
3
|
+
cwd?: () => string;
|
|
4
|
+
homedir?: () => string;
|
|
5
|
+
realpathSync?: (value: string) => string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Convert a user-entered path into the canonical absolute form persisted in
|
|
9
|
+
* ~/.codiedev/config.json. Existing symlinks resolve to their real target so a
|
|
10
|
+
* session cannot bypass an exclusion by entering the same folder through a
|
|
11
|
+
* different alias. Non-existent paths still normalize deterministically.
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeCapturePath(input: string, deps?: NormalizeCapturePathDeps): string;
|
|
14
|
+
export declare function findMatchingCaptureExclusion(candidate: string | string[] | undefined, ignoredPaths: string[] | undefined): string | null;
|
|
15
|
+
export declare function isCaptureIgnored(candidate: string | string[] | undefined, ignoredPaths: string[] | undefined): boolean;
|
|
16
|
+
export interface CaptureScopeInput {
|
|
17
|
+
cwd?: string;
|
|
18
|
+
workspace_roots?: string[];
|
|
19
|
+
}
|
|
20
|
+
/** Every local root associated with a hook event, deduped in stable order. */
|
|
21
|
+
export declare function captureScopePaths(input: CaptureScopeInput, fallback?: string): string[];
|
|
22
|
+
export declare function shouldIgnoreCaptureInput(config: Pick<CodiedevConfig, "captureIgnoredPaths"> | null | undefined, input: CaptureScopeInput, fallback?: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Final egress decision for queued transcript uploads. Jobs written by older
|
|
25
|
+
* CLI versions have no scope metadata; once any exclusion exists, dropping
|
|
26
|
+
* those legacy jobs is safer than guessing that they are public.
|
|
27
|
+
*/
|
|
28
|
+
export declare function shouldSkipCaptureUploadJob(job: {
|
|
29
|
+
scopePaths?: string[];
|
|
30
|
+
}, config: Pick<CodiedevConfig, "captureIgnoredPaths"> | null | undefined): boolean;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.normalizeCapturePath = normalizeCapturePath;
|
|
37
|
+
exports.findMatchingCaptureExclusion = findMatchingCaptureExclusion;
|
|
38
|
+
exports.isCaptureIgnored = isCaptureIgnored;
|
|
39
|
+
exports.captureScopePaths = captureScopePaths;
|
|
40
|
+
exports.shouldIgnoreCaptureInput = shouldIgnoreCaptureInput;
|
|
41
|
+
exports.shouldSkipCaptureUploadJob = shouldSkipCaptureUploadJob;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const DEFAULT_NORMALIZE_DEPS = {
|
|
46
|
+
cwd: () => process.cwd(),
|
|
47
|
+
homedir: () => os.homedir(),
|
|
48
|
+
realpathSync: (value) => fs.realpathSync.native(value),
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Convert a user-entered path into the canonical absolute form persisted in
|
|
52
|
+
* ~/.codiedev/config.json. Existing symlinks resolve to their real target so a
|
|
53
|
+
* session cannot bypass an exclusion by entering the same folder through a
|
|
54
|
+
* different alias. Non-existent paths still normalize deterministically.
|
|
55
|
+
*/
|
|
56
|
+
function normalizeCapturePath(input, deps = {}) {
|
|
57
|
+
const d = { ...DEFAULT_NORMALIZE_DEPS, ...deps };
|
|
58
|
+
const trimmed = input.trim();
|
|
59
|
+
if (!trimmed)
|
|
60
|
+
throw new Error("Folder path is required");
|
|
61
|
+
const expanded = /^~(?=$|[\\/])/.test(trimmed)
|
|
62
|
+
? path.join(d.homedir(), trimmed.slice(1))
|
|
63
|
+
: trimmed;
|
|
64
|
+
const absolute = path.resolve(d.cwd(), expanded);
|
|
65
|
+
try {
|
|
66
|
+
return path.normalize(d.realpathSync(absolute));
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return path.normalize(absolute);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function comparisonKey(value) {
|
|
73
|
+
const normalized = path.normalize(value);
|
|
74
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
75
|
+
}
|
|
76
|
+
function containsPath(root, candidate) {
|
|
77
|
+
const relative = path.relative(comparisonKey(root), comparisonKey(candidate));
|
|
78
|
+
return (relative === "" ||
|
|
79
|
+
(relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)));
|
|
80
|
+
}
|
|
81
|
+
function findMatchingCaptureExclusion(candidate, ignoredPaths) {
|
|
82
|
+
if (!candidate || !ignoredPaths || ignoredPaths.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
const candidates = Array.isArray(candidate) ? candidate : [candidate];
|
|
85
|
+
for (const ignored of ignoredPaths) {
|
|
86
|
+
const root = normalizeCapturePath(ignored);
|
|
87
|
+
for (const value of candidates) {
|
|
88
|
+
if (containsPath(root, normalizeCapturePath(value)))
|
|
89
|
+
return root;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
function isCaptureIgnored(candidate, ignoredPaths) {
|
|
95
|
+
return findMatchingCaptureExclusion(candidate, ignoredPaths) !== null;
|
|
96
|
+
}
|
|
97
|
+
/** Every local root associated with a hook event, deduped in stable order. */
|
|
98
|
+
function captureScopePaths(input, fallback = process.cwd()) {
|
|
99
|
+
const values = [input.cwd, ...(input.workspace_roots ?? [])]
|
|
100
|
+
.filter((value) => typeof value === "string" && value.length > 0);
|
|
101
|
+
return [...new Set(values.length > 0 ? values : [fallback])];
|
|
102
|
+
}
|
|
103
|
+
function shouldIgnoreCaptureInput(config, input, fallback) {
|
|
104
|
+
return isCaptureIgnored(captureScopePaths(input, fallback), config?.captureIgnoredPaths);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Final egress decision for queued transcript uploads. Jobs written by older
|
|
108
|
+
* CLI versions have no scope metadata; once any exclusion exists, dropping
|
|
109
|
+
* those legacy jobs is safer than guessing that they are public.
|
|
110
|
+
*/
|
|
111
|
+
function shouldSkipCaptureUploadJob(job, config) {
|
|
112
|
+
const ignoredPaths = config?.captureIgnoredPaths ?? [];
|
|
113
|
+
if (ignoredPaths.length === 0)
|
|
114
|
+
return false;
|
|
115
|
+
if (!job.scopePaths || job.scopePaths.length === 0)
|
|
116
|
+
return true;
|
|
117
|
+
return isCaptureIgnored(job.scopePaths, ignoredPaths);
|
|
118
|
+
}
|
package/dist/captureLog.js
CHANGED
|
@@ -36,7 +36,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.CAPTURE_LOG_PATH = exports.CAPTURE_LOG_MAX_BYTES = void 0;
|
|
37
37
|
exports.appendCaptureLog = appendCaptureLog;
|
|
38
38
|
exports.readCaptureLogTail = readCaptureLogTail;
|
|
39
|
-
// Rotating capture diagnostic log at
|
|
39
|
+
// Rotating capture diagnostic log at <codiedevStateDir()>/capture.log
|
|
40
|
+
// (~/.codiedev by default; ~/.codiedev-desktop under CODIEDEV_CONFIG_DIR).
|
|
40
41
|
//
|
|
41
42
|
// Every stage of the capture pipeline (capture-finish child, upload child,
|
|
42
43
|
// stderr from detached children) writes one line here so users — and
|
|
@@ -45,12 +46,14 @@ exports.readCaptureLogTail = readCaptureLogTail;
|
|
|
45
46
|
// best-effort throughout: appendCaptureLog NEVER throws into the hook path.
|
|
46
47
|
const fs = __importStar(require("fs"));
|
|
47
48
|
const path = __importStar(require("path"));
|
|
48
|
-
|
|
49
|
+
// Imported from configDir (not utils) — utils.ts imports this module, so
|
|
50
|
+
// importing utils.ts here would create a circular import.
|
|
51
|
+
const configDir_1 = require("./configDir");
|
|
49
52
|
// Rotate the log when it exceeds this size (keeps the newest ~half). 256 KB
|
|
50
53
|
// holds thousands of entries; a user would have to see hundreds of errors
|
|
51
54
|
// before hitting this limit, so it's a generous safety valve.
|
|
52
55
|
exports.CAPTURE_LOG_MAX_BYTES = 256 * 1024;
|
|
53
|
-
exports.CAPTURE_LOG_PATH = path.join(
|
|
56
|
+
exports.CAPTURE_LOG_PATH = path.join((0, configDir_1.codiedevStateDir)(), "capture.log");
|
|
54
57
|
// Append one structured line to the capture log. Rotates the file when it
|
|
55
58
|
// grows past CAPTURE_LOG_MAX_BYTES by truncating it to the newest half (keeps
|
|
56
59
|
// the most recent diagnostics). Best-effort: NEVER throws into the hook path —
|
package/dist/cli.js
CHANGED
|
@@ -33,6 +33,7 @@ const post_1 = require("./commands/post");
|
|
|
33
33
|
const share_1 = require("./commands/share");
|
|
34
34
|
const send_1 = require("./commands/send");
|
|
35
35
|
const react_1 = require("./commands/react");
|
|
36
|
+
const capture_1 = require("./commands/capture");
|
|
36
37
|
const version_1 = require("./version");
|
|
37
38
|
const HELP = `
|
|
38
39
|
Codiedev CLI
|
|
@@ -45,6 +46,13 @@ Connect:
|
|
|
45
46
|
codiedev connect Link Claude Code / Codex to your org
|
|
46
47
|
codiedev doctor Verify your setup after connecting
|
|
47
48
|
|
|
49
|
+
Harness:
|
|
50
|
+
codie Launch the governed Codie harness.
|
|
51
|
+
Same install, same token as above —
|
|
52
|
+
use your own agent (Claude Code,
|
|
53
|
+
Codex, Cursor) or Codie, your call.
|
|
54
|
+
The engine downloads on first run.
|
|
55
|
+
|
|
48
56
|
Artifacts:
|
|
49
57
|
codiedev push <file.md> Author or update an artifact
|
|
50
58
|
codiedev pull <key> [--version N] [--out path]
|
|
@@ -95,6 +103,11 @@ Feed:
|
|
|
95
103
|
[--mention <name>]... Publish to the team feed
|
|
96
104
|
codiedev react <postId> <emoji> Toggle a reaction on a feed post
|
|
97
105
|
|
|
106
|
+
Privacy:
|
|
107
|
+
codiedev ignore <path> Never capture this folder or its children
|
|
108
|
+
codiedev unignore <path> Stop ignoring a folder
|
|
109
|
+
codiedev ignored [path] List ignored folders, or check one path
|
|
110
|
+
|
|
98
111
|
Capture:
|
|
99
112
|
codiedev note "<text>" Capture a passing thought
|
|
100
113
|
|
|
@@ -130,6 +143,18 @@ Backend: ${process.env.CODIEDEV_URL ?? "https://codiedev.com"}
|
|
|
130
143
|
Token: https://codiedev.com/portal/integrations/claude-code
|
|
131
144
|
Docs: codiedev docs
|
|
132
145
|
`.trim();
|
|
146
|
+
const IGNORE_HELP = `
|
|
147
|
+
codiedev ignore — keep folders out of session capture
|
|
148
|
+
|
|
149
|
+
codiedev ignore <path> Never capture this folder or its children
|
|
150
|
+
codiedev unignore <path> Stop ignoring a folder
|
|
151
|
+
codiedev ignored List ignored folders on this device
|
|
152
|
+
codiedev ignored <path> Check whether a specific path is ignored
|
|
153
|
+
|
|
154
|
+
Exclusions are per-device and cover every child folder. The rule is written
|
|
155
|
+
locally before any capture leaves your machine, so an offline or failed portal
|
|
156
|
+
status sync never weakens it.
|
|
157
|
+
`.trim();
|
|
133
158
|
const COMMAND_HELP = {
|
|
134
159
|
connect: `
|
|
135
160
|
codiedev connect — link your agent CLI to Codiedev
|
|
@@ -237,6 +262,10 @@ codiedev note — capture a passing thought, linked to your session
|
|
|
237
262
|
codiedev note "idempotency key is worth a follow-up"
|
|
238
263
|
codiedev note "timeout threshold feels arbitrary — validate on slow networks"
|
|
239
264
|
`.trim(),
|
|
265
|
+
ignore: IGNORE_HELP,
|
|
266
|
+
unignore: IGNORE_HELP,
|
|
267
|
+
ignored: IGNORE_HELP,
|
|
268
|
+
capture: IGNORE_HELP,
|
|
240
269
|
promote: `
|
|
241
270
|
codiedev promote — promote an auto-extracted artifact to authored
|
|
242
271
|
|
|
@@ -482,6 +511,15 @@ async function main() {
|
|
|
482
511
|
case "react":
|
|
483
512
|
await (0, react_1.runReact)(rest);
|
|
484
513
|
return;
|
|
514
|
+
case "ignore":
|
|
515
|
+
case "unignore":
|
|
516
|
+
case "ignored":
|
|
517
|
+
await (0, capture_1.runCaptureCommand)([command, ...rest]);
|
|
518
|
+
return;
|
|
519
|
+
case "capture":
|
|
520
|
+
// Back-compat alias for the earlier `codiedev capture <sub>` form.
|
|
521
|
+
await (0, capture_1.runCaptureCommand)(rest);
|
|
522
|
+
return;
|
|
485
523
|
default:
|
|
486
524
|
console.error(`Unknown command: ${command}`);
|
|
487
525
|
console.error(HELP);
|
package/dist/codie.d.ts
ADDED