@nonameolsson/nightjar 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/README.md +405 -2
- package/dist/account.d.ts +12 -0
- package/dist/account.js +57 -0
- package/dist/account.js.map +1 -0
- package/dist/adapter-module.d.ts +18 -0
- package/dist/adapter-module.js +83 -0
- package/dist/adapter-module.js.map +1 -0
- package/dist/adapters.d.ts +15 -0
- package/dist/adapters.js +160 -0
- package/dist/adapters.js.map +1 -0
- package/dist/args.d.ts +13 -0
- package/dist/args.js +84 -0
- package/dist/args.js.map +1 -0
- package/dist/ask.d.ts +6 -0
- package/dist/ask.js +27 -0
- package/dist/ask.js.map +1 -0
- package/dist/azure-devops/api.d.ts +34 -0
- package/dist/azure-devops/api.js +98 -0
- package/dist/azure-devops/api.js.map +1 -0
- package/dist/azure-devops/code-host.d.ts +36 -0
- package/dist/azure-devops/code-host.js +185 -0
- package/dist/azure-devops/code-host.js.map +1 -0
- package/dist/azure-devops/fake-azure-devops.d.ts +90 -0
- package/dist/azure-devops/fake-azure-devops.js +728 -0
- package/dist/azure-devops/fake-azure-devops.js.map +1 -0
- package/dist/azure-devops/index.d.ts +8 -0
- package/dist/azure-devops/index.js +11 -0
- package/dist/azure-devops/index.js.map +1 -0
- package/dist/azure-devops/sign-in.d.ts +11 -0
- package/dist/azure-devops/sign-in.js +68 -0
- package/dist/azure-devops/sign-in.js.map +1 -0
- package/dist/azure-devops/text.d.ts +1 -0
- package/dist/azure-devops/text.js +41 -0
- package/dist/azure-devops/text.js.map +1 -0
- package/dist/azure-devops/tracker.d.ts +44 -0
- package/dist/azure-devops/tracker.js +333 -0
- package/dist/azure-devops/tracker.js.map +1 -0
- package/dist/build.d.ts +75 -0
- package/dist/build.js +698 -0
- package/dist/build.js.map +1 -0
- package/dist/check.d.ts +8 -0
- package/dist/check.js +25 -0
- package/dist/check.js.map +1 -0
- package/dist/checks.d.ts +45 -0
- package/dist/checks.js +243 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/code-host.d.ts +19 -0
- package/dist/code-host.js +2 -0
- package/dist/code-host.js.map +1 -0
- package/dist/config.d.ts +86 -0
- package/dist/config.js +294 -0
- package/dist/config.js.map +1 -0
- package/dist/contract/case.d.ts +4 -0
- package/dist/contract/case.js +2 -0
- package/dist/contract/case.js.map +1 -0
- package/dist/contract/code-host.d.ts +24 -0
- package/dist/contract/code-host.js +108 -0
- package/dist/contract/code-host.js.map +1 -0
- package/dist/contract/command.d.ts +2 -0
- package/dist/contract/command.js +36 -0
- package/dist/contract/command.js.map +1 -0
- package/dist/contract/feature-writer.d.ts +3 -0
- package/dist/contract/feature-writer.js +101 -0
- package/dist/contract/feature-writer.js.map +1 -0
- package/dist/contract/run.d.ts +18 -0
- package/dist/contract/run.js +89 -0
- package/dist/contract/run.js.map +1 -0
- package/dist/contract/tracker.d.ts +30 -0
- package/dist/contract/tracker.js +250 -0
- package/dist/contract/tracker.js.map +1 -0
- package/dist/create.d.ts +9 -0
- package/dist/create.js +112 -0
- package/dist/create.js.map +1 -0
- package/dist/doctor.d.ts +4 -0
- package/dist/doctor.js +42 -0
- package/dist/doctor.js.map +1 -0
- package/dist/fakes/code-host.d.ts +21 -0
- package/dist/fakes/code-host.js +42 -0
- package/dist/fakes/code-host.js.map +1 -0
- package/dist/fakes/harness.d.ts +7 -0
- package/dist/fakes/harness.js +68 -0
- package/dist/fakes/harness.js.map +1 -0
- package/dist/fakes/machine.d.ts +11 -0
- package/dist/fakes/machine.js +101 -0
- package/dist/fakes/machine.js.map +1 -0
- package/dist/fakes/tracker.d.ts +40 -0
- package/dist/fakes/tracker.js +116 -0
- package/dist/fakes/tracker.js.map +1 -0
- package/dist/feature-file.d.ts +12 -0
- package/dist/feature-file.js +84 -0
- package/dist/feature-file.js.map +1 -0
- package/dist/git.d.ts +9 -0
- package/dist/git.js +12 -0
- package/dist/git.js.map +1 -0
- package/dist/github/api.d.ts +37 -0
- package/dist/github/api.js +66 -0
- package/dist/github/api.js.map +1 -0
- package/dist/github/code-host.d.ts +19 -0
- package/dist/github/code-host.js +105 -0
- package/dist/github/code-host.js.map +1 -0
- package/dist/github/fake-gh.d.ts +17 -0
- package/dist/github/fake-gh.js +51 -0
- package/dist/github/fake-gh.js.map +1 -0
- package/dist/github/fake-github.d.ts +58 -0
- package/dist/github/fake-github.js +285 -0
- package/dist/github/fake-github.js.map +1 -0
- package/dist/github/labels.d.ts +3 -0
- package/dist/github/labels.js +44 -0
- package/dist/github/labels.js.map +1 -0
- package/dist/github/tracker.d.ts +28 -0
- package/dist/github/tracker.js +208 -0
- package/dist/github/tracker.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +19 -0
- package/dist/init.js +225 -0
- package/dist/init.js.map +1 -0
- package/dist/ledger.d.ts +13 -0
- package/dist/ledger.js +49 -0
- package/dist/ledger.js.map +1 -0
- package/dist/main.d.ts +11 -0
- package/dist/main.js +215 -0
- package/dist/main.js.map +1 -0
- package/dist/person-config.d.ts +9 -0
- package/dist/person-config.js +46 -0
- package/dist/person-config.js.map +1 -0
- package/dist/plan.d.ts +9 -0
- package/dist/plan.js +27 -0
- package/dist/plan.js.map +1 -0
- package/dist/ports.d.ts +16 -0
- package/dist/ports.js +104 -0
- package/dist/ports.js.map +1 -0
- package/dist/prompt.d.ts +166 -0
- package/dist/prompt.js +217 -0
- package/dist/prompt.js.map +1 -0
- package/dist/queue.d.ts +20 -0
- package/dist/queue.js +94 -0
- package/dist/queue.js.map +1 -0
- package/dist/say.d.ts +2 -0
- package/dist/say.js +4 -0
- package/dist/say.js.map +1 -0
- package/dist/serve.d.ts +10 -0
- package/dist/serve.js +85 -0
- package/dist/serve.js.map +1 -0
- package/dist/session.d.ts +39 -0
- package/dist/session.js +144 -0
- package/dist/session.js.map +1 -0
- package/dist/settings.d.ts +10 -0
- package/dist/settings.js +92 -0
- package/dist/settings.js.map +1 -0
- package/dist/signals.d.ts +5 -0
- package/dist/signals.js +13 -0
- package/dist/signals.js.map +1 -0
- package/dist/skills.d.ts +4 -0
- package/dist/skills.js +51 -0
- package/dist/skills.js.map +1 -0
- package/dist/status-shape.d.ts +53 -0
- package/dist/status-shape.js +3 -0
- package/dist/status-shape.js.map +1 -0
- package/dist/status.d.ts +23 -0
- package/dist/status.js +56 -0
- package/dist/status.js.map +1 -0
- package/dist/tracker.d.ts +56 -0
- package/dist/tracker.js +12 -0
- package/dist/tracker.js.map +1 -0
- package/dist/workflow.d.ts +33 -0
- package/dist/workflow.js +53 -0
- package/dist/workflow.js.map +1 -0
- package/dist/worktree.d.ts +44 -0
- package/dist/worktree.js +193 -0
- package/dist/worktree.js.map +1 -0
- package/docs/ticket-contract.md +95 -0
- package/package.json +74 -5
- package/plugin/nightjar-status/.claude-plugin/plugin.json +5 -0
- package/plugin/nightjar-status/hooks/format.ts +48 -0
- package/plugin/nightjar-status/hooks/hooks.json +1 -0
- package/plugin/nightjar-status/hooks/register.ts +51 -0
- package/schema/factory.schema.json +437 -0
- package/skills/nightjar-feature/SKILL.md +73 -0
- package/src/status-shape.ts +44 -0
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Builds the Tracker and Code host factory.json names, paired so each Ticket reference is one the Code host can place.
|
|
2
|
+
import { codeHostFromModule, trackerFromModule } from './adapter-module.js';
|
|
3
|
+
import { AzureBoardsTracker, AzureReposCodeHost, azRunner, azureDevOpsSignIn, fetchRequest, openAzureDevOps } from './azure-devops/index.js';
|
|
4
|
+
import { CONFIG_FILE, ConfigError } from './config.js';
|
|
5
|
+
import { run } from './git.js';
|
|
6
|
+
import { GitHubApi, ghRunner, repoFromRemote } from './github/api.js';
|
|
7
|
+
import { GitHubCodeHost } from './github/code-host.js';
|
|
8
|
+
import { createSignalLabels } from './github/labels.js';
|
|
9
|
+
import { GitHubTracker } from './github/tracker.js';
|
|
10
|
+
import { canCreate, FEATURE_WRITER_METHODS } from './tracker.js';
|
|
11
|
+
const WRITER_LIST = `${FEATURE_WRITER_METHODS.slice(0, -1).join(', ')} and ${FEATURE_WRITER_METHODS.at(-1) ?? ''}`;
|
|
12
|
+
// The Tracker with its references rewritten for the Code host; every other call goes to it as it is.
|
|
13
|
+
function referencing(tracker, fit) {
|
|
14
|
+
return {
|
|
15
|
+
me: () => tracker.me(),
|
|
16
|
+
assignedFeatures: (person) => tracker.assignedFeatures(person),
|
|
17
|
+
feature: (id) => tracker.feature(id),
|
|
18
|
+
standing: (id) => tracker.standing(id),
|
|
19
|
+
tickets: (featureId) => tracker.tickets(featureId),
|
|
20
|
+
comments: (id) => tracker.comments(id),
|
|
21
|
+
addSignal: (id, signal) => tracker.addSignal(id, signal),
|
|
22
|
+
removeSignal: (id, signal) => tracker.removeSignal(id, signal),
|
|
23
|
+
comment: (id, body) => tracker.comment(id, body),
|
|
24
|
+
reference: (id) => fit(tracker.reference(id))
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const sameName = (a, b) => a.toLowerCase() === b.toLowerCase();
|
|
28
|
+
const TRACKERS = {
|
|
29
|
+
module: async (spec, m) => {
|
|
30
|
+
const tracker = await trackerFromModule(spec, m.context);
|
|
31
|
+
return {
|
|
32
|
+
tracker,
|
|
33
|
+
checked: (person) => `${spec.path} as ${person}`,
|
|
34
|
+
prepareSignals: () => Promise.resolve([
|
|
35
|
+
`${spec.path} shows Signals its own way: Nightjar creates nothing for it.`
|
|
36
|
+
]),
|
|
37
|
+
cannotCreate: canCreate(tracker)
|
|
38
|
+
? null
|
|
39
|
+
: `${CONFIG_FILE}: tracker: ${spec.path} makes no Features; its Tracker needs ${WRITER_LIST}`
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
'azure-devops': (spec, m) => {
|
|
43
|
+
const { organization, project } = spec;
|
|
44
|
+
const api = m.azureDevOps(organization);
|
|
45
|
+
const items = `https://dev.azure.com/${encodeURIComponent(organization)}/${encodeURIComponent(project)}/_workitems/edit/`;
|
|
46
|
+
return Promise.resolve({
|
|
47
|
+
tracker: new AzureBoardsTracker(api, spec, m.config.signals, m.config.trusted),
|
|
48
|
+
checked: (person) => `Azure DevOps as ${person} on ${organization}/${project}`,
|
|
49
|
+
prepareSignals: () => Promise.resolve([
|
|
50
|
+
'Azure DevOps shows Signals as tags, which appear on first use: there is nothing to create.'
|
|
51
|
+
]),
|
|
52
|
+
cannotCreate: spec.ticketType === undefined
|
|
53
|
+
? `${CONFIG_FILE}: tracker.ticketType: name the work item type each Ticket is made as, such as User Story`
|
|
54
|
+
: null,
|
|
55
|
+
organization,
|
|
56
|
+
page: (id) => `[work item ${id}](${items}${id})`
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
github: async (spec, m) => {
|
|
60
|
+
const named = spec.repo ?? (await m.fromOrigin('tracker.repo'));
|
|
61
|
+
return {
|
|
62
|
+
tracker: new GitHubTracker(named, m.gh, m.config.signals, m.config.trusted),
|
|
63
|
+
checked: (person) => `gh as ${person} on ${named}`,
|
|
64
|
+
prepareSignals: () => createSignalLabels(m.gh, named, m.config.signals),
|
|
65
|
+
cannotCreate: null,
|
|
66
|
+
page: (id) => `[issue ${id}](https://github.com/${named}/issues/${id})`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const CODE_HOSTS = {
|
|
71
|
+
module: async (spec, m) => ({
|
|
72
|
+
codeHost: await codeHostFromModule(spec, m.context),
|
|
73
|
+
repo: spec.path,
|
|
74
|
+
reachCodeHost: () => Promise.resolve(),
|
|
75
|
+
checkedTail: '',
|
|
76
|
+
fit: null
|
|
77
|
+
}),
|
|
78
|
+
github: async (spec, m) => {
|
|
79
|
+
const repo = spec.repo ?? (await m.fromOrigin('codeHost.repo'));
|
|
80
|
+
return {
|
|
81
|
+
codeHost: new GitHubCodeHost(repo, m.gh, (args, cwd) => run('git', args, cwd, m.env)),
|
|
82
|
+
repo,
|
|
83
|
+
// the branch is pushed and the pull request opened as the person gh is signed in as
|
|
84
|
+
reachCodeHost: async () => {
|
|
85
|
+
await new GitHubApi(repo, m.gh).call('read the signed-in user', ['user']);
|
|
86
|
+
},
|
|
87
|
+
checkedTail: '',
|
|
88
|
+
fit: null
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
'azure-devops': (spec, m, t) => {
|
|
92
|
+
const { organization, project, repo } = spec;
|
|
93
|
+
const linked = t.organization !== undefined && sameName(t.organization, organization);
|
|
94
|
+
const referencesAs = linked ? 'work items' : 'text';
|
|
95
|
+
const codeHost = new AzureReposCodeHost(m.azureDevOps(organization), { project, repo, referencesAs }, (args, cwd, extra) => run('git', args, cwd, { ...m.env, ...extra }));
|
|
96
|
+
// Azure Repos reads #N as a work item of its own organization, so any other Ticket is named by its page
|
|
97
|
+
const page = t.page;
|
|
98
|
+
const fit = linked
|
|
99
|
+
? (r) => ({ ...r, text: `#${r.id}` })
|
|
100
|
+
: page === undefined
|
|
101
|
+
? null
|
|
102
|
+
: (r) => ({ ...r, text: page(r.id) });
|
|
103
|
+
return Promise.resolve({
|
|
104
|
+
codeHost,
|
|
105
|
+
repo: `${organization}/${project}/${repo}`,
|
|
106
|
+
reachCodeHost: () => codeHost.check(),
|
|
107
|
+
checkedTail: `, Azure Repos ${organization}/${project}/${repo}`,
|
|
108
|
+
fit
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
// Calls the bundle maker of `spec`'s own kind; TypeScript cannot pair a union's member with its key.
|
|
113
|
+
const trackerFor = (spec, m) => TRACKERS[spec.type](spec, m);
|
|
114
|
+
const codeHostFor = (spec, m, t) => CODE_HOSTS[spec.type](spec, m, t);
|
|
115
|
+
// `request` answers every Azure DevOps call; a spec passes a fake Azure DevOps.
|
|
116
|
+
export async function makeAdapters(config, root, env, request = fetchRequest) {
|
|
117
|
+
let origin;
|
|
118
|
+
// one sign-in for every Azure DevOps Adapter, made when the first needs it
|
|
119
|
+
let signIn;
|
|
120
|
+
const machine = {
|
|
121
|
+
config,
|
|
122
|
+
env,
|
|
123
|
+
gh: ghRunner(root, env),
|
|
124
|
+
context: {
|
|
125
|
+
root,
|
|
126
|
+
signals: config.signals,
|
|
127
|
+
...(config.trusted === undefined ? {} : { trusted: config.trusted })
|
|
128
|
+
},
|
|
129
|
+
fromOrigin: async (field) => {
|
|
130
|
+
if (origin === undefined) {
|
|
131
|
+
const got = await run('git', ['remote', 'get-url', 'origin'], root, env);
|
|
132
|
+
origin = got.ok ? repoFromRemote(got.out) : null;
|
|
133
|
+
}
|
|
134
|
+
if (origin === null) {
|
|
135
|
+
throw new ConfigError(`origin is not a GitHub repo; set ${field} to owner/name in factory.json`);
|
|
136
|
+
}
|
|
137
|
+
return origin;
|
|
138
|
+
},
|
|
139
|
+
azureDevOps: (organization) => {
|
|
140
|
+
signIn ??= azureDevOpsSignIn(azRunner(root, env), env);
|
|
141
|
+
return openAzureDevOps(organization, root, env, signIn, request);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const t = await trackerFor(config.tracker, machine);
|
|
145
|
+
// taken before any wrapping for the Code host, which keeps only the Tracker's own methods
|
|
146
|
+
const writer = t.cannotCreate === null && canCreate(t.tracker)
|
|
147
|
+
? t.tracker
|
|
148
|
+
: (t.cannotCreate ?? `${CONFIG_FILE}: tracker: this Tracker makes no Features`);
|
|
149
|
+
const host = await codeHostFor(config.codeHost, machine, t);
|
|
150
|
+
return {
|
|
151
|
+
tracker: host.fit === null ? t.tracker : referencing(t.tracker, host.fit),
|
|
152
|
+
codeHost: host.codeHost,
|
|
153
|
+
repo: host.repo,
|
|
154
|
+
checked: (person) => `${t.checked(person)}${host.checkedTail}`,
|
|
155
|
+
reachCodeHost: host.reachCodeHost,
|
|
156
|
+
prepareSignals: t.prepareSignals,
|
|
157
|
+
writer
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
|
package/dist/args.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Env } from './git.js';
|
|
2
|
+
export declare const USAGE = "usage: nightjar <--watch | --once | FEATURE | doctor> [--use-api-key] [--profile NAME] [--model M] [--effort LEVEL]\n\n --watch build the Features assigned to you with the Go, oldest first, and look again every 2 minutes\n --once build the oldest Feature assigned to you with the Go, then exit\n FEATURE build that Feature, by its id (42, #42, PROJ-123), now\n doctor check this machine and list the Features it would build, building nothing (--dry-run is the old name)\n --use-api-key let the sessions bill ANTHROPIC_API_KEY instead of your Claude plan\n --profile NAME run the sessions as the Claude login in ~/.claude-NAME (a path is the folder itself, default is ~/.claude); over config.json's profile\n --model M the model of every session, over a Ticket's own line and factory.json\n --effort LEVEL the effort of every session, over a Ticket's own line and factory.json\n\n nightjar init ask for the Tracker and Code host, write factory.json, create the Signal labels, check the logins\n nightjar create [--dry-run] FILE make a Feature and its Tickets on the Tracker from a Feature file\n nightjar contract MODULE check a module's own Tracker or Code host against the contract suites";
|
|
3
|
+
export interface Args {
|
|
4
|
+
readonly mode: 'watch' | 'once' | 'feature' | 'doctor';
|
|
5
|
+
readonly feature?: string;
|
|
6
|
+
readonly useApiKey: boolean;
|
|
7
|
+
readonly profile?: string;
|
|
8
|
+
readonly model?: string;
|
|
9
|
+
readonly effort?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function parseArgs(argv: readonly string[]): Args | string;
|
|
12
|
+
export declare function apiKeyProblem(env: Env, useApiKey: boolean): string | null;
|
|
13
|
+
export declare function platformProblem(platform: NodeJS.Platform): string | null;
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export const USAGE = `usage: nightjar <--watch | --once | FEATURE | doctor> [--use-api-key] [--profile NAME] [--model M] [--effort LEVEL]
|
|
2
|
+
|
|
3
|
+
--watch build the Features assigned to you with the Go, oldest first, and look again every 2 minutes
|
|
4
|
+
--once build the oldest Feature assigned to you with the Go, then exit
|
|
5
|
+
FEATURE build that Feature, by its id (42, #42, PROJ-123), now
|
|
6
|
+
doctor check this machine and list the Features it would build, building nothing (--dry-run is the old name)
|
|
7
|
+
--use-api-key let the sessions bill ANTHROPIC_API_KEY instead of your Claude plan
|
|
8
|
+
--profile NAME run the sessions as the Claude login in ~/.claude-NAME (a path is the folder itself, default is ~/.claude); over config.json's profile
|
|
9
|
+
--model M the model of every session, over a Ticket's own line and factory.json
|
|
10
|
+
--effort LEVEL the effort of every session, over a Ticket's own line and factory.json
|
|
11
|
+
|
|
12
|
+
nightjar init ask for the Tracker and Code host, write factory.json, create the Signal labels, check the logins
|
|
13
|
+
nightjar create [--dry-run] FILE make a Feature and its Tickets on the Tracker from a Feature file
|
|
14
|
+
nightjar contract MODULE check a module's own Tracker or Code host against the contract suites`;
|
|
15
|
+
// The arguments, or the line that says what is wrong with them.
|
|
16
|
+
export function parseArgs(argv) {
|
|
17
|
+
const chosen = { mode: null };
|
|
18
|
+
let feature;
|
|
19
|
+
let useApiKey = false;
|
|
20
|
+
let profile;
|
|
21
|
+
let model;
|
|
22
|
+
let effort;
|
|
23
|
+
const pick = (m) => {
|
|
24
|
+
if (chosen.mode !== null && chosen.mode !== m)
|
|
25
|
+
return 'choose one of --watch, --once, a Feature and doctor';
|
|
26
|
+
chosen.mode = m;
|
|
27
|
+
return null;
|
|
28
|
+
};
|
|
29
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
30
|
+
const a = argv[i] ?? '';
|
|
31
|
+
let fault = null;
|
|
32
|
+
if (a === '--watch')
|
|
33
|
+
fault = pick('watch');
|
|
34
|
+
else if (a === '--once')
|
|
35
|
+
fault = pick('once');
|
|
36
|
+
else if (a === 'doctor' || a === '--dry-run')
|
|
37
|
+
fault = pick('doctor');
|
|
38
|
+
else if (a === '--use-api-key')
|
|
39
|
+
useApiKey = true;
|
|
40
|
+
else if (a === '--model' || a === '--effort' || a === '--profile') {
|
|
41
|
+
const value = argv[i + 1];
|
|
42
|
+
if (value === undefined || value.startsWith('--'))
|
|
43
|
+
return `${a} needs a value`;
|
|
44
|
+
if (a === '--model')
|
|
45
|
+
model = value;
|
|
46
|
+
else if (a === '--profile')
|
|
47
|
+
profile = value;
|
|
48
|
+
else
|
|
49
|
+
effort = value;
|
|
50
|
+
i += 1;
|
|
51
|
+
}
|
|
52
|
+
else if (/^#?[A-Za-z0-9][\w.-]*$/.test(a)) {
|
|
53
|
+
fault = pick('feature');
|
|
54
|
+
feature = a.replace(/^#/, '');
|
|
55
|
+
}
|
|
56
|
+
else
|
|
57
|
+
return `unknown argument ${a}`;
|
|
58
|
+
if (fault)
|
|
59
|
+
return fault;
|
|
60
|
+
}
|
|
61
|
+
const { mode } = chosen;
|
|
62
|
+
if (mode === null)
|
|
63
|
+
return 'say what to build';
|
|
64
|
+
return {
|
|
65
|
+
mode,
|
|
66
|
+
useApiKey,
|
|
67
|
+
...(feature === undefined ? {} : { feature }),
|
|
68
|
+
...(profile === undefined ? {} : { profile }),
|
|
69
|
+
...(model === undefined ? {} : { model }),
|
|
70
|
+
...(effort === undefined ? {} : { effort })
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function apiKeyProblem(env, useApiKey) {
|
|
74
|
+
if (useApiKey || !env.ANTHROPIC_API_KEY)
|
|
75
|
+
return null;
|
|
76
|
+
return 'ANTHROPIC_API_KEY is set, so every session would bill it per token instead of your Claude plan. Unset it, or pass --use-api-key if that is what you want.';
|
|
77
|
+
}
|
|
78
|
+
// WSL2 reports linux, so only a native Windows process is stopped.
|
|
79
|
+
export function platformProblem(platform) {
|
|
80
|
+
return platform === 'win32'
|
|
81
|
+
? 'native Windows is not supported; Nightjar runs on macOS, Linux and WSL2.'
|
|
82
|
+
: null;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=args.js.map
|
package/dist/args.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
|
package/dist/ask.d.ts
ADDED
package/dist/ask.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Questions put to a person on a terminal, or to a script that pipes its answers in, one per line.
|
|
2
|
+
import { createInterface } from 'node:readline';
|
|
3
|
+
export function askOnStdin() {
|
|
4
|
+
const tty = process.stdin.isTTY;
|
|
5
|
+
// on a terminal readline echoes what is typed; a pipe has no echo, so the answer is written out
|
|
6
|
+
const lines = createInterface({
|
|
7
|
+
input: process.stdin,
|
|
8
|
+
...(tty ? { output: process.stdout } : {}),
|
|
9
|
+
terminal: tty
|
|
10
|
+
});
|
|
11
|
+
const iterator = lines[Symbol.asyncIterator]();
|
|
12
|
+
return {
|
|
13
|
+
ask: async (question) => {
|
|
14
|
+
process.stdout.write(question);
|
|
15
|
+
const next = await iterator.next();
|
|
16
|
+
if (next.done) {
|
|
17
|
+
process.stdout.write('\n');
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (!tty)
|
|
21
|
+
process.stdout.write(`${next.value}\n`);
|
|
22
|
+
return next.value;
|
|
23
|
+
},
|
|
24
|
+
close: () => lines.close()
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=ask.js.map
|
package/dist/ask.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../src/ask.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAUhD,MAAM,UAAU,UAAU;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAChC,gGAAgG;IAChG,MAAM,KAAK,GAAG,eAAe,CAAC;QAC7B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1C,QAAQ,EAAE,GAAG;KACb,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC;IAC/C,OAAO;QACN,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;YACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC/B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3B,OAAO,IAAI,CAAC;YACb,CAAC;YACD,IAAI,CAAC,GAAG;gBAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAClD,OAAO,IAAI,CAAC,KAAK,CAAC;QACnB,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE;KAC1B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { AzureDevOpsSignIn } from './sign-in.js';
|
|
3
|
+
export declare class AzureDevOpsFailure extends Error {
|
|
4
|
+
readonly status?: number | undefined;
|
|
5
|
+
constructor(message: string, status?: number | undefined);
|
|
6
|
+
}
|
|
7
|
+
export interface AzureDevOpsCall {
|
|
8
|
+
readonly method: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
9
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
10
|
+
readonly body?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AzureDevOpsReply {
|
|
13
|
+
readonly status: number;
|
|
14
|
+
readonly text: string;
|
|
15
|
+
}
|
|
16
|
+
export type AzureDevOpsRequest = (url: string, call: AzureDevOpsCall) => Promise<AzureDevOpsReply>;
|
|
17
|
+
export declare const fetchRequest: AzureDevOpsRequest;
|
|
18
|
+
export interface Sending {
|
|
19
|
+
readonly method: AzureDevOpsCall['method'];
|
|
20
|
+
readonly url: string;
|
|
21
|
+
readonly body?: unknown;
|
|
22
|
+
readonly contentType?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class AzureDevOpsApi {
|
|
25
|
+
readonly organization: string;
|
|
26
|
+
readonly signIn: AzureDevOpsSignIn;
|
|
27
|
+
private readonly request;
|
|
28
|
+
constructor(organization: string, signIn: AzureDevOpsSignIn, request?: AzureDevOpsRequest);
|
|
29
|
+
at(path: string): string;
|
|
30
|
+
identities(path: string): string;
|
|
31
|
+
call(what: string, sending: Sending): Promise<unknown>;
|
|
32
|
+
parse<T>(what: string, sending: Sending, schema: z.ZodType<T>): Promise<T>;
|
|
33
|
+
private send;
|
|
34
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { why } from '../say.js';
|
|
2
|
+
// An Azure DevOps call Nightjar cannot do without; its message names the call and the reason.
|
|
3
|
+
export class AzureDevOpsFailure extends Error {
|
|
4
|
+
status;
|
|
5
|
+
constructor(message,
|
|
6
|
+
// the HTTP status Azure DevOps answered, when it answered one
|
|
7
|
+
status) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.status = status;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
const WAIT_MS = 60_000;
|
|
13
|
+
export const fetchRequest = async (url, call) => {
|
|
14
|
+
const reply = await fetch(url, { ...call, signal: AbortSignal.timeout(WAIT_MS) });
|
|
15
|
+
return { status: reply.status, text: await reply.text() };
|
|
16
|
+
};
|
|
17
|
+
// what Azure DevOps answers a call it refuses with, as far as a message goes
|
|
18
|
+
const said = (text) => {
|
|
19
|
+
try {
|
|
20
|
+
const value = JSON.parse(text);
|
|
21
|
+
if (typeof value?.message === 'string')
|
|
22
|
+
return value.message;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// not JSON: its first line says as much as anything
|
|
26
|
+
}
|
|
27
|
+
return text.trim().split('\n')[0] ?? '';
|
|
28
|
+
};
|
|
29
|
+
export class AzureDevOpsApi {
|
|
30
|
+
organization;
|
|
31
|
+
signIn;
|
|
32
|
+
request;
|
|
33
|
+
constructor(organization, signIn, request = fetchRequest) {
|
|
34
|
+
this.organization = organization;
|
|
35
|
+
this.signIn = signIn;
|
|
36
|
+
this.request = request;
|
|
37
|
+
}
|
|
38
|
+
// An address on the organization's own host: `path` comes after dev.azure.com/<organization>/.
|
|
39
|
+
at(path) {
|
|
40
|
+
return `https://dev.azure.com/${encodeURIComponent(this.organization)}/${path}`;
|
|
41
|
+
}
|
|
42
|
+
// An address on the organization's identity host, which answers who people are and their groups.
|
|
43
|
+
identities(path) {
|
|
44
|
+
return `https://vssps.dev.azure.com/${encodeURIComponent(this.organization)}/${path}`;
|
|
45
|
+
}
|
|
46
|
+
// The JSON Azure DevOps answers, or null for an empty answer.
|
|
47
|
+
async call(what, sending) {
|
|
48
|
+
let reply = await this.send(what, sending);
|
|
49
|
+
if (reply.status === 401) {
|
|
50
|
+
await this.signIn.refresh();
|
|
51
|
+
reply = await this.send(what, sending);
|
|
52
|
+
}
|
|
53
|
+
// 203 is the sign-in page Azure DevOps answers a token it does not take with
|
|
54
|
+
if (reply.status === 401 || reply.status === 403 || reply.status === 203) {
|
|
55
|
+
throw new AzureDevOpsFailure(`Azure DevOps refused ${await this.signIn.via()} when asked to ${what}: HTTP ${String(reply.status)}`, reply.status);
|
|
56
|
+
}
|
|
57
|
+
if (reply.status >= 400) {
|
|
58
|
+
const reason = said(reply.text);
|
|
59
|
+
throw new AzureDevOpsFailure(`Azure DevOps could not ${what}: HTTP ${String(reply.status)}${reason ? `: ${reason}` : ''}`, reply.status);
|
|
60
|
+
}
|
|
61
|
+
if (reply.text.trim() === '')
|
|
62
|
+
return null;
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(reply.text);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new AzureDevOpsFailure(`Azure DevOps answered no JSON when asked to ${what}.`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async parse(what, sending, schema) {
|
|
71
|
+
const parsed = schema.safeParse(await this.call(what, sending));
|
|
72
|
+
if (!parsed.success) {
|
|
73
|
+
throw new AzureDevOpsFailure(`Azure DevOps answered ${what} in a shape not known.`);
|
|
74
|
+
}
|
|
75
|
+
return parsed.data;
|
|
76
|
+
}
|
|
77
|
+
async send(what, sending) {
|
|
78
|
+
const headers = {
|
|
79
|
+
Authorization: await this.signIn.authorization(),
|
|
80
|
+
Accept: 'application/json'
|
|
81
|
+
};
|
|
82
|
+
if (sending.body !== undefined) {
|
|
83
|
+
headers['Content-Type'] = sending.contentType ?? 'application/json';
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
return await this.request(sending.url, {
|
|
87
|
+
method: sending.method,
|
|
88
|
+
headers,
|
|
89
|
+
...(sending.body === undefined ? {} : { body: JSON.stringify(sending.body) })
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (fault) {
|
|
93
|
+
const reason = why(fault);
|
|
94
|
+
throw new AzureDevOpsFailure(`Azure DevOps could not ${what}: ${reason}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/azure-devops/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { CodeHost, DraftRequest, Pull } from '../code-host.js';
|
|
2
|
+
import { type Env, type Run } from '../git.js';
|
|
3
|
+
import type { TicketReference } from '../tracker.js';
|
|
4
|
+
import { type AzureDevOpsApi } from './api.js';
|
|
5
|
+
export type AzureGitRunner = (args: readonly string[], cwd: string, extra: Env) => Promise<Run>;
|
|
6
|
+
export type ReferencesAs = 'work items' | 'text';
|
|
7
|
+
export interface AzureReposSettings {
|
|
8
|
+
readonly project: string;
|
|
9
|
+
readonly repo: string;
|
|
10
|
+
readonly referencesAs: ReferencesAs;
|
|
11
|
+
}
|
|
12
|
+
export declare const DESCRIPTION_LIMIT = 4000;
|
|
13
|
+
export declare const REFERENCES_MARK = "<!-- nightjar:references -->";
|
|
14
|
+
export declare class AzureReposCodeHost implements CodeHost {
|
|
15
|
+
private readonly api;
|
|
16
|
+
private readonly settings;
|
|
17
|
+
private readonly git;
|
|
18
|
+
private readonly project;
|
|
19
|
+
private readonly repo;
|
|
20
|
+
private readonly remote;
|
|
21
|
+
constructor(api: AzureDevOpsApi, settings: AzureReposSettings, git: AzureGitRunner, remote?: string);
|
|
22
|
+
private at;
|
|
23
|
+
private pullUrl;
|
|
24
|
+
private toPull;
|
|
25
|
+
check(): Promise<void>;
|
|
26
|
+
private signedIn;
|
|
27
|
+
push(folder: string, branch: string): Promise<void>;
|
|
28
|
+
openPull(branch: string): Promise<Pull | null>;
|
|
29
|
+
createDraft(request: DraftRequest): Promise<Pull>;
|
|
30
|
+
private read;
|
|
31
|
+
private setBody;
|
|
32
|
+
editBody(pull: Pull, body: string): Promise<void>;
|
|
33
|
+
placeReferences(pull: Pull, references: readonly TicketReference[]): Promise<void>;
|
|
34
|
+
private linkWorkItems;
|
|
35
|
+
comment(pull: Pull, body: string): Promise<void>;
|
|
36
|
+
}
|