weir-harness 2.1.1 → 2.1.2
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/package.json +1 -1
- package/src/capabilities/apply-engine.js +20 -4
- package/src/capabilities/lifecycle-feed.js +47 -0
- package/src/capabilities/mcp-drain.js +6 -0
- package/src/capabilities/mcp-facade-plugin.js +14 -4
- package/src/capabilities/mcp-facade.js +1 -1
- package/src/capabilities/mcp-inventory.js +152 -0
- package/src/capabilities/mcp-manager.js +220 -171
- package/src/capabilities/mcp-mount-ownership.js +114 -0
- package/src/capabilities/mcp-mount.js +334 -82
- package/src/capabilities/mcp-operation-coordinator.js +76 -0
- package/src/capabilities/mcp-runtime.js +3 -29
- package/src/capabilities/skill-selection-plugin.js +8 -0
- package/src/file-lease/client.js +61 -3
- package/src/file-lease/negotiation.js +89 -0
- package/src/file-lease/plugin.js +25 -23
- package/src/file-lease/tools.js +71 -121
- package/src/file-lease/watch.js +225 -36
package/src/file-lease/watch.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
// notices for one release — and would let one mount's teardown cancel a wait
|
|
8
8
|
// another mount still owns.
|
|
9
9
|
//
|
|
10
|
-
// The coordinator holds three collections
|
|
10
|
+
// The coordinator holds three collections, plus a WeakMap of private episode
|
|
11
|
+
// records keyed by the stable opaque handles handed to callers:
|
|
11
12
|
//
|
|
12
13
|
// active one entry per `(session, normalized path)`, in `watching`
|
|
13
14
|
// pendingDelivery consumed entries (`hit` / `reset`) whose notice has not
|
|
@@ -46,16 +47,54 @@ export const WATCH_STATES = Object.freeze(['watching', 'hit', 'reset', 'self', '
|
|
|
46
47
|
*/
|
|
47
48
|
|
|
48
49
|
/**
|
|
50
|
+
* The stable opaque handle returned to callers. Its four public fields are
|
|
51
|
+
* live, getter-only views; all mutable state lives in the coordinator's WeakMap.
|
|
52
|
+
*
|
|
49
53
|
* @typedef {object} WatchEntry
|
|
50
54
|
* @property {string} sessionId the session that subscribed
|
|
51
55
|
* @property {string} path normalized absolute path
|
|
52
56
|
* @property {WatchState} state
|
|
53
57
|
* @property {boolean} settledByTool true once a running tool already reported
|
|
54
58
|
* this episode to the model, so a deferred notice would only repeat it
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The coordinator's structured establishment verdict. Model-facing wording and
|
|
63
|
+
* presentation metadata stay in tools.js; this vocabulary describes decisions.
|
|
64
|
+
*
|
|
65
|
+
* @typedef {object} WatchOutcome
|
|
66
|
+
* @property {'watching' | 'free' | 'self' | 'released' | 'reset' | 'unsupported' | 'cancelled' | 'transport'} state
|
|
67
|
+
* @property {any} [holder] the current foreign holder for a watching outcome
|
|
68
|
+
* @property {unknown} [error] the transport failure for a transport outcome
|
|
69
|
+
* @property {boolean} [raced] ownership arrived asynchronously while establishing
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The lease-specific facts the coordinator needs to classify a status reply.
|
|
74
|
+
* The read and capability query remain injected, so this module has no socket.
|
|
75
|
+
*
|
|
76
|
+
* @typedef {object} WatchStatusOptions
|
|
77
|
+
* @property {{ id: string, session: string }} owner the subscribing identity
|
|
78
|
+
* @property {() => boolean} supportsRelease whether the CURRENT connection
|
|
79
|
+
* announces released events
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The private mutable record behind one WatchEntry handle.
|
|
84
|
+
*
|
|
85
|
+
* @typedef {object} WatchEpisodeRecord
|
|
86
|
+
* @property {string} sessionId the session that subscribed
|
|
87
|
+
* @property {string} path normalized absolute path
|
|
88
|
+
* @property {WatchState} state
|
|
89
|
+
* @property {boolean} settledByTool true once a running tool already reported
|
|
90
|
+
* this episode to the model, so a deferred notice would only repeat it
|
|
55
91
|
* @property {any} agent the agent that subscribed: delivery re-resolves the
|
|
56
92
|
* session and refuses to land on a replacement agent
|
|
57
93
|
* @property {Promise<any> | null} statusFlight the ONE authoritative read this
|
|
58
94
|
* entry is currently sharing, so overlapping calls cannot disagree
|
|
95
|
+
* @property {Promise<WatchOutcome> | null} establishFlight the ONE complete
|
|
96
|
+
* establishment attempt shared by overlapping callers; cleared after watching
|
|
97
|
+
* so a later call performs a fresh authoritative read
|
|
59
98
|
* @property {Set<WatchMount>} mounts the mount references that still want it
|
|
60
99
|
* @property {ReturnType<typeof setTimeout> | null} timer the deferred notice
|
|
61
100
|
*/
|
|
@@ -84,6 +123,11 @@ function unrefTimer(timer) {
|
|
|
84
123
|
if (typeof handle.unref === 'function') handle.unref()
|
|
85
124
|
}
|
|
86
125
|
|
|
126
|
+
/** @param {unknown} error @returns {boolean} */
|
|
127
|
+
function isTransport(error) {
|
|
128
|
+
return error !== null && typeof error === 'object' && /** @type {any} */ (error).code === 'transport'
|
|
129
|
+
}
|
|
130
|
+
|
|
87
131
|
/**
|
|
88
132
|
* The coordinator surface: one factory is the single definition of what a
|
|
89
133
|
* consumer holds, so the tool surface and the plugin row never re-describe it.
|
|
@@ -96,12 +140,25 @@ export function createWatchCoordinator() {
|
|
|
96
140
|
const pendingDelivery = new Set()
|
|
97
141
|
/** @type {Set<WatchMount>} */
|
|
98
142
|
const mounts = new Set()
|
|
143
|
+
/** @type {WeakMap<WatchEntry, WatchEpisodeRecord>} */
|
|
144
|
+
const records = new WeakMap()
|
|
99
145
|
|
|
100
146
|
/** @param {string} sessionId @param {string} path @returns {string} */
|
|
101
147
|
function keyOf(sessionId, path) {
|
|
102
148
|
return `${sessionId}\u0000${path}`
|
|
103
149
|
}
|
|
104
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the private record without exposing it on the stable public handle.
|
|
153
|
+
* @param {WatchEntry} entry
|
|
154
|
+
* @returns {WatchEpisodeRecord}
|
|
155
|
+
*/
|
|
156
|
+
function recordOf(entry) {
|
|
157
|
+
const record = records.get(entry)
|
|
158
|
+
if (record === undefined) throw new TypeError('Unknown watch episode handle')
|
|
159
|
+
return record
|
|
160
|
+
}
|
|
161
|
+
|
|
105
162
|
/**
|
|
106
163
|
* The public shape of an entry. Internals (mounts, flight, timer, agent
|
|
107
164
|
* identity) stay inside the coordinator.
|
|
@@ -109,7 +166,8 @@ export function createWatchCoordinator() {
|
|
|
109
166
|
* @returns {WatchProjection}
|
|
110
167
|
*/
|
|
111
168
|
function project(entry) {
|
|
112
|
-
|
|
169
|
+
const record = recordOf(entry)
|
|
170
|
+
return { sessionId: record.sessionId, path: record.path, state: record.state, settledByTool: record.settledByTool }
|
|
113
171
|
}
|
|
114
172
|
|
|
115
173
|
/**
|
|
@@ -120,16 +178,18 @@ export function createWatchCoordinator() {
|
|
|
120
178
|
* @returns {WatchMount | undefined}
|
|
121
179
|
*/
|
|
122
180
|
function liveMount(entry) {
|
|
123
|
-
|
|
181
|
+
const record = recordOf(entry)
|
|
182
|
+
for (const mount of record.mounts) if (!mount.disposed) return mount
|
|
124
183
|
for (const mount of mounts) if (!mount.disposed) return mount
|
|
125
184
|
return undefined
|
|
126
185
|
}
|
|
127
186
|
|
|
128
187
|
/** @param {WatchEntry} entry */
|
|
129
188
|
function cancelTimer(entry) {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
189
|
+
const record = recordOf(entry)
|
|
190
|
+
if (record.timer === null) return
|
|
191
|
+
clearTimeout(record.timer)
|
|
192
|
+
record.timer = null
|
|
133
193
|
}
|
|
134
194
|
|
|
135
195
|
/**
|
|
@@ -146,7 +206,7 @@ export function createWatchCoordinator() {
|
|
|
146
206
|
*/
|
|
147
207
|
function scheduleNotice(entry) {
|
|
148
208
|
pendingDelivery.add(entry)
|
|
149
|
-
const flight = entry.statusFlight
|
|
209
|
+
const flight = recordOf(entry).statusFlight
|
|
150
210
|
if (flight === null) {
|
|
151
211
|
armNotice(entry)
|
|
152
212
|
return
|
|
@@ -172,28 +232,29 @@ export function createWatchCoordinator() {
|
|
|
172
232
|
*/
|
|
173
233
|
function armNotice(entry) {
|
|
174
234
|
if (!pendingDelivery.has(entry)) return
|
|
175
|
-
|
|
235
|
+
const record = recordOf(entry)
|
|
236
|
+
if (record.state !== 'hit' && record.state !== 'reset') {
|
|
176
237
|
pendingDelivery.delete(entry)
|
|
177
238
|
return
|
|
178
239
|
}
|
|
179
|
-
if (
|
|
240
|
+
if (record.timer !== null) return
|
|
180
241
|
const timer = setTimeout(() => {
|
|
181
|
-
|
|
242
|
+
record.timer = null
|
|
182
243
|
pendingDelivery.delete(entry)
|
|
183
|
-
if (
|
|
184
|
-
if (
|
|
244
|
+
if (record.state !== 'hit' && record.state !== 'reset') return
|
|
245
|
+
if (record.settledByTool === true) return
|
|
185
246
|
const mount = liveMount(entry)
|
|
186
247
|
if (mount === undefined) return
|
|
187
|
-
const agent = mount.agentFor(
|
|
248
|
+
const agent = mount.agentFor(record.sessionId)
|
|
188
249
|
if (agent === undefined || agent === null) return
|
|
189
|
-
if (
|
|
250
|
+
if (record.agent !== undefined && agent !== record.agent) return
|
|
190
251
|
try {
|
|
191
252
|
mount.notify(entry, agent)
|
|
192
253
|
} catch {
|
|
193
254
|
// A notice is best effort: delivery must never break the transport.
|
|
194
255
|
}
|
|
195
256
|
}, 0)
|
|
196
|
-
|
|
257
|
+
record.timer = timer
|
|
197
258
|
unrefTimer(timer)
|
|
198
259
|
}
|
|
199
260
|
|
|
@@ -204,7 +265,7 @@ export function createWatchCoordinator() {
|
|
|
204
265
|
*/
|
|
205
266
|
function endPending(entry, state) {
|
|
206
267
|
if (pendingDelivery.delete(entry)) cancelTimer(entry)
|
|
207
|
-
entry.state = state
|
|
268
|
+
recordOf(entry).state = state
|
|
208
269
|
}
|
|
209
270
|
|
|
210
271
|
/**
|
|
@@ -229,12 +290,13 @@ export function createWatchCoordinator() {
|
|
|
229
290
|
if (!mounts.delete(mount)) return
|
|
230
291
|
mount.disposed = true
|
|
231
292
|
for (const [key, entry] of [...active]) {
|
|
232
|
-
|
|
233
|
-
if (
|
|
293
|
+
const record = recordOf(entry)
|
|
294
|
+
if (!record.mounts.delete(mount)) continue
|
|
295
|
+
if (record.mounts.size > 0) continue
|
|
234
296
|
active.delete(key)
|
|
235
|
-
|
|
297
|
+
record.state = 'cancelled'
|
|
236
298
|
}
|
|
237
|
-
for (const entry of [...pendingDelivery]) entry.mounts.delete(mount)
|
|
299
|
+
for (const entry of [...pendingDelivery]) recordOf(entry).mounts.delete(mount)
|
|
238
300
|
if (mounts.size === 0) clear()
|
|
239
301
|
}
|
|
240
302
|
|
|
@@ -253,22 +315,31 @@ export function createWatchCoordinator() {
|
|
|
253
315
|
const key = keyOf(sessionId, path)
|
|
254
316
|
const known = active.get(key)
|
|
255
317
|
if (known !== undefined) {
|
|
256
|
-
|
|
257
|
-
if (
|
|
318
|
+
const record = recordOf(known)
|
|
319
|
+
if (mount !== undefined) record.mounts.add(mount)
|
|
320
|
+
if (agent !== undefined && agent !== null) record.agent = agent
|
|
258
321
|
return known
|
|
259
322
|
}
|
|
260
|
-
/** @type {
|
|
261
|
-
const
|
|
323
|
+
/** @type {WatchEpisodeRecord} */
|
|
324
|
+
const record = {
|
|
262
325
|
sessionId,
|
|
263
326
|
path,
|
|
264
327
|
state: 'watching',
|
|
265
328
|
settledByTool: false,
|
|
266
329
|
agent,
|
|
267
330
|
statusFlight: null,
|
|
331
|
+
establishFlight: null,
|
|
268
332
|
mounts: new Set(),
|
|
269
333
|
timer: null,
|
|
270
334
|
}
|
|
271
|
-
|
|
335
|
+
const entry = /** @type {WatchEntry} */ (Object.freeze({
|
|
336
|
+
get sessionId() { return record.sessionId },
|
|
337
|
+
get path() { return record.path },
|
|
338
|
+
get state() { return record.state },
|
|
339
|
+
get settledByTool() { return record.settledByTool },
|
|
340
|
+
}))
|
|
341
|
+
records.set(entry, record)
|
|
342
|
+
if (mount !== undefined) record.mounts.add(mount)
|
|
272
343
|
active.set(key, entry)
|
|
273
344
|
return entry
|
|
274
345
|
}
|
|
@@ -292,14 +363,127 @@ export function createWatchCoordinator() {
|
|
|
292
363
|
* @returns {Promise<any>}
|
|
293
364
|
*/
|
|
294
365
|
function shareStatus(entry, run) {
|
|
295
|
-
|
|
366
|
+
const record = recordOf(entry)
|
|
367
|
+
if (record.statusFlight !== null) return record.statusFlight
|
|
296
368
|
/** @type {Promise<any>} */
|
|
297
369
|
const flight = Promise.resolve()
|
|
298
370
|
.then(run)
|
|
299
371
|
.finally(() => {
|
|
300
|
-
if (
|
|
372
|
+
if (record.statusFlight === flight) record.statusFlight = null
|
|
301
373
|
})
|
|
302
|
-
|
|
374
|
+
record.statusFlight = flight
|
|
375
|
+
return flight
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** Record that the running tool reported this episode to the model.
|
|
379
|
+
* @param {WatchEntry} entry
|
|
380
|
+
*/
|
|
381
|
+
function report(entry) {
|
|
382
|
+
recordOf(entry).settledByTool = true
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Reconcile one opaque entry at an await boundary. Terminal facts win over
|
|
387
|
+
* whatever the authoritative read now says, and `watching` is reserved for
|
|
388
|
+
* the SAME handle that is still active. Callers never re-implement either
|
|
389
|
+
* identity rule or mark terminal episodes themselves.
|
|
390
|
+
*
|
|
391
|
+
* @param {WatchEntry} entry
|
|
392
|
+
* @returns {WatchOutcome}
|
|
393
|
+
*/
|
|
394
|
+
function reconcile(entry) {
|
|
395
|
+
const record = recordOf(entry)
|
|
396
|
+
if (record.state === 'hit') {
|
|
397
|
+
report(entry)
|
|
398
|
+
return { state: 'released' }
|
|
399
|
+
}
|
|
400
|
+
if (record.state === 'reset') {
|
|
401
|
+
report(entry)
|
|
402
|
+
return { state: 'reset' }
|
|
403
|
+
}
|
|
404
|
+
if (record.state === 'self') {
|
|
405
|
+
report(entry)
|
|
406
|
+
return { state: 'self', raced: true }
|
|
407
|
+
}
|
|
408
|
+
if (record.state === 'watching' && active.get(keyOf(record.sessionId, record.path)) === entry) {
|
|
409
|
+
return { state: 'watching' }
|
|
410
|
+
}
|
|
411
|
+
return { state: 'cancelled' }
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Run the complete establishment episode after registration. The read is
|
|
416
|
+
* shared by shareStatus; every continuation reconciles the same entry before
|
|
417
|
+
* trusting a reply or failure. Only a plain, still-active wait may be removed
|
|
418
|
+
* by a late status verdict, and removal is conditional on that exact handle.
|
|
419
|
+
*
|
|
420
|
+
* @param {WatchEntry} entry
|
|
421
|
+
* @param {() => any} run the injected authoritative read
|
|
422
|
+
* @param {WatchStatusOptions} options
|
|
423
|
+
* @returns {Promise<WatchOutcome>}
|
|
424
|
+
*/
|
|
425
|
+
async function establish(entry, run, options) {
|
|
426
|
+
const record = recordOf(entry)
|
|
427
|
+
/** @type {any} */
|
|
428
|
+
let reply
|
|
429
|
+
try {
|
|
430
|
+
reply = await shareStatus(entry, run)
|
|
431
|
+
} catch (error) {
|
|
432
|
+
const terminal = reconcile(entry)
|
|
433
|
+
if (terminal.state !== 'watching') return terminal
|
|
434
|
+
cancel(record.sessionId, record.path, entry)
|
|
435
|
+
if (isTransport(error)) return { state: 'transport', error }
|
|
436
|
+
throw error
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
let outcome = reconcile(entry)
|
|
440
|
+
if (outcome.state !== 'watching') return outcome
|
|
441
|
+
|
|
442
|
+
const leases = Array.isArray(reply?.leases) ? reply.leases : []
|
|
443
|
+
if (leases.length === 0) {
|
|
444
|
+
cancel(record.sessionId, record.path, entry)
|
|
445
|
+
return { state: 'free' }
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const holder = leases[0]?.owner ?? {}
|
|
449
|
+
const mine = (typeof holder.id === 'string' && holder.id.length > 0 && holder.id === options.owner.id)
|
|
450
|
+
|| (typeof holder.session === 'string' && holder.session.length > 0 && holder.session === options.owner.session)
|
|
451
|
+
if (mine) {
|
|
452
|
+
cancel(record.sessionId, record.path, entry, 'self')
|
|
453
|
+
return { state: 'self' }
|
|
454
|
+
}
|
|
455
|
+
if (options.supportsRelease() !== true) {
|
|
456
|
+
cancel(record.sessionId, record.path, entry)
|
|
457
|
+
return { state: 'unsupported' }
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// A capability probe is injectable and may synchronously route an event.
|
|
461
|
+
// Reconcile once more before claiming that this exact wait is still live.
|
|
462
|
+
outcome = reconcile(entry)
|
|
463
|
+
if (outcome.state !== 'watching') return outcome
|
|
464
|
+
return { state: 'watching', holder }
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Share the whole establishment attempt, not merely its read. In particular,
|
|
469
|
+
* two overlapping callers cannot turn one free/unsupported/error verdict into
|
|
470
|
+
* a second contradictory cancelled verdict. A watching attempt is cleared so
|
|
471
|
+
* idempotent later calls still refresh the authority; terminal attempts remain
|
|
472
|
+
* attached only to their private, now-inactive episode record.
|
|
473
|
+
*
|
|
474
|
+
* @param {WatchEntry} entry
|
|
475
|
+
* @param {() => any} run
|
|
476
|
+
* @param {WatchStatusOptions} options
|
|
477
|
+
* @returns {Promise<WatchOutcome>}
|
|
478
|
+
*/
|
|
479
|
+
function status(entry, run, options) {
|
|
480
|
+
const record = recordOf(entry)
|
|
481
|
+
if (record.establishFlight !== null) return record.establishFlight
|
|
482
|
+
/** @type {Promise<WatchOutcome>} */
|
|
483
|
+
const flight = establish(entry, run, options).finally(() => {
|
|
484
|
+
if (record.establishFlight === flight && record.state === 'watching') record.establishFlight = null
|
|
485
|
+
})
|
|
486
|
+
record.establishFlight = flight
|
|
303
487
|
return flight
|
|
304
488
|
}
|
|
305
489
|
|
|
@@ -321,7 +505,7 @@ export function createWatchCoordinator() {
|
|
|
321
505
|
if (expected !== undefined && entry !== expected) return undefined
|
|
322
506
|
active.delete(key)
|
|
323
507
|
if (pendingDelivery.delete(entry)) cancelTimer(entry)
|
|
324
|
-
entry.state = state
|
|
508
|
+
recordOf(entry).state = state
|
|
325
509
|
return entry
|
|
326
510
|
}
|
|
327
511
|
|
|
@@ -346,7 +530,7 @@ export function createWatchCoordinator() {
|
|
|
346
530
|
const activeEntry = active.get(key)
|
|
347
531
|
if (activeEntry !== undefined) {
|
|
348
532
|
active.delete(key)
|
|
349
|
-
activeEntry.state = 'self'
|
|
533
|
+
recordOf(activeEntry).state = 'self'
|
|
350
534
|
ended = ended ?? activeEntry
|
|
351
535
|
}
|
|
352
536
|
return ended
|
|
@@ -364,9 +548,10 @@ export function createWatchCoordinator() {
|
|
|
364
548
|
/** @type {WatchEntry[]} */
|
|
365
549
|
const consumed = []
|
|
366
550
|
for (const [key, entry] of [...active]) {
|
|
367
|
-
|
|
551
|
+
const record = recordOf(entry)
|
|
552
|
+
if (record.path !== path) continue
|
|
368
553
|
active.delete(key)
|
|
369
|
-
|
|
554
|
+
record.state = 'hit'
|
|
370
555
|
scheduleNotice(entry)
|
|
371
556
|
consumed.push(entry)
|
|
372
557
|
}
|
|
@@ -383,7 +568,7 @@ export function createWatchCoordinator() {
|
|
|
383
568
|
const entries = [...active.values()]
|
|
384
569
|
active.clear()
|
|
385
570
|
for (const entry of entries) {
|
|
386
|
-
entry.state = 'reset'
|
|
571
|
+
recordOf(entry).state = 'reset'
|
|
387
572
|
scheduleNotice(entry)
|
|
388
573
|
}
|
|
389
574
|
return entries
|
|
@@ -399,9 +584,10 @@ export function createWatchCoordinator() {
|
|
|
399
584
|
/** @type {WatchEntry[]} */
|
|
400
585
|
const cancelled = []
|
|
401
586
|
for (const [key, entry] of [...active]) {
|
|
402
|
-
|
|
587
|
+
const record = recordOf(entry)
|
|
588
|
+
if (record.sessionId !== sessionId) continue
|
|
403
589
|
active.delete(key)
|
|
404
|
-
|
|
590
|
+
record.state = 'cancelled'
|
|
405
591
|
cancelled.push(entry)
|
|
406
592
|
}
|
|
407
593
|
for (const entry of [...pendingDelivery]) {
|
|
@@ -423,7 +609,7 @@ export function createWatchCoordinator() {
|
|
|
423
609
|
active.clear()
|
|
424
610
|
for (const entry of [...pendingDelivery]) cancelTimer(entry)
|
|
425
611
|
pendingDelivery.clear()
|
|
426
|
-
for (const entry of entries) entry.state = 'cancelled'
|
|
612
|
+
for (const entry of entries) recordOf(entry).state = 'cancelled'
|
|
427
613
|
return entries
|
|
428
614
|
}
|
|
429
615
|
|
|
@@ -458,6 +644,9 @@ export function createWatchCoordinator() {
|
|
|
458
644
|
register,
|
|
459
645
|
peek,
|
|
460
646
|
shareStatus,
|
|
647
|
+
status,
|
|
648
|
+
reconcile,
|
|
649
|
+
report,
|
|
461
650
|
cancel,
|
|
462
651
|
settleSelf,
|
|
463
652
|
consumePath,
|