@creativeintelligence/abbie 0.1.6 → 0.1.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.
- package/bin/dev.js +1 -49
- package/bin/run.js +42 -49
- package/dist/cli/commands/project/add.d.ts +0 -1
- package/dist/cli/commands/project/add.js +16 -52
- package/dist/cli/commands/project/list.js +13 -93
- package/dist/cli/commands/project/remove.d.ts +0 -2
- package/dist/cli/commands/project/remove.js +11 -28
- package/dist/cli/commands/session/list.js +3 -12
- package/dist/cli/commands/session/mark-done.js +1 -7
- package/dist/cli/commands/session/start.d.ts +0 -1
- package/dist/cli/commands/session/start.js +5 -7
- package/dist/lib/active-sessions.d.ts +0 -12
- package/dist/lib/active-sessions.js +6 -175
- package/dist/lib/project-path.d.ts +6 -0
- package/dist/lib/project-path.js +21 -0
- package/dist/lib.d.ts +1 -2
- package/dist/lib.js +2 -4
- package/oclif.manifest.json +2569 -6368
- package/package.json +1 -1
- package/dist/cli/commands/backlog/add.d.ts +0 -22
- package/dist/cli/commands/backlog/add.js +0 -65
- package/dist/cli/commands/backlog/claim.d.ts +0 -19
- package/dist/cli/commands/backlog/claim.js +0 -45
- package/dist/cli/commands/backlog/complete.d.ts +0 -18
- package/dist/cli/commands/backlog/complete.js +0 -42
- package/dist/cli/commands/backlog/list.d.ts +0 -20
- package/dist/cli/commands/backlog/list.js +0 -91
- package/dist/cli/commands/backlog/pick.d.ts +0 -18
- package/dist/cli/commands/backlog/pick.js +0 -42
- package/dist/cli/commands/backlog/sync.d.ts +0 -24
- package/dist/cli/commands/backlog/sync.js +0 -109
- package/dist/cli/commands/daemon.d.ts +0 -56
- package/dist/cli/commands/daemon.js +0 -1465
- package/dist/cli/commands/docs/lint.d.ts +0 -18
- package/dist/cli/commands/docs/lint.js +0 -82
- package/dist/cli/commands/docs/sync.d.ts +0 -19
- package/dist/cli/commands/docs/sync.js +0 -76
- package/dist/cli/commands/gc.d.ts +0 -29
- package/dist/cli/commands/gc.js +0 -211
- package/dist/cli/commands/index.d.ts +0 -36
- package/dist/cli/commands/index.js +0 -228
- package/dist/cli/commands/panes/broker.d.ts +0 -17
- package/dist/cli/commands/panes/broker.js +0 -57
- package/dist/cli/commands/panes/pipe-sink.d.ts +0 -17
- package/dist/cli/commands/panes/pipe-sink.js +0 -90
- package/dist/cli/commands/panes/snapshot.d.ts +0 -20
- package/dist/cli/commands/panes/snapshot.js +0 -125
- package/dist/cli/commands/preview/init.d.ts +0 -25
- package/dist/cli/commands/preview/init.js +0 -159
- package/dist/cli/commands/preview/sync.d.ts +0 -23
- package/dist/cli/commands/preview/sync.js +0 -144
- package/dist/cli/commands/preview/watch.d.ts +0 -24
- package/dist/cli/commands/preview/watch.js +0 -153
- package/dist/cli/commands/resource/acquire.d.ts +0 -21
- package/dist/cli/commands/resource/acquire.js +0 -90
- package/dist/cli/commands/resource/list.d.ts +0 -15
- package/dist/cli/commands/resource/list.js +0 -61
- package/dist/cli/commands/resource/release.d.ts +0 -18
- package/dist/cli/commands/resource/release.js +0 -50
- package/dist/cli/commands/resource/wait.d.ts +0 -21
- package/dist/cli/commands/resource/wait.js +0 -73
- package/dist/cli/commands/session/view.d.ts +0 -24
- package/dist/cli/commands/session/view.js +0 -145
- package/dist/cli/commands/start.d.ts +0 -37
- package/dist/cli/commands/start.js +0 -234
- package/dist/cli/commands/triage/claim.d.ts +0 -23
- package/dist/cli/commands/triage/claim.js +0 -186
- package/dist/cli/commands/triage/list.d.ts +0 -22
- package/dist/cli/commands/triage/list.js +0 -112
- package/dist/cli/commands/triage/next.d.ts +0 -18
- package/dist/cli/commands/triage/next.js +0 -63
- package/dist/cli/commands/triage/pull.d.ts +0 -19
- package/dist/cli/commands/triage/pull.js +0 -82
- package/dist/cli/commands/triage/stats.d.ts +0 -16
- package/dist/cli/commands/triage/stats.js +0 -69
- package/dist/cli/commands/tunnel/list.d.ts +0 -16
- package/dist/cli/commands/tunnel/list.js +0 -98
- package/dist/cli/commands/tunnel/start.d.ts +0 -24
- package/dist/cli/commands/tunnel/start.js +0 -107
- package/dist/cli/commands/tunnel/stop.d.ts +0 -20
- package/dist/cli/commands/tunnel/stop.js +0 -90
- package/dist/cli/commands/tunnel/url.d.ts +0 -21
- package/dist/cli/commands/tunnel/url.js +0 -70
- package/dist/cli/commands/windows/context.d.ts +0 -18
- package/dist/cli/commands/windows/context.js +0 -326
- package/dist/cli/commands/windows/focus.d.ts +0 -17
- package/dist/cli/commands/windows/focus.js +0 -103
- package/dist/cli/commands/windows/list.d.ts +0 -21
- package/dist/cli/commands/windows/list.js +0 -172
- package/dist/cli/commands/windows/map.d.ts +0 -17
- package/dist/cli/commands/windows/map.js +0 -168
- package/dist/cli/commands/windows/read.d.ts +0 -21
- package/dist/cli/commands/windows/read.js +0 -241
- package/dist/cli/commands/windows/search.d.ts +0 -24
- package/dist/cli/commands/windows/search.js +0 -171
- package/dist/cli/commands/windows/show.d.ts +0 -19
- package/dist/cli/commands/windows/show.js +0 -165
- package/dist/cli/commands/windows/watch.d.ts +0 -19
- package/dist/cli/commands/windows/watch.js +0 -241
- package/dist/lib/managed-session.d.ts +0 -27
- package/dist/lib/managed-session.js +0 -105
- package/dist/lib/panes/broker.d.ts +0 -130
- package/dist/lib/panes/broker.js +0 -97
- package/dist/lib/panes/index.d.ts +0 -2
- package/dist/lib/panes/index.js +0 -1
- package/dist/lib/panes/server.d.ts +0 -17
- package/dist/lib/panes/server.js +0 -308
- package/dist/lib/preview/manager.d.ts +0 -77
- package/dist/lib/preview/manager.js +0 -369
- package/dist/lib/preview/schema.d.ts +0 -2
- package/dist/lib/preview/schema.js +0 -32
- package/dist/lib/preview/sprite.d.ts +0 -85
- package/dist/lib/preview/sprite.js +0 -321
- package/dist/lib/preview/watcher.d.ts +0 -63
- package/dist/lib/preview/watcher.js +0 -185
- package/dist/lib/project-identity.d.ts +0 -16
- package/dist/lib/project-identity.js +0 -75
- package/dist/lib/tmux/bridge.d.ts +0 -133
- package/dist/lib/tmux/bridge.js +0 -315
- package/dist/lib/tmux/context.d.ts +0 -82
- package/dist/lib/tmux/context.js +0 -239
- package/dist/lib/tmux/index.d.ts +0 -8
- package/dist/lib/tmux/index.js +0 -11
- package/dist/lib/tmux/map.d.ts +0 -57
- package/dist/lib/tmux/map.js +0 -198
- package/dist/lib/tmux/panes.d.ts +0 -27
- package/dist/lib/tmux/panes.js +0 -151
- package/dist/lib/tmux/redaction.d.ts +0 -57
- package/dist/lib/tmux/redaction.js +0 -152
- package/dist/lib/web/analytics.d.ts +0 -63
- package/dist/lib/web/analytics.js +0 -168
- package/dist/lib/web/server.d.ts +0 -26
- package/dist/lib/web/server.js +0 -697
- package/dist/lib/web/tmux-bridge.d.ts +0 -7
- package/dist/lib/web/tmux-bridge.js +0 -7
- package/dist/lib/windows/index.d.ts +0 -3
- package/dist/lib/windows/index.js +0 -2
- package/dist/lib/windows/inventory.d.ts +0 -21
- package/dist/lib/windows/inventory.js +0 -263
- package/dist/lib/windows/types.d.ts +0 -46
- package/dist/lib/windows/types.js +0 -1
package/bin/dev.js
CHANGED
|
@@ -3,59 +3,11 @@
|
|
|
3
3
|
// @ts-check
|
|
4
4
|
|
|
5
5
|
import { execute, settings } from '@oclif/core';
|
|
6
|
-
import {
|
|
7
|
-
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { dirname, resolve } from "node:path";
|
|
8
7
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { Plugin } from "@oclif/core";
|
|
10
8
|
|
|
11
9
|
settings.performanceEnabled = false;
|
|
12
10
|
|
|
13
11
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
14
12
|
|
|
15
|
-
async function ensureManifestIsFresh() {
|
|
16
|
-
const manifestPath = join(root, "oclif.manifest.json");
|
|
17
|
-
const panesSnapshotPath = join(root, "dist", "cli", "commands", "panes", "snapshot.js");
|
|
18
|
-
const panesBrokerPath = join(root, "dist", "cli", "commands", "panes", "broker.js");
|
|
19
|
-
const panesPipeSinkPath = join(root, "dist", "cli", "commands", "panes", "pipe-sink.js");
|
|
20
|
-
|
|
21
|
-
if (!existsSync(panesSnapshotPath)) return;
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
if (existsSync(manifestPath)) {
|
|
25
|
-
const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
26
|
-
const commands = parsed?.commands ?? {};
|
|
27
|
-
const hasSnapshot = Boolean(commands["panes:snapshot"]);
|
|
28
|
-
const hasBroker = Boolean(commands["panes:broker"]);
|
|
29
|
-
const hasPipeSink = Boolean(commands["panes:pipe-sink"]);
|
|
30
|
-
|
|
31
|
-
const distHasBroker = existsSync(panesBrokerPath);
|
|
32
|
-
const distHasPipeSink = existsSync(panesPipeSinkPath);
|
|
33
|
-
|
|
34
|
-
if (hasSnapshot && (!distHasBroker || hasBroker) && (!distHasPipeSink || hasPipeSink)) return;
|
|
35
|
-
}
|
|
36
|
-
} catch {
|
|
37
|
-
// fall through -> regenerate
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const pjson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
42
|
-
const plugin = new Plugin({ root, pjson, isRoot: true, ignoreManifest: true });
|
|
43
|
-
await plugin.load();
|
|
44
|
-
writeFileSync(manifestPath, `${JSON.stringify(plugin.manifest, null, 2)}\n`);
|
|
45
|
-
} catch {
|
|
46
|
-
// Best-effort. If manifest regen fails, oclif will surface errors as usual.
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
await ensureManifestIsFresh();
|
|
51
|
-
|
|
52
|
-
// Default command: if no args (or only flags), run "start"
|
|
53
|
-
const userArgs = process.argv.slice(2);
|
|
54
|
-
const firstArg = userArgs[0];
|
|
55
|
-
const isSubcommand = firstArg && !firstArg.startsWith("-");
|
|
56
|
-
|
|
57
|
-
if (!isSubcommand) {
|
|
58
|
-
process.argv.splice(2, 0, "start");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
13
|
await execute({ development: true, dir: import.meta.url });
|
package/bin/run.js
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// @ts-check
|
|
4
4
|
|
|
5
|
-
import { execute,
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { execute, settings } from "@oclif/core";
|
|
7
6
|
import { dirname, join, resolve } from "node:path";
|
|
8
7
|
import { fileURLToPath } from "node:url";
|
|
9
8
|
|
|
@@ -11,56 +10,50 @@ settings.performanceEnabled = false;
|
|
|
11
10
|
|
|
12
11
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
const manifestPath = join(root, "oclif.manifest.json");
|
|
16
|
-
const panesSnapshotPath = join(root, "dist", "cli", "commands", "panes", "snapshot.js");
|
|
17
|
-
const panesBrokerPath = join(root, "dist", "cli", "commands", "panes", "broker.js");
|
|
18
|
-
const panesPipeSinkPath = join(root, "dist", "cli", "commands", "panes", "pipe-sink.js");
|
|
13
|
+
// No manifest fixup needed — panes commands removed
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
if (existsSync(manifestPath)) {
|
|
25
|
-
const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
26
|
-
const commands = parsed?.commands ?? {};
|
|
27
|
-
const hasSnapshot = Boolean(commands["panes:snapshot"]);
|
|
28
|
-
const hasBroker = Boolean(commands["panes:broker"]);
|
|
29
|
-
const hasPipeSink = Boolean(commands["panes:pipe-sink"]);
|
|
30
|
-
|
|
31
|
-
// If dist contains the command but manifest doesn't, regenerate.
|
|
32
|
-
const distHasBroker = existsSync(panesBrokerPath);
|
|
33
|
-
const distHasPipeSink = existsSync(panesPipeSinkPath);
|
|
34
|
-
|
|
35
|
-
if (hasSnapshot && (!distHasBroker || hasBroker) && (!distHasPipeSink || hasPipeSink)) return;
|
|
36
|
-
}
|
|
37
|
-
} catch {
|
|
38
|
-
// fall through -> regenerate
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const pjson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
43
|
-
const plugin = new Plugin({ root, pjson, isRoot: true, ignoreManifest: true });
|
|
44
|
-
await plugin.load();
|
|
45
|
-
writeFileSync(manifestPath, `${JSON.stringify(plugin.manifest, null, 2)}\n`);
|
|
46
|
-
} catch {
|
|
47
|
-
// Best-effort. If manifest regen fails, oclif will surface errors as usual.
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
await ensureManifestIsFresh();
|
|
52
|
-
|
|
53
|
-
// Default command: if no args (or only flags like --status/--setup), run "start"
|
|
15
|
+
// Default behavior: if no args, launch TUI (like `claude` launches Claude Code).
|
|
16
|
+
// If subcommand provided, dispatch to oclif.
|
|
54
17
|
const userArgs = process.argv.slice(2);
|
|
55
18
|
const firstArg = userArgs[0];
|
|
56
19
|
const isSubcommand = firstArg && !firstArg.startsWith("-");
|
|
57
20
|
|
|
58
|
-
if (!isSubcommand) {
|
|
59
|
-
// No
|
|
60
|
-
|
|
61
|
-
}
|
|
21
|
+
if (!isSubcommand && !firstArg) {
|
|
22
|
+
// No args at all — launch TUI
|
|
23
|
+
const { existsSync } = await import("node:fs");
|
|
24
|
+
const { join } = await import("node:path");
|
|
25
|
+
const { spawn } = await import("node:child_process");
|
|
26
|
+
|
|
27
|
+
// Look for TUI binary
|
|
28
|
+
const candidates = [
|
|
29
|
+
join(root, "..", "tui", "target", "release", "abbie-tui"),
|
|
30
|
+
join(root, "..", "..", "apps", "tui", "target", "release", "abbie-tui"),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// Also check if installed globally
|
|
34
|
+
const { spawnSync } = await import("node:child_process");
|
|
35
|
+
const whichResult = spawnSync("which", ["abbie-tui"], { encoding: "utf8" });
|
|
36
|
+
if (whichResult.status === 0 && whichResult.stdout.trim()) {
|
|
37
|
+
candidates.unshift(whichResult.stdout.trim());
|
|
38
|
+
}
|
|
62
39
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
});
|
|
40
|
+
const tuiBin = candidates.find((c) => existsSync(c));
|
|
41
|
+
|
|
42
|
+
if (tuiBin) {
|
|
43
|
+
const tui = spawn(tuiBin, userArgs, { stdio: "inherit" });
|
|
44
|
+
tui.on("exit", (code) => { process.exitCode = code ?? 0; });
|
|
45
|
+
} else {
|
|
46
|
+
// TUI not built — show help
|
|
47
|
+
console.log("Abbie TUI not found. Run: cd apps/tui && cargo build --release");
|
|
48
|
+
console.log("");
|
|
49
|
+
console.log("Available commands:");
|
|
50
|
+
process.argv.splice(2, 0, "--help");
|
|
51
|
+
await execute({ development: false, loadOptions: { root } });
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
// Has subcommand or flags — dispatch to oclif
|
|
55
|
+
await execute({
|
|
56
|
+
development: false,
|
|
57
|
+
loadOptions: { root },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -8,7 +8,6 @@ export default class ProjectAdd extends BaseCommand {
|
|
|
8
8
|
path: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
9
9
|
};
|
|
10
10
|
static flags: {
|
|
11
|
-
bootstrap: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
11
|
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
12
|
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
13
|
"json-errors": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { api, getHttpClient } from "@creativeintelligence/sdk/convex";
|
|
4
|
+
import { Args } from "@oclif/core";
|
|
4
5
|
import { findProjectPath } from "../../../lib/config-loader.js";
|
|
5
|
-
import { ensureManagedSession, hasProjectWindow } from "../../../lib/managed-session.js";
|
|
6
6
|
import { BaseCommand } from "../../base-command.js";
|
|
7
7
|
export default class ProjectAdd extends BaseCommand {
|
|
8
|
-
static description = "Add a project to
|
|
8
|
+
static description = "Add a project to Abbie";
|
|
9
9
|
static hidden = false;
|
|
10
10
|
static examples = [
|
|
11
11
|
"<%= config.bin %> project add arbor",
|
|
12
12
|
"<%= config.bin %> project add arbor ~/Developer/apps/arbor/arbor-xyz",
|
|
13
|
-
"<%= config.bin %> project add arbor --bootstrap",
|
|
14
13
|
];
|
|
15
14
|
static args = {
|
|
16
15
|
name: Args.string({ required: true, description: "Project name" }),
|
|
@@ -18,22 +17,11 @@ export default class ProjectAdd extends BaseCommand {
|
|
|
18
17
|
};
|
|
19
18
|
static flags = {
|
|
20
19
|
...BaseCommand.baseFlags,
|
|
21
|
-
bootstrap: Flags.boolean({
|
|
22
|
-
description: "Run bootstrap if .abbie/config.json is missing",
|
|
23
|
-
default: false,
|
|
24
|
-
}),
|
|
25
20
|
};
|
|
26
21
|
async execute() {
|
|
27
22
|
const { args, flags } = await this.parse(ProjectAdd);
|
|
28
23
|
this.parsedFlags = flags;
|
|
29
24
|
const name = args.name;
|
|
30
|
-
// Ensure the managed abbie tmux session exists
|
|
31
|
-
const session = await ensureManagedSession();
|
|
32
|
-
// Check if project window already exists
|
|
33
|
-
if (await hasProjectWindow(name)) {
|
|
34
|
-
this.error(`Project "${name}" already exists in the ${session} session`);
|
|
35
|
-
}
|
|
36
|
-
// Resolve project path
|
|
37
25
|
let projectPath = args.path;
|
|
38
26
|
if (!projectPath) {
|
|
39
27
|
projectPath = findProjectPath(name);
|
|
@@ -41,49 +29,25 @@ export default class ProjectAdd extends BaseCommand {
|
|
|
41
29
|
this.error(`Could not find project "${name}". Provide an explicit path: abbie project add ${name} /path/to/project`);
|
|
42
30
|
}
|
|
43
31
|
}
|
|
32
|
+
projectPath = resolve(projectPath);
|
|
44
33
|
if (!existsSync(projectPath)) {
|
|
45
34
|
this.error(`Path does not exist: ${projectPath}`);
|
|
46
35
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
});
|
|
36
|
+
try {
|
|
37
|
+
const client = getHttpClient();
|
|
38
|
+
await client.mutation(api.projects.create, {
|
|
39
|
+
name,
|
|
40
|
+
path: projectPath,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
this.logWarn(`Failed to sync to Convex: ${error.message}`);
|
|
45
|
+
}
|
|
58
46
|
const isJson = flags.json || flags.format === "json";
|
|
47
|
+
const result = { name, path: projectPath, status: "added" };
|
|
59
48
|
if (!isJson) {
|
|
60
49
|
this.log(`Added project: ${name}`);
|
|
61
50
|
this.log(`Path: ${projectPath}`);
|
|
62
|
-
this.log(`Session: ${session}`);
|
|
63
|
-
if (!hasConfig) {
|
|
64
|
-
this.log(`Note: No .abbie/config.json found. Run: abbie bootstrap --path ${projectPath}`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// Run bootstrap if requested and config missing
|
|
68
|
-
if (flags.bootstrap && !hasConfig) {
|
|
69
|
-
this.logInfo(`Bootstrapping .abbie for ${name}...`);
|
|
70
|
-
const { spawn } = await import("node:child_process");
|
|
71
|
-
await new Promise((resolve) => {
|
|
72
|
-
const proc = spawn("abbie", ["bootstrap", "--path", projectPath], {
|
|
73
|
-
stdio: "inherit",
|
|
74
|
-
});
|
|
75
|
-
proc.on("close", () => resolve());
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
const result = {
|
|
79
|
-
name,
|
|
80
|
-
path: projectPath,
|
|
81
|
-
session,
|
|
82
|
-
hasConfig,
|
|
83
|
-
status: "added",
|
|
84
|
-
};
|
|
85
|
-
if (isJson) {
|
|
86
|
-
return result;
|
|
87
51
|
}
|
|
88
52
|
return result;
|
|
89
53
|
}
|
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getManagedSessionName, listManagedWindows } from "../../../lib/managed-session.js";
|
|
1
|
+
import { api, getHttpClient } from "@creativeintelligence/sdk/convex";
|
|
3
2
|
import { BaseCommand } from "../../base-command.js";
|
|
4
|
-
const INTERNAL_WINDOW_NAMES = new Set(["_abbie"]);
|
|
5
|
-
const INTERNAL_SHELL_COMMANDS = new Set(["zsh", "bash", "fish", "sh"]);
|
|
6
|
-
function abbreviateHome(path) {
|
|
7
|
-
const home = process.env.HOME;
|
|
8
|
-
if (!home)
|
|
9
|
-
return path;
|
|
10
|
-
if (path === home)
|
|
11
|
-
return "~";
|
|
12
|
-
if (path.startsWith(`${home}/`))
|
|
13
|
-
return `~/${path.slice(home.length + 1)}`;
|
|
14
|
-
return path;
|
|
15
|
-
}
|
|
16
3
|
export default class ProjectList extends BaseCommand {
|
|
17
|
-
static description = "List projects
|
|
4
|
+
static description = "List projects";
|
|
18
5
|
static hidden = false;
|
|
19
6
|
static examples = [
|
|
20
7
|
"<%= config.bin %> project list",
|
|
21
|
-
"<%= config.bin %> project list --json
|
|
8
|
+
"<%= config.bin %> project list --json",
|
|
22
9
|
];
|
|
23
10
|
static flags = {
|
|
24
11
|
...BaseCommand.baseFlags,
|
|
@@ -26,88 +13,21 @@ export default class ProjectList extends BaseCommand {
|
|
|
26
13
|
async execute() {
|
|
27
14
|
const { flags } = await this.parse(ProjectList);
|
|
28
15
|
this.parsedFlags = flags;
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
// Enrich each window with project config metadata
|
|
32
|
-
const projects = [];
|
|
33
|
-
for (const win of windows) {
|
|
34
|
-
// Exclude internal/session bootstrap window from project list
|
|
35
|
-
if (INTERNAL_WINDOW_NAMES.has(win.name))
|
|
36
|
-
continue;
|
|
37
|
-
// Get pane cwd for config lookup
|
|
38
|
-
let path = "";
|
|
39
|
-
let currentCommand = "";
|
|
40
|
-
let hasConfig = false;
|
|
41
|
-
let emoji;
|
|
42
|
-
let team;
|
|
43
|
-
try {
|
|
44
|
-
const { listPanes } = await import("../../../lib/tmux/bridge.js");
|
|
45
|
-
const panes = await listPanes(win.index, session);
|
|
46
|
-
if (panes.length > 0) {
|
|
47
|
-
path = panes[0].currentPath;
|
|
48
|
-
currentCommand = panes[0].currentCommand;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
// Fall back to discovery
|
|
53
|
-
}
|
|
54
|
-
// Best-effort heuristic to hide legacy bootstrap windows created before `_abbie`
|
|
55
|
-
if (win.index === 0 &&
|
|
56
|
-
INTERNAL_SHELL_COMMANDS.has(currentCommand) &&
|
|
57
|
-
win.name === currentCommand) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
// Try to load config from pane path
|
|
61
|
-
if (path) {
|
|
62
|
-
try {
|
|
63
|
-
const loaded = loadConfigFromPath(path);
|
|
64
|
-
if (loaded) {
|
|
65
|
-
hasConfig = true;
|
|
66
|
-
emoji = loaded.config.emoji;
|
|
67
|
-
team = loaded.config.team;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
// No config — fine
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Fall back to project discovery
|
|
75
|
-
if (!hasConfig) {
|
|
76
|
-
const discovered = findProject(win.name);
|
|
77
|
-
if (discovered) {
|
|
78
|
-
if (!path)
|
|
79
|
-
path = discovered.path;
|
|
80
|
-
hasConfig = discovered.hasConfig;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
projects.push({
|
|
84
|
-
name: win.name,
|
|
85
|
-
path,
|
|
86
|
-
windowIndex: win.index,
|
|
87
|
-
hasConfig,
|
|
88
|
-
emoji,
|
|
89
|
-
team,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
16
|
+
const client = getHttpClient();
|
|
17
|
+
const projects = await client.query(api.projects.list, {});
|
|
92
18
|
const isJson = flags.json || flags.format === "json";
|
|
93
19
|
if (isJson) {
|
|
94
|
-
return
|
|
20
|
+
return projects;
|
|
95
21
|
}
|
|
96
22
|
if (projects.length === 0) {
|
|
97
|
-
this.log(
|
|
98
|
-
|
|
99
|
-
this.log("Add one with: abbie project add <name> [path]");
|
|
100
|
-
return { session, projects };
|
|
23
|
+
this.log("No projects found. Add one with: abbie project add <name>");
|
|
24
|
+
return [];
|
|
101
25
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const configMark = p.hasConfig ? "✓" : "-";
|
|
107
|
-
const teamLabel = p.team ? ` [${p.team}]` : "";
|
|
108
|
-
this.log(` ${icon} ${p.name}${teamLabel} ${abbreviateHome(p.path)} config:${configMark}`);
|
|
26
|
+
for (const project of projects) {
|
|
27
|
+
const emoji = project.emoji ?? "📁";
|
|
28
|
+
const path = project.path ?? "";
|
|
29
|
+
this.log(`${emoji} ${project.name}${path ? ` ${path}` : ""}`);
|
|
109
30
|
}
|
|
110
|
-
|
|
111
|
-
return { session, projects };
|
|
31
|
+
return projects;
|
|
112
32
|
}
|
|
113
33
|
}
|
|
@@ -2,12 +2,10 @@ import { BaseCommand } from "../../base-command.js";
|
|
|
2
2
|
export default class ProjectRemove extends BaseCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static hidden: boolean;
|
|
5
|
-
static examples: string[];
|
|
6
5
|
static args: {
|
|
7
6
|
name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
7
|
};
|
|
9
8
|
static flags: {
|
|
10
|
-
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
9
|
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
10
|
quiet: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
11
|
"json-errors": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -1,46 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { api, getHttpClient } from "@creativeintelligence/sdk/convex";
|
|
2
|
+
import { Args } from "@oclif/core";
|
|
3
3
|
import { BaseCommand } from "../../base-command.js";
|
|
4
4
|
export default class ProjectRemove extends BaseCommand {
|
|
5
|
-
static description = "Remove a project
|
|
5
|
+
static description = "Remove a project";
|
|
6
6
|
static hidden = false;
|
|
7
|
-
static examples = [
|
|
8
|
-
"<%= config.bin %> project remove arbor",
|
|
9
|
-
"<%= config.bin %> project remove arbor --force",
|
|
10
|
-
];
|
|
11
7
|
static args = {
|
|
12
8
|
name: Args.string({ required: true, description: "Project name" }),
|
|
13
9
|
};
|
|
14
10
|
static flags = {
|
|
15
11
|
...BaseCommand.baseFlags,
|
|
16
|
-
force: Flags.boolean({
|
|
17
|
-
char: "f",
|
|
18
|
-
description: "Skip confirmation",
|
|
19
|
-
default: false,
|
|
20
|
-
}),
|
|
21
12
|
};
|
|
22
13
|
async execute() {
|
|
23
14
|
const { args, flags } = await this.parse(ProjectRemove);
|
|
24
15
|
this.parsedFlags = flags;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.error(`Project "${name}" not found in the ${session} session`);
|
|
16
|
+
try {
|
|
17
|
+
const client = getHttpClient();
|
|
18
|
+
await client.mutation(api.projects.remove, { name: args.name });
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
this.error(`Failed to remove project: ${error.message}`);
|
|
32
22
|
}
|
|
33
|
-
// Kill the window
|
|
34
|
-
const { killWindow } = await import("../../../lib/tmux/bridge.js");
|
|
35
|
-
await killWindow(target.index, session);
|
|
36
23
|
const isJson = flags.json || flags.format === "json";
|
|
37
24
|
if (!isJson) {
|
|
38
|
-
this.log(`Removed project: ${name}`);
|
|
39
|
-
}
|
|
40
|
-
const result = { name, status: "removed" };
|
|
41
|
-
if (isJson) {
|
|
42
|
-
return result;
|
|
25
|
+
this.log(`Removed project: ${args.name}`);
|
|
43
26
|
}
|
|
44
|
-
return
|
|
27
|
+
return { name: args.name, status: "removed" };
|
|
45
28
|
}
|
|
46
29
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
1
|
import { getHttpClient, api } from "@creativeintelligence/sdk/convex";
|
|
3
2
|
import { Flags } from "@oclif/core";
|
|
4
3
|
import { getActiveSessionManager } from "../../../lib/active-sessions.js";
|
|
@@ -123,7 +122,7 @@ export default class SessionList extends BaseCommand {
|
|
|
123
122
|
catch { }
|
|
124
123
|
continue;
|
|
125
124
|
}
|
|
126
|
-
// Process
|
|
125
|
+
// Process liveness check
|
|
127
126
|
let dead = false;
|
|
128
127
|
if (session.pid > 0) {
|
|
129
128
|
try {
|
|
@@ -133,16 +132,8 @@ export default class SessionList extends BaseCommand {
|
|
|
133
132
|
dead = true;
|
|
134
133
|
}
|
|
135
134
|
}
|
|
136
|
-
else if (localSession
|
|
137
|
-
|
|
138
|
-
stdio: ["ignore", "ignore", "ignore"],
|
|
139
|
-
});
|
|
140
|
-
if (result.status !== 0) {
|
|
141
|
-
dead = true;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
else if (localSession && localSession.pid <= 0 && !localSession.pane_id) {
|
|
145
|
-
// No PID and no pane — cannot verify liveness
|
|
135
|
+
else if (localSession && localSession.pid <= 0) {
|
|
136
|
+
// No PID — cannot verify liveness
|
|
146
137
|
dead = true;
|
|
147
138
|
}
|
|
148
139
|
if (dead) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
3
|
import { join } from "node:path";
|
|
@@ -101,12 +100,7 @@ export default class SessionMarkDone extends BaseCommand {
|
|
|
101
100
|
catch {
|
|
102
101
|
// Store update is best-effort — local JSON is the source of truth
|
|
103
102
|
}
|
|
104
|
-
//
|
|
105
|
-
if (session.pane_id) {
|
|
106
|
-
spawnSync("tmux", ["kill-pane", "-t", session.pane_id], {
|
|
107
|
-
stdio: ["ignore", "ignore", "ignore"],
|
|
108
|
-
});
|
|
109
|
-
}
|
|
103
|
+
// Legacy tmux cleanup removed — sessions are headless now
|
|
110
104
|
const isJson = this.parsedFlags?.json || this.parsedFlags?.format === "json";
|
|
111
105
|
if (!isJson) {
|
|
112
106
|
this.log(`Session ${args.sessionId} marked as ${status} (exit code: ${args.exitCode})`);
|
|
@@ -20,7 +20,6 @@ export default class SessionStart extends BaseCommand {
|
|
|
20
20
|
"trace-id": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
21
|
await: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
22
|
headless: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
23
|
-
"tmux-session": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
23
|
"auto-context": import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
25
24
|
skills: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
25
|
format: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -8,7 +8,7 @@ import { loadConfigFromPath } from "../../../lib/config-loader.js";
|
|
|
8
8
|
import { validateOutputContract } from "../../../lib/contracts.js";
|
|
9
9
|
import { getDeviceId } from "../../../lib/device.js";
|
|
10
10
|
import { readSessionResult } from "../../../lib/session-result.js";
|
|
11
|
-
import { extractProjectFromPath } from "../../../lib/
|
|
11
|
+
import { extractProjectFromPath } from "../../../lib/project-path.js";
|
|
12
12
|
import { AGENTS } from "../../../lib/types.js";
|
|
13
13
|
import { BaseCommand } from "../../base-command.js";
|
|
14
14
|
function hasExplicitSkillRouting(goal, skills) {
|
|
@@ -235,11 +235,9 @@ export default class SessionStart extends BaseCommand {
|
|
|
235
235
|
default: false,
|
|
236
236
|
}),
|
|
237
237
|
headless: Flags.boolean({
|
|
238
|
-
description: "Run as headless subprocess (
|
|
239
|
-
default:
|
|
240
|
-
|
|
241
|
-
"tmux-session": Flags.string({
|
|
242
|
-
description: 'Tmux session name for terminal mode (default: "abbie"). Prevents hijacking your personal tmux.',
|
|
238
|
+
description: "Run as headless background subprocess (default).",
|
|
239
|
+
default: true,
|
|
240
|
+
allowNo: true,
|
|
243
241
|
}),
|
|
244
242
|
"auto-context": Flags.boolean({
|
|
245
243
|
description: "Inject recent file_activity from prior sessions as context (default: true)",
|
|
@@ -342,7 +340,7 @@ export default class SessionStart extends BaseCommand {
|
|
|
342
340
|
model: flags.model,
|
|
343
341
|
awaitCompletion: flags.await, // Use runner foreground mode for --await
|
|
344
342
|
headless: flags.headless,
|
|
345
|
-
tmuxSession:
|
|
343
|
+
tmuxSession: undefined,
|
|
346
344
|
autoContext: flags["auto-context"],
|
|
347
345
|
skills: flags.skills,
|
|
348
346
|
});
|
|
@@ -185,7 +185,6 @@ export declare class ActiveSessionManager {
|
|
|
185
185
|
* Kill processes running inside a tmux pane.
|
|
186
186
|
* Used only as a legacy fallback for pre-runner terminal sessions.
|
|
187
187
|
*/
|
|
188
|
-
private killPaneProcesses;
|
|
189
188
|
/**
|
|
190
189
|
* Get events for a session.
|
|
191
190
|
*/
|
|
@@ -194,11 +193,6 @@ export declare class ActiveSessionManager {
|
|
|
194
193
|
* Clean up completed/failed sessions older than N days.
|
|
195
194
|
*/
|
|
196
195
|
cleanup(daysOld?: number): number;
|
|
197
|
-
private shellEscape;
|
|
198
|
-
private buildRunnerLaunchScript;
|
|
199
|
-
/**
|
|
200
|
-
* Build prompt for agent.
|
|
201
|
-
*/
|
|
202
196
|
/**
|
|
203
197
|
* Build workspace awareness context from other active sessions in the same cwd.
|
|
204
198
|
*/
|
|
@@ -267,12 +261,6 @@ export declare class ActiveSessionManager {
|
|
|
267
261
|
* Check if a process is running.
|
|
268
262
|
*/
|
|
269
263
|
private isProcessRunning;
|
|
270
|
-
/**
|
|
271
|
-
* Check if a tmux pane is still alive.
|
|
272
|
-
* Uses list-panes which returns exit 1 for nonexistent targets
|
|
273
|
-
* (display-message returns 0 even for dead panes).
|
|
274
|
-
*/
|
|
275
|
-
private isTmuxPaneAlive;
|
|
276
264
|
}
|
|
277
265
|
export declare function getActiveSessionManager(): ActiveSessionManager;
|
|
278
266
|
//# sourceMappingURL=active-sessions.d.ts.map
|