codiedev 0.9.81 → 0.9.83
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/dist/cli.js +5 -33
- package/dist/launcher.d.ts +5 -0
- package/dist/launcher.js +28 -1
- package/dist/localScrub.js +8 -0
- package/dist/localScrubReport.js +5 -2
- package/dist/utils.js +0 -6
- package/package.json +1 -1
- package/dist/commands/createTicket.d.ts +0 -27
- package/dist/commands/createTicket.js +0 -192
package/dist/cli.js
CHANGED
|
@@ -57,7 +57,6 @@ const ask_1 = require("./commands/ask");
|
|
|
57
57
|
const ping_1 = require("./commands/ping");
|
|
58
58
|
const inbox_1 = require("./commands/inbox");
|
|
59
59
|
const note_1 = require("./commands/note");
|
|
60
|
-
const createTicket_1 = require("./commands/createTicket");
|
|
61
60
|
const doctor_1 = require("./commands/doctor");
|
|
62
61
|
const search_1 = require("./commands/search");
|
|
63
62
|
const library_1 = require("./commands/library");
|
|
@@ -105,14 +104,6 @@ Artifacts:
|
|
|
105
104
|
team's collective memory. Returns an
|
|
106
105
|
LLM-synthesized answer with citations
|
|
107
106
|
pointing at sessions + artifacts.
|
|
108
|
-
codiedev create-ticket [<prompt>] Forward-write a scoped ticket plan.
|
|
109
|
-
Claude investigates the codebase, asks
|
|
110
|
-
"single repo or multiple? where?", then
|
|
111
|
-
emits a plan with N+1 split. Lands in
|
|
112
|
-
/portal/research/<id>; push to Jira from there.
|
|
113
|
-
codiedev create-ticket --submit <path|->
|
|
114
|
-
Internal: Claude calls this itself with
|
|
115
|
-
a plan JSON to submit. Use - for stdin.
|
|
116
107
|
|
|
117
108
|
Messaging:
|
|
118
109
|
codiedev ping <user> "<msg>" [--with <key>]
|
|
@@ -352,25 +343,6 @@ codiedev note — capture a passing thought, linked to your session
|
|
|
352
343
|
unignore: IGNORE_HELP,
|
|
353
344
|
ignored: IGNORE_HELP,
|
|
354
345
|
capture: IGNORE_HELP,
|
|
355
|
-
"create-ticket": `
|
|
356
|
-
codiedev create-ticket — forward-write a scoped ticket plan
|
|
357
|
-
|
|
358
|
-
Default path:
|
|
359
|
-
codiedev create-ticket "I want to add SSO with Google"
|
|
360
|
-
|
|
361
|
-
Bare mode (no --submit) prints skill instructions for Claude to follow.
|
|
362
|
-
Claude asks where your repos live, investigates them locally, and emits a
|
|
363
|
-
plan as JSON. The CLI then re-invokes itself with --submit to upload it.
|
|
364
|
-
|
|
365
|
-
The plan lands at /portal/research/<id> as a ready-state research session.
|
|
366
|
-
Single ticket renders as one ticket; multi-ticket renders as a folder/group.
|
|
367
|
-
Push to Jira from the portal.
|
|
368
|
-
|
|
369
|
-
Examples:
|
|
370
|
-
codiedev create-ticket
|
|
371
|
-
codiedev create-ticket "I want to add Google SSO"
|
|
372
|
-
codiedev create-ticket --submit /tmp/plan.json # internal, called by Claude
|
|
373
|
-
`.trim(),
|
|
374
346
|
};
|
|
375
347
|
const DOCS = `
|
|
376
348
|
Codiedev — usage guide
|
|
@@ -483,8 +455,10 @@ Run 'codiedev help <command>' for each, or see the quick list:
|
|
|
483
455
|
// instructions written by older installs may still reference them.
|
|
484
456
|
const REMOVED_COMMANDS = {
|
|
485
457
|
promote: "Share an auto-saved spec with 'Promote to team' in the portal's My artifacts list.",
|
|
486
|
-
"reverse-ticket": "
|
|
487
|
-
reverseTicket: "
|
|
458
|
+
"reverse-ticket": "Ask your agent to file tickets with your team's own Jira or Linear tooling.",
|
|
459
|
+
reverseTicket: "Ask your agent to file tickets with your team's own Jira or Linear tooling.",
|
|
460
|
+
"create-ticket": "Ask your agent to file tickets with your team's own Jira or Linear tooling.",
|
|
461
|
+
createTicket: "Ask your agent to file tickets with your team's own Jira or Linear tooling.",
|
|
488
462
|
react: "React to feed posts in the portal.",
|
|
489
463
|
};
|
|
490
464
|
function removedCommand(command) {
|
|
@@ -623,11 +597,9 @@ async function main() {
|
|
|
623
597
|
case "reverse-ticket":
|
|
624
598
|
case "reverseTicket":
|
|
625
599
|
case "react":
|
|
626
|
-
removedCommand(command);
|
|
627
|
-
return;
|
|
628
600
|
case "create-ticket":
|
|
629
601
|
case "createTicket":
|
|
630
|
-
|
|
602
|
+
removedCommand(command);
|
|
631
603
|
return;
|
|
632
604
|
case "search":
|
|
633
605
|
await (0, search_1.runSearch)(rest);
|
package/dist/launcher.d.ts
CHANGED
|
@@ -8,9 +8,14 @@ export declare function launcherPath(): string;
|
|
|
8
8
|
/** True iff `cmd` invokes the stable launcher (from any state dir). */
|
|
9
9
|
export declare function usesLauncher(cmd: string | undefined): boolean;
|
|
10
10
|
export declare function readInstallRecord(): InstallRecord | null;
|
|
11
|
+
/** True if `p` is inside the OS temp folder (real paths, so /var vs /private/var on macOS match). */
|
|
12
|
+
export declare function isInTempDir(p: string, tmp?: string): boolean;
|
|
11
13
|
/**
|
|
12
14
|
* The hook script worth recording: absolute and present, and a global install over an npx cache
|
|
13
15
|
* copy (npm prunes ~/.npm/_npx, and hooks pointed there go quietly dead). Null = don't record.
|
|
16
|
+
* Never a build in the temp folder: test runs stage one there, delete it, and if that landed in
|
|
17
|
+
* the real install.json every hook went quietly dead. CODIEDEV_ALLOW_TEMP_HOOK=1 (the CLI's own
|
|
18
|
+
* test setup) lets sandboxed tests use one.
|
|
14
19
|
*/
|
|
15
20
|
export declare function stableHookScript(hookScript: string, globalCandidates?: string[]): string | null;
|
|
16
21
|
/** Point the launcher at `hookScript`. Atomic, so a hook mid-launch never reads half a file. */
|
package/dist/launcher.js
CHANGED
|
@@ -48,16 +48,18 @@ exports.LAUNCHER_FILE = void 0;
|
|
|
48
48
|
exports.launcherPath = launcherPath;
|
|
49
49
|
exports.usesLauncher = usesLauncher;
|
|
50
50
|
exports.readInstallRecord = readInstallRecord;
|
|
51
|
+
exports.isInTempDir = isInTempDir;
|
|
51
52
|
exports.stableHookScript = stableHookScript;
|
|
52
53
|
exports.recordCurrentInstall = recordCurrentInstall;
|
|
53
54
|
exports.ensureLauncher = ensureLauncher;
|
|
54
55
|
exports.resetLauncherCacheForTests = resetLauncherCacheForTests;
|
|
55
56
|
const fs = __importStar(require("fs"));
|
|
57
|
+
const os = __importStar(require("os"));
|
|
56
58
|
const path = __importStar(require("path"));
|
|
57
59
|
const configDir_1 = require("./configDir");
|
|
58
60
|
exports.LAUNCHER_FILE = "codiedev-hook-launcher.cjs";
|
|
59
61
|
// Bump when LAUNCHER_SOURCE changes so existing launchers get rewritten.
|
|
60
|
-
const LAUNCHER_REVISION =
|
|
62
|
+
const LAUNCHER_REVISION = 2;
|
|
61
63
|
function launcherPath() {
|
|
62
64
|
return path.join((0, configDir_1.codiedevStateDir)(), "bin", exports.LAUNCHER_FILE);
|
|
63
65
|
}
|
|
@@ -85,6 +87,12 @@ try {
|
|
|
85
87
|
if (rec && typeof rec.hookScript === "string" && fs.existsSync(rec.hookScript)) target = rec.hookScript;
|
|
86
88
|
} catch {}
|
|
87
89
|
if (!target && fs.existsSync(FALLBACK)) target = FALLBACK;
|
|
90
|
+
if (!target) {
|
|
91
|
+
// Both stranded (e.g. a deleted temp build): use a global install next to this node.
|
|
92
|
+
const prefix = path.dirname(path.dirname(process.execPath));
|
|
93
|
+
target = [path.join(prefix, "lib", "node_modules", "codiedev", "dist", "hook.js"),
|
|
94
|
+
path.join(prefix, "node_modules", "codiedev", "dist", "hook.js")].find((p) => fs.existsSync(p)) || null;
|
|
95
|
+
}
|
|
88
96
|
if (!target) process.exit(0);
|
|
89
97
|
process.env.CODIEDEV_VIA_LAUNCHER = "1";
|
|
90
98
|
process.argv[1] = target;
|
|
@@ -115,15 +123,34 @@ function packageVersionFor(hookScript) {
|
|
|
115
123
|
return undefined;
|
|
116
124
|
}
|
|
117
125
|
}
|
|
126
|
+
/** True if `p` is inside the OS temp folder (real paths, so /var vs /private/var on macOS match). */
|
|
127
|
+
function isInTempDir(p, tmp = os.tmpdir()) {
|
|
128
|
+
const real = (x) => {
|
|
129
|
+
try {
|
|
130
|
+
return fs.realpathSync(x);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return path.resolve(x);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const rel = path.relative(real(tmp), real(p));
|
|
137
|
+
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
138
|
+
}
|
|
118
139
|
/**
|
|
119
140
|
* The hook script worth recording: absolute and present, and a global install over an npx cache
|
|
120
141
|
* copy (npm prunes ~/.npm/_npx, and hooks pointed there go quietly dead). Null = don't record.
|
|
142
|
+
* Never a build in the temp folder: test runs stage one there, delete it, and if that landed in
|
|
143
|
+
* the real install.json every hook went quietly dead. CODIEDEV_ALLOW_TEMP_HOOK=1 (the CLI's own
|
|
144
|
+
* test setup) lets sandboxed tests use one.
|
|
121
145
|
*/
|
|
122
146
|
function stableHookScript(hookScript, globalCandidates = globalHookScripts()) {
|
|
123
147
|
if (!hookScript || !path.isAbsolute(hookScript) || hookScript.includes(`${path.sep}~${path.sep}`))
|
|
124
148
|
return null;
|
|
125
149
|
if (!fs.existsSync(hookScript))
|
|
126
150
|
return null;
|
|
151
|
+
if (process.env.CODIEDEV_ALLOW_TEMP_HOOK !== "1" && isInTempDir(hookScript)) {
|
|
152
|
+
return globalCandidates.find((p) => path.isAbsolute(p) && fs.existsSync(p) && !isInTempDir(p)) ?? null;
|
|
153
|
+
}
|
|
127
154
|
if (hookScript.includes(`${path.sep}_npx${path.sep}`)) {
|
|
128
155
|
const global = globalCandidates.find((p) => path.isAbsolute(p) && fs.existsSync(p));
|
|
129
156
|
if (global)
|
package/dist/localScrub.js
CHANGED
|
@@ -119,6 +119,14 @@ function sessionStores(env = process.env, home = os.homedir(), stateDir = (0, co
|
|
|
119
119
|
root: path.join((0, copilotHooks_1.copilotHome)(env, home), "session-state"),
|
|
120
120
|
match: (f) => path.basename(f) === "workspace.yaml",
|
|
121
121
|
},
|
|
122
|
+
// Copilot's rewind index keeps the prompt (userMessage) of every turn that
|
|
123
|
+
// edited files.
|
|
124
|
+
{
|
|
125
|
+
harness: "copilot",
|
|
126
|
+
kind: "json",
|
|
127
|
+
root: path.join((0, copilotHooks_1.copilotHome)(env, home), "session-state"),
|
|
128
|
+
match: (f) => path.basename(f) === "index.json" && path.basename(path.dirname(f)) === "rewind-file-snapshots",
|
|
129
|
+
},
|
|
122
130
|
{ harness: "pi", kind: "jsonl", root: path.join((0, harnessDirs_1.piAgentDir)(env, home), "sessions"), match: isJsonl },
|
|
123
131
|
{ harness: "pi", kind: "jsonl", root: path.join(stateDir, "managed", "pi", "agent", "sessions"), match: isJsonl },
|
|
124
132
|
{ harness: "opencode", kind: "json", root: path.join(stateDir, "opencode-captures"), match: (f) => f.endsWith(".json") },
|
package/dist/localScrubReport.js
CHANGED
|
@@ -195,8 +195,11 @@ function sessionKeyOf(harness, file) {
|
|
|
195
195
|
const base = path.basename(file);
|
|
196
196
|
if (base === "history.jsonl")
|
|
197
197
|
return "history";
|
|
198
|
-
if (harness === "copilot")
|
|
199
|
-
|
|
198
|
+
if (harness === "copilot") {
|
|
199
|
+
// session-state/<id>/… or session-state/<id>/rewind-file-snapshots/index.json
|
|
200
|
+
const dir = path.dirname(file);
|
|
201
|
+
return path.basename(path.basename(dir) === "rewind-file-snapshots" ? path.dirname(dir) : dir);
|
|
202
|
+
}
|
|
200
203
|
const uuid = base.match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i);
|
|
201
204
|
if (uuid)
|
|
202
205
|
return uuid[1];
|
package/dist/utils.js
CHANGED
|
@@ -1677,7 +1677,6 @@ thought, use the \`codiedev\` CLI via Bash:**
|
|
|
1677
1677
|
| "any messages?" / "check my inbox" / "what did a teammate say?" | \`codiedev inbox\` |
|
|
1678
1678
|
| "read that reply" / "mark that ping read" | \`codiedev read <ping-id>\` |
|
|
1679
1679
|
| "note that X is a follow-up" / "remember X" | \`codiedev note "<text>"\` |
|
|
1680
|
-
| "create a ticket" / "scope this into tickets" / "ticket this for me" | \`codiedev create-ticket [optional-inline-prompt]\` |
|
|
1681
1680
|
| "share with a teammate" / "give someone access" (no notification) | \`codiedev share <key> <name> [--role read\\|edit]\` |
|
|
1682
1681
|
| "send this to a teammate" / "ask someone to look at this" | \`codiedev send <key> <name> ["<msg>"]\` |
|
|
1683
1682
|
| "find something about X" / "has anyone solved Y?" | \`codiedev search "<query>" [--limit N]\` |
|
|
@@ -1726,11 +1725,6 @@ iterate rather than duplicating.
|
|
|
1726
1725
|
notification). \`codiedev send\` both grants access AND pings the
|
|
1727
1726
|
recipient. Use send when the user is actively looping someone in.
|
|
1728
1727
|
|
|
1729
|
-
**\`create-ticket\` flow:** when invoked without \`--submit\`, the CLI prints
|
|
1730
|
-
skill instructions you should follow. Step 1 is asking the user about repos.
|
|
1731
|
-
Step 4 calls \`codiedev create-ticket --submit <path>\` with the plan JSON.
|
|
1732
|
-
Tell the user the portal URL when the submit returns.
|
|
1733
|
-
|
|
1734
1728
|
**Errors:**
|
|
1735
1729
|
- "not connected" → user needs to run \`npx codiedev connect\` with their
|
|
1736
1730
|
API token from https://codiedev.com/portal/integrations/claude-code
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codiedev",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.83",
|
|
4
4
|
"description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
|
|
5
5
|
"bin": {
|
|
6
6
|
"codiedev": "dist/cli.js",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { CodiedevConfig } from "../utils";
|
|
2
|
-
export declare function substitutePrompt(protocol: string, prompt: string | undefined): string;
|
|
3
|
-
interface ConnectedRepo {
|
|
4
|
-
repoId: string;
|
|
5
|
-
fullName: string;
|
|
6
|
-
}
|
|
7
|
-
export declare function validatePlanHasRepo(parsedPlan: any): string | null;
|
|
8
|
-
export declare function resolveRepoIds(fullNames: string[], repos: ConnectedRepo[]): string[];
|
|
9
|
-
export interface CreateTicketArgs {
|
|
10
|
-
mode: "bare" | "submit";
|
|
11
|
-
prompt?: string;
|
|
12
|
-
submitSource?: "stdin" | string;
|
|
13
|
-
}
|
|
14
|
-
export declare function parseCreateTicketArgs(args: string[]): CreateTicketArgs;
|
|
15
|
-
export declare function runCreateTicket(args: string[]): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Bare-mode entrypoint. Fetches the protocol body from the backend so we can
|
|
18
|
-
* iterate on it without shipping a new CLI, substitutes the user's prompt,
|
|
19
|
-
* and writes the result to stdout for the agent to follow. Hard-errors on
|
|
20
|
-
* fetch failure rather than falling back to a stale local copy — the whole
|
|
21
|
-
* point of moving the protocol server-side is that the freshest version is
|
|
22
|
-
* the only version.
|
|
23
|
-
*/
|
|
24
|
-
export declare function runBare(config: CodiedevConfig, prompt: string | undefined): Promise<void>;
|
|
25
|
-
export declare function runSubmit(config: CodiedevConfig, rawJson: string): Promise<void>;
|
|
26
|
-
export declare function readSubmitInput(source: "stdin" | string): string;
|
|
27
|
-
export {};
|
|
@@ -1,192 +0,0 @@
|
|
|
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.substitutePrompt = substitutePrompt;
|
|
37
|
-
exports.validatePlanHasRepo = validatePlanHasRepo;
|
|
38
|
-
exports.resolveRepoIds = resolveRepoIds;
|
|
39
|
-
exports.parseCreateTicketArgs = parseCreateTicketArgs;
|
|
40
|
-
exports.runCreateTicket = runCreateTicket;
|
|
41
|
-
exports.runBare = runBare;
|
|
42
|
-
exports.runSubmit = runSubmit;
|
|
43
|
-
exports.readSubmitInput = readSubmitInput;
|
|
44
|
-
const fs = __importStar(require("node:fs"));
|
|
45
|
-
const shared_1 = require("./shared");
|
|
46
|
-
const PROMPT_PLACEHOLDER = "{{USER_PROMPT}}";
|
|
47
|
-
const MISSING_PROMPT_FALLBACK = "(not yet provided — ask the user a single combined question that covers both the intent AND repo locations: \"What are you working on, and is this in a single repo or multiple? If multiple, give me the paths.\" Skip Step 1 since you've folded it into this question. Then proceed to Step 2.)";
|
|
48
|
-
function substitutePrompt(protocol, prompt) {
|
|
49
|
-
return protocol.replace(PROMPT_PLACEHOLDER, prompt && prompt.length > 0 ? prompt : MISSING_PROMPT_FALLBACK);
|
|
50
|
-
}
|
|
51
|
-
function validatePlanHasRepo(parsedPlan) {
|
|
52
|
-
const fullNames = Array.isArray(parsedPlan?.repoFullNames) ? parsedPlan.repoFullNames : [];
|
|
53
|
-
const explicitIds = Array.isArray(parsedPlan?.repoIds) ? parsedPlan.repoIds : [];
|
|
54
|
-
if (fullNames.length === 0 && explicitIds.length === 0) {
|
|
55
|
-
return "Plan must include at least one repo (repoFullNames: ['owner/name'] or repoIds: [...])";
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
function resolveRepoIds(fullNames, repos) {
|
|
60
|
-
const lookup = new Map();
|
|
61
|
-
for (const r of repos) {
|
|
62
|
-
lookup.set(r.fullName.toLowerCase(), r.repoId);
|
|
63
|
-
}
|
|
64
|
-
const ids = [];
|
|
65
|
-
for (const fn of fullNames) {
|
|
66
|
-
const id = lookup.get(fn.toLowerCase());
|
|
67
|
-
if (!id) {
|
|
68
|
-
throw new Error(`Repo "${fn}" is not connected to your Codiedev account. Run \`codiedev connect\` to refresh, or push the missing repo through Settings.`);
|
|
69
|
-
}
|
|
70
|
-
ids.push(id);
|
|
71
|
-
}
|
|
72
|
-
return ids;
|
|
73
|
-
}
|
|
74
|
-
function parseCreateTicketArgs(args) {
|
|
75
|
-
let mode = "bare";
|
|
76
|
-
let prompt;
|
|
77
|
-
let submitSource;
|
|
78
|
-
for (let i = 0; i < args.length; i++) {
|
|
79
|
-
const a = args[i];
|
|
80
|
-
if (a === "--submit" && i + 1 < args.length) {
|
|
81
|
-
mode = "submit";
|
|
82
|
-
const next = args[++i];
|
|
83
|
-
submitSource = next === "-" ? "stdin" : next;
|
|
84
|
-
}
|
|
85
|
-
else if (a.startsWith("--submit=")) {
|
|
86
|
-
mode = "submit";
|
|
87
|
-
const v = a.slice("--submit=".length);
|
|
88
|
-
submitSource = v === "-" ? "stdin" : v;
|
|
89
|
-
}
|
|
90
|
-
else if (!a.startsWith("--") && !prompt && mode === "bare") {
|
|
91
|
-
prompt = a;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return { mode, prompt, submitSource };
|
|
95
|
-
}
|
|
96
|
-
async function runCreateTicket(args) {
|
|
97
|
-
const parsed = parseCreateTicketArgs(args);
|
|
98
|
-
if (parsed.mode === "bare") {
|
|
99
|
-
const config = (0, shared_1.requireConfig)();
|
|
100
|
-
await runBare(config, parsed.prompt);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
// submit mode
|
|
104
|
-
if (!parsed.submitSource) {
|
|
105
|
-
console.error("--submit requires a path or '-' for stdin");
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
const config = (0, shared_1.requireConfig)();
|
|
109
|
-
let raw;
|
|
110
|
-
try {
|
|
111
|
-
raw = readSubmitInput(parsed.submitSource);
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
console.error(`Failed to read plan: ${err.message}`);
|
|
115
|
-
process.exit(1);
|
|
116
|
-
}
|
|
117
|
-
// Translate fullNames → IDs before submitting
|
|
118
|
-
let parsedPlan;
|
|
119
|
-
try {
|
|
120
|
-
parsedPlan = JSON.parse(raw);
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
console.error(`Plan JSON did not parse: ${err.message}`);
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
|
-
const validationError = validatePlanHasRepo(parsedPlan);
|
|
127
|
-
if (validationError) {
|
|
128
|
-
console.error(validationError);
|
|
129
|
-
process.exit(1);
|
|
130
|
-
}
|
|
131
|
-
const fullNames = Array.isArray(parsedPlan.repoFullNames) ? parsedPlan.repoFullNames : [];
|
|
132
|
-
const explicitIds = Array.isArray(parsedPlan.repoIds) ? parsedPlan.repoIds : [];
|
|
133
|
-
if (fullNames.length > 0 && explicitIds.length === 0) {
|
|
134
|
-
parsedPlan.repoIds = resolveRepoIds(fullNames, config.repos);
|
|
135
|
-
}
|
|
136
|
-
for (const t of parsedPlan.plan?.tickets ?? []) {
|
|
137
|
-
if (t.targetRepoFullName && !t.targetRepoId) {
|
|
138
|
-
const ids = resolveRepoIds([t.targetRepoFullName], config.repos);
|
|
139
|
-
t.targetRepoId = ids[0];
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
await runSubmit(config, JSON.stringify(parsedPlan));
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Bare-mode entrypoint. Fetches the protocol body from the backend so we can
|
|
146
|
-
* iterate on it without shipping a new CLI, substitutes the user's prompt,
|
|
147
|
-
* and writes the result to stdout for the agent to follow. Hard-errors on
|
|
148
|
-
* fetch failure rather than falling back to a stale local copy — the whole
|
|
149
|
-
* point of moving the protocol server-side is that the freshest version is
|
|
150
|
-
* the only version.
|
|
151
|
-
*/
|
|
152
|
-
async function runBare(config, prompt) {
|
|
153
|
-
let res;
|
|
154
|
-
try {
|
|
155
|
-
res = await (0, shared_1.apiRequest)("GET", "/api/cli/createTicketProtocol", { config });
|
|
156
|
-
}
|
|
157
|
-
catch (err) {
|
|
158
|
-
console.error(`Failed to fetch create-ticket protocol: ${err.message}. Check your network connection and re-run.`);
|
|
159
|
-
process.exit(1);
|
|
160
|
-
}
|
|
161
|
-
process.stdout.write(substitutePrompt(res.protocol, prompt));
|
|
162
|
-
}
|
|
163
|
-
async function runSubmit(config, rawJson) {
|
|
164
|
-
let payload;
|
|
165
|
-
try {
|
|
166
|
-
payload = JSON.parse(rawJson);
|
|
167
|
-
}
|
|
168
|
-
catch (err) {
|
|
169
|
-
throw new Error(`Plan JSON did not parse — emit valid JSON matching the schema printed by \`codiedev create-ticket\`. Original error: ${err.message}`);
|
|
170
|
-
}
|
|
171
|
-
if (!payload.plan || !payload.prompt || !payload.repoIds) {
|
|
172
|
-
throw new Error("Plan JSON missing one of: plan, prompt, repoIds");
|
|
173
|
-
}
|
|
174
|
-
const res = await (0, shared_1.withTelemetry)(config, "codiedev_create_ticket", () => (0, shared_1.apiRequest)("POST", "/api/cli/createPlan", {
|
|
175
|
-
config,
|
|
176
|
-
body: payload,
|
|
177
|
-
}));
|
|
178
|
-
const portalHost = (process.env.CODIEDEV_PORTAL_URL || "https://codiedev.com").replace(/\/$/, "");
|
|
179
|
-
const portalLink = res.portalUrl.startsWith("http")
|
|
180
|
-
? res.portalUrl
|
|
181
|
-
: `${portalHost}${res.portalUrl}`;
|
|
182
|
-
console.log(`✓ Created ${res.ticketCount} ticket(s).`);
|
|
183
|
-
console.log(` portal: ${portalLink}`);
|
|
184
|
-
console.log("");
|
|
185
|
-
console.log("Open in your portal to review and push to Jira.");
|
|
186
|
-
}
|
|
187
|
-
function readSubmitInput(source) {
|
|
188
|
-
if (source === "stdin") {
|
|
189
|
-
return fs.readFileSync(0, "utf8");
|
|
190
|
-
}
|
|
191
|
-
return fs.readFileSync(source, "utf8");
|
|
192
|
-
}
|