@thxgg/steward 0.1.7 → 0.1.11
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/.output/nitro.json +1 -1
- package/.output/public/_nuxt/{Bo1Fdv48.js → BPaqwWyl.js} +2 -2
- package/.output/public/_nuxt/{DhQtydpF.js → C8LtDyY4.js} +1 -1
- package/.output/public/_nuxt/{D0zW6lUK.js → CQgu_W_k.js} +1 -1
- package/.output/public/_nuxt/{BRDbaJqY.js → CZKCADv6.js} +2 -2
- package/.output/public/_nuxt/{CEJOILWG.js → CeO4HNxC.js} +1 -1
- package/.output/public/_nuxt/{BNzFoVmP.js → Cs5ptsBk.js} +1 -1
- package/.output/public/_nuxt/{CFsNy2aC.js → CshyynD6.js} +1 -1
- package/.output/public/_nuxt/{DYDTtHLR.js → CzKPXRws.js} +1 -1
- package/.output/public/_nuxt/{BqmZq_gb.js → DOvbLsAq.js} +1 -1
- package/.output/public/_nuxt/{Bri1ZtcQ.js → DbloiS5Y.js} +1 -1
- package/.output/public/_nuxt/{B3hkJjmY.js → DcRwFvvS.js} +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/e2995e80-736c-47cd-8041-a131bab2f136.json +1 -0
- package/.output/public/_nuxt/{X6fIXIFO.js → vr7VLA9A.js} +1 -1
- package/.output/server/chunks/build/{_prd_-CnwhMRyf.mjs → _prd_-CkKfJB6U.mjs} +2 -2
- package/.output/server/chunks/build/_prd_-CkKfJB6U.mjs.map +1 -0
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/server.mjs +1 -1
- package/.output/server/chunks/nitro/nitro.mjs +684 -622
- package/.output/server/package.json +1 -1
- package/README.md +31 -4
- package/bin/prd +117 -0
- package/dist/host/src/api/git.js +1 -8
- package/dist/host/src/api/prds.js +2 -8
- package/dist/host/src/api/repo-context.js +60 -0
- package/dist/host/src/api/repos.js +6 -0
- package/dist/host/src/api/state.js +20 -21
- package/dist/host/src/executor.js +215 -29
- package/dist/host/src/help.js +124 -0
- package/dist/host/src/mcp.js +51 -25
- package/dist/server/utils/db.js +86 -1
- package/docs/MCP.md +64 -3
- package/package.json +1 -1
- package/.output/public/_nuxt/builds/meta/6683a0d9-9c02-4098-b750-bbbc0305261e.json +0 -1
- package/.output/server/chunks/build/_prd_-CnwhMRyf.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -41,6 +41,15 @@ Add to your MCP client config:
|
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
Steward MCP requires a Node runtime with built-in sqlite support (`node:sqlite`) for `repos`, `prds`, and `state` APIs.
|
|
45
|
+
If you see `ERR_UNKNOWN_BUILTIN_MODULE: node:sqlite`, run with sqlite enabled:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
NODE_OPTIONS=--experimental-sqlite npx -y @thxgg/steward mcp
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Note: `execute` runs in a VM sandbox by design, so globals like `process` are intentionally not exposed.
|
|
52
|
+
|
|
44
53
|
### CLI
|
|
45
54
|
|
|
46
55
|
```bash
|
|
@@ -77,9 +86,7 @@ prd mcp
|
|
|
77
86
|
Steward exposes one MCP tool: `execute`.
|
|
78
87
|
|
|
79
88
|
```js
|
|
80
|
-
const
|
|
81
|
-
const repo = reposList[0]
|
|
82
|
-
if (!repo) return { error: 'No repos configured' }
|
|
89
|
+
const repo = await repos.current()
|
|
83
90
|
|
|
84
91
|
const prdList = await prds.list(repo.id)
|
|
85
92
|
if (prdList.length === 0) return { repo: repo.name, prds: 0 }
|
|
@@ -92,6 +99,26 @@ return {
|
|
|
92
99
|
}
|
|
93
100
|
```
|
|
94
101
|
|
|
102
|
+
Every call returns a structured envelope:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"ok": true,
|
|
107
|
+
"result": {},
|
|
108
|
+
"logs": [],
|
|
109
|
+
"error": null,
|
|
110
|
+
"meta": {
|
|
111
|
+
"timeoutMs": 30000,
|
|
112
|
+
"durationMs": 10,
|
|
113
|
+
"truncatedResult": false,
|
|
114
|
+
"truncatedLogs": false,
|
|
115
|
+
"resultWasUndefined": false
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use `steward.help()` inside `execute` for runtime API signatures and examples.
|
|
121
|
+
|
|
95
122
|
## APIs
|
|
96
123
|
|
|
97
124
|
Inside `execute`, these APIs are available:
|
|
@@ -99,7 +126,7 @@ Inside `execute`, these APIs are available:
|
|
|
99
126
|
- `repos` - register/list/remove repos and refresh discovered git repos
|
|
100
127
|
- `prds` - list/read PRD docs, tasks, progress, and task commit refs
|
|
101
128
|
- `git` - commit metadata, diffs, file diffs, and file contents
|
|
102
|
-
- `state` - direct PRD state get/upsert by repo id or
|
|
129
|
+
- `state` - direct PRD state get/upsert by repo id, path, or current repo
|
|
103
130
|
|
|
104
131
|
Detailed API docs and examples: `docs/MCP.md`
|
|
105
132
|
|
package/bin/prd
CHANGED
|
@@ -1,11 +1,128 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process'
|
|
2
3
|
import { existsSync } from 'node:fs'
|
|
3
4
|
import { dirname, resolve } from 'node:path'
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
5
6
|
|
|
7
|
+
const SQLITE_ENABLE_FLAG = '--experimental-sqlite'
|
|
8
|
+
const SQLITE_DISABLE_FLAG = '--no-experimental-sqlite'
|
|
9
|
+
const SQLITE_REEXEC_ENV = 'STEWARD_SQLITE_REEXEC'
|
|
10
|
+
|
|
6
11
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
7
12
|
const entryPath = resolve(packageRoot, 'dist', 'host', 'src', 'index.js')
|
|
8
13
|
|
|
14
|
+
function requiresSqliteRuntime(command) {
|
|
15
|
+
return command === 'mcp' || command === 'ui'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isSqliteRuntimeError(error) {
|
|
19
|
+
if (!(error instanceof Error)) {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const code = error.code
|
|
24
|
+
return typeof code === 'string'
|
|
25
|
+
&& code === 'ERR_UNKNOWN_BUILTIN_MODULE'
|
|
26
|
+
&& error.message.includes('node:sqlite')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function sanitizeNodeOptions(rawNodeOptions = '') {
|
|
30
|
+
const options = rawNodeOptions
|
|
31
|
+
.split(/\s+/)
|
|
32
|
+
.filter(Boolean)
|
|
33
|
+
.filter((option) => option !== SQLITE_ENABLE_FLAG && option !== SQLITE_DISABLE_FLAG)
|
|
34
|
+
|
|
35
|
+
return options.join(' ')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function buildReexecEnv() {
|
|
39
|
+
const env = { ...process.env }
|
|
40
|
+
const sanitizedNodeOptions = sanitizeNodeOptions(env.NODE_OPTIONS)
|
|
41
|
+
|
|
42
|
+
if (sanitizedNodeOptions.length > 0) {
|
|
43
|
+
env.NODE_OPTIONS = sanitizedNodeOptions
|
|
44
|
+
} else {
|
|
45
|
+
delete env.NODE_OPTIONS
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
env[SQLITE_REEXEC_ENV] = '1'
|
|
49
|
+
return env
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function canEnableSqliteWithFlag() {
|
|
53
|
+
const probe = spawnSync(
|
|
54
|
+
process.execPath,
|
|
55
|
+
[SQLITE_ENABLE_FLAG, '-e', "import('node:sqlite').then(() => process.exit(0)).catch(() => process.exit(1))"],
|
|
56
|
+
{
|
|
57
|
+
stdio: 'ignore',
|
|
58
|
+
env: buildReexecEnv()
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return probe.status === 0
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function reexecWithSqliteFlag() {
|
|
66
|
+
const result = spawnSync(
|
|
67
|
+
process.execPath,
|
|
68
|
+
[SQLITE_ENABLE_FLAG, fileURLToPath(import.meta.url), ...process.argv.slice(2)],
|
|
69
|
+
{
|
|
70
|
+
stdio: 'inherit',
|
|
71
|
+
env: buildReexecEnv()
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
if (result.error) {
|
|
76
|
+
throw result.error
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
process.exit(result.status ?? 1)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function ensureSqliteRuntime(command) {
|
|
83
|
+
if (!requiresSqliteRuntime(command)) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
await import('node:sqlite')
|
|
89
|
+
return
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (!isSqliteRuntimeError(error)) {
|
|
92
|
+
throw error
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const alreadyReexecuted = process.env[SQLITE_REEXEC_ENV] === '1'
|
|
96
|
+
if (!alreadyReexecuted && canEnableSqliteWithFlag()) {
|
|
97
|
+
reexecWithSqliteFlag()
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
102
|
+
const nodeOptions = process.env.NODE_OPTIONS || ''
|
|
103
|
+
const hasDisableFlag = process.execArgv.includes(SQLITE_DISABLE_FLAG)
|
|
104
|
+
|| nodeOptions.includes(SQLITE_DISABLE_FLAG)
|
|
105
|
+
|
|
106
|
+
console.error('Steward requires SQLite runtime support for repos/prds/state APIs.')
|
|
107
|
+
console.error(`Runtime: ${process.version} (${process.execPath})`)
|
|
108
|
+
if (nodeOptions) {
|
|
109
|
+
console.error(`NODE_OPTIONS: ${nodeOptions}`)
|
|
110
|
+
}
|
|
111
|
+
console.error(`Cause: ${message}`)
|
|
112
|
+
|
|
113
|
+
if (hasDisableFlag) {
|
|
114
|
+
console.error(`Hint: remove ${SQLITE_DISABLE_FLAG} from NODE_OPTIONS or runtime args and retry.`)
|
|
115
|
+
} else {
|
|
116
|
+
console.error(`Hint: use a Node runtime with sqlite support or launch with ${SQLITE_ENABLE_FLAG}.`)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
process.exit(1)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const command = process.argv[2] || ''
|
|
124
|
+
await ensureSqliteRuntime(command)
|
|
125
|
+
|
|
9
126
|
if (!existsSync(entryPath)) {
|
|
10
127
|
console.error('Steward host runtime is not built.')
|
|
11
128
|
console.error('Run `npm run build:host` in this package before invoking `prd`.')
|
package/dist/host/src/api/git.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { getCommitDiff, getCommitInfo, getFileContent, getFileDiff, isGitRepo, validatePathInRepo } from '../../../server/utils/git.js';
|
|
2
|
-
import {
|
|
3
|
-
async function requireRepo(repoId) {
|
|
4
|
-
const repo = await getRepoById(repoId);
|
|
5
|
-
if (!repo) {
|
|
6
|
-
throw new Error('Repository not found');
|
|
7
|
-
}
|
|
8
|
-
return repo;
|
|
9
|
-
}
|
|
2
|
+
import { requireRepo } from './repo-context.js';
|
|
10
3
|
function resolveGitRepoPath(repo, repoPath) {
|
|
11
4
|
if (!repoPath) {
|
|
12
5
|
return repo.path;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import { basename, join } from 'node:path';
|
|
3
3
|
import { resolveCommitRepo } from '../../../server/utils/git.js';
|
|
4
|
-
import { discoverGitRepos,
|
|
4
|
+
import { discoverGitRepos, getRepos, saveRepos } from '../../../server/utils/repos.js';
|
|
5
5
|
import { getPrdState, getPrdStateSummaries, migrateLegacyStateForRepo } from '../../../server/utils/prd-state.js';
|
|
6
|
+
import { requireRepo } from './repo-context.js';
|
|
6
7
|
function parseMetadata(content) {
|
|
7
8
|
const metadata = {};
|
|
8
9
|
const authorMatch = content.match(/\*{0,2}Author\*{0,2}:\*{0,2}\s*(.+?)(?:\n|$)/i);
|
|
@@ -30,13 +31,6 @@ function parseMetadata(content) {
|
|
|
30
31
|
}
|
|
31
32
|
return metadata;
|
|
32
33
|
}
|
|
33
|
-
async function requireRepo(repoId) {
|
|
34
|
-
const repo = await getRepoById(repoId);
|
|
35
|
-
if (!repo) {
|
|
36
|
-
throw new Error('Repository not found');
|
|
37
|
-
}
|
|
38
|
-
return repo;
|
|
39
|
-
}
|
|
40
34
|
async function readPrdFile(repo, prdSlug) {
|
|
41
35
|
const prdPath = join(repo.path, 'docs', 'prd', `${prdSlug}.md`);
|
|
42
36
|
try {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { getRepoById, getRepos } from '../../../server/utils/repos.js';
|
|
3
|
+
export class RepoLookupError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
details;
|
|
6
|
+
constructor(message, code, details) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.details = details;
|
|
10
|
+
this.name = 'RepoLookupError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function summarizeRepos(repos) {
|
|
14
|
+
return repos.map((repo) => ({
|
|
15
|
+
id: repo.id,
|
|
16
|
+
name: repo.name,
|
|
17
|
+
path: repo.path
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
function formatKnownRepos(knownRepos) {
|
|
21
|
+
return knownRepos
|
|
22
|
+
.map((repo) => `${repo.id} (${repo.name}) ${repo.path}`)
|
|
23
|
+
.join('; ');
|
|
24
|
+
}
|
|
25
|
+
export async function requireRepo(repoId) {
|
|
26
|
+
const repo = await getRepoById(repoId);
|
|
27
|
+
if (repo) {
|
|
28
|
+
return repo;
|
|
29
|
+
}
|
|
30
|
+
const allRepos = await getRepos();
|
|
31
|
+
const knownRepos = summarizeRepos(allRepos);
|
|
32
|
+
if (knownRepos.length === 0) {
|
|
33
|
+
throw new RepoLookupError(`Unknown repoId "${repoId}". No repositories are registered. Use repos.add(path) first.`, 'NO_REPOS', { repoId, knownRepos });
|
|
34
|
+
}
|
|
35
|
+
throw new RepoLookupError(`Unknown repoId "${repoId}". Known repositories: ${formatKnownRepos(knownRepos)}`, 'REPO_NOT_FOUND', { repoId, knownRepos });
|
|
36
|
+
}
|
|
37
|
+
export async function requireRepoByPath(repoPath) {
|
|
38
|
+
const absolutePath = resolve(repoPath);
|
|
39
|
+
const allRepos = await getRepos();
|
|
40
|
+
const repo = allRepos.find((candidate) => resolve(candidate.path) === absolutePath);
|
|
41
|
+
if (repo) {
|
|
42
|
+
return repo;
|
|
43
|
+
}
|
|
44
|
+
const knownRepos = summarizeRepos(allRepos);
|
|
45
|
+
if (knownRepos.length === 0) {
|
|
46
|
+
throw new RepoLookupError(`No registered repository found for path: ${absolutePath}. No repositories are registered. Use repos.add(path) first.`, 'NO_REPOS', { repoPath: absolutePath, knownRepos });
|
|
47
|
+
}
|
|
48
|
+
throw new RepoLookupError(`No registered repository found for path: ${absolutePath}. Known repositories: ${formatKnownRepos(knownRepos)}`, 'REPO_PATH_NOT_FOUND', { repoPath: absolutePath, knownRepos });
|
|
49
|
+
}
|
|
50
|
+
export async function requireCurrentRepo() {
|
|
51
|
+
const allRepos = await getRepos();
|
|
52
|
+
if (allRepos.length === 1) {
|
|
53
|
+
return allRepos[0];
|
|
54
|
+
}
|
|
55
|
+
const knownRepos = summarizeRepos(allRepos);
|
|
56
|
+
if (knownRepos.length === 0) {
|
|
57
|
+
throw new RepoLookupError('No repositories are registered. Use repos.add(path) first.', 'NO_REPOS', { knownRepos });
|
|
58
|
+
}
|
|
59
|
+
throw new RepoLookupError(`Cannot resolve a current repository because ${knownRepos.length} repositories are registered. Use an explicit repoId or by-path API. Known repositories: ${formatKnownRepos(knownRepos)}`, 'AMBIGUOUS_REPO', { knownRepos });
|
|
60
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { addRepo, discoverGitRepos, getRepoById, getRepos, removeRepo, saveRepos, validateRepoPath } from '../../../server/utils/repos.js';
|
|
2
2
|
import { migrateLegacyStateForRepo } from '../../../server/utils/prd-state.js';
|
|
3
|
+
import { requireCurrentRepo, requireRepo } from './repo-context.js';
|
|
3
4
|
export const repos = {
|
|
4
5
|
async list() {
|
|
5
6
|
return await getRepos();
|
|
@@ -7,6 +8,9 @@ export const repos = {
|
|
|
7
8
|
async get(repoId) {
|
|
8
9
|
return await getRepoById(repoId) ?? null;
|
|
9
10
|
},
|
|
11
|
+
async current() {
|
|
12
|
+
return await requireCurrentRepo();
|
|
13
|
+
},
|
|
10
14
|
async add(path, name) {
|
|
11
15
|
const validation = await validateRepoPath(path);
|
|
12
16
|
if (!validation.valid) {
|
|
@@ -17,6 +21,7 @@ export const repos = {
|
|
|
17
21
|
return repo;
|
|
18
22
|
},
|
|
19
23
|
async remove(repoId) {
|
|
24
|
+
await requireRepo(repoId);
|
|
20
25
|
const removed = await removeRepo(repoId);
|
|
21
26
|
if (!removed) {
|
|
22
27
|
throw new Error('Repository not found');
|
|
@@ -24,6 +29,7 @@ export const repos = {
|
|
|
24
29
|
return { removed: true };
|
|
25
30
|
},
|
|
26
31
|
async refreshGitRepos(repoId) {
|
|
32
|
+
await requireRepo(repoId);
|
|
27
33
|
const allRepos = await getRepos();
|
|
28
34
|
const repoIndex = allRepos.findIndex((repo) => repo.id === repoId);
|
|
29
35
|
if (repoIndex === -1) {
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
1
|
import { getPrdState, getPrdStateSummaries, migrateLegacyStateForRepo, upsertPrdState } from '../../../server/utils/prd-state.js';
|
|
3
|
-
import {
|
|
4
|
-
async function requireRepo(repoId) {
|
|
5
|
-
const repo = await getRepoById(repoId);
|
|
6
|
-
if (!repo) {
|
|
7
|
-
throw new Error('Repository not found');
|
|
8
|
-
}
|
|
9
|
-
return repo;
|
|
10
|
-
}
|
|
11
|
-
async function findRepoByPath(repoPath) {
|
|
12
|
-
const absolutePath = resolve(repoPath);
|
|
13
|
-
const repos = await getRepos();
|
|
14
|
-
const repo = repos.find((candidate) => resolve(candidate.path) === absolutePath);
|
|
15
|
-
if (!repo) {
|
|
16
|
-
throw new Error(`No registered repository found for path: ${absolutePath}`);
|
|
17
|
-
}
|
|
18
|
-
return repo;
|
|
19
|
-
}
|
|
2
|
+
import { requireCurrentRepo, requireRepo, requireRepoByPath } from './repo-context.js';
|
|
20
3
|
function mapStateUpdate(payload) {
|
|
21
4
|
return {
|
|
22
5
|
...(payload.tasks !== undefined && { tasks: payload.tasks }),
|
|
@@ -34,7 +17,12 @@ export const state = {
|
|
|
34
17
|
return await getPrdState(repo.id, slug);
|
|
35
18
|
},
|
|
36
19
|
async getByPath(repoPath, slug) {
|
|
37
|
-
const repo = await
|
|
20
|
+
const repo = await requireRepoByPath(repoPath);
|
|
21
|
+
await migrateLegacyStateForRepo(repo);
|
|
22
|
+
return await getPrdState(repo.id, slug);
|
|
23
|
+
},
|
|
24
|
+
async getCurrent(slug) {
|
|
25
|
+
const repo = await requireCurrentRepo();
|
|
38
26
|
await migrateLegacyStateForRepo(repo);
|
|
39
27
|
return await getPrdState(repo.id, slug);
|
|
40
28
|
},
|
|
@@ -45,7 +33,13 @@ export const state = {
|
|
|
45
33
|
return mapSummaryMap(summaries);
|
|
46
34
|
},
|
|
47
35
|
async summariesByPath(repoPath) {
|
|
48
|
-
const repo = await
|
|
36
|
+
const repo = await requireRepoByPath(repoPath);
|
|
37
|
+
await migrateLegacyStateForRepo(repo);
|
|
38
|
+
const summaries = await getPrdStateSummaries(repo.id);
|
|
39
|
+
return mapSummaryMap(summaries);
|
|
40
|
+
},
|
|
41
|
+
async summariesCurrent() {
|
|
42
|
+
const repo = await requireCurrentRepo();
|
|
49
43
|
await migrateLegacyStateForRepo(repo);
|
|
50
44
|
const summaries = await getPrdStateSummaries(repo.id);
|
|
51
45
|
return mapSummaryMap(summaries);
|
|
@@ -56,7 +50,12 @@ export const state = {
|
|
|
56
50
|
return { saved: true };
|
|
57
51
|
},
|
|
58
52
|
async upsertByPath(repoPath, slug, payload) {
|
|
59
|
-
const repo = await
|
|
53
|
+
const repo = await requireRepoByPath(repoPath);
|
|
54
|
+
await upsertPrdState(repo.id, slug, mapStateUpdate(payload));
|
|
55
|
+
return { saved: true };
|
|
56
|
+
},
|
|
57
|
+
async upsertCurrent(slug, payload) {
|
|
58
|
+
const repo = await requireCurrentRepo();
|
|
60
59
|
await upsertPrdState(repo.id, slug, mapStateUpdate(payload));
|
|
61
60
|
return { saved: true };
|
|
62
61
|
}
|