@bluewombat/manager-kit 0.1.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/README.md +120 -0
- package/SPECS.md +130 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +126 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +2 -0
- package/dist/module.js.map +1 -0
- package/dist/options.d.ts +31 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +77 -0
- package/dist/options.js.map +1 -0
- package/dist/port.d.ts +191 -0
- package/dist/port.d.ts.map +1 -0
- package/dist/port.js +24 -0
- package/dist/port.js.map +1 -0
- package/dist/product.d.ts +9 -0
- package/dist/product.d.ts.map +1 -0
- package/dist/product.js +9 -0
- package/dist/product.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Manager kit
|
|
2
|
+
|
|
3
|
+
The FeatureManager plugin contract. Types only — no runtime, no dependency, no
|
|
4
|
+
Transformer. A package that wants mason to drive its tracker imports this and
|
|
5
|
+
nothing else. Contract: [SPECS.md](./SPECS.md).
|
|
6
|
+
|
|
7
|
+
## Stack
|
|
8
|
+
|
|
9
|
+
Repository stack — TypeScript, Node 24.20, Biome, `node:test`. See [docs/DEVELOPMENT.md](../../../docs/DEVELOPMENT.md).
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
From the repository root:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
nvm use
|
|
17
|
+
npm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Commands
|
|
21
|
+
|
|
22
|
+
| Task | Command |
|
|
23
|
+
| --------- | ---------------- |
|
|
24
|
+
| Lint | `npm run lint` |
|
|
25
|
+
| Format | `npm run format` |
|
|
26
|
+
| Typecheck | `npm run tsc` |
|
|
27
|
+
| Test | `npm test` |
|
|
28
|
+
| Build | `npm run build` |
|
|
29
|
+
|
|
30
|
+
## Write a manager
|
|
31
|
+
|
|
32
|
+
One export is required: `createManager`. Host calls it once at boot and drives
|
|
33
|
+
the `ManagerPort` it returns.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import {
|
|
37
|
+
type CreateManagerResult,
|
|
38
|
+
type ManagerContext,
|
|
39
|
+
rejectUnknownOptions,
|
|
40
|
+
stringOption,
|
|
41
|
+
} from "@bluewombat/manager-kit";
|
|
42
|
+
|
|
43
|
+
const KNOWN_OPTIONS = ["board", "tokenEnv"] as const;
|
|
44
|
+
|
|
45
|
+
export function createManager(context: ManagerContext): CreateManagerResult {
|
|
46
|
+
const known = rejectUnknownOptions(context.options, KNOWN_OPTIONS);
|
|
47
|
+
if (!known.ok) {
|
|
48
|
+
return known;
|
|
49
|
+
}
|
|
50
|
+
const board = stringOption(context.options, "board");
|
|
51
|
+
if (!board.ok) {
|
|
52
|
+
return board;
|
|
53
|
+
}
|
|
54
|
+
if (board.value === undefined) {
|
|
55
|
+
return { ok: false, reason: 'managerOptions "board" is required.' };
|
|
56
|
+
}
|
|
57
|
+
return { ok: true, manager: openMyTracker(board.value, context) };
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Then point a config at it:
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{ "manager": "@acme/manager-jira", "managerOptions": { "board": "APP" } }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`checkManager` is optional. Export it and `mason doctor` prints your findings
|
|
68
|
+
under the shared ones. It must not use the network.
|
|
69
|
+
|
|
70
|
+
`setupManager` is optional too, and is the one hook that may call the tracker
|
|
71
|
+
and write to it — `mason setup` plans, `mason setup --apply` performs. Keep it
|
|
72
|
+
idempotent.
|
|
73
|
+
|
|
74
|
+
`questionsManager` is optional as well. Return the questions `mason init`
|
|
75
|
+
should ask, and Host fills `managerOptions` from the answers:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
export function questionsManager(): ManagerQuestion[] {
|
|
79
|
+
return [
|
|
80
|
+
{
|
|
81
|
+
key: "board",
|
|
82
|
+
prompt: "Board key",
|
|
83
|
+
required: true,
|
|
84
|
+
parse: (answer) =>
|
|
85
|
+
/^[A-Z]+$/.test(answer)
|
|
86
|
+
? { ok: true, value: answer }
|
|
87
|
+
: { ok: false, reason: `"${answer}" is not a board key.` },
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Your package is offered by `mason init` when its `package.json` keywords
|
|
94
|
+
contain `mason-manager`.
|
|
95
|
+
|
|
96
|
+
`probe` is optional. Export it when the tracker can answer whether an intention
|
|
97
|
+
Host already holds is still there — a poll cannot see a deletion. `gone` is
|
|
98
|
+
abandon; `unavailable` is not.
|
|
99
|
+
|
|
100
|
+
`scaffoldManager` is optional. Export it and `mason init --manager this-package`
|
|
101
|
+
fills `managerOptions` from it. A tracker field (`repo`, a board id) belongs
|
|
102
|
+
there, not as a Host flag.
|
|
103
|
+
|
|
104
|
+
`referenceManager` is optional, and only for a manager whose Authority holds
|
|
105
|
+
the reference work line. It returns where that reference is, as a record Host
|
|
106
|
+
copies through unread; the Isolation strategy the Project names is what reads
|
|
107
|
+
it, strictly, so agree on the words with that package (`remote` and `branch`
|
|
108
|
+
for `@bluewombat/isolation-git`). With it, `mason init` asks nothing about the
|
|
109
|
+
work line and Host keeps its own copy at `<home>/work-line` (`.mason` by default).
|
|
110
|
+
|
|
111
|
+
## Layout
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
SPECS.md the contract a manager package implements
|
|
115
|
+
README.md how to build it, and how to write a manager
|
|
116
|
+
src/
|
|
117
|
+
port.ts ManagerPort and the values it exchanges
|
|
118
|
+
module.ts ManagerContext, ManagerModule, Finding
|
|
119
|
+
options.ts readers for one managerOptions object
|
|
120
|
+
```
|
package/SPECS.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Manager kit
|
|
2
|
+
|
|
3
|
+
A contract, not a Transformer. It holds no behaviour: it is the type boundary
|
|
4
|
+
between Host and one FeatureManager, so a third party can write a tracker
|
|
5
|
+
integration without depending on Host and without Host depending on them.
|
|
6
|
+
|
|
7
|
+
## 1. Job
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Host manager-kit a manager package
|
|
11
|
+
---- -------- -----------------
|
|
12
|
+
reads a specifier ManagerPort implements createManager
|
|
13
|
+
hands over managerOptions ManagerContext reads its own options
|
|
14
|
+
asks doctor for findings Finding may implement checkManager
|
|
15
|
+
asks init for a scaffold ManagerScaffold may implement scaffoldManager
|
|
16
|
+
asks init its questions ManagerQuestion may implement questionsManager
|
|
17
|
+
asks setup for a plan SetupStep may implement setupManager
|
|
18
|
+
asks where the reference is Record<string, unknown> may implement referenceManager
|
|
19
|
+
← nothing at runtime
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**In:** nothing. **Out:** types, and five pure option readers.
|
|
23
|
+
|
|
24
|
+
## 2. The Port
|
|
25
|
+
|
|
26
|
+
| Member | Required | Job |
|
|
27
|
+
| -------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
28
|
+
| `listen` | yes | Drain the tracker since a Cursor. Returns an outcome and ordered Deliveries |
|
|
29
|
+
| `adapt` | yes | One raw payload → a FeatureStandard, or `invalid` / `unavailable` / `interrupted` |
|
|
30
|
+
| `report` | yes | One semantic Event onto the tracker. `false` when it could not be written |
|
|
31
|
+
| `signalsReady` | no | Whether this payload says a human unblocked an escalated Feature (a label, a status) |
|
|
32
|
+
| `clearReady` | no | Take that signal back once it has been acted on. Left in place it resumes the Feature again on every pass, and an escalation freezes nothing |
|
|
33
|
+
| `submit` | no | Offer an assembled feature to the Authority. Returns an opaque reference |
|
|
34
|
+
| `fold` | no | Have the Authority take an accepted Submission into the work line |
|
|
35
|
+
| `probe` | no | Whether the intention this key named is still on the tracker (`present` / `gone` / `unavailable` / `interrupted`) |
|
|
36
|
+
|
|
37
|
+
The two Authority methods, `submit` and `fold`, come as a set. A manager that declares none has no
|
|
38
|
+
Authority, and an assembled feature is folded into WorkLineStable directly — the
|
|
39
|
+
way it was before any of this existed. `report` may carry an `eventId`: an Event
|
|
40
|
+
that states a fact rather than a change is written once, however many passes see
|
|
41
|
+
it.
|
|
42
|
+
|
|
43
|
+
`probe` exists because a poll cannot see an absence: a deleted item is missing
|
|
44
|
+
from every later page and never becomes a Delivery. Host already holds the keys.
|
|
45
|
+
`gone` is abandon, the same intent as a `cancel` delivery. `unavailable` is not
|
|
46
|
+
abandon — a missed read must not cancel work. Host only calls `probe` after a
|
|
47
|
+
listen that reached the source, so a token that can no longer list the tracker
|
|
48
|
+
is not read as every Feature disappearing. A manager that cannot answer omits
|
|
49
|
+
the method; Host does not invent an absence.
|
|
50
|
+
|
|
51
|
+
Host never reads a payload itself. A tracker's issue number, label, or status
|
|
52
|
+
is recoverable from the `key` the manager minted, so nothing tracker-shaped
|
|
53
|
+
crosses the Port.
|
|
54
|
+
|
|
55
|
+
## 3. The module
|
|
56
|
+
|
|
57
|
+
`createManager(context)` returns `{ ok: true, manager }` or `{ ok: false, reason }`.
|
|
58
|
+
It must not throw for a bad option: the reason is what the user reads.
|
|
59
|
+
|
|
60
|
+
| Context field | Content |
|
|
61
|
+
| --------------- | ------------------------------------------------------ |
|
|
62
|
+
| `options` | The config's `managerOptions`, unread by Host |
|
|
63
|
+
| `durationMs` | Wall clock every call of this manager must stay inside |
|
|
64
|
+
| `interruptFlag` | Flips on SIGINT / SIGTERM; long calls must stop |
|
|
65
|
+
| `configDir` | Directory a relative option path resolves against |
|
|
66
|
+
| `env` | Where a secret named by an option is read from |
|
|
67
|
+
|
|
68
|
+
A secret is read by the manager, from `context.env`, never by Host and never
|
|
69
|
+
from the config file.
|
|
70
|
+
|
|
71
|
+
`checkManager(context)` is optional and returns `Finding[]`. `ok`, `warn`,
|
|
72
|
+
`fail`; only `fail` makes `mason doctor` exit non-zero. It must answer the
|
|
73
|
+
same offline as online.
|
|
74
|
+
|
|
75
|
+
`questionsManager(context)` is optional and returns `ManagerQuestion[]`: the
|
|
76
|
+
wording, the fallback, and the validation of each `managerOptions` key a human
|
|
77
|
+
should be asked for. It declares them — Host reads the terminal, so no manager
|
|
78
|
+
ever touches stdin. A question whose key already has a value is skipped.
|
|
79
|
+
|
|
80
|
+
`referenceManager(context)` is optional and returns where the Authority keeps
|
|
81
|
+
the reference work line, or `undefined`. Host does not read it: the Isolation
|
|
82
|
+
strategy named by `workLine.isolation` does, strictly, and refuses a key it does
|
|
83
|
+
not know before a run writes anything. Only a manager that also declares
|
|
84
|
+
`submit` and `fold` has a reference to name — with no Authority the work line is
|
|
85
|
+
the operator's directory, whatever this returns. Offline.
|
|
86
|
+
|
|
87
|
+
`setupManager(context, { apply })` is optional and is the **only hook allowed
|
|
88
|
+
to reach the tracker over the network and to write to it**. The hooks form one
|
|
89
|
+
progression:
|
|
90
|
+
|
|
91
|
+
| Hook | Command | Network | Writes |
|
|
92
|
+
| ------------------ | ----------------------------- | ------- | ------------------------------------------------ |
|
|
93
|
+
| `questionsManager` | `mason init` | no | nothing — it only declares |
|
|
94
|
+
| `scaffoldManager` | `mason init` | no | the local config file |
|
|
95
|
+
| `referenceManager` | `mason init`, `doctor`, `run` | no | nothing — the strategy fetches the copy on `run` |
|
|
96
|
+
| `checkManager` | `mason doctor` | no | nothing |
|
|
97
|
+
| `setupManager` | `mason setup` | yes | the tracker, on `--apply` |
|
|
98
|
+
| `createManager` | `mason run` | yes | the tracker |
|
|
99
|
+
|
|
100
|
+
With `apply` false it reports a plan and changes nothing: a step is `satisfied`
|
|
101
|
+
or `missing`. With `apply` true a step it fixed is `applied`. A step nothing
|
|
102
|
+
here can fix is `blocked`, and `ok` is false. It must be idempotent — a second
|
|
103
|
+
call with `apply` true reports everything `satisfied` and writes nothing.
|
|
104
|
+
|
|
105
|
+
`scaffoldManager(context)` is optional and returns `{ options, nextSteps, prepare? }`.
|
|
106
|
+
`mason init` copies `options` into `managerOptions` (flag `--manager-option`
|
|
107
|
+
wins per key), prints `nextSteps`, and calls `prepare(cwd)` so a directory
|
|
108
|
+
Source can exist before the first run. Host does not grow a flag for a
|
|
109
|
+
tracker's fields.
|
|
110
|
+
|
|
111
|
+
## 4. Option readers
|
|
112
|
+
|
|
113
|
+
`stringOption`, `stringArrayOption`, `intOption`, `booleanOption`,
|
|
114
|
+
`rejectUnknownOptions`. Values arrive either from JSON (already typed) or from
|
|
115
|
+
repeated `--manager-option key=value` flags (always strings), so every reader
|
|
116
|
+
accepts the string spelling of its type, and a repeated flag key arrives as an
|
|
117
|
+
array.
|
|
118
|
+
|
|
119
|
+
`rejectUnknownOptions` exists because a silently ignored typo leaves a manager
|
|
120
|
+
running with a default the user thought they had changed.
|
|
121
|
+
|
|
122
|
+
## 5. Acceptance
|
|
123
|
+
|
|
124
|
+
1. A module exporting only `createManager` loads and drives a full run.
|
|
125
|
+
2. A reader given the string spelling of a number or a boolean returns the value.
|
|
126
|
+
3. A misspelled option key is refused, and the message lists the known keys.
|
|
127
|
+
4. `EVENT_NAMES` is the same list as the `EventName` union, at runtime.
|
|
128
|
+
5. `probe` is optional. `gone` is abandon; `unavailable` is not.
|
|
129
|
+
|
|
130
|
+
How to build and write a manager: [README.md](./README.md).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { CreateManagerResult, Finding, FindingLevel, ManagerContext, ManagerModule, ManagerQuestion, ManagerScaffold, SetupResult, SetupStep, } from "./module.js";
|
|
2
|
+
export type { OptionResult, Options, } from "./options.js";
|
|
3
|
+
export { booleanOption, intOption, rejectUnknownOptions, stringArrayOption, stringOption, } from "./options.js";
|
|
4
|
+
export type { AdaptResult, Delivery, EventFields, EventName, FeatureStandard, FoldResult, ListenResult, ManagerPort, ProbeResult, ReportInput, SubmissionRequest, SubmissionResult, } from "./port.js";
|
|
5
|
+
export { EVENT_NAMES } from "./port.js";
|
|
6
|
+
export { PRODUCT } from "./product.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mBAAmB,EACnB,OAAO,EACP,YAAY,EACZ,cAAc,EACd,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,EACX,SAAS,GACV,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,YAAY,EACZ,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,WAAW,EACX,QAAQ,EACR,WAAW,EACX,SAAS,EACT,eAAe,EACf,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,aAAa,EACb,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,GACb,MAAM,cAAc,CAAC;AAetB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { ManagerPort } from "./port.js";
|
|
2
|
+
/**
|
|
3
|
+
* What Host hands a manager package at boot. `options` is the config file's
|
|
4
|
+
* `managerOptions` object, unread: Host never validates a tracker's fields.
|
|
5
|
+
*/
|
|
6
|
+
export type ManagerContext = {
|
|
7
|
+
options: Record<string, unknown>;
|
|
8
|
+
/** Wall clock every call of this manager must stay inside. */
|
|
9
|
+
durationMs: number;
|
|
10
|
+
/** Flips on SIGINT / SIGTERM. Long calls must stop when it is true. */
|
|
11
|
+
interruptFlag: {
|
|
12
|
+
interrupted: boolean;
|
|
13
|
+
};
|
|
14
|
+
/** Directory a relative option path resolves against (the config file's). */
|
|
15
|
+
configDir: string;
|
|
16
|
+
/** Where a secret named by an option is read from. Never logged by Host. */
|
|
17
|
+
env: Record<string, string | undefined>;
|
|
18
|
+
};
|
|
19
|
+
export type CreateManagerResult = {
|
|
20
|
+
ok: true;
|
|
21
|
+
manager: ManagerPort;
|
|
22
|
+
} | {
|
|
23
|
+
ok: false;
|
|
24
|
+
reason: string;
|
|
25
|
+
};
|
|
26
|
+
export type FindingLevel = "ok" | "warn" | "fail";
|
|
27
|
+
/** One line of `mason doctor`. `fail` is what makes the command exit non-zero. */
|
|
28
|
+
export type Finding = {
|
|
29
|
+
level: FindingLevel;
|
|
30
|
+
label: string;
|
|
31
|
+
detail?: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* What `mason init` asks a manager for. Host writes the config and the slot
|
|
35
|
+
* stubs; the manager fills `managerOptions` and any directories it needs.
|
|
36
|
+
* Nothing here is tracker-shaped: a GitHub repo or a Linear team lives in
|
|
37
|
+
* `options`, in words the manager chose.
|
|
38
|
+
*/
|
|
39
|
+
export type ManagerScaffold = {
|
|
40
|
+
options: Record<string, unknown>;
|
|
41
|
+
nextSteps: string[];
|
|
42
|
+
prepare?(cwd: string): void;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* One thing `mason init` asks a human, to fill one `managerOptions` key.
|
|
46
|
+
*
|
|
47
|
+
* The manager owns the wording and the validation — "owner/name" is GitHub's
|
|
48
|
+
* vocabulary, not Host's. Host owns the terminal: it reads the line, and hands
|
|
49
|
+
* it back here to be turned into a value.
|
|
50
|
+
*/
|
|
51
|
+
export type ManagerQuestion = {
|
|
52
|
+
/** The `managerOptions` key the answer fills. */
|
|
53
|
+
key: string;
|
|
54
|
+
/** One line, no trailing colon: `GitHub repository (owner/name)`. */
|
|
55
|
+
prompt: string;
|
|
56
|
+
/** Offered on the line, and used when the answer is empty. */
|
|
57
|
+
fallback?: string;
|
|
58
|
+
/** An empty answer with no fallback is refused, and the question repeats. */
|
|
59
|
+
required?: boolean;
|
|
60
|
+
/** Turns the typed line into the option value, or says what is wrong with it. */
|
|
61
|
+
parse?(answer: string): {
|
|
62
|
+
ok: true;
|
|
63
|
+
value: unknown;
|
|
64
|
+
} | {
|
|
65
|
+
ok: false;
|
|
66
|
+
reason: string;
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* One thing the tracker needs before a run — a label that must exist, a
|
|
71
|
+
* permission the token must hold.
|
|
72
|
+
*
|
|
73
|
+
* `satisfied` it already was; `missing` it is not there yet and `apply` was
|
|
74
|
+
* false; `applied` this call created it; `blocked` nothing here can fix it.
|
|
75
|
+
*/
|
|
76
|
+
export type SetupStep = {
|
|
77
|
+
/** Stable across runs, so two reports can be compared: `label:mason`. */
|
|
78
|
+
id: string;
|
|
79
|
+
summary: string;
|
|
80
|
+
state: "satisfied" | "missing" | "applied" | "blocked";
|
|
81
|
+
detail?: string;
|
|
82
|
+
};
|
|
83
|
+
export type SetupResult = {
|
|
84
|
+
/** False when a step is `blocked`. A `missing` step in a plan is not a failure. */
|
|
85
|
+
ok: boolean;
|
|
86
|
+
steps: SetupStep[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The module shape `manager` in the config resolves to. A package that exports
|
|
90
|
+
* `createManager` is a manager; nothing else is required of it.
|
|
91
|
+
*/
|
|
92
|
+
export type ManagerModule = {
|
|
93
|
+
createManager(context: ManagerContext): CreateManagerResult | Promise<CreateManagerResult>;
|
|
94
|
+
/** Optional. What `mason doctor` reports for this manager. Must not use the network. */
|
|
95
|
+
checkManager?(context: ManagerContext): Finding[] | Promise<Finding[]>;
|
|
96
|
+
/** Optional. What `mason init` writes into `managerOptions`. */
|
|
97
|
+
scaffoldManager?(context: ManagerContext): ManagerScaffold | Promise<ManagerScaffold>;
|
|
98
|
+
/**
|
|
99
|
+
* Optional. What `mason init` asks when it runs interactively, in order.
|
|
100
|
+
* Declaring the questions rather than asking them keeps every read of the
|
|
101
|
+
* terminal in Host, and every word about the tracker here.
|
|
102
|
+
*/
|
|
103
|
+
questionsManager?(context: ManagerContext): ManagerQuestion[] | Promise<ManagerQuestion[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Optional. What `mason setup` does. The only hook allowed to reach the
|
|
106
|
+
* tracker over the network and to write to it.
|
|
107
|
+
*
|
|
108
|
+
* With `apply` false it reports a plan and changes nothing — that is the
|
|
109
|
+
* default, because creating labels on somebody's repository is not a side
|
|
110
|
+
* effect to have by accident. It must be idempotent: a second call with
|
|
111
|
+
* `apply` true reports every step `satisfied` and writes nothing.
|
|
112
|
+
*/
|
|
113
|
+
setupManager?(context: ManagerContext, input: {
|
|
114
|
+
apply: boolean;
|
|
115
|
+
}): SetupResult | Promise<SetupResult>;
|
|
116
|
+
/**
|
|
117
|
+
* Optional. Where the Authority keeps the reference work line.
|
|
118
|
+
*
|
|
119
|
+
* Opaque here, like `options`: the words are the Isolation strategy's, and
|
|
120
|
+
* Host copies them through unread. Declaring it lets Host keep its own copy
|
|
121
|
+
* of the work line under the ledger's roof instead of asking the operator to
|
|
122
|
+
* maintain one. A manager with no Authority has no reference to name.
|
|
123
|
+
*/
|
|
124
|
+
referenceManager?(context: ManagerContext): Record<string, unknown> | undefined;
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"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"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Readers for one `managerOptions` object.
|
|
3
|
+
*
|
|
4
|
+
* Values reach a manager either from JSON (already typed) or from repeated
|
|
5
|
+
* `--manager-option key=value` flags (always strings), so a reader that wants a
|
|
6
|
+
* number or a boolean accepts the string spelling of one.
|
|
7
|
+
*/
|
|
8
|
+
export type OptionResult<T> = {
|
|
9
|
+
ok: true;
|
|
10
|
+
value: T | undefined;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
reason: string;
|
|
14
|
+
};
|
|
15
|
+
export type Options = Record<string, unknown>;
|
|
16
|
+
export declare function stringOption(options: Options, key: string): OptionResult<string>;
|
|
17
|
+
/** A JSON array of strings, or one string from a single `--manager-option`. */
|
|
18
|
+
export declare function stringArrayOption(options: Options, key: string): OptionResult<string[]>;
|
|
19
|
+
export declare function intOption(options: Options, key: string, min: number, max: number): OptionResult<number>;
|
|
20
|
+
export declare function booleanOption(options: Options, key: string): OptionResult<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* A misspelled option is silently ignored otherwise, and the manager then runs
|
|
23
|
+
* with a default the user thought they had changed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function rejectUnknownOptions(options: Options, known: readonly string[]): {
|
|
26
|
+
ok: true;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
reason: string;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,SAAS,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjG,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAShF;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAcvF;AAED,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,YAAY,CAAC,MAAM,CAAC,CAatB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAYlF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAW9C"}
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Readers for one `managerOptions` object.
|
|
3
|
+
*
|
|
4
|
+
* Values reach a manager either from JSON (already typed) or from repeated
|
|
5
|
+
* `--manager-option key=value` flags (always strings), so a reader that wants a
|
|
6
|
+
* number or a boolean accepts the string spelling of one.
|
|
7
|
+
*/
|
|
8
|
+
export function stringOption(options, key) {
|
|
9
|
+
const value = options[key];
|
|
10
|
+
if (value === undefined) {
|
|
11
|
+
return { ok: true, value: undefined };
|
|
12
|
+
}
|
|
13
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
14
|
+
return { ok: false, reason: `managerOptions "${key}" must be a non-empty string.` };
|
|
15
|
+
}
|
|
16
|
+
return { ok: true, value };
|
|
17
|
+
}
|
|
18
|
+
/** A JSON array of strings, or one string from a single `--manager-option`. */
|
|
19
|
+
export function stringArrayOption(options, key) {
|
|
20
|
+
const value = options[key];
|
|
21
|
+
if (value === undefined) {
|
|
22
|
+
return { ok: true, value: undefined };
|
|
23
|
+
}
|
|
24
|
+
if (typeof value === "string") {
|
|
25
|
+
return value.trim().length === 0
|
|
26
|
+
? { ok: false, reason: `managerOptions "${key}" must not be empty.` }
|
|
27
|
+
: { ok: true, value: [value] };
|
|
28
|
+
}
|
|
29
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
30
|
+
return { ok: false, reason: `managerOptions "${key}" must be an array of strings.` };
|
|
31
|
+
}
|
|
32
|
+
return { ok: true, value: value };
|
|
33
|
+
}
|
|
34
|
+
export function intOption(options, key, min, max) {
|
|
35
|
+
const value = options[key];
|
|
36
|
+
if (value === undefined) {
|
|
37
|
+
return { ok: true, value: undefined };
|
|
38
|
+
}
|
|
39
|
+
const parsed = typeof value === "string" && /^-?\d+$/.test(value.trim()) ? Number(value) : value;
|
|
40
|
+
if (typeof parsed !== "number" || !Number.isSafeInteger(parsed) || parsed < min || parsed > max) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
reason: `managerOptions "${key}" must be an integer between ${min} and ${max}.`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return { ok: true, value: parsed };
|
|
47
|
+
}
|
|
48
|
+
export function booleanOption(options, key) {
|
|
49
|
+
const value = options[key];
|
|
50
|
+
if (value === undefined) {
|
|
51
|
+
return { ok: true, value: undefined };
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "boolean") {
|
|
54
|
+
return { ok: true, value };
|
|
55
|
+
}
|
|
56
|
+
if (value === "true" || value === "false") {
|
|
57
|
+
return { ok: true, value: value === "true" };
|
|
58
|
+
}
|
|
59
|
+
return { ok: false, reason: `managerOptions "${key}" must be true or false.` };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A misspelled option is silently ignored otherwise, and the manager then runs
|
|
63
|
+
* with a default the user thought they had changed.
|
|
64
|
+
*/
|
|
65
|
+
export function rejectUnknownOptions(options, known) {
|
|
66
|
+
const allowed = new Set(known);
|
|
67
|
+
for (const key of Object.keys(options)) {
|
|
68
|
+
if (!allowed.has(key)) {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
reason: `managerOptions has unknown key "${key}". Known: ${[...allowed].sort().join(", ")}.`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { ok: true };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"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"}
|
package/dist/port.d.ts
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What Host asks of one FeatureManager, whatever the tracker behind it.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here names GitHub, an issue, or a label: a manager package owns its
|
|
5
|
+
* tracker's vocabulary and hands Host these shapes only.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Every semantic Event, as values. A manager that mirrors states onto the
|
|
9
|
+
* tracker needs the list at runtime, not only as a type.
|
|
10
|
+
*/
|
|
11
|
+
export declare const EVENT_NAMES: readonly ["invalid", "accepted", "planned", "progress", "escalated", "escalation_reminder", "resumed", "submitted", "done", "cancelled", "reject_late"];
|
|
12
|
+
export type EventName = (typeof EVENT_NAMES)[number];
|
|
13
|
+
export type EventFields = {
|
|
14
|
+
/** One sentence a reader gets first, under the heading and before any field. */
|
|
15
|
+
summary?: string;
|
|
16
|
+
reason?: string;
|
|
17
|
+
stage?: "plan" | "unit" | "integrating" | "submitting" | "merging";
|
|
18
|
+
trace?: string;
|
|
19
|
+
counters?: Record<string, string>;
|
|
20
|
+
plan?: string;
|
|
21
|
+
priority?: number;
|
|
22
|
+
unit?: string;
|
|
23
|
+
remaining?: number;
|
|
24
|
+
state?: string;
|
|
25
|
+
resume_point?: "planning" | "running" | "integrating";
|
|
26
|
+
reference?: string;
|
|
27
|
+
/** On `done`: the work line's own name for the fold, when the Authority gave one. Opaque. */
|
|
28
|
+
integration_reference?: string;
|
|
29
|
+
workspace_ref?: string;
|
|
30
|
+
};
|
|
31
|
+
export type FeatureStandard = {
|
|
32
|
+
key: string;
|
|
33
|
+
manager: string;
|
|
34
|
+
external_id: string;
|
|
35
|
+
intent: "upsert" | "ready" | "cancel";
|
|
36
|
+
project: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
intention?: string;
|
|
39
|
+
priority: number;
|
|
40
|
+
source?: {
|
|
41
|
+
ref?: string;
|
|
42
|
+
revision?: string;
|
|
43
|
+
};
|
|
44
|
+
fingerprint: string;
|
|
45
|
+
normalized_at: string;
|
|
46
|
+
};
|
|
47
|
+
/** One raw intention, plus the Cursor Host saves once it is handled. */
|
|
48
|
+
export type Delivery = {
|
|
49
|
+
cursor: string;
|
|
50
|
+
payload: Record<string, unknown>;
|
|
51
|
+
};
|
|
52
|
+
export type AdaptResult = {
|
|
53
|
+
outcome: "converted";
|
|
54
|
+
feature: FeatureStandard;
|
|
55
|
+
} | {
|
|
56
|
+
outcome: "invalid";
|
|
57
|
+
invalid: {
|
|
58
|
+
code: string;
|
|
59
|
+
reason: string;
|
|
60
|
+
};
|
|
61
|
+
key: string;
|
|
62
|
+
project: string;
|
|
63
|
+
/**
|
|
64
|
+
* Hash of what a human wrote — not of what the tracker does to the
|
|
65
|
+
* intention afterwards. Reporting an intention invalid writes to the
|
|
66
|
+
* tracker, and that write delivers it again; the same fingerprint says
|
|
67
|
+
* nothing changed, so nothing is said again.
|
|
68
|
+
*/
|
|
69
|
+
fingerprint: string;
|
|
70
|
+
} | {
|
|
71
|
+
outcome: "unavailable";
|
|
72
|
+
} | {
|
|
73
|
+
outcome: "interrupted";
|
|
74
|
+
};
|
|
75
|
+
export type ReportInput = {
|
|
76
|
+
event: EventName;
|
|
77
|
+
key: string;
|
|
78
|
+
project: string;
|
|
79
|
+
fields: EventFields;
|
|
80
|
+
/**
|
|
81
|
+
* Names this Event so it is reported once.
|
|
82
|
+
*
|
|
83
|
+
* A feature is driven again on every pass while it waits, and an Event that
|
|
84
|
+
* only says what already happened must not be said twice. A manager that
|
|
85
|
+
* keeps a thread skips an id it has already written.
|
|
86
|
+
*/
|
|
87
|
+
eventId?: string;
|
|
88
|
+
};
|
|
89
|
+
export type ListenResult = {
|
|
90
|
+
outcome: string;
|
|
91
|
+
deliveries: Delivery[];
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* A Submission: an assembled feature placed where an Authority can judge it.
|
|
95
|
+
*
|
|
96
|
+
* `ref` is what the system published and `target` the work line it is offered
|
|
97
|
+
* to — both opaque here. The Authority reads them; this contract does not.
|
|
98
|
+
*/
|
|
99
|
+
export type SubmissionRequest = {
|
|
100
|
+
key: string;
|
|
101
|
+
project: string;
|
|
102
|
+
ref: string;
|
|
103
|
+
target: string;
|
|
104
|
+
title?: string;
|
|
105
|
+
intention?: string;
|
|
106
|
+
/** The Plan's Subtasks, in order — what the Submission is made of. */
|
|
107
|
+
steps?: string[];
|
|
108
|
+
/**
|
|
109
|
+
* How the delivered work describes itself, when the Project has a say — a
|
|
110
|
+
* subject line and a body. What the Authority makes of them is its own: a
|
|
111
|
+
* fold's message, a pull request's text, a comment. Absent: the title and
|
|
112
|
+
* the intention, as the human wrote them.
|
|
113
|
+
*/
|
|
114
|
+
description?: {
|
|
115
|
+
subject: string;
|
|
116
|
+
body?: string;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
export type SubmissionResult = {
|
|
120
|
+
outcome: "submitted";
|
|
121
|
+
reference: string;
|
|
122
|
+
} | {
|
|
123
|
+
outcome: "refused";
|
|
124
|
+
reason: string;
|
|
125
|
+
} | {
|
|
126
|
+
outcome: "unavailable";
|
|
127
|
+
};
|
|
128
|
+
export type FoldResult =
|
|
129
|
+
/** `reference`: the work line's own name for the fold, when the Authority can give one. Opaque. */
|
|
130
|
+
{
|
|
131
|
+
outcome: "folded";
|
|
132
|
+
reference?: string;
|
|
133
|
+
} | {
|
|
134
|
+
outcome: "conflict";
|
|
135
|
+
reason: string;
|
|
136
|
+
} | {
|
|
137
|
+
outcome: "unavailable";
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Whether the intention this key named is still on the tracker.
|
|
141
|
+
*
|
|
142
|
+
* A poll cannot see an absence: a deleted item simply never appears again.
|
|
143
|
+
* Host asks this of keys it already holds. `gone` is abandon — the same
|
|
144
|
+
* intent as a `cancel` delivery. `unavailable` is not: a missed read must
|
|
145
|
+
* not abandon work.
|
|
146
|
+
*/
|
|
147
|
+
export type ProbeResult = "present" | "gone" | "unavailable" | "interrupted";
|
|
148
|
+
export type ManagerPort = {
|
|
149
|
+
listen(input: {
|
|
150
|
+
since?: string;
|
|
151
|
+
}): Promise<ListenResult>;
|
|
152
|
+
adapt(payload: Record<string, unknown>): Promise<AdaptResult>;
|
|
153
|
+
report(input: ReportInput): Promise<boolean>;
|
|
154
|
+
/**
|
|
155
|
+
* Whether this raw payload says a human unblocked an escalated Feature.
|
|
156
|
+
* A poll snapshot carries no `ready` edge, so the manager reads its own
|
|
157
|
+
* signal (a label, a status, a field) and Host stays tracker-agnostic.
|
|
158
|
+
*/
|
|
159
|
+
signalsReady?(payload: Record<string, unknown>): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Take the resume signal back once it has been acted on.
|
|
162
|
+
*
|
|
163
|
+
* The signal is an instruction, not a state. Left where a human put it, it
|
|
164
|
+
* resumes the Feature again on every pass, and an escalation that is supposed
|
|
165
|
+
* to freeze the work freezes nothing.
|
|
166
|
+
*/
|
|
167
|
+
clearReady?(key: string): Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Offer an assembled feature to the Authority.
|
|
170
|
+
*
|
|
171
|
+
* Both Submission methods come as a pair: a manager that declares neither has
|
|
172
|
+
* no Authority, and the work is folded into WorkLineStable directly, as it was
|
|
173
|
+
* before any of this existed. Whether the Submission is good is not asked
|
|
174
|
+
* here — that is a Gate's answer.
|
|
175
|
+
*/
|
|
176
|
+
submit?(input: SubmissionRequest): Promise<SubmissionResult>;
|
|
177
|
+
/** Have the Authority fold a Submission the Gates accepted into the work line. */
|
|
178
|
+
fold?(input: {
|
|
179
|
+
reference: string;
|
|
180
|
+
}): Promise<FoldResult>;
|
|
181
|
+
/**
|
|
182
|
+
* Whether the intention this key named is still on the tracker.
|
|
183
|
+
*
|
|
184
|
+
* Optional: a manager that cannot answer (a directory of files, a tracker
|
|
185
|
+
* without a fetch-by-id) omits it, and Host does not invent an absence.
|
|
186
|
+
* Host only asks after a listen that reached the source, so a dead token
|
|
187
|
+
* is not read as a mass abandon.
|
|
188
|
+
*/
|
|
189
|
+
probe?(key: string): Promise<ProbeResult>;
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=port.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port.d.ts","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"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"}
|
package/dist/port.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What Host asks of one FeatureManager, whatever the tracker behind it.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here names GitHub, an issue, or a label: a manager package owns its
|
|
5
|
+
* tracker's vocabulary and hands Host these shapes only.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Every semantic Event, as values. A manager that mirrors states onto the
|
|
9
|
+
* tracker needs the list at runtime, not only as a type.
|
|
10
|
+
*/
|
|
11
|
+
export const EVENT_NAMES = [
|
|
12
|
+
"invalid",
|
|
13
|
+
"accepted",
|
|
14
|
+
"planned",
|
|
15
|
+
"progress",
|
|
16
|
+
"escalated",
|
|
17
|
+
"escalation_reminder",
|
|
18
|
+
"resumed",
|
|
19
|
+
"submitted",
|
|
20
|
+
"done",
|
|
21
|
+
"cancelled",
|
|
22
|
+
"reject_late",
|
|
23
|
+
];
|
|
24
|
+
//# sourceMappingURL=port.js.map
|
package/dist/port.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"port.js","sourceRoot":"","sources":["../src/port.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,SAAS;IACT,UAAU;IACV,SAAS;IACT,UAAU;IACV,WAAW;IACX,qBAAqB;IACrB,SAAS;IACT,WAAW;IACX,MAAM;IACN,WAAW;IACX,aAAa;CACL,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name the product goes by — the binary, the config file, the home
|
|
3
|
+
* directory, the labels a manager writes, the words in a message. It is
|
|
4
|
+
* written here once. Host and every manager read it from the kit; the only
|
|
5
|
+
* other file that spells it is `isolation-git`'s branch prefix, which has no
|
|
6
|
+
* kit to import. `scripts/check-name.mjs` refuses it anywhere else in source.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PRODUCT = "mason";
|
|
9
|
+
//# sourceMappingURL=product.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product.d.ts","sourceRoot":"","sources":["../src/product.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,UAAU,CAAC"}
|
package/dist/product.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The name the product goes by — the binary, the config file, the home
|
|
3
|
+
* directory, the labels a manager writes, the words in a message. It is
|
|
4
|
+
* written here once. Host and every manager read it from the kit; the only
|
|
5
|
+
* other file that spells it is `isolation-git`'s branch prefix, which has no
|
|
6
|
+
* kit to import. `scripts/check-name.mjs` refuses it anywhere else in source.
|
|
7
|
+
*/
|
|
8
|
+
export const PRODUCT = "mason";
|
|
9
|
+
//# sourceMappingURL=product.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product.js","sourceRoot":"","sources":["../src/product.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bluewombat/manager-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Contract a FeatureManager package implements for Host.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mason",
|
|
8
|
+
"bluewombat",
|
|
9
|
+
"plugin",
|
|
10
|
+
"types"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"homepage": "https://github.com/tilap/bluewombat/tree/main/packages/host/manager-kit#readme",
|
|
14
|
+
"bugs": "https://github.com/tilap/bluewombat/issues",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/tilap/bluewombat.git",
|
|
18
|
+
"directory": "packages/host/manager-kit"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"SPECS.md"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=24.20.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"lint": "biome check .",
|
|
40
|
+
"format": "biome check --write .",
|
|
41
|
+
"tsc": "tsc --noEmit",
|
|
42
|
+
"test": "tsx --test $(find src -name '*.test.ts')",
|
|
43
|
+
"build": "tsc -p tsconfig.build.json"
|
|
44
|
+
}
|
|
45
|
+
}
|